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