DPDK  24.11.0-rc3
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
37 extern "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 
53 struct rte_ipv6_addr {
54  uint8_t a[RTE_IPV6_ADDR_SIZE];
55 };
56 
67 static inline bool
68 rte_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 
83 static inline void
84 rte_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 
108 static inline bool
109 rte_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 
131 static 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 
243 static 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 
262 static inline bool
264 {
265  struct rte_ipv6_addr loopback = RTE_IPV6_ADDR_LOOPBACK;
266  return rte_ipv6_addr_eq(ip, &loopback);
267 }
268 
277 static inline bool
279 {
280  return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0x80;
281 }
282 
291 static inline bool
293 {
294  return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0xc0;
295 }
296 
306 static 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 
324 static 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 
339 static inline bool
341 {
342  return ip->a[0] == 0xff;
343 }
344 
361 } __rte_packed;
362 
372 static inline enum rte_ipv6_mc_scope
374 {
375  if (!rte_ipv6_addr_is_mcast(ip))
376  return RTE_IPV6_MC_SCOPE_NONE;
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)
384 
385 #define RTE_IPV6_ADDR_ALLNODES_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 1)
386 
387 #define RTE_IPV6_ADDR_ALLROUTERS_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 2)
388 
389 #define RTE_IPV6_ADDR_ALLROUTERS_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 2)
390 
391 #define RTE_IPV6_ADDR_ALLROUTERS_SITE_LOCAL RTE_IPV6(0xff05, 0, 0, 0, 0, 0, 0, 2)
392 
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  */
403 static inline void
404 rte_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 
428 static 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 
450 static inline void
451 rte_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 
464 struct __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;
487 } __rte_packed;
488 
497 static 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 
511 struct __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. */
526 } __rte_packed;
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
555 static inline uint16_t
556 rte_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);
565  if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
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 
580 static 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 
609 static inline uint16_t
610 rte_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 
630 static 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 
666 static 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 
699 static inline int
700 rte_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 
727 static 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 
755 struct __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;
760 } __rte_packed;
761 
762 /* IPv6 fragment extension header size */
763 #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
764 
781 static inline int
782 rte_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_ */
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
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_linklocal(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:278
uint32_t rte_be32_t
static int rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
Definition: rte_ip6.h:782
static void rte_ipv6_solnode_from_addr(struct rte_ipv6_addr *sol, const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:429
static int rte_ipv6_check_version(const struct rte_ipv6_hdr *ip)
Definition: rte_ip6.h:497
static bool rte_ipv6_addr_is_mcast(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:340
#define RTE_DIM(a)
Definition: rte_common.h:793
#define RTE_MBUF_F_TX_UDP_SEG
#define __rte_packed
Definition: rte_common.h:108
#define RTE_IPV6_ADDR_UNSPEC
Definition: rte_ip6.h:233
rte_ipv6_mc_scope
Definition: rte_ip6.h:348
#define unlikely(x)
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 uint8_t rte_ipv6_mask_depth(const struct rte_ipv6_addr *mask)
Definition: rte_ip6.h:132
static int rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
Definition: rte_ip6.h:700
static void rte_ipv6_addr_mask(struct rte_ipv6_addr *ip, uint8_t depth)
Definition: rte_ip6.h:84
#define RTE_IPV6_ADDR_LOOPBACK
Definition: rte_ip6.h:251
static uint16_t rte_raw_cksum(const void *buf, size_t len)
Definition: rte_cksum.h:94
#define RTE_IPV6_MAX_DEPTH
Definition: rte_ip6.h:48
static bool rte_ipv6_addr_is_v4mapped(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:325
uint32_t pkt_len
static bool rte_ipv6_addr_eq(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b)
Definition: rte_ip6.h:68
#define RTE_MBUF_F_TX_TCP_SEG
static bool rte_ipv6_addr_is_unspec(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:244
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 void rte_ether_mcast_from_ipv6(struct rte_ether_addr *mac, const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:451
uint16_t rte_be16_t
static bool rte_ipv6_addr_is_loopback(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:263
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
static uint16_t rte_be_to_cpu_16(rte_be16_t x)
static bool rte_ipv6_addr_is_sitelocal(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:292
#define RTE_IPV6_ADDR_SIZE
Definition: rte_ip6.h:43
struct __rte_aligned(2) rte_ipv6_hdr
Definition: rte_ip6.h:464
static bool rte_ipv6_addr_is_v4compat(const struct rte_ipv6_addr *ip)
Definition: rte_ip6.h:307
static uint16_t rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
Definition: rte_ip6.h:556