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 [ + + + + : 172140 : 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 [ + + + - : 18727 : if (depth < RTE_IPV6_MAX_DEPTH) {
+ + + + ]
87 : 18575 : unsigned int d = depth / CHAR_BIT;
88 : 18575 : uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
89 [ - + ]: 18576 : ip->a[d] &= mask;
90 : 18575 : d++;
91 [ + + + + : 184548 : while (d < sizeof(*ip))
+ + + + ]
92 : 165969 : 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 : 2349364 : rte_ipv6_addr_eq_prefix(const struct rte_ipv6_addr *a, const struct rte_ipv6_addr *b, uint8_t depth)
110 : : {
111 [ + + ]: 2349364 : if (depth < RTE_IPV6_MAX_DEPTH) {
112 : 2348816 : unsigned int d = depth / CHAR_BIT;
113 : 2348816 : uint8_t mask = ~(UINT8_MAX >> (depth % CHAR_BIT));
114 : :
115 [ + + ]: 2348816 : if ((a->a[d] ^ b->a[d]) & mask)
116 : : return false;
117 : :
118 : 2334223 : 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 [ - + - + : 7 : 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 [ - + - + : 7 : 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 : 7 : rte_ipv6_addr_is_v4compat(const struct rte_ipv6_addr *ip)
308 : : {
309 : 7 : const struct rte_ipv6_addr unspec = RTE_IPV6_ADDR_UNSPEC;
310 [ + + + + ]: 7 : return rte_ipv6_addr_eq_prefix(ip, &unspec, 96) && !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 : 7 : const struct rte_ipv6_addr prefix = RTE_IPV6_ADDR_PREFIX_V4MAPPED;
328 [ - + - + : 7 : return rte_ipv6_addr_eq_prefix(ip, &prefix, 96);
- + - + -
+ - + -
+ ]
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 : : };
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 4291, section 2.5.1.
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 : : /*
410 : : * The "u" bit (universal/local bit in IEEE EUI-64 terminology)
411 : : * must be inverted for IPv6 link local address.
412 : : * 0 means local scope, 1 means universal scope.
413 : : */
414 : 1 : ip->a[8] = mac->addr_bytes[0] ^ RTE_ETHER_LOCAL_ADMIN_ADDR;
415 : 1 : ip->a[9] = mac->addr_bytes[1];
416 : 1 : ip->a[10] = mac->addr_bytes[2];
417 : 1 : ip->a[11] = 0xff;
418 : 1 : ip->a[12] = 0xfe;
419 : 1 : ip->a[13] = mac->addr_bytes[3];
420 : 1 : ip->a[14] = mac->addr_bytes[4];
421 : 1 : ip->a[15] = mac->addr_bytes[5];
422 : 1 : }
423 : :
424 : : /**
425 : : * Convert a unicast or anycast IPv6 address to a solicited-node multicast
426 : : * address as defined in RFC 4291, section 2.7.1.
427 : : *
428 : : * @param[out] sol
429 : : * The IPv6 solicited-node multicast address to generate.
430 : : * @param[in] ip
431 : : * A unicast or anycast address.
432 : : */
433 : : static inline void
434 : : rte_ipv6_solnode_from_addr(struct rte_ipv6_addr *sol, const struct rte_ipv6_addr *ip)
435 : : {
436 : 1 : sol->a[0] = 0xff;
437 [ - + ]: 1 : sol->a[1] = 0x02;
438 : : memset(&sol->a[2], 0, 9);
439 : 1 : sol->a[11] = 0x01;
440 : 1 : sol->a[12] = 0xff;
441 : 2 : sol->a[13] = ip->a[13];
442 : 2 : sol->a[14] = ip->a[14];
443 [ - + - + ]: 1 : sol->a[15] = ip->a[15];
444 : : }
445 : :
446 : : /**
447 : : * Generate a multicast Ethernet address from a multicast IPv6 address as defined
448 : : * in RFC 2464, section 7.
449 : : *
450 : : * @param[out] mac
451 : : * The multicast Ethernet address to generate.
452 : : * @param[in] ip
453 : : * A multicast IPv6 address.
454 : : */
455 : : static inline void
456 : : rte_ether_mcast_from_ipv6(struct rte_ether_addr *mac, const struct rte_ipv6_addr *ip)
457 : : {
458 : : mac->addr_bytes[0] = 0x33;
459 : : mac->addr_bytes[1] = 0x33;
460 : : mac->addr_bytes[2] = ip->a[12];
461 : : mac->addr_bytes[3] = ip->a[13];
462 : : mac->addr_bytes[4] = ip->a[14];
463 : : mac->addr_bytes[5] = ip->a[15];
464 : : }
465 : :
466 : : /**
467 : : * IPv6 Header
468 : : */
469 : : struct __rte_aligned(2) __rte_packed_begin rte_ipv6_hdr {
470 : : union {
471 : : rte_be32_t vtc_flow; /**< IP version, traffic class & flow label. */
472 : : __extension__
473 : : struct {
474 : : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
475 : : uint32_t flow_label:20; /**< Flow label */
476 : : uint32_t ecn:2; /**< ECN */
477 : : uint32_t ds:6; /**< Differentiated services */
478 : : uint32_t version:4; /**< Version */
479 : : #elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
480 : : uint32_t version:4; /**< Version */
481 : : uint32_t ds:6; /**< Differentiated services */
482 : : uint32_t ecn:2; /**< ECN */
483 : : uint32_t flow_label:20; /**< Flow label */
484 : : #endif
485 : : };
486 : : };
487 : : rte_be16_t payload_len; /**< IP payload size, including ext. headers */
488 : : uint8_t proto; /**< Protocol, next header. */
489 : : uint8_t hop_limits; /**< Hop limits. */
490 : : struct rte_ipv6_addr src_addr; /**< IP address of source host. */
491 : : struct rte_ipv6_addr dst_addr; /**< IP address of destination host(s). */
492 : : } __rte_packed_end;
493 : :
494 : : /**
495 : : * Check that the IPv6 header version field is valid according to RFC 8200 section 3.
496 : : *
497 : : * @param ip
498 : : * The IPv6 header.
499 : : * @return
500 : : * @c 0 if the version field is valid. @c -EINVAL otherwise.
501 : : */
502 : : static inline int rte_ipv6_check_version(const struct rte_ipv6_hdr *ip)
503 : : {
504 : : uint8_t version = ((const uint8_t *)ip)[0];
505 : : if ((version & 0xf0) != 0x60)
506 : : return -EINVAL;
507 : : return 0;
508 : : }
509 : :
510 : : /* IPv6 routing extension type definition. */
511 : : #define RTE_IPV6_SRCRT_TYPE_4 4
512 : :
513 : : /**
514 : : * IPv6 Routing Extension Header
515 : : */
516 : : struct __rte_aligned(2) __rte_packed_begin rte_ipv6_routing_ext {
517 : : uint8_t next_hdr; /**< Protocol, next header. */
518 : : uint8_t hdr_len; /**< Header length. */
519 : : uint8_t type; /**< Extension header type. */
520 : : uint8_t segments_left; /**< Valid segments number. */
521 : : __extension__
522 : : union {
523 : : rte_be32_t flags; /**< Packet control data per type. */
524 : : struct {
525 : : uint8_t last_entry; /**< The last_entry field of SRH */
526 : : uint8_t flag; /**< Packet flag. */
527 : : rte_be16_t tag; /**< Packet tag. */
528 : : };
529 : : };
530 : : /* Next are 128-bit IPv6 address fields to describe segments. */
531 : : } __rte_packed_end;
532 : :
533 : : /* IPv6 vtc_flow: IPv / TC / flow_label */
534 : : #define RTE_IPV6_HDR_FL_SHIFT 0
535 : : #define RTE_IPV6_HDR_TC_SHIFT 20
536 : : #define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1)
537 : : #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT)
538 : : #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT)
539 : : #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT)
540 : : #define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK
541 : :
542 : : #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */
543 : :
544 : : /**
545 : : * Process the pseudo-header checksum of an IPv6 header.
546 : : *
547 : : * Depending on the ol_flags, the pseudo-header checksum expected by the
548 : : * drivers is not the same. For instance, when TSO is enabled, the IPv6
549 : : * payload length must not be included in the packet.
550 : : *
551 : : * When ol_flags is 0, it computes the standard pseudo-header checksum.
552 : : *
553 : : * @param ipv6_hdr
554 : : * The pointer to the contiguous IPv6 header.
555 : : * @param ol_flags
556 : : * The ol_flags of the associated mbuf.
557 : : * @return
558 : : * The non-complemented checksum to set in the L4 header.
559 : : */
560 : : static inline uint16_t
561 : 3 : rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
562 : : {
563 : : uint32_t sum;
564 : : struct {
565 : : rte_be32_t len; /* L4 length. */
566 : : rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
567 : : } psd_hdr;
568 : :
569 : 3 : psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
570 [ - + ]: 3 : if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
571 : 0 : psd_hdr.len = 0;
572 : : else
573 : 3 : psd_hdr.len = ipv6_hdr->payload_len;
574 : :
575 : 3 : sum = __rte_raw_cksum(&ipv6_hdr->src_addr,
576 : : sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr),
577 : : 0);
578 : : sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum);
579 : 3 : return __rte_raw_cksum_reduce(sum);
580 : : }
581 : :
582 : : /**
583 : : * @internal Calculate the non-complemented IPv6 L4 checksum
584 : : */
585 : : static inline uint16_t
586 : 3 : __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
587 : : {
588 : : uint32_t cksum;
589 : : uint32_t l4_len;
590 : :
591 [ - + ]: 6 : l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
592 : :
593 : 3 : cksum = rte_raw_cksum(l4_hdr, l4_len);
594 : 3 : cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
595 : :
596 : 3 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
597 : :
598 : 3 : return (uint16_t)cksum;
599 : : }
600 : :
601 : : /**
602 : : * Process the IPv6 UDP or TCP checksum.
603 : : *
604 : : * The IPv6 header must not be followed by extension headers. The layer 4
605 : : * checksum must be set to 0 in the L4 header by the caller.
606 : : *
607 : : * @param ipv6_hdr
608 : : * The pointer to the contiguous IPv6 header.
609 : : * @param l4_hdr
610 : : * The pointer to the beginning of the L4 header.
611 : : * @return
612 : : * The complemented checksum to set in the L4 header.
613 : : */
614 : : static inline uint16_t
615 : : rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
616 : : {
617 : 1 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
618 : :
619 : 1 : cksum = ~cksum;
620 : :
621 : : /*
622 : : * Per RFC 768: If the computed checksum is zero for UDP,
623 : : * it is transmitted as all ones
624 : : * (the equivalent in one's complement arithmetic).
625 : : */
626 [ - - - - : 1 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
- + - - #
# # # ]
627 : : cksum = 0xffff;
628 : :
629 : : return cksum;
630 : : }
631 : :
632 : : /**
633 : : * @internal Calculate the non-complemented IPv6 L4 checksum of a packet
634 : : */
635 : : static inline uint16_t
636 : 0 : __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
637 : : const struct rte_ipv6_hdr *ipv6_hdr,
638 : : uint16_t l4_off)
639 : : {
640 : : uint16_t raw_cksum;
641 : : uint32_t cksum;
642 : :
643 [ # # ]: 0 : if (unlikely(l4_off > m->pkt_len))
644 : : return 0; /* invalid params, return a dummy value */
645 : :
646 [ # # # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, rte_be_to_cpu_16(ipv6_hdr->payload_len), &raw_cksum))
647 : : return 0;
648 : :
649 : 0 : cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
650 : :
651 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
652 : :
653 : 0 : return (uint16_t)cksum;
654 : : }
655 : :
656 : : /**
657 : : * Process the IPv6 UDP or TCP checksum of a packet.
658 : : *
659 : : * The IPv6 header must not be followed by extension headers. The layer 4
660 : : * checksum must be set to 0 in the L4 header by the caller.
661 : : *
662 : : * @param m
663 : : * The pointer to the mbuf.
664 : : * @param ipv6_hdr
665 : : * The pointer to the contiguous IPv6 header.
666 : : * @param l4_off
667 : : * The offset in bytes to start L4 checksum.
668 : : * @return
669 : : * The complemented checksum to set in the L4 header.
670 : : */
671 : : static inline uint16_t
672 : : rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
673 : : const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
674 : : {
675 : 0 : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
676 : :
677 : 0 : cksum = ~cksum;
678 : :
679 : : /*
680 : : * Per RFC 768: If the computed checksum is zero for UDP,
681 : : * it is transmitted as all ones
682 : : * (the equivalent in one's complement arithmetic).
683 : : */
684 [ # # # # ]: 0 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
685 : : cksum = 0xffff;
686 : :
687 : : return cksum;
688 : : }
689 : :
690 : : /**
691 : : * Validate the IPv6 UDP or TCP checksum.
692 : : *
693 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
694 : : * this is either invalid or means no checksum in some situations. See 8.1
695 : : * (Upper-Layer Checksums) in RFC 8200.
696 : : *
697 : : * @param ipv6_hdr
698 : : * The pointer to the contiguous IPv6 header.
699 : : * @param l4_hdr
700 : : * The pointer to the beginning of the L4 header.
701 : : * @return
702 : : * Return 0 if the checksum is correct, else -1.
703 : : */
704 : : static inline int
705 : : rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr,
706 : : const void *l4_hdr)
707 : : {
708 : 2 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
709 : :
710 [ - + - - : 2 : if (cksum != 0xffff)
+ - ]
711 : 0 : return -1;
712 : :
713 : : return 0;
714 : : }
715 : :
716 : : /**
717 : : * Validate the IPv6 UDP or TCP checksum of a packet.
718 : : *
719 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
720 : : * this is either invalid or means no checksum in some situations. See 8.1
721 : : * (Upper-Layer Checksums) in RFC 8200.
722 : : *
723 : : * @param m
724 : : * The pointer to the mbuf.
725 : : * @param ipv6_hdr
726 : : * The pointer to the contiguous IPv6 header.
727 : : * @param l4_off
728 : : * The offset in bytes to start L4 checksum.
729 : : * @return
730 : : * Return 0 if the checksum is correct, else -1.
731 : : */
732 : : static inline int
733 : : rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
734 : : const struct rte_ipv6_hdr *ipv6_hdr,
735 : : uint16_t l4_off)
736 : : {
737 : : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
738 : :
739 : : if (cksum != 0xffff)
740 : : return -1;
741 : :
742 : : return 0;
743 : : }
744 : :
745 : : /** IPv6 fragment extension header. */
746 : : #define RTE_IPV6_EHDR_MF_SHIFT 0
747 : : #define RTE_IPV6_EHDR_MF_MASK 1
748 : : #define RTE_IPV6_EHDR_FO_SHIFT 3
749 : : #define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
750 : : #define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT)
751 : :
752 : : #define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
753 : :
754 : : #define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK)
755 : : #define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT)
756 : :
757 : : #define RTE_IPV6_SET_FRAG_DATA(fo, mf) \
758 : : (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
759 : :
760 : : struct __rte_aligned(2) __rte_packed_begin rte_ipv6_fragment_ext {
761 : : uint8_t next_header; /**< Next header type */
762 : : uint8_t reserved; /**< Reserved */
763 : : rte_be16_t frag_data; /**< All fragmentation data */
764 : : rte_be32_t id; /**< Packet ID */
765 : : } __rte_packed_end;
766 : :
767 : : /* IPv6 fragment extension header size */
768 : : #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
769 : :
770 : : /**
771 : : * Parse next IPv6 header extension
772 : : *
773 : : * This function checks if proto number is an IPv6 extensions and parses its
774 : : * data if so, providing information on next header and extension length.
775 : : *
776 : : * @param p
777 : : * Pointer to an extension raw data.
778 : : * @param proto
779 : : * Protocol number extracted from the "next header" field from
780 : : * the IPv6 header or the previous extension.
781 : : * @param ext_len
782 : : * Extension data length.
783 : : * @return
784 : : * next protocol number if proto is an IPv6 extension, -EINVAL otherwise
785 : : */
786 : : static inline int
787 : 0 : rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
788 : : {
789 : : int next_proto;
790 : :
791 [ # # # # ]: 0 : switch (proto) {
792 : 0 : case IPPROTO_AH:
793 : 0 : next_proto = *p++;
794 : 0 : *ext_len = (*p + 2) * sizeof(uint32_t);
795 : 0 : break;
796 : :
797 : 0 : case IPPROTO_HOPOPTS:
798 : : case IPPROTO_ROUTING:
799 : : case IPPROTO_DSTOPTS:
800 : 0 : next_proto = *p++;
801 : 0 : *ext_len = (*p + 1) * sizeof(uint64_t);
802 : 0 : break;
803 : :
804 : 0 : case IPPROTO_FRAGMENT:
805 : 0 : next_proto = *p;
806 : 0 : *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
807 : 0 : break;
808 : :
809 : : default:
810 : : return -EINVAL;
811 : : }
812 : :
813 : : return next_proto;
814 : : }
815 : :
816 : : #ifdef __cplusplus
817 : : }
818 : : #endif
819 : :
820 : : #endif /* _RTE_IP6_H_ */
|