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