Branch data Line data Source code
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 [ + + + + : 168997 : 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 [ + + + - : 12304 : if (depth < RTE_IPV6_MAX_DEPTH) {
+ + + + ]
87 : 12152 : unsigned int d = depth / CHAR_BIT;
88 : 12152 : uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
89 [ - + ]: 12153 : ip->a[d] &= mask;
90 : 12152 : d++;
91 [ + + + + : 102687 : while (d < sizeof(*ip))
+ + + + ]
92 : 90531 : 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 : 2308217 : rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth)
110 : : {
111 [ + + ]: 2308217 : if (depth < RTE_IPV6_MAX_DEPTH) {
112 : 2307669 : unsigned int d = depth / CHAR_BIT;
113 : 2307669 : uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
114 : :
115 [ + + ]: 2307669 : if ((a->a[d] ^ b->a[d]) & mask)
116 : : return false;
117 : :
118 : 2293076 : return memcmp(a, b, d) == 0;
119 : : }
120 : 548 : 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 [ + - + - : 57 : for (unsigned int i = 0; i < RTE_DIM(mask->a); i++) {
+ - + + +
- ]
137 : 56 : uint8_t m = mask->a[i];
138 [ + + + + : 56 : if (m == 0xff) {
+ + + - +
+ ]
139 : 52 : depth += 8;
140 : : } else {
141 [ + + + + : 25 : while (m & 0x80) {
+ + + + -
- + + ]
142 : 20 : m <<= 1;
143 : 20 : 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 [ - + - + : 5 : 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 [ - + - + : 5 : 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 : 1 : rte_ipv6_llocal_from_ethernet(struct rte_ipv6_addr *ip, const struct rte_ether_addr *mac)
405 : : {
406 : 1 : ip->a[0] = 0xfe;
407 : 1 : ip->a[1] = 0x80;
408 : 1 : memset(&ip->a[2], 0, 6);
409 : 1 : ip->a[8] = mac->addr_bytes[0];
410 : 1 : ip->a[9] = mac->addr_bytes[1];
411 : 1 : ip->a[10] = mac->addr_bytes[2];
412 : 1 : ip->a[11] = 0xff;
413 : 1 : ip->a[12] = 0xfe;
414 : 1 : ip->a[13] = mac->addr_bytes[3];
415 : 1 : ip->a[14] = mac->addr_bytes[4];
416 : 1 : ip->a[15] = mac->addr_bytes[5];
417 : 1 : }
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 : 1 : sol->a[0] = 0xff;
432 [ - + ]: 1 : sol->a[1] = 0x02;
433 : : memset(&sol->a[2], 0, 9);
434 : 1 : sol->a[11] = 0x01;
435 : 1 : sol->a[12] = 0xff;
436 : 2 : sol->a[13] = ip->a[13];
437 : 2 : sol->a[14] = ip->a[14];
438 [ - + - + ]: 1 : 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 : 3 : 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 : 3 : psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
565 [ - + ]: 3 : if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
566 : 0 : psd_hdr.len = 0;
567 : : else
568 : 3 : psd_hdr.len = ipv6_hdr->payload_len;
569 : :
570 : 3 : 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 : 3 : 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 : 3 : __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 [ - + ]: 6 : l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
587 : :
588 : 3 : cksum = rte_raw_cksum(l4_hdr, l4_len);
589 : 3 : cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
590 : :
591 : 3 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
592 : :
593 : 3 : 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 : 1 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
613 : :
614 : 1 : 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 [ - - - - : 1 : 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 : 0 : __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 [ # # ]: 0 : if (unlikely(l4_off > m->pkt_len))
639 : : return 0; /* invalid params, return a dummy value */
640 : :
641 [ # # # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, rte_be_to_cpu_16(ipv6_hdr->payload_len), &raw_cksum))
642 : : return 0;
643 : :
644 : 0 : cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
645 : :
646 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
647 : :
648 : 0 : 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 : 0 : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
671 : :
672 : 0 : 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 [ # # # # ]: 0 : 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 : 2 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
704 : :
705 [ - + - - : 2 : if (cksum != 0xffff)
+ - ]
706 : 0 : 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 : 0 : rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
783 : : {
784 : : int next_proto;
785 : :
786 [ # # # # ]: 0 : switch (proto) {
787 : 0 : case IPPROTO_AH:
788 : 0 : next_proto = *p++;
789 : 0 : *ext_len = (*p + 2) * sizeof(uint32_t);
790 : 0 : break;
791 : :
792 : 0 : case IPPROTO_HOPOPTS:
793 : : case IPPROTO_ROUTING:
794 : : case IPPROTO_DSTOPTS:
795 : 0 : next_proto = *p++;
796 : 0 : *ext_len = (*p + 1) * sizeof(uint64_t);
797 : 0 : break;
798 : :
799 : 0 : case IPPROTO_FRAGMENT:
800 : 0 : next_proto = *p;
801 : 0 : *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
802 : 0 : 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_ */
|