DPDK 25.03.0-rc0
rte_ip6.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 1982, 1986, 1990, 1993
3 * The Regents of the University of California.
4 * Copyright(c) 2010-2014 Intel Corporation.
5 * Copyright(c) 2014 6WIND S.A.
6 * All rights reserved.
7 */
8
9#ifndef _RTE_IP6_H_
10#define _RTE_IP6_H_
11
18#include <stdint.h>
19#include <string.h>
20
21#ifdef RTE_EXEC_ENV_WINDOWS
22#include <ws2tcpip.h>
23#else
24#include <sys/socket.h>
25#include <sys/types.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <netinet/ip6.h>
29#endif
30
31#include <rte_byteorder.h>
32#include <rte_cksum.h>
33#include <rte_ether.h>
34#include <rte_mbuf.h>
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
43#define RTE_IPV6_ADDR_SIZE 16
44
48#define RTE_IPV6_MAX_DEPTH (RTE_IPV6_ADDR_SIZE * CHAR_BIT)
49
54 uint8_t a[RTE_IPV6_ADDR_SIZE];
55};
56
67static inline bool
68rte_ipv6_addr_eq(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b)
69{
70 return memcmp(a, b, sizeof(*a)) == 0;
71}
72
83static inline void
84rte_ipv6_addr_mask(struct rte_ipv6_addr *ip, uint8_t depth)
85{
86 if (depth < RTE_IPV6_MAX_DEPTH) {
87 unsigned int d = depth / CHAR_BIT;
88 uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
89 ip->a[d] &= mask;
90 d++;
91 while (d < sizeof(*ip))
92 ip->a[d++] = 0;
93 }
94}
95
108static inline bool
109rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth)
110{
111 if (depth < RTE_IPV6_MAX_DEPTH) {
112 unsigned int d = depth / CHAR_BIT;
113 uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
114
115 if ((a->a[d] ^ b->a[d]) & mask)
116 return false;
117
118 return memcmp(a, b, d) == 0;
119 }
120 return rte_ipv6_addr_eq(a, b);
121}
122
131static inline uint8_t
133{
134 uint8_t depth = 0;
135
136 for (unsigned int i = 0; i < RTE_DIM(mask->a); i++) {
137 uint8_t m = mask->a[i];
138 if (m == 0xff) {
139 depth += 8;
140 } else {
141 while (m & 0x80) {
142 m <<= 1;
143 depth++;
144 }
145 break;
146 }
147 }
148
149 return depth;
150}
151
161#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
162#define RTE_IPV6_U16_SPLIT(x) \
163 (uint8_t)((uint16_t)(x) & UINT16_C(0xff)), \
164 (uint8_t)(((uint16_t)(x) >> 8) & UINT16_C(0xff))
165#else
166#define RTE_IPV6_U16_SPLIT(x) \
167 (uint8_t)(((uint16_t)(x) >> 8) & UINT16_C(0xff)), \
168 (uint8_t)((uint16_t)(x) & UINT16_C(0xff))
169#endif
170
179#define RTE_IPV6(a, b, c, d, e, f, g, h) \
180 {{ \
181 RTE_IPV6_U16_SPLIT(a), \
182 RTE_IPV6_U16_SPLIT(b), \
183 RTE_IPV6_U16_SPLIT(c), \
184 RTE_IPV6_U16_SPLIT(d), \
185 RTE_IPV6_U16_SPLIT(e), \
186 RTE_IPV6_U16_SPLIT(f), \
187 RTE_IPV6_U16_SPLIT(g), \
188 RTE_IPV6_U16_SPLIT(h) \
189 }}
190
195#define RTE_IPV6_ADDR_FMT \
196 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
197
210#define RTE_IPV6_ADDR_SPLIT(ip) \
211 ((uint8_t)(ip)->a[0]), \
212 ((uint8_t)(ip)->a[1]), \
213 ((uint8_t)(ip)->a[2]), \
214 ((uint8_t)(ip)->a[3]), \
215 ((uint8_t)(ip)->a[4]), \
216 ((uint8_t)(ip)->a[5]), \
217 ((uint8_t)(ip)->a[6]), \
218 ((uint8_t)(ip)->a[7]), \
219 ((uint8_t)(ip)->a[8]), \
220 ((uint8_t)(ip)->a[9]), \
221 ((uint8_t)(ip)->a[10]), \
222 ((uint8_t)(ip)->a[11]), \
223 ((uint8_t)(ip)->a[12]), \
224 ((uint8_t)(ip)->a[13]), \
225 ((uint8_t)(ip)->a[14]), \
226 ((uint8_t)(ip)->a[15])
227
229#define RTE_IPV6_MASK_FULL \
230 RTE_IPV6(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
231
233#define RTE_IPV6_ADDR_UNSPEC RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
234
243static inline bool
245{
246 const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
247 return rte_ipv6_addr_eq(ip, &unspec);
248}
249
251#define RTE_IPV6_ADDR_LOOPBACK RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 1)
252
262static inline bool
264{
265 struct rte_ipv6_addr loopback = RTE_IPV6_ADDR_LOOPBACK;
266 return rte_ipv6_addr_eq(ip, &loopback);
267}
268
277static inline bool
279{
280 return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0x80;
281}
282
291static inline bool
293{
294 return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0xc0;
295}
296
306static inline bool
308{
309 const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
310 return rte_ipv6_addr_eq_prefix(ip, &unspec, 32) && !rte_ipv6_addr_is_loopback(ip);
311}
312
313#define RTE_IPV6_ADDR_PREFIX_V4MAPPED RTE_IPV6(0, 0, 0, 0, 0, 0xffff, 0, 0)
314
324static inline bool
326{
327 const struct rte_ipv6_addr prefix = RTE_IPV6_ADDR_PREFIX_V4MAPPED;
328 return rte_ipv6_addr_eq_prefix(ip, &prefix, 32);
329}
330
339static inline bool
341{
342 return ip->a[0] == 0xff;
343}
344
362
372static inline enum rte_ipv6_mc_scope
374{
375 if (!rte_ipv6_addr_is_mcast(ip))
377 return (enum rte_ipv6_mc_scope)(ip->a[1] & 0x0f);
378}
379
383#define RTE_IPV6_ADDR_ALLNODES_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 1)
385#define RTE_IPV6_ADDR_ALLNODES_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 1)
387#define RTE_IPV6_ADDR_ALLROUTERS_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 2)
389#define RTE_IPV6_ADDR_ALLROUTERS_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 2)
391#define RTE_IPV6_ADDR_ALLROUTERS_SITE_LOCAL RTE_IPV6(0xff05, 0, 0, 0, 0, 0, 0, 2)
394/*
395 * Generate a link-local IPv6 address from an Ethernet address as specified in
396 * RFC 2464, section 5.
397 *
398 * @param[out] ip
399 * The link-local IPv6 address to generate.
400 * @param[in] mac
401 * An Ethernet address.
402 */
403static inline void
404rte_ipv6_llocal_from_ethernet(struct rte_ipv6_addr *ip, const struct rte_ether_addr *mac)
405{
406 ip->a[0] = 0xfe;
407 ip->a[1] = 0x80;
408 memset(&ip->a[2], 0, 6);
409 ip->a[8] = mac->addr_bytes[0];
410 ip->a[9] = mac->addr_bytes[1];
411 ip->a[10] = mac->addr_bytes[2];
412 ip->a[11] = 0xff;
413 ip->a[12] = 0xfe;
414 ip->a[13] = mac->addr_bytes[3];
415 ip->a[14] = mac->addr_bytes[4];
416 ip->a[15] = mac->addr_bytes[5];
417}
418
428static inline void
430{
431 sol->a[0] = 0xff;
432 sol->a[1] = 0x02;
433 memset(&sol->a[2], 0, 9);
434 sol->a[11] = 0x01;
435 sol->a[12] = 0xff;
436 sol->a[13] = ip->a[13];
437 sol->a[14] = ip->a[14];
438 sol->a[15] = ip->a[15];
439}
440
450static inline void
451rte_ether_mcast_from_ipv6(struct rte_ether_addr *mac, const struct rte_ipv6_addr *ip)
452{
453 mac->addr_bytes[0] = 0x33;
454 mac->addr_bytes[1] = 0x33;
455 mac->addr_bytes[2] = ip->a[12];
456 mac->addr_bytes[3] = ip->a[13];
457 mac->addr_bytes[4] = ip->a[14];
458 mac->addr_bytes[5] = ip->a[15];
459}
460
464struct __rte_aligned(2) rte_ipv6_hdr {
465 union {
466 rte_be32_t vtc_flow;
467 __extension__
468 struct {
469#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
470 uint32_t flow_label:20;
471 uint32_t ecn:2;
472 uint32_t ds:6;
473 uint32_t version:4;
474#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
475 uint32_t version:4;
476 uint32_t ds:6;
477 uint32_t ecn:2;
478 uint32_t flow_label:20;
479#endif
480 };
481 };
482 rte_be16_t payload_len;
483 uint8_t proto;
484 uint8_t hop_limits;
485 struct rte_ipv6_addr src_addr;
486 struct rte_ipv6_addr dst_addr;
488
497static inline int rte_ipv6_check_version(const struct rte_ipv6_hdr *ip)
498{
499 uint8_t version = ((const uint8_t *)ip)[0];
500 if ((version & 0xf0) != 0x60)
501 return -EINVAL;
502 return 0;
503}
504
505/* IPv6 routing extension type definition. */
506#define RTE_IPV6_SRCRT_TYPE_4 4
507
511struct __rte_aligned(2) rte_ipv6_routing_ext {
512 uint8_t next_hdr;
513 uint8_t hdr_len;
514 uint8_t type;
515 uint8_t segments_left;
516 __extension__
517 union {
518 rte_be32_t flags;
519 struct {
520 uint8_t last_entry;
521 uint8_t flag;
522 rte_be16_t tag;
523 };
524 };
525 /* Next are 128-bit IPv6 address fields to describe segments. */
527
528/* IPv6 vtc_flow: IPv / TC / flow_label */
529#define RTE_IPV6_HDR_FL_SHIFT 0
530#define RTE_IPV6_HDR_TC_SHIFT 20
531#define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1)
532#define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT)
533#define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT)
534#define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT)
535#define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK
536
537#define RTE_IPV6_MIN_MTU 1280
555static inline uint16_t
556rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
557{
558 uint32_t sum;
559 struct {
560 rte_be32_t len; /* L4 length. */
561 rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
562 } psd_hdr;
563
564 psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
566 psd_hdr.len = 0;
567 else
568 psd_hdr.len = ipv6_hdr->payload_len;
569
570 sum = __rte_raw_cksum(&ipv6_hdr->src_addr,
571 sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr),
572 0);
573 sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum);
574 return __rte_raw_cksum_reduce(sum);
575}
576
580static inline uint16_t
581__rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
582{
583 uint32_t cksum;
584 uint32_t l4_len;
585
586 l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
587
588 cksum = rte_raw_cksum(l4_hdr, l4_len);
589 cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
590
591 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
592
593 return (uint16_t)cksum;
594}
595
609static inline uint16_t
610rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
611{
612 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
613
614 cksum = ~cksum;
615
616 /*
617 * Per RFC 768: If the computed checksum is zero for UDP,
618 * it is transmitted as all ones
619 * (the equivalent in one's complement arithmetic).
620 */
621 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
622 cksum = 0xffff;
623
624 return cksum;
625}
626
630static inline uint16_t
631__rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
632 const struct rte_ipv6_hdr *ipv6_hdr,
633 uint16_t l4_off)
634{
635 uint16_t raw_cksum;
636 uint32_t cksum;
637
638 if (unlikely(l4_off > m->pkt_len))
639 return 0; /* invalid params, return a dummy value */
640
641 if (rte_raw_cksum_mbuf(m, l4_off, rte_be_to_cpu_16(ipv6_hdr->payload_len), &raw_cksum))
642 return 0;
643
644 cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
645
646 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
647
648 return (uint16_t)cksum;
649}
650
666static inline uint16_t
668 const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
669{
670 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
671
672 cksum = ~cksum;
673
674 /*
675 * Per RFC 768: If the computed checksum is zero for UDP,
676 * it is transmitted as all ones
677 * (the equivalent in one's complement arithmetic).
678 */
679 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
680 cksum = 0xffff;
681
682 return cksum;
683}
684
699static inline int
700rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr,
701 const void *l4_hdr)
702{
703 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
704
705 if (cksum != 0xffff)
706 return -1;
707
708 return 0;
709}
710
727static inline int
729 const struct rte_ipv6_hdr *ipv6_hdr,
730 uint16_t l4_off)
731{
732 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
733
734 if (cksum != 0xffff)
735 return -1;
736
737 return 0;
738}
739
741#define RTE_IPV6_EHDR_MF_SHIFT 0
742#define RTE_IPV6_EHDR_MF_MASK 1
743#define RTE_IPV6_EHDR_FO_SHIFT 3
744#define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
745#define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT)
746
747#define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
748
749#define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK)
750#define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT)
751
752#define RTE_IPV6_SET_FRAG_DATA(fo, mf) \
753 (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
754
755struct __rte_aligned(2) rte_ipv6_fragment_ext {
756 uint8_t next_header;
757 uint8_t reserved;
758 rte_be16_t frag_data;
759 rte_be32_t id;
761
762/* IPv6 fragment extension header size */
763#define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
764
781static inline int
782rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
783{
784 int next_proto;
785
786 switch (proto) {
787 case IPPROTO_AH:
788 next_proto = *p++;
789 *ext_len = (*p + 2) * sizeof(uint32_t);
790 break;
791
792 case IPPROTO_HOPOPTS:
793 case IPPROTO_ROUTING:
794 case IPPROTO_DSTOPTS:
795 next_proto = *p++;
796 *ext_len = (*p + 1) * sizeof(uint64_t);
797 break;
798
799 case IPPROTO_FRAGMENT:
800 next_proto = *p;
801 *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
802 break;
803
804 default:
805 return -EINVAL;
806 }
807
808 return next_proto;
809}
810
811#ifdef __cplusplus
812}
813#endif
814
815#endif /* _RTE_IP6_H_ */
#define unlikely(x)
static uint16_t rte_be_to_cpu_16(rte_be16_t x)
uint32_t rte_be32_t
uint16_t rte_be16_t
static uint16_t rte_raw_cksum(const void *buf, size_t len)
Definition: rte_cksum.h:94
static int rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len, uint16_t *cksum)
Definition: rte_cksum.h:117
#define __rte_packed
Definition: rte_common.h:108
#define RTE_DIM(a)
Definition: rte_common.h:793
static bool rte_ipv6_addr_is_linklocal(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:278
static bool rte_ipv6_addr_is_sitelocal(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:292
static uint16_t rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
Definition: rte_ip6.h:556
static uint16_t rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
Definition: rte_ip6.h:610
static bool rte_ipv6_addr_is_v4compat(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:307
static bool rte_ipv6_addr_is_unspec(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:244
static int rte_ipv6_check_version(const struct rte_ipv6_hdr *ip)
Definition: rte_ip6.h:497
#define RTE_IPV6_ADDR_LOOPBACK
Definition: rte_ip6.h:251
struct __rte_aligned(2) rte_ipv6_hdr
Definition: rte_ip6.h:464
static bool rte_ipv6_addr_is_v4mapped(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:325
static void rte_ether_mcast_from_ipv6(struct rte_ether_addr *mac, const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:451
static int rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
Definition: rte_ip6.h:728
static int rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
Definition: rte_ip6.h:782
static int rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
Definition: rte_ip6.h:700
#define RTE_IPV6_MAX_DEPTH
Definition: rte_ip6.h:48
rte_ipv6_mc_scope
Definition: rte_ip6.h:348
@ RTE_IPV6_MC_SCOPE_NONE
Definition: rte_ip6.h:350
@ RTE_IPV6_MC_SCOPE_LINKLOCAL
Definition: rte_ip6.h:354
@ RTE_IPV6_MC_SCOPE_GLOBAL
Definition: rte_ip6.h:360
@ RTE_IPV6_MC_SCOPE_ORGLOCAL
Definition: rte_ip6.h:358
@ RTE_IPV6_MC_SCOPE_IFACELOCAL
Definition: rte_ip6.h:352
@ RTE_IPV6_MC_SCOPE_SITELOCAL
Definition: rte_ip6.h:356
#define RTE_IPV6_ADDR_UNSPEC
Definition: rte_ip6.h:233
static bool rte_ipv6_addr_eq(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b)
Definition: rte_ip6.h:68
static uint16_t rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m, const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
Definition: rte_ip6.h:667
#define RTE_IPV6_ADDR_SIZE
Definition: rte_ip6.h:43
static void rte_ipv6_solnode_from_addr(struct rte_ipv6_addr *sol, const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:429
static bool rte_ipv6_addr_is_loopback(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:263
static void rte_ipv6_addr_mask(struct rte_ipv6_addr *ip, uint8_t depth)
Definition: rte_ip6.h:84
static bool rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth)
Definition: rte_ip6.h:109
static uint8_t rte_ipv6_mask_depth(const struct rte_ipv6_addr *mask)
Definition: rte_ip6.h:132
static bool rte_ipv6_addr_is_mcast(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:340
#define RTE_MBUF_F_TX_UDP_SEG
#define RTE_MBUF_F_TX_TCP_SEG
uint32_t pkt_len