xref: /dpdk/lib/net/rte_ip6.h (revision 12dc2539f7b12b2ec4570197c1e8a16a973d71f6)
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 		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 
96 /**
97  * Check if two IPv6 addresses belong to the same network prefix.
98  *
99  * @param a
100  *  The first address or network.
101  * @param b
102  *  The second address or network.
103  * @param depth
104  *  The network prefix length.
105  * @return
106  *   @c true if the first @p depth bits of both addresses are identical.
107  */
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 
123 /**
124  * Get the depth of a given IPv6 address mask.
125  *
126  * @param mask
127  *   The address mask.
128  * @return
129  *   The number of consecutive bits set to 1 starting from the beginning of the mask.
130  */
131 static inline uint8_t
132 rte_ipv6_mask_depth(const struct rte_ipv6_addr *mask)
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 
152 /**
153  * Split a literal 16 bit unsigned integer into two bytes separated by a comma
154  * according to the platform endianness.
155  *
156  * @param x
157  *   A @c uint16_t literal value.
158  * @return
159  *   Two @c uint8_t literals separated by a coma.
160  */
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 
171 /**
172  * Shorthand to define a literal IPv6 address based on 16bit unsigned integers.
173  *
174  * @param a,b,c,d,e,f,g,h
175  *   @c uint8_t literals that will be passed to RTE_IPV6_U16_SPLIT(x).
176  * @return
177  *   A literal @ref rte_ipv6_addr value suitable for static initialization.
178  */
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 
191 /**
192  * printf() format element for @ref rte_ipv6_addr structures.
193  * To be used along with RTE_IPV6_ADDR_SPLIT(ip).
194  */
195 #define RTE_IPV6_ADDR_FMT \
196 	"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
197 
198 /**
199  * For use with #RTE_IPV6_ADDR_FMT. E.g.:
200  *
201  * @code
202  * printf(RTE_IPV6_ADDR_FMT "\n", RTE_IPV6_ADDR_SPLIT(&ip));
203  * @endcode
204  *
205  * @param ip
206  *   A struct rte_ipv6_addr pointer.
207  * @return
208  *   A set of 16 @c uint8_t values separated by comas for use in printf().
209  */
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 
228 /** Full IPv6 mask. NB: this is not a valid/routable IPv6 address. */
229 #define RTE_IPV6_MASK_FULL \
230 	RTE_IPV6(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
231 
232 /** Unspecified IPv6 address as defined in RFC 4291, section 2.5.2. */
233 #define RTE_IPV6_ADDR_UNSPEC RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
234 
235 /**
236  * Check if an IPv6 address is unspecified as defined in RFC 4291, section 2.5.2.
237  *
238  * @param ip
239  *   The address to check.
240  * @return
241  *   @c true if the address is the unspecified address (all zeroes).
242  */
243 static inline bool
244 rte_ipv6_addr_is_unspec(const struct rte_ipv6_addr *ip)
245 {
246 	const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
247 	return rte_ipv6_addr_eq(ip, &unspec);
248 }
249 
250 /** Loopback IPv6 address as defined in RFC 4291, section 2.5.3. */
251 #define RTE_IPV6_ADDR_LOOPBACK RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 1)
252 
253 /**
254  * Check if an IPv6 address is the loopback address as defined in RFC 4291,
255  * section 2.5.3.
256  *
257  * @param ip
258  *   The address to check.
259  * @return
260  *   @c true if the address is the loopback address (all zeroes except the last bit).
261  */
262 static inline bool
263 rte_ipv6_addr_is_loopback(const struct rte_ipv6_addr *ip)
264 {
265 	struct rte_ipv6_addr loopback = RTE_IPV6_ADDR_LOOPBACK;
266 	return rte_ipv6_addr_eq(ip, &loopback);
267 }
268 
269 /**
270  * Check if an IPv6 address is link-local as defined in RFC 4291, section 2.5.6.
271  *
272  * @param ip
273  *   The address to check.
274  * @return
275  *   @c true if the address is a link-local address.
276  */
277 static inline bool
278 rte_ipv6_addr_is_linklocal(const struct rte_ipv6_addr *ip)
279 {
280 	return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0x80;
281 }
282 
283 /**
284  * Check if an IPv6 address is site-local as defined in RFC 4291, section 2.5.7.
285  *
286  * @param ip
287  *   The address to check.
288  * @return
289  *   @c true if the address is a site-local address.
290  */
291 static inline bool
292 rte_ipv6_addr_is_sitelocal(const struct rte_ipv6_addr *ip)
293 {
294 	return ip->a[0] == 0xfe && (ip->a[1] & 0xc0) == 0xc0;
295 }
296 
297 /**
298  * Check if an IPv6 address is an IPv4-compatible address as defined in RFC 4291,
299  * section 2.5.5.1.
300  *
301  * @param ip
302  *   The address to check.
303  * @return
304  *   @c true if the address is an IPv4-compatible address.
305  */
306 static inline bool
307 rte_ipv6_addr_is_v4compat(const struct rte_ipv6_addr *ip)
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 
315 /**
316  * Check if an IPv6 address is an IPv4-mapped address as defined in RFC 4291,
317  * section 2.5.5.2.
318  *
319  * @param ip
320  *   The address to check.
321  * @return
322  *   @c true if the address is an IPv4-mapped address.
323  */
324 static inline bool
325 rte_ipv6_addr_is_v4mapped(const struct rte_ipv6_addr *ip)
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 
331 /**
332  * Check if an IPv6 address is multicast as defined in RFC 4291, section 2.7.
333  *
334  * @param ip
335  *   The address to check.
336  * @return
337  *   @c true if the address is multicast.
338  */
339 static inline bool
340 rte_ipv6_addr_is_mcast(const struct rte_ipv6_addr *ip)
341 {
342 	return ip->a[0] == 0xff;
343 }
344 
345 /**
346  * IPv6 multicast scope values as defined in RFC 4291, section 2.7.
347  */
348 enum rte_ipv6_mc_scope {
349 	/** Invalid multicast scope. */
350 	RTE_IPV6_MC_SCOPE_NONE = 0x00,
351 	/** Interface-local multicast scope. */
352 	RTE_IPV6_MC_SCOPE_IFACELOCAL = 0x01,
353 	/** Link-local multicast scope. */
354 	RTE_IPV6_MC_SCOPE_LINKLOCAL = 0x02,
355 	/** Site-local multicast scope. */
356 	RTE_IPV6_MC_SCOPE_SITELOCAL = 0x05,
357 	/** Organizational-local multicast scope. */
358 	RTE_IPV6_MC_SCOPE_ORGLOCAL = 0x08,
359 	/** Global multicast scope. */
360 	RTE_IPV6_MC_SCOPE_GLOBAL = 0x0e,
361 } __rte_packed;
362 
363 /**
364  * Extract the IPv6 multicast scope value as defined in RFC 4291, section 2.7.
365  *
366  * @param ip
367  *   The address from which to get the multicast scope.
368  * @return
369  *   The multicast scope of the address, or #RTE_IPV6_MC_SCOPE_NONE if the
370  *   address is not multicast.
371  */
372 static inline enum rte_ipv6_mc_scope
373 rte_ipv6_mc_scope(const struct rte_ipv6_addr *ip)
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 
380 /** @name Well known multicast addresses */
381 /**@{*/
382 /** Interface-local all-nodes multicast address as defined in RFC 4291, section 2.7.1. */
383 #define RTE_IPV6_ADDR_ALLNODES_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 1)
384 /** Link-local all-nodes multicast address as defined in RFC 4291, section 2.7.1. */
385 #define RTE_IPV6_ADDR_ALLNODES_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 1)
386 /** Interface-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
387 #define RTE_IPV6_ADDR_ALLROUTERS_IFACE_LOCAL RTE_IPV6(0xff01, 0, 0, 0, 0, 0, 0, 2)
388 /** Link-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
389 #define RTE_IPV6_ADDR_ALLROUTERS_LINK_LOCAL RTE_IPV6(0xff02, 0, 0, 0, 0, 0, 0, 2)
390 /** Site-local all-routers multicast address as defined in RFC 4291, section 2.7.1. */
391 #define RTE_IPV6_ADDR_ALLROUTERS_SITE_LOCAL RTE_IPV6(0xff05, 0, 0, 0, 0, 0, 0, 2)
392 /**@}*/
393 
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 
419 /**
420  * Convert a unicast or anycast IPv6 address to a solicited-node multicast
421  * address as defined in RFC 4291, section 2.7.1.
422  *
423  * @param[out] sol
424  *   The IPv6 solicited-node multicast address to generate.
425  * @param[in] ip
426  *   A unicast or anycast address.
427  */
428 static inline void
429 rte_ipv6_solnode_from_addr(struct rte_ipv6_addr *sol, const struct rte_ipv6_addr *ip)
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 
441 /**
442  * Generate a multicast Ethernet address from a multicast IPv6 address as defined
443  * in RFC 2464, section 7.
444  *
445  * @param[out] mac
446  *   The multicast Ethernet address to generate.
447  * @param[in] ip
448  *   A multicast IPv6 address.
449  */
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 
461 /**
462  * IPv6 Header
463  */
464 struct __rte_aligned(2) rte_ipv6_hdr {
465 	union {
466 		rte_be32_t vtc_flow;        /**< IP version, traffic class & flow label. */
467 		__extension__
468 		struct {
469 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
470 			uint32_t flow_label:20; /**< Flow label */
471 			uint32_t ecn:2;         /**< ECN */
472 			uint32_t ds:6;          /**< Differentiated services */
473 			uint32_t version:4;     /**< Version */
474 #elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
475 			uint32_t version:4;     /**< Version */
476 			uint32_t ds:6;          /**< Differentiated services */
477 			uint32_t ecn:2;         /**< ECN */
478 			uint32_t flow_label:20; /**< Flow label */
479 #endif
480 		};
481 	};
482 	rte_be16_t payload_len;	/**< IP payload size, including ext. headers */
483 	uint8_t  proto;		/**< Protocol, next header. */
484 	uint8_t  hop_limits;	/**< Hop limits. */
485 	struct rte_ipv6_addr src_addr;	/**< IP address of source host. */
486 	struct rte_ipv6_addr dst_addr;	/**< IP address of destination host(s). */
487 } __rte_packed;
488 
489 /**
490  * Check that the IPv6 header version field is valid according to RFC 8200 section 3.
491  *
492  * @param ip
493  *   The IPv6 header.
494  * @return
495  *   @c 0 if the version field is valid. @c -EINVAL otherwise.
496  */
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 
508 /**
509  * IPv6 Routing Extension Header
510  */
511 struct __rte_aligned(2) rte_ipv6_routing_ext {
512 	uint8_t next_hdr;			/**< Protocol, next header. */
513 	uint8_t hdr_len;			/**< Header length. */
514 	uint8_t type;				/**< Extension header type. */
515 	uint8_t segments_left;			/**< Valid segments number. */
516 	__extension__
517 	union {
518 		rte_be32_t flags;		/**< Packet control data per type. */
519 		struct {
520 			uint8_t last_entry;	/**< The last_entry field of SRH */
521 			uint8_t flag;		/**< Packet flag. */
522 			rte_be16_t tag;		/**< Packet 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 /**< Minimum MTU for IPv6, see RFC 8200. */
538 
539 /**
540  * Process the pseudo-header checksum of an IPv6 header.
541  *
542  * Depending on the ol_flags, the pseudo-header checksum expected by the
543  * drivers is not the same. For instance, when TSO is enabled, the IPv6
544  * payload length must not be included in the packet.
545  *
546  * When ol_flags is 0, it computes the standard pseudo-header checksum.
547  *
548  * @param ipv6_hdr
549  *   The pointer to the contiguous IPv6 header.
550  * @param ol_flags
551  *   The ol_flags of the associated mbuf.
552  * @return
553  *   The non-complemented checksum to set in the L4 header.
554  */
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 
577 /**
578  * @internal Calculate the non-complemented IPv6 L4 checksum
579  */
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 
596 /**
597  * Process the IPv6 UDP or TCP checksum.
598  *
599  * The IPv6 header must not be followed by extension headers. The layer 4
600  * checksum must be set to 0 in the L4 header by the caller.
601  *
602  * @param ipv6_hdr
603  *   The pointer to the contiguous IPv6 header.
604  * @param l4_hdr
605  *   The pointer to the beginning of the L4 header.
606  * @return
607  *   The complemented checksum to set in the L4 header.
608  */
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 
627 /**
628  * @internal Calculate the non-complemented IPv6 L4 checksum of a packet
629  */
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 
651 /**
652  * Process the IPv6 UDP or TCP checksum of a packet.
653  *
654  * The IPv6 header must not be followed by extension headers. The layer 4
655  * checksum must be set to 0 in the L4 header by the caller.
656  *
657  * @param m
658  *   The pointer to the mbuf.
659  * @param ipv6_hdr
660  *   The pointer to the contiguous IPv6 header.
661  * @param l4_off
662  *   The offset in bytes to start L4 checksum.
663  * @return
664  *   The complemented checksum to set in the L4 header.
665  */
666 static inline uint16_t
667 rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
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 
685 /**
686  * Validate the IPv6 UDP or TCP checksum.
687  *
688  * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
689  * this is either invalid or means no checksum in some situations. See 8.1
690  * (Upper-Layer Checksums) in RFC 8200.
691  *
692  * @param ipv6_hdr
693  *   The pointer to the contiguous IPv6 header.
694  * @param l4_hdr
695  *   The pointer to the beginning of the L4 header.
696  * @return
697  *   Return 0 if the checksum is correct, else -1.
698  */
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 
711 /**
712  * Validate the IPv6 UDP or TCP checksum of a packet.
713  *
714  * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
715  * this is either invalid or means no checksum in some situations. See 8.1
716  * (Upper-Layer Checksums) in RFC 8200.
717  *
718  * @param m
719  *   The pointer to the mbuf.
720  * @param ipv6_hdr
721  *   The pointer to the contiguous IPv6 header.
722  * @param l4_off
723  *   The offset in bytes to start L4 checksum.
724  * @return
725  *   Return 0 if the checksum is correct, else -1.
726  */
727 static inline int
728 rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
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 
740 /** IPv6 fragment extension header. */
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;	/**< Next header type */
757 	uint8_t reserved;	/**< Reserved */
758 	rte_be16_t frag_data;	/**< All fragmentation data */
759 	rte_be32_t id;		/**< Packet 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 
765 /**
766  * Parse next IPv6 header extension
767  *
768  * This function checks if proto number is an IPv6 extensions and parses its
769  * data if so, providing information on next header and extension length.
770  *
771  * @param p
772  *   Pointer to an extension raw data.
773  * @param proto
774  *   Protocol number extracted from the "next header" field from
775  *   the IPv6 header or the previous extension.
776  * @param ext_len
777  *   Extension data length.
778  * @return
779  *   next protocol number if proto is an IPv6 extension, -EINVAL otherwise
780  */
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_ */
816