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 5F10845834; Wed, 21 Aug 2024 18:27:39 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6575C427D4; Wed, 21 Aug 2024 18:27:32 +0200 (CEST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mails.dpdk.org (Postfix) with ESMTP id 0A01F427D2 for ; Wed, 21 Aug 2024 18:27:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724257650; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EfHaGRWPrItlsX+vWzcOYgOhCBiuDhi1LJZpDf+C2V8=; b=Iax5WVxj5/shXYvTeosPMl+ZbeZnQ1H0RXSDf2HlIVrnlmytU/vKdISvvNU9eqOkPBBI/7 3UmAcw99E2eEEFKimW0qohzr0HuJ84k7YJ/aqjBYvPdEeLliTeqkur+LxtGUd4qTV6JSyB Z+UCy6MVflbGU1L+y5+V3pASeqEe5jA= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-674-kjqLCdBQOrq19iu0avW2qQ-1; Wed, 21 Aug 2024 12:27:29 -0400 X-MC-Unique: kjqLCdBQOrq19iu0avW2qQ-1 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 345E9187370B for ; Wed, 21 Aug 2024 16:27:18 +0000 (UTC) Received: from localhost.localdomain (unknown [10.39.208.21]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A81221978F67; Wed, 21 Aug 2024 16:26:35 +0000 (UTC) From: Robin Jarry To: dev@dpdk.org Subject: [PATCH dpdk v1 06/15] net: add ipv6 address utilities Date: Wed, 21 Aug 2024 18:25:23 +0200 Message-ID: <20240821162516.610624-23-rjarry@redhat.com> In-Reply-To: <20240821162516.610624-17-rjarry@redhat.com> References: <20240821162516.610624-17-rjarry@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true 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 utility functions that use the previously introduced IPv6 address structure. Add basic unit tests to ensure everything works as expected. These functions will be used in the next commits to replace private and/or duplicated functions. Signed-off-by: Robin Jarry --- app/test/meson.build | 1 + app/test/test_net_ipv6.c | 129 +++++++++++++++++++++++++++++++++++++++ lib/net/rte_ip6.h | 112 +++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 app/test/test_net_ipv6.c diff --git a/app/test/meson.build b/app/test/meson.build index e29258e6ec05..f5276e28c3b9 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -130,6 +130,7 @@ source_file_deps = { 'test_metrics.c': ['metrics'], 'test_mp_secondary.c': ['hash'], 'test_net_ether.c': ['net'], + 'test_net_ipv6.c': ['net'], 'test_pcapng.c': ['ethdev', 'net', 'pcapng', 'bus_vdev'], 'test_pdcp.c': ['eventdev', 'pdcp', 'net', 'timer', 'security'], 'test_pdump.c': ['pdump'] + sample_packet_forward_deps, diff --git a/app/test/test_net_ipv6.c b/app/test/test_net_ipv6.c new file mode 100644 index 000000000000..c2b42d67285e --- /dev/null +++ b/app/test/test_net_ipv6.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2024 Robin Jarry + */ + +#include + +#include "test.h" + +static const struct rte_ipv6_addr bcast_addr = { + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +}; +static const struct rte_ipv6_addr zero_addr = { 0 }; + +static int +test_ipv6_addr_mask(void) +{ + const struct rte_ipv6_addr masked_3 = { + "\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + }; + const struct rte_ipv6_addr masked_42 = { + "\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + }; + const struct rte_ipv6_addr masked_85 = { + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00" + }; + const struct rte_ipv6_addr masked_127 = { + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe" + }; + struct rte_ipv6_addr ip; + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 0); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &zero_addr), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&zero_addr), 0, ""); + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 3); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &masked_3), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&masked_3), 3, ""); + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 42); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &masked_42), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&masked_42), 42, ""); + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 85); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &masked_85), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&masked_85), 85, ""); + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 127); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &masked_127), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&masked_127), 127, ""); + + ip = bcast_addr; + rte_ipv6_addr_mask(&ip, 128); + TEST_ASSERT(rte_ipv6_addr_eq(&ip, &bcast_addr), ""); + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&bcast_addr), 128, ""); + + const struct rte_ipv6_addr holed_mask = { + "\xff\xff\xff\xff\xff\xff\xef\xff\xff\xff\xff\xff\xff\xff\xff\xff" + }; + TEST_ASSERT_EQUAL(rte_ipv6_mask_depth(&holed_mask), 51, ""); + + return TEST_SUCCESS; +} + +static int +test_ipv6_addr_eq_prefix(void) +{ + struct rte_ipv6_addr ip1 = { + "\x2a\x01\xcb\x00\x02\x54\x33\x00\x1b\x9f\x80\x71\x67\xcd\xbf\x20" + }; + struct rte_ipv6_addr ip2 = { + "\x2a\x01\xcb\x00\x02\x54\x33\x00\x62\x39\xe1\xf4\x7a\x0b\x23\x71" + }; + struct rte_ipv6_addr ip3 = { + "\xfd\x10\x00\x39\x02\x08\x00\x01\x00\x00\x00\x00\x00\x00\x10\x08" + }; + + TEST_ASSERT(rte_ipv6_addr_eq_prefix(&ip1, &ip2, 1), ""); + TEST_ASSERT(rte_ipv6_addr_eq_prefix(&ip1, &ip2, 37), ""); + TEST_ASSERT(rte_ipv6_addr_eq_prefix(&ip1, &ip2, 64), ""); + TEST_ASSERT(!rte_ipv6_addr_eq_prefix(&ip1, &ip2, 112), ""); + TEST_ASSERT(rte_ipv6_addr_eq_prefix(&ip1, &ip3, 0), ""); + TEST_ASSERT(!rte_ipv6_addr_eq_prefix(&ip1, &ip3, 13), ""); + + return TEST_SUCCESS; +} + +static int +test_ipv6_addr_kind(void) +{ + TEST_ASSERT(rte_ipv6_addr_is_unspec(&zero_addr), ""); + + struct rte_ipv6_addr ucast = { + "\x2a\x01\xcb\x00\x02\x54\x33\x00\x62\x39\xe1\xf4\x7a\x0b\x23\x71" + }; + TEST_ASSERT(!rte_ipv6_addr_is_unspec(&ucast), ""); + + struct rte_ipv6_addr mcast = { + "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + }; + TEST_ASSERT(!rte_ipv6_addr_is_unspec(&mcast), ""); + + struct rte_ipv6_addr lo = { + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + }; + TEST_ASSERT(!rte_ipv6_addr_is_unspec(&lo), ""); + + struct rte_ipv6_addr local = { + "\xfe\x80\x00\x00\x00\x00\x00\x00\x5a\x84\xc5\x2c\x6a\xef\x46\x39" + }; + TEST_ASSERT(!rte_ipv6_addr_is_unspec(&local), ""); + + return TEST_SUCCESS; +} + +static int +test_net_ipv6(void) +{ + TEST_ASSERT_SUCCESS(test_ipv6_addr_mask(), ""); + TEST_ASSERT_SUCCESS(test_ipv6_addr_eq_prefix(), ""); + TEST_ASSERT_SUCCESS(test_ipv6_addr_kind(), ""); + return TEST_SUCCESS; +} + +REGISTER_FAST_TEST(net_ipv6_autotest, true, true, test_net_ipv6); diff --git a/lib/net/rte_ip6.h b/lib/net/rte_ip6.h index 58cab86895eb..6bc18a1c8dd6 100644 --- a/lib/net/rte_ip6.h +++ b/lib/net/rte_ip6.h @@ -16,6 +16,7 @@ */ #include +#include #ifdef RTE_EXEC_ENV_WINDOWS #include @@ -29,6 +30,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -45,6 +47,116 @@ struct rte_ipv6_addr { unsigned char a[RTE_IPV6_ADDR_SIZE]; }; +/** + * Copy an IPv6 address into another one. + * + * @param dst + * The address into which to copy data. + * @param src + * The address from which to copy. + */ +static inline void +rte_ipv6_addr_cpy(struct rte_ipv6_addr *dst, const struct rte_ipv6_addr *src) +{ + rte_memcpy(dst, src, sizeof(*dst)); +} + +/** + * Check if two IPv6 Addresses are equal. + */ +static inline bool +rte_ipv6_addr_eq(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b) +{ + return memcmp(a, b, sizeof(*a)) == 0; +} + +/** + * Mask an IPv6 address using the specified depth. + * + * Leave untouched one bit per unit in the depth variable and set the rest to 0. + * + * @param ip + * The address to mask. + * @param depth + * All bits starting from this bit number will be set to zero. + */ +static inline void +rte_ipv6_addr_mask(struct rte_ipv6_addr *ip, uint8_t depth) +{ + if (depth < RTE_IPV6_MAX_DEPTH) { + uint8_t d = depth / 8; + uint8_t mask = ~(UINT8_MAX >> (depth % 8)); + ip->a[d] &= mask; + d++; + memset(&ip->a[d], 0, sizeof(*ip) - d); + } +} + +/** + * Check if two IPv6 addresses belong to the same network prefix. + * + * @param a + * The first address or network. + * @param b + * The second address or network. + * @param depth + * The network prefix length. + */ +static inline bool +rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth) +{ + if (depth < RTE_IPV6_MAX_DEPTH) { + uint8_t d = depth / 8; + uint8_t mask = ~(UINT8_MAX >> (depth % 8)); + + if ((a->a[d] ^ b->a[d]) & mask) + return false; + + return memcmp(a, b, d) == 0; + } + return rte_ipv6_addr_eq(a, b); +} + +/** + * Get the depth of a given IPv6 address mask. + * + * This function does not handle masks with "holes" and will return the number + * of consecurive bits set to 1 starting from the beginning of the mask. + * + * @param mask + * The address mask. + */ +static inline uint8_t +rte_ipv6_mask_depth(const struct rte_ipv6_addr *mask) +{ + uint8_t depth = 0; + + for (int i = 0; i < RTE_IPV6_ADDR_SIZE; i++) { + uint8_t m = mask->a[i]; + if (m == 0xff) { + depth += 8; + } else { + while (m & 0x80) { + m <<= 1; + depth++; + } + break; + } + } + + return depth; +} + +/** + * Check if an IPv6 address is unspecified as defined in RFC 4291, section 2.5.2. + */ +static inline bool +rte_ipv6_addr_is_unspec(const struct rte_ipv6_addr *ip) +{ + static const struct rte_ipv6_addr unspec = {0}; + return rte_ipv6_addr_eq(ip, &unspec); +} + /** * IPv6 Header */ -- 2.46.0