From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id CDAF0459B0;
	Tue, 17 Sep 2024 05:31:53 +0200 (CEST)
Received: from mails.dpdk.org (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id 52799402E3;
	Tue, 17 Sep 2024 05:31:35 +0200 (CEST)
Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com
 [209.85.214.172])
 by mails.dpdk.org (Postfix) with ESMTP id F3B6740281
 for <dev@dpdk.org>; Tue, 17 Sep 2024 05:31:30 +0200 (CEST)
Received: by mail-pl1-f172.google.com with SMTP id
 d9443c01a7336-2068bee21d8so51463835ad.2
 for <dev@dpdk.org>; Mon, 16 Sep 2024 20:31:30 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1726543890;
 x=1727148690; darn=dpdk.org; 
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=pl1l1tJQ2ZlZgU57jaZlCmKOkJ5NKuAcvPPs3gTomuU=;
 b=Mnh5PzNxJwkMkAO9AyN7k/oOlANrZ690yhXn5m2OD8Bjed42umOY3iJLGN/dkc834O
 OCl4SmXYPFgsnGvJHuH7j52Xvpq4Vy7ynSvi+b5BRUshHFJqFIsctRL42yzfbPEDmf8g
 SWblWMhqY3hbt8VI8BRudHqkcKXMpaV8fDNWvZ6l5hS6wJncU7jJOVamS57Ovt+pL5SB
 iiOnkeK32mL+r0vAHjTp+McFF/hyDazZgnfK88wLH5jSlHR/I+vLFeM6PLld0qTQaFgR
 FoyGG+uxlH5Jnq++cvZQ+nhV4h6vOMmS/f3H4NkolYOpEIJgz1PyFQbW55gJUpcMBwjq
 9XhQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1726543890; x=1727148690;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=pl1l1tJQ2ZlZgU57jaZlCmKOkJ5NKuAcvPPs3gTomuU=;
 b=frx7ntm3FCDgkPHFQR1gf6yAaPoGiu+hc4Y2iGzRbajldzOIUTob+LEWM25WCM++Nw
 CYyKZorEzhhPpgjb6qlOjfo3w+GJV3r/BhnNuzZ/KhaqV9Zenu5l/XMjzVwW918t+7hq
 GBjcGR03SGwR/KvJ8R16OUqvCO0k6YIuKPBD6I1+JkoOpZwQ280nTUasGpW0g4uBELOu
 T+VIc6Pk+HZUCXzIOQZwqkNdHtCLahG7Zw+w/gkI/PZh04uZBWiIjZvOe3pZOPxILy1z
 JY0PQPhkGUi0pHVJNOI1p6WIhxcvWnH6GnbllopopN/Xp3ql98gmD3FAA2il7SkAU0MG
 R+VA==
X-Gm-Message-State: AOJu0Yw56oQNOm5uARq9hKTzK6KDCaGW4ttkHbOGdyLMpVb4pWoiH+iE
 GT5xsNItlf2UHSC4LfaleocbUbNbeniPqaiGw9G6lZO6/IcKPfLbjsojsamTwYA88LHZ0AQ23t7
 +
X-Google-Smtp-Source: AGHT+IHiUTqQqCpo+ZZtfiEUByhSIwwsqgOupU7O9P6RIjiaRpcKF0FXm4ZxNN24OLYpymr4TWpXkw==
X-Received: by 2002:a17:902:f70c:b0:206:8acc:8871 with SMTP id
 d9443c01a7336-2076e39c331mr229654635ad.31.1726543890077; 
 Mon, 16 Sep 2024 20:31:30 -0700 (PDT)
Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-2079473d05dsm42647735ad.287.2024.09.16.20.31.29
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Mon, 16 Sep 2024 20:31:29 -0700 (PDT)
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH v8 3/7] test: add test for packet dissector
Date: Mon, 16 Sep 2024 20:28:00 -0700
Message-ID: <20240917033117.66346-4-stephen@networkplumber.org>
X-Mailer: git-send-email 2.45.2
In-Reply-To: <20240917033117.66346-1-stephen@networkplumber.org>
References: <20240312220129.70667-1-stephen@networkplumber.org>
 <20240917033117.66346-1-stephen@networkplumber.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org

Add some tests for new packet dissector.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/meson.build    |   1 +
 app/test/test_dissect.c | 302 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 303 insertions(+)
 create mode 100644 app/test/test_dissect.c

diff --git a/app/test/meson.build b/app/test/meson.build
index e29258e6ec..9cd2051320 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -62,6 +62,7 @@ source_file_deps = {
     'test_debug.c': [],
     'test_devargs.c': ['kvargs'],
     'test_dispatcher.c': ['dispatcher'],
+    'test_dissect.c': ['net'],
     'test_distributor.c': ['distributor'],
     'test_distributor_perf.c': ['distributor'],
     'test_dmadev.c': ['dmadev', 'bus_vdev'],
diff --git a/app/test/test_dissect.c b/app/test/test_dissect.c
new file mode 100644
index 0000000000..08734134d5
--- /dev/null
+++ b/app/test/test_dissect.c
@@ -0,0 +1,302 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Stephen Hemminger <stephen@networkplumber.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rte_bus_vdev.h>
+#include <rte_dissect.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_mbuf.h>
+#include <rte_net.h>
+#include <rte_random.h>
+#include <rte_udp.h>
+#include <rte_vxlan.h>
+
+#include "test.h"
+
+#ifndef LINE_MAX
+#define LINE_MAX	2048
+#endif
+
+#define TOTAL_PACKETS	100
+#define PACKET_LEN	1000
+#define ETH_IP_UDP_VXLAN_SIZE (sizeof(struct rte_ether_hdr) + \
+			       sizeof(struct rte_ipv4_hdr) + \
+			       sizeof(struct rte_udp_hdr) + \
+			       sizeof(struct rte_vxlan_hdr))
+
+
+static uint16_t port_id;
+static const char null_dev[] = "net_null0";
+
+static void
+add_header(struct rte_mbuf *mb, uint32_t plen,
+	   rte_be16_t src_port, rte_be16_t dst_port)
+{
+	struct {
+		struct rte_ether_hdr eth;
+		struct rte_ipv4_hdr ip;
+		struct rte_udp_hdr udp;
+	} pkt = {
+		.eth = {
+			.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+			.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4),
+		},
+		.ip = {
+			.version_ihl = RTE_IPV4_VHL_DEF,
+			.time_to_live = 1,
+			.next_proto_id = IPPROTO_UDP,
+			.src_addr = rte_cpu_to_be_32(RTE_IPV4_LOOPBACK),
+			.dst_addr = rte_cpu_to_be_32(RTE_IPV4_BROADCAST),
+		},
+		.udp = {
+			.dst_port = dst_port,
+			.src_port = src_port,
+		},
+	};
+
+	rte_eth_random_addr(pkt.eth.src_addr.addr_bytes);
+
+	plen -= sizeof(struct rte_ether_hdr);
+	pkt.ip.total_length = rte_cpu_to_be_16(plen);
+	pkt.ip.hdr_checksum = rte_ipv4_cksum(&pkt.ip);
+
+	plen -= sizeof(struct rte_ipv4_hdr);
+	pkt.udp.dgram_len = rte_cpu_to_be_16(plen);
+
+	/* Copy header into mbuf */
+	memcpy(rte_pktmbuf_append(mb, sizeof(pkt)), &pkt, sizeof(pkt));
+}
+
+static void
+add_vxlan(struct rte_mbuf *mb, rte_be32_t vni)
+{
+	struct rte_vxlan_hdr *vxlan;
+
+	vxlan = (struct rte_vxlan_hdr *)rte_pktmbuf_append(mb, sizeof(*vxlan));
+	memset(vxlan, 0, sizeof(*vxlan));
+	vxlan->flag_i = 1;
+	vxlan->vx_vni = vni;
+}
+
+
+static void
+fill_data(struct rte_mbuf *mb, uint32_t len)
+{
+	uint32_t i;
+	char *ptr = rte_pktmbuf_append(mb, len);
+	char c = '!';
+
+	/* traditional barber pole pattern */
+	for (i = 0; i < len; i++) {
+		ptr[i] = c++;
+		if (c == 0x7f)
+			c = '!';
+	}
+}
+
+static void
+mbuf_prep(struct rte_mbuf *mb, uint8_t buf[], uint32_t buf_len)
+{
+	mb->buf_addr = buf;
+	rte_mbuf_iova_set(mb, (uintptr_t)buf);
+	mb->buf_len = buf_len;
+	rte_mbuf_refcnt_set(mb, 1);
+
+	/* set pool pointer to dummy value, test doesn't use it */
+	mb->pool = (void *)buf;
+
+	rte_pktmbuf_reset(mb);
+}
+
+static int
+test_setup(void)
+{
+	port_id = rte_eth_dev_count_avail();
+
+	/* Make a dummy null device to snoop on */
+	if (rte_vdev_init(null_dev, NULL) != 0) {
+		fprintf(stderr, "Failed to create vdev '%s'\n", null_dev);
+		goto fail;
+	}
+	return 0;
+
+fail:
+	rte_vdev_uninit(null_dev);
+	return -1;
+}
+
+static void
+test_cleanup(void)
+{
+	rte_vdev_uninit(null_dev);
+}
+
+
+static int
+test_simple(void)
+{
+	struct rte_mbuf mb;
+	uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE];
+	uint32_t data_len = PACKET_LEN;
+	rte_be16_t src_port = rte_rand_max(UINT16_MAX);
+	const rte_be16_t dst_port = rte_cpu_to_be_16(9); /* Discard port */
+	char obuf[LINE_MAX] = { };
+	char result[LINE_MAX] = { };
+	int ret;
+
+	/* make a dummy packet */
+	mbuf_prep(&mb, buf, sizeof(buf));
+	add_header(&mb, data_len, src_port, dst_port);
+	fill_data(&mb, data_len - mb.data_off);
+
+	/* construct the expected result */
+	int len = snprintf(result, sizeof(result),
+			   "127.0.0.1 → 224.0.0.0 UDP 966 %u → 9",
+			   rte_be_to_cpu_16(src_port));
+
+	ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0);
+	TEST_ASSERT(ret > 0, "Dissect returned: %d", ret);
+
+	TEST_ASSERT_BUFFERS_ARE_EQUAL(obuf, result, len,
+				      "Dissect string differs:\nexpect \"%s\"\n   got \"%s\"",
+				      result, obuf);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_buffer(void)
+{
+	struct rte_mbuf mb;
+	uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE];
+	uint32_t data_len = PACKET_LEN;
+	rte_be16_t src_port = rte_rand_max(UINT16_MAX);
+	const rte_be16_t dst_port = rte_cpu_to_be_16(9); /* Discard port */
+	char *obuf = NULL;
+	char result[LINE_MAX] = { };
+	int ret;
+
+	/* make a dummy packet */
+	mbuf_prep(&mb, buf, sizeof(buf));
+	add_header(&mb, data_len, src_port, dst_port);
+	fill_data(&mb, data_len - mb.data_off);
+
+	/* construct the expected result */
+	int len = snprintf(result, sizeof(result),
+			   "127.0.0.1 → 224.0.0.0 UDP 966 %u → 9",
+			   rte_be_to_cpu_16(src_port));
+
+	/* call rte_dissect first to determine buffer length needed. */
+	ret = rte_dissect_mbuf(obuf, 0, &mb, 0);
+	TEST_ASSERT(ret == len, "Dissect with NULL returned %d not %d", ret, len);
+
+	size_t size = (size_t) ret + 1;      /* One extra byte for '\0' */
+	obuf = malloc(size);
+	TEST_ASSERT_NOT_NULL(obuf, "Malloc for buf failed");
+
+	ret = rte_dissect_mbuf(obuf, size, &mb, 0);
+	TEST_ASSERT(ret == len, "Dissect with buffer returned %d not %d", ret, len);
+
+	TEST_ASSERT_BUFFERS_ARE_EQUAL(obuf, result, len,
+				      "Dissect string differs:\nexpect \"%s\"\n   got \"%s\"",
+				      result, obuf);
+	free(obuf);
+	return TEST_SUCCESS;
+}
+
+static int
+test_truncated(void)
+{
+	struct rte_mbuf mb;
+	uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE];
+	uint32_t pkt_len, data_len = PACKET_LEN;
+	rte_be16_t dst_port = rte_cpu_to_be_16(RTE_VXLAN_DEFAULT_PORT);
+	char obuf[LINE_MAX];
+	int ret;
+
+	/* make a really nested vxlan packet */
+	mbuf_prep(&mb, buf, sizeof(buf));
+	pkt_len = data_len;
+	do {
+		rte_be16_t src_port = rte_rand_max(UINT16_MAX);
+		uint32_t vni = rte_rand_max(1ul << 24);
+
+		add_header(&mb, data_len, src_port, dst_port);
+		add_vxlan(&mb, vni);
+		pkt_len -= ETH_IP_UDP_VXLAN_SIZE;
+	} while (pkt_len > ETH_IP_UDP_VXLAN_SIZE);
+
+	fill_data(&mb, pkt_len);
+
+	/* dissect it but snip off some amount of data */
+	for (unsigned int i = 0; i < TOTAL_PACKETS; i++) {
+		uint32_t snaplen = rte_rand_max(pkt_len);
+
+		ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, snaplen);
+		TEST_ASSERT(ret > 0, "Truncated len %u failed: %d",
+				    snaplen, ret);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_fuzz(void)
+{
+	struct rte_mbuf mb;
+	uint8_t buf[RTE_MBUF_DEFAULT_BUF_SIZE];
+	uint32_t data_len = PACKET_LEN;
+	const rte_be16_t dst_port = rte_cpu_to_be_16(rte_rand_max(1024));
+	const rte_be16_t src_port = rte_rand_max(UINT16_MAX);
+	char obuf[LINE_MAX];
+	int ret;
+
+	/* make a dummy packet */
+	mbuf_prep(&mb, buf, sizeof(buf));
+	add_header(&mb, data_len, src_port, dst_port);
+	fill_data(&mb, data_len - mb.data_off);
+
+	/* randomly flip bits in it */
+	for (unsigned int i = 0; i < TOTAL_PACKETS; i++) {
+		uint32_t bit = rte_rand_max(data_len) * 8;
+		uint8_t *bp = buf + bit / 8;
+		uint8_t mask = 1u << (bit % 8);
+
+		/* twiddle one bit */
+		*bp ^= mask;
+		ret = rte_dissect_mbuf(obuf, sizeof(obuf), &mb, 0);
+		TEST_ASSERT(ret > 0, "Fuzz bit %u failed", bit);
+		*bp ^= mask;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static struct
+unit_test_suite test_dissect_suite  = {
+	.setup = test_setup,
+	.teardown = test_cleanup,
+	.suite_name = "Test Dissect Unit Test Suite",
+	.unit_test_cases = {
+		TEST_CASE(test_simple),
+		TEST_CASE(test_buffer),
+		TEST_CASE(test_truncated),
+		TEST_CASE(test_fuzz),
+		TEST_CASES_END()
+	}
+};
+
+static int
+test_dissect(void)
+{
+	return unit_test_suite_runner(&test_dissect_suite);
+}
+
+REGISTER_FAST_TEST(dissect_autotest, true, true, test_dissect);
-- 
2.45.2