From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0A6CA45BE5; Mon, 28 Oct 2024 03:22:09 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E9F5F4068A; Mon, 28 Oct 2024 03:21:54 +0100 (CET) Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) by mails.dpdk.org (Postfix) with ESMTP id E21A440655 for ; Mon, 28 Oct 2024 03:21:44 +0100 (CET) Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-20c8c50fdd9so29490515ad.0 for ; Sun, 27 Oct 2024 19:21:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730082104; x=1730686904; 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=ZVRlP9OcpXv3Wy8Rp3wfMvs8R4zhfL0FFcJBSTuQlXk=; b=0FkSYc2ZUkT2ja+CnJ/VbPlhSYOxpfpeBmkEA+9CsFxbJtlwrF+qTOIA05BAvfW06R Pyk5PWCLgw6byOh/Nsc4/gks+mX87JREr8ERETzdTjAYUWJlk2LlT7LNIq5WRq3v9NO/ JRN5p9IwKaNsyztMKRTnwf+AfNpnNfSvx8KkqBxJkp/oznfQXpGxZT+ocV/B+nhttyd9 nY7hCY1Rlu30+C4SxR8UJban6fh19eRY6xbdq9uPQRxRrYCK9NmUNjSemFHjzhDEWK3I Hg4o1yENpr0mTx2dRKvOOtjaCKlIJ+cmxlZE6NKhjLc0HXJHNgzcwStIGEpOAVBgCKPS Is0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730082104; x=1730686904; 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=ZVRlP9OcpXv3Wy8Rp3wfMvs8R4zhfL0FFcJBSTuQlXk=; b=QmP9B8W7lmHYhzB4QY+YZ0LNyeMUdbSMibt32yk3TpPFic8CDRc5TDTgh/6uLWUU84 2Xg5/VeczbCRITaB3cK2UzNkpbdKxnT5SVNATsPWUQUZiUiVHAX68d3tPfU9HeIGb63X D3PUVQSFkOWEvMqh/KwM9OvHgRlpHowLKUKHsR4gMzRCDrrmUzg/M25TdjDmOJldov1D lmXjkaNw/rgXV9wL4MI2BL3ZHIjLCmktBUMhSv6s1D2ZFsqY2eMQ5pjOILAUqoVHugtN sknCFsT30DXus4GgAdj5fPA8pWrb6kcjYX2xt8FaCYxY+olMPUXfgPIRQZVTx74dCkwu G6UA== X-Gm-Message-State: AOJu0Yz7hxd2nVuKAbQKiEcG4CT2QBm3byZJd7oUAWIDGIjW4yJRe2kl JY3axJKd7FclQujFKd5EJZe4seMJTSCwnO49TvbzwwEmivi7qeb37psFqUPRJoq9X1/FVJEdgsm 5z78= X-Google-Smtp-Source: AGHT+IHb/CGjCKHKIFU0noX/REgik3rVUVIv4+beo67Wla5x0tKbqO+aKTMoqetuprvATVlLZXbqew== X-Received: by 2002:a17:902:d4c4:b0:20c:b6cf:f450 with SMTP id d9443c01a7336-20fb8ab9eecmr194141525ad.29.1730082104018; Sun, 27 Oct 2024 19:21:44 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bc04b8bbsm41095615ad.244.2024.10.27.19.21.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 19:21:43 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v10 4/8] test: add test for packet dissector Date: Sun, 27 Oct 2024 19:19:30 -0700 Message-ID: <20241028022131.142609-5-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241028022131.142609-1-stephen@networkplumber.org> References: <20240312220129.70667-1-stephen@networkplumber.org> <20241028022131.142609-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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add some tests for new packet dissector. Signed-off-by: Stephen Hemminger --- 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 0f7e11969a..9fa0ad7cfe 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -63,6 +63,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 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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