xref: /dpdk/lib/net/rte_ip6.h (revision ad6833e5accbf67b4e1e8c9ca4911ba1163d3cb5)
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 
12 /**
13  * @file
14  *
15  * IPv6-related defines
16  */
17 
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 
40 /**
41  * Maximum IPv6 address size in bytes.
42  */
43 #define RTE_IPV6_ADDR_SIZE 16
44 
45 /**
46  * Maximum IPv6 address size in bits.
47  */
48 #define RTE_IPV6_MAX_DEPTH (RTE_IPV6_ADDR_SIZE * CHAR_BIT)
49 
50 /**
51  * IPv6 Address
52  */
53 struct rte_ipv6_addr {
54 	uint8_t a[RTE_IPV6_ADDR_SIZE];
55 };
56 
57 /**
58  * Check if two IPv6 Addresses are equal.
59  *
60  * @param a
61  *   The first address.
62  * @param b
63  *   The second address.
64  * @return
65  *   true if both addresses are identical.
66  */
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 
73 /**
74  * Mask an IPv6 address using the specified depth.
75  *
76  * Leave untouched one bit per unit in the depth variable and set the rest to 0.
77  *
78  * @param[in] ip
79  *   The address to mask.
80  * @param[out] depth
81  *   All bits starting from this bit number will be set to zero.
82  */
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 		uint8_t d = depth / 8;
88 		uint8_t mask = ~(UINT8_MAX >> (depth % 8));
89 		ip->a[d] &= mask;
90 		d++;
91 		memset(&ip->a[d], 0, sizeof(*ip) - d);
92 	}
93 }
94 
95 /**
96  * Check if two IPv6 addresses belong to the same network prefix.
97  *
98  * @param a
99  *  The first address or network.
100  * @param b
101  *  The second address or network.
102  * @param depth
103  *  The network prefix length.
104  * @return
105  *   @c true if the first @p depth bits of both addresses are identical.
106  */
107 static inline bool
108 rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth)
109 {
110 	if (depth < RTE_IPV6_MAX_DEPTH) {
111 		uint8_t d = depth / 8;
112 		uint8_t mask = ~(UINT8_MAX >> (depth % 8));
113 
114 		if ((a->a[d] ^ b->a[d]) & mask)
115 			return false;
116 
117 		return memcmp(a, b, d) == 0;
118 	}
119 	return rte_ipv6_addr_eq(a, b);
120 }
121 
122 /**
123  * Get the depth of a given IPv6 address mask.
124  *
125  * @param mask
126  *   The address mask.
127  * @return
128  *   The number of consecutive bits set to 1 starting from the beginning of the mask.
129  */
130 static inline uint8_t
131 rte_ipv6_mask_depth(const struct rte_ipv6_addr *mask)
132 {
133 	uint8_t depth = 0;
134 
135 	for (unsigned int i = 0; i < RTE_DIM(mask->a); i++) {
136 		uint8_t m = mask->a[i];
137 		if (m == 0xff) {
138 			depth += 8;
139 		} else {
140 			while (m & 0x80) {
141 				m <<= 1;
142 				depth++;
143 			}
144 			break;
145 		}
146 	}
147 
148 	return depth;
149 }
150 
151 /**
152  * Split a literal 16 bit unsigned integer into two bytes separated by a comma
153  * according to the platform endianness.
154  *
155  * @param x
156  *   A @c uint16_t literal value.
157  * @return
158  *   Two @c uint8_t literals separated by a coma.
159  */
160 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
161 #define RTE_IPV6_U16_SPLIT(x) \
162 	(uint8_t)((uint16_t)(x) & UINT16_C(0xff)), \
163 	(uint8_t)(((uint16_t)(x) >> 8) & UINT16_C(0xff))
164 #else
165 #define RTE_IPV6_U16_SPLIT(x) \
166 	(uint8_t)(((uint16_t)(x) >> 8) & UINT16_C(0xff)), \
167 	(uint8_t)((uint16_t)(x) & UINT16_C(0xff))
168 #endif
169 
170 /**
171  * Shorthand to define a literal IPv6 address based on 16bit unsigned integers.
172  *
173  * @param a,b,c,d,e,f,g,h
174  *   @c uint8_t literals that will be passed to RTE_IPV6_U16_SPLIT(x).
175  * @return
176  *   A literal @ref rte_ipv6_addr value suitable for static initialization.
177  */
178 #define RTE_IPV6(a, b, c, d, e, f, g, h) \
179 	{{ \
180 		RTE_IPV6_U16_SPLIT(a), \
181 		RTE_IPV6_U16_SPLIT(b), \
182 		RTE_IPV6_U16_SPLIT(c), \
183 		RTE_IPV6_U16_SPLIT(d), \
184 		RTE_IPV6_U16_SPLIT(e), \
185 		RTE_IPV6_U16_SPLIT(f), \
186 		RTE_IPV6_U16_SPLIT(g), \
187 		RTE_IPV6_U16_SPLIT(h) \
188 	}}
189 
190 /**
191  * printf() format element for @ref rte_ipv6_addr structures.
192  * To be used along with RTE_IPV6_ADDR_SPLIT(ip).
193  */
194 #define RTE_IPV6_ADDR_FMT \
195 	"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
196 
197 /**
198  * For use with #RTE_IPV6_ADDR_FMT. E.g.:
199  *
200  * @code
201  * printf(RTE_IPV6_ADDR_FMT "\n", RTE_IPV6_ADDR_SPLIT(&ip));
202  * @endcode
203  *
204  * @param ip
205  *   A struct rte_ipv6_addr pointer.
206  * @return
207  *   A set of 16 @c uint8_t values separated by comas for use in printf().
208  */
209 #define RTE_IPV6_ADDR_SPLIT(ip) \
210 	((uint8_t)(ip)->a[0]), \
211 	((uint8_t)(ip)->a[1]), \
212 	((uint8_t)(ip)->a[2]), \
213 	((uint8_t)(ip)->a[3]), \
214 	((uint8_t)(ip)->a[4]), \
215 	((uint8_t)(ip)->a[5]), \
216 	((uint8_t)(ip)->a[6]), \
217 	((uint8_t)(ip)->a[7]), \
218 	((uint8_t)(ip)->a[8]), \
219 	((uint8_t)(ip)->a[9]), \
220 	((uint8_t)(ip)->a[10]), \
221 	((uint8_t)(ip)->a[11]), \
222 	((uint8_t)(ip)->a[12]), \
223 	((uint8_t)(ip)->a[13]), \
224 	((uint8_t)(ip)->a[14]), \
225 	((uint8_t)(ip)->a[15])
226 
227 /** Full IPv6 mask. NB: this is not a valid/routable IPv6 address. */
228 #define RTE_IPV6_MASK_FULL \
229 	RTE_IPV6(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
230 
231 /** Unspecified IPv6 address as defined in RFC 4291, section 2.5.2. */
232 #define RTE_IPV6_ADDR_UNSPEC RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
233 
234 /**
235  * Check if an IPv6 address is unspecified as defined in RFC 4291, section 2.5.2.
236  *
237  * @param ip
238  *   The address to check.
239  * @return
240  *   @c true if the address is the unspecified address (all zeroes).
241  */
242 static inline bool
243 rte_ipv6_addr_is_unspec(const struct rte_ipv6_addr *ip)
244 {
245 	const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
246 	return rte_ipv6_addr_eq(ip, &unspec);
247 }
248 
249 /** Loopback IPv6 address as defined in RFC 4291, section 2.5.3. */
250 #define RTE_IPV6_ADDR_LOOPBACK RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 1)
251 
252 /**
253  * Check if an IPv6 address is the loopback address as defined in RFC 4291,
254  * section 2.5.3.
255  *
256  * @param ip
257  *   The address to check.
258  * @return
259  *   @c true if the address is the loopback address (all zeroes except the last bit).
260  */
261 static inline bool
262 rte_ipv6_addr_is_loopback(const struct rte_ipv6_addr *ip)
263 {
264 	struct rte_ipv6_addr loopback = RTE_IPV6_ADDR_LOOPBACK;
265 	return rte_ipv6_addr_eq(ip, &loopback);
266 }
267 
268 /**
269  * Check if an IPv6 address is link-local as defined in RFC 4291, section 2.5.6.
270  *
271  * @param ip
272  *   The address to check.
273  * @return
274  *   @c true if the address is a link-local address.
275  */
276 static inline bool
277 rte_ipv6_addr_is_linklocal(const struct rte_ipv6_addr *ip)
278 {
279 	return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0x80;
280 }
281 
282 /**
283  * Check if an IPv6 address is site-local as defined in RFC 4291, section 2.5.7.
284  *
285  * @param ip
286  *   The address to check.
287  * @return
288  *   @c true if the address is a site-local address.
289  */
290 static inline bool
291 rte_ipv6_addr_is_sitelocal(const struct rte_ipv6_addr *ip)
292 {
293 	return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0xc0;
294 }
295 
296 /**
297  * Check if an IPv6 address is an IPv4-compatible address as defined in RFC 4291,
298  * section 2.5.5.1.
299  *
300  * @param ip
301  *   The address to check.
302  * @return
303  *   @c true if the address is an IPv4-compatible address.
304  */
305 static inline bool
306 rte_ipv6_addr_is_v4compat(const struct rte_ipv6_addr *ip)
307 {
308 	const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
309 	return rte_ipv6_addr_eq_prefix(ip, &unspec, 32) && !rte_ipv6_addr_is_loopback(ip);
310 }
311 
312 #define RTE_IPV6_ADDR_PREFIX_V4MAPPED RTE_IPV6(0, 0, 0, 0, 0, 0xffff, 0, 0)
313 
314 /**
315  * Check if an IPv6 address is an IPv4-mapped address as defined in RFC 4291,
316  * section 2.5.5.2.
317  *
318  * @param ip
319  *   The address to check.
320  * @return
321  *   @c true if the address is an IPv4-mapped address.
322  */
323 static inline bool
324 rte_ipv6_addr_is_v4mapped(const struct rte_ipv6_addr *ip)
325 {
326 	const struct rte_ipv6_addr prefix = RTE_IPV6_ADDR_PREFIX_V4MAPPED;
327 	return rte_ipv6_addr_eq_prefix(ip, &prefix, 32);
328 }
329 
330 /**
331  * Check if an IPv6 address is multicast as defined in RFC 4291, section 2.7.
332  *
333  * @param ip
334  *   The address to check.
335  * @return
336  *   @c true if the address is multicast.
337  */
338 static inline bool
339 rte_ipv6_addr_is_mcast(const struct rte_ipv6_addr *ip)
340 {
341 	return ip->a[0] == 0xff;
342 }
343 
344 /**
345  * IPv6 multicast scope values as defined in RFC 4291, section 2.7.
346  */
347 enum rte_ipv6_mc_scope {
348 	/** Invalid multicast scope. */
349 	RTE_IPV6_MC_SCOPE_NONE = 0x00,
350 	/** Interface-local multicast scope. */
351 	RTE_IPV6_MC_SCOPE_IFACELOCAL = 0x01,
352 	/** Link-local multicast scope. */
353 	RTE_IPV6_MC_SCOPE_LINKLOCAL = 0x02,
354 	/** Site-local multicast scope. */
355 	RTE_IPV6_MC_SCOPE_SITELOCAL = 0x05,
356 	/** Organizational-local multicast scope. */
357 	RTE_IPV6_MC_SCOPE_ORGLOCAL = 0x08,
358 	/** Global multicast scope. */
359 	RTE_IPV6_MC_SCOPE_GLOBAL = 0x0e,
360 } __rte_packed;
361 
362 /**
363  * Extract the IPv6 multicast scope value as defined in RFC 4291, section 2.7.
364  *
365  * @param ip
366  *   The address from which to get the multicast scope.
367  * @return
368  *   The multicast scope of the address, or #RTE_IPV6_MC_SCOPE_NONE if the
369  *   address is not multicast.
370  */
371 static inline enum rte_ipv6_mc_scope
372 rte_ipv6_mc_scope(const struct rte_ipv6_addr *ip)
373 {
374 	if (!rte_ipv6_addr_is_mcast(ip))
375 		return RTE_IPV6_MC_SCOPE_NONE;
376 	return (enum rte_ipv6_mc_scope)(ip->a[1] & 0x0f);
377 }
378 
379 /** @name Well known multicast addresses */
380 /**@{*/
381 /** Interface-local all-nodes multicast address as defined in RFC 4291, section 2.7.1. */
382 #define RTE_IPV6_ADDR_ALLNODES_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 1)
383 /** Link-local all-nodes multicast address as defined in RFC 4291, section 2.7.1. */
384 #define RTE_IPV6_ADDR_ALLNODES_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 1)
385 /** Interface-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
386 #define RTE_IPV6_ADDR_ALLROUTERS_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 2)
387 /** Link-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
388 #define RTE_IPV6_ADDR_ALLROUTERS_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 2)
389 /** Site-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
390 #define RTE_IPV6_ADDR_ALLROUTERS_SITE_LOCAL RTE_IPV6(0xff05, 0, 0, 0, 0, 0, 0, 2)
391 /**@}*/
392 
393 /*
394  * Generate a link-local IPv6 address from an Ethernet address as specified in
395  * RFC 2464, section 5.
396  *
397  * @param[out] ip
398  *   The link-local IPv6 address to generate.
399  * @param[in] mac
400  *   An Ethernet address.
401  */
402 static inline void
403 rte_ipv6_llocal_from_ethernet(struct rte_ipv6_addr *ip, const struct rte_ether_addr *mac)
404 {
405 	ip->a[0] = 0xfe;
406 	ip->a[1] = 0x80;
407 	memset(&ip->a[2], 0, 6);
408 	ip->a[8] = mac->addr_bytes[0];
409 	ip->a[9] = mac->addr_bytes[1];
410 	ip->a[10] = mac->addr_bytes[2];
411 	ip->a[11] = 0xff;
412 	ip->a[12] = 0xfe;
413 	ip->a[13] = mac->addr_bytes[3];
414 	ip->a[14] = mac->addr_bytes[4];
415 	ip->a[15] = mac->addr_bytes[5];
416 }
417 
418 /**
419  * Convert a unicast or anycast IPv6 address to a solicited-node multicast
420  * address as defined in RFC 4291, section 2.7.1.
421  *
422  * @param[out] sol
423  *   The IPv6 solicited-node multicast address to generate.
424  * @param[in] ip
425  *   A unicast or anycast address.
426  */
427 static inline void
428 rte_ipv6_solnode_from_addr(struct rte_ipv6_addr *sol, const struct rte_ipv6_addr *ip)
429 {
430 	sol->a[0] = 0xff;
431 	sol->a[1] = 0x02;
432 	memset(&sol->a[2], 0, 9);
433 	sol->a[11] = 0x01;
434 	sol->a[12] = 0xff;
435 	sol->a[13] = ip->a[13];
436 	sol->a[14] = ip->a[14];
437 	sol->a[15] = ip->a[15];
438 }
439 
440 /**
441  * Generate a multicast Ethernet address from a multicast IPv6 address as defined
442  * in RFC 2464, section 7.
443  *
444  * @param[out] mac
445  *   The multicast Ethernet address to generate.
446  * @param[in] ip
447  *   A multicast IPv6 address.
448  */
449 static inline void
450 rte_ether_mcast_from_ipv6(struct rte_ether_addr *mac, const struct rte_ipv6_addr *ip)
451 {
452 	mac->addr_bytes[0] = 0x33;
453 	mac->addr_bytes[1] = 0x33;
454 	mac->addr_bytes[2] = ip->a[12];
455 	mac->addr_bytes[3] = ip->a[13];
456 	mac->addr_bytes[4] = ip->a[14];
457 	mac->addr_bytes[5] = ip->a[15];
458 }
459 
460 /**
461  * IPv6 Header
462  */
463 struct rte_ipv6_hdr {
464 	rte_be32_t vtc_flow;	/**< IP version, traffic class & flow label. */
465 	rte_be16_t payload_len;	/**< IP payload size, including ext. headers */
466 	uint8_t  proto;		/**< Protocol, next header. */
467 	uint8_t  hop_limits;	/**< Hop limits. */
468 	struct rte_ipv6_addr src_addr;	/**< IP address of source host. */
469 	struct rte_ipv6_addr dst_addr;	/**< IP address of destination host(s). */
470 } __rte_packed;
471 
472 /**
473  * Check that the IPv6 header version field is valid according to RFC 8200 section 3.
474  *
475  * @param ip
476  *   The IPv6 header.
477  * @return
478  *   @c 0 if the version field is valid. @c -EINVAL otherwise.
479  */
480 static inline int rte_ipv6_check_version(const struct rte_ipv6_hdr *ip)
481 {
482 	uint8_t version = ((const uint8_t *)ip)[0];
483 	if ((version & 0xf0) != 0x60)
484 		return -EINVAL;
485 	return 0;
486 }
487 
488 /* IPv6 routing extension type definition. */
489 #define RTE_IPV6_SRCRT_TYPE_4 4
490 
491 /**
492  * IPv6 Routing Extension Header
493  */
494 struct rte_ipv6_routing_ext {
495 	uint8_t next_hdr;			/**< Protocol, next header. */
496 	uint8_t hdr_len;			/**< Header length. */
497 	uint8_t type;				/**< Extension header type. */
498 	uint8_t segments_left;			/**< Valid segments number. */
499 	__extension__
500 	union {
501 		rte_be32_t flags;		/**< Packet control data per type. */
502 		struct {
503 			uint8_t last_entry;	/**< The last_entry field of SRH */
504 			uint8_t flag;		/**< Packet flag. */
505 			rte_be16_t tag;		/**< Packet tag. */
506 		};
507 	};
508 	/* Next are 128-bit IPv6 address fields to describe segments. */
509 } __rte_packed;
510 
511 /* IPv6 vtc_flow: IPv / TC / flow_label */
512 #define RTE_IPV6_HDR_FL_SHIFT 0
513 #define RTE_IPV6_HDR_TC_SHIFT 20
514 #define RTE_IPV6_HDR_FL_MASK	((1u << RTE_IPV6_HDR_TC_SHIFT) - 1)
515 #define RTE_IPV6_HDR_TC_MASK	(0xff << RTE_IPV6_HDR_TC_SHIFT)
516 #define RTE_IPV6_HDR_DSCP_MASK	(0xfc << RTE_IPV6_HDR_TC_SHIFT)
517 #define RTE_IPV6_HDR_ECN_MASK	(0x03 << RTE_IPV6_HDR_TC_SHIFT)
518 #define RTE_IPV6_HDR_ECN_CE	RTE_IPV6_HDR_ECN_MASK
519 
520 #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */
521 
522 /**
523  * Process the pseudo-header checksum of an IPv6 header.
524  *
525  * Depending on the ol_flags, the pseudo-header checksum expected by the
526  * drivers is not the same. For instance, when TSO is enabled, the IPv6
527  * payload length must not be included in the packet.
528  *
529  * When ol_flags is 0, it computes the standard pseudo-header checksum.
530  *
531  * @param ipv6_hdr
532  *   The pointer to the contiguous IPv6 header.
533  * @param ol_flags
534  *   The ol_flags of the associated mbuf.
535  * @return
536  *   The non-complemented checksum to set in the L4 header.
537  */
538 static inline uint16_t
539 rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
540 {
541 	uint32_t sum;
542 	struct {
543 		rte_be32_t len;   /* L4 length. */
544 		rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
545 	} psd_hdr;
546 
547 	psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
548 	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
549 		psd_hdr.len = 0;
550 	else
551 		psd_hdr.len = ipv6_hdr->payload_len;
552 
553 	sum = __rte_raw_cksum(&ipv6_hdr->src_addr,
554 		sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr),
555 		0);
556 	sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum);
557 	return __rte_raw_cksum_reduce(sum);
558 }
559 
560 /**
561  * @internal Calculate the non-complemented IPv6 L4 checksum
562  */
563 static inline uint16_t
564 __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
565 {
566 	uint32_t cksum;
567 	uint32_t l4_len;
568 
569 	l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
570 
571 	cksum = rte_raw_cksum(l4_hdr, l4_len);
572 	cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
573 
574 	cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
575 
576 	return (uint16_t)cksum;
577 }
578 
579 /**
580  * Process the IPv6 UDP or TCP checksum.
581  *
582  * The IPv6 header must not be followed by extension headers. The layer 4
583  * checksum must be set to 0 in the L4 header by the caller.
584  *
585  * @param ipv6_hdr
586  *   The pointer to the contiguous IPv6 header.
587  * @param l4_hdr
588  *   The pointer to the beginning of the L4 header.
589  * @return
590  *   The complemented checksum to set in the L4 header.
591  */
592 static inline uint16_t
593 rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
594 {
595 	uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
596 
597 	cksum = ~cksum;
598 
599 	/*
600 	 * Per RFC 768: If the computed checksum is zero for UDP,
601 	 * it is transmitted as all ones
602 	 * (the equivalent in one's complement arithmetic).
603 	 */
604 	if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
605 		cksum = 0xffff;
606 
607 	return cksum;
608 }
609 
610 /**
611  * @internal Calculate the non-complemented IPv6 L4 checksum of a packet
612  */
613 static inline uint16_t
614 __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
615 			     const struct rte_ipv6_hdr *ipv6_hdr,
616 			     uint16_t l4_off)
617 {
618 	uint16_t raw_cksum;
619 	uint32_t cksum;
620 
621 	if (unlikely(l4_off > m->pkt_len))
622 		return 0; /* invalid params, return a dummy value */
623 
624 	if (rte_raw_cksum_mbuf(m, l4_off, rte_be_to_cpu_16(ipv6_hdr->payload_len), &raw_cksum))
625 		return 0;
626 
627 	cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
628 
629 	cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
630 
631 	return (uint16_t)cksum;
632 }
633 
634 /**
635  * Process the IPv6 UDP or TCP checksum of a packet.
636  *
637  * The IPv6 header must not be followed by extension headers. The layer 4
638  * checksum must be set to 0 in the L4 header by the caller.
639  *
640  * @param m
641  *   The pointer to the mbuf.
642  * @param ipv6_hdr
643  *   The pointer to the contiguous IPv6 header.
644  * @param l4_off
645  *   The offset in bytes to start L4 checksum.
646  * @return
647  *   The complemented checksum to set in the L4 header.
648  */
649 static inline uint16_t
650 rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
651 			   const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
652 {
653 	uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
654 
655 	cksum = ~cksum;
656 
657 	/*
658 	 * Per RFC 768: If the computed checksum is zero for UDP,
659 	 * it is transmitted as all ones
660 	 * (the equivalent in one's complement arithmetic).
661 	 */
662 	if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
663 		cksum = 0xffff;
664 
665 	return cksum;
666 }
667 
668 /**
669  * Validate the IPv6 UDP or TCP checksum.
670  *
671  * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
672  * this is either invalid or means no checksum in some situations. See 8.1
673  * (Upper-Layer Checksums) in RFC 8200.
674  *
675  * @param ipv6_hdr
676  *   The pointer to the contiguous IPv6 header.
677  * @param l4_hdr
678  *   The pointer to the beginning of the L4 header.
679  * @return
680  *   Return 0 if the checksum is correct, else -1.
681  */
682 static inline int
683 rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr,
684 			     const void *l4_hdr)
685 {
686 	uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
687 
688 	if (cksum != 0xffff)
689 		return -1;
690 
691 	return 0;
692 }
693 
694 /**
695  * Validate the IPv6 UDP or TCP checksum of a packet.
696  *
697  * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
698  * this is either invalid or means no checksum in some situations. See 8.1
699  * (Upper-Layer Checksums) in RFC 8200.
700  *
701  * @param m
702  *   The pointer to the mbuf.
703  * @param ipv6_hdr
704  *   The pointer to the contiguous IPv6 header.
705  * @param l4_off
706  *   The offset in bytes to start L4 checksum.
707  * @return
708  *   Return 0 if the checksum is correct, else -1.
709  */
710 static inline int
711 rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
712 				  const struct rte_ipv6_hdr *ipv6_hdr,
713 				  uint16_t l4_off)
714 {
715 	uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
716 
717 	if (cksum != 0xffff)
718 		return -1;
719 
720 	return 0;
721 }
722 
723 /** IPv6 fragment extension header. */
724 #define	RTE_IPV6_EHDR_MF_SHIFT	0
725 #define	RTE_IPV6_EHDR_MF_MASK	1
726 #define	RTE_IPV6_EHDR_FO_SHIFT	3
727 #define	RTE_IPV6_EHDR_FO_MASK	(~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
728 #define	RTE_IPV6_EHDR_FO_ALIGN	(1 << RTE_IPV6_EHDR_FO_SHIFT)
729 
730 #define RTE_IPV6_FRAG_USED_MASK	(RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
731 
732 #define RTE_IPV6_GET_MF(x)	((x) & RTE_IPV6_EHDR_MF_MASK)
733 #define RTE_IPV6_GET_FO(x)	((x) >> RTE_IPV6_EHDR_FO_SHIFT)
734 
735 #define RTE_IPV6_SET_FRAG_DATA(fo, mf)	\
736 	(((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
737 
738 struct rte_ipv6_fragment_ext {
739 	uint8_t next_header;	/**< Next header type */
740 	uint8_t reserved;	/**< Reserved */
741 	rte_be16_t frag_data;	/**< All fragmentation data */
742 	rte_be32_t id;		/**< Packet ID */
743 } __rte_packed;
744 
745 /* IPv6 fragment extension header size */
746 #define RTE_IPV6_FRAG_HDR_SIZE	sizeof(struct rte_ipv6_fragment_ext)
747 
748 /**
749  * Parse next IPv6 header extension
750  *
751  * This function checks if proto number is an IPv6 extensions and parses its
752  * data if so, providing information on next header and extension length.
753  *
754  * @param p
755  *   Pointer to an extension raw data.
756  * @param proto
757  *   Protocol number extracted from the "next header" field from
758  *   the IPv6 header or the previous extension.
759  * @param ext_len
760  *   Extension data length.
761  * @return
762  *   next protocol number if proto is an IPv6 extension, -EINVAL otherwise
763  */
764 static inline int
765 rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
766 {
767 	int next_proto;
768 
769 	switch (proto) {
770 	case IPPROTO_AH:
771 		next_proto = *p++;
772 		*ext_len = (*p + 2) * sizeof(uint32_t);
773 		break;
774 
775 	case IPPROTO_HOPOPTS:
776 	case IPPROTO_ROUTING:
777 	case IPPROTO_DSTOPTS:
778 		next_proto = *p++;
779 		*ext_len = (*p + 1) * sizeof(uint64_t);
780 		break;
781 
782 	case IPPROTO_FRAGMENT:
783 		next_proto = *p;
784 		*ext_len = RTE_IPV6_FRAG_HDR_SIZE;
785 		break;
786 
787 	default:
788 		return -EINVAL;
789 	}
790 
791 	return next_proto;
792 }
793 
794 #ifdef __cplusplus
795 }
796 #endif
797 
798 #endif /* _RTE_IP6_H_ */
799