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_IP_H_ 10 #define _RTE_IP_H_ 11 12 /** 13 * @file 14 * 15 * IP-related defines 16 */ 17 18 #include <stdint.h> 19 20 #ifdef RTE_EXEC_ENV_WINDOWS 21 #include <ws2tcpip.h> 22 #else 23 #include <sys/socket.h> 24 #include <sys/types.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <netinet/ip.h> 28 #include <netinet/ip6.h> 29 #endif 30 31 #include <rte_compat.h> 32 #include <rte_byteorder.h> 33 #include <rte_mbuf.h> 34 35 #ifdef __cplusplus 36 extern "C" { 37 #endif 38 39 /** 40 * IPv4 Header 41 */ 42 struct rte_ipv4_hdr { 43 __extension__ 44 union { 45 uint8_t version_ihl; /**< version and header length */ 46 struct { 47 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 48 uint8_t ihl:4; /**< header length */ 49 uint8_t version:4; /**< version */ 50 #elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN 51 uint8_t version:4; /**< version */ 52 uint8_t ihl:4; /**< header length */ 53 #endif 54 }; 55 }; 56 uint8_t type_of_service; /**< type of service */ 57 rte_be16_t total_length; /**< length of packet */ 58 rte_be16_t packet_id; /**< packet ID */ 59 rte_be16_t fragment_offset; /**< fragmentation offset */ 60 uint8_t time_to_live; /**< time to live */ 61 uint8_t next_proto_id; /**< protocol ID */ 62 rte_be16_t hdr_checksum; /**< header checksum */ 63 rte_be32_t src_addr; /**< source address */ 64 rte_be32_t dst_addr; /**< destination address */ 65 } __rte_packed; 66 67 /** Create IPv4 address */ 68 #define RTE_IPV4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \ 69 (((b) & 0xff) << 16) | \ 70 (((c) & 0xff) << 8) | \ 71 ((d) & 0xff)) 72 73 /** Maximal IPv4 packet length (including a header) */ 74 #define RTE_IPV4_MAX_PKT_LEN 65535 75 76 /** Internet header length mask for version_ihl field */ 77 #define RTE_IPV4_HDR_IHL_MASK (0x0f) 78 /** 79 * Internet header length field multiplier (IHL field specifies overall header 80 * length in number of 4-byte words) 81 */ 82 #define RTE_IPV4_IHL_MULTIPLIER (4) 83 84 /* Type of Service fields */ 85 #define RTE_IPV4_HDR_DSCP_MASK (0xfc) 86 #define RTE_IPV4_HDR_ECN_MASK (0x03) 87 #define RTE_IPV4_HDR_ECN_CE RTE_IPV4_HDR_ECN_MASK 88 89 /* Fragment Offset * Flags. */ 90 #define RTE_IPV4_HDR_DF_SHIFT 14 91 #define RTE_IPV4_HDR_MF_SHIFT 13 92 #define RTE_IPV4_HDR_FO_SHIFT 3 93 94 #define RTE_IPV4_HDR_DF_FLAG (1 << RTE_IPV4_HDR_DF_SHIFT) 95 #define RTE_IPV4_HDR_MF_FLAG (1 << RTE_IPV4_HDR_MF_SHIFT) 96 97 #define RTE_IPV4_HDR_OFFSET_MASK ((1 << RTE_IPV4_HDR_MF_SHIFT) - 1) 98 99 #define RTE_IPV4_HDR_OFFSET_UNITS 8 100 101 /* IPv4 options */ 102 #define RTE_IPV4_HDR_OPT_EOL 0 103 #define RTE_IPV4_HDR_OPT_NOP 1 104 #define RTE_IPV4_HDR_OPT_COPIED(v) ((v) & 0x80) 105 #define RTE_IPV4_HDR_OPT_MAX_LEN 40 106 107 /* 108 * IPv4 address types 109 */ 110 #define RTE_IPV4_ANY ((uint32_t)0x00000000) /**< 0.0.0.0 */ 111 #define RTE_IPV4_LOOPBACK ((uint32_t)0x7f000001) /**< 127.0.0.1 */ 112 #define RTE_IPV4_BROADCAST ((uint32_t)0xe0000000) /**< 224.0.0.0 */ 113 #define RTE_IPV4_ALLHOSTS_GROUP ((uint32_t)0xe0000001) /**< 224.0.0.1 */ 114 #define RTE_IPV4_ALLRTRS_GROUP ((uint32_t)0xe0000002) /**< 224.0.0.2 */ 115 #define RTE_IPV4_MAX_LOCAL_GROUP ((uint32_t)0xe00000ff) /**< 224.0.0.255 */ 116 117 /* 118 * IPv4 Multicast-related macros 119 */ 120 #define RTE_IPV4_MIN_MCAST \ 121 RTE_IPV4(224, 0, 0, 0) /**< Minimal IPv4-multicast address */ 122 #define RTE_IPV4_MAX_MCAST \ 123 RTE_IPV4(239, 255, 255, 255) /**< Maximum IPv4 multicast address */ 124 125 #define RTE_IS_IPV4_MCAST(x) \ 126 ((x) >= RTE_IPV4_MIN_MCAST && (x) <= RTE_IPV4_MAX_MCAST) 127 /**< check if IPv4 address is multicast */ 128 129 /* IPv4 default fields values */ 130 #define RTE_IPV4_MIN_IHL (0x5) 131 #define RTE_IPV4_VHL_DEF ((IPVERSION << 4) | RTE_IPV4_MIN_IHL) 132 133 /** 134 * Get the length of an IPv4 header. 135 * 136 * @param ipv4_hdr 137 * Pointer to the IPv4 header. 138 * @return 139 * The length of the IPv4 header (with options if present) in bytes. 140 */ 141 static inline uint8_t 142 rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) 143 { 144 return (uint8_t)((ipv4_hdr->version_ihl & RTE_IPV4_HDR_IHL_MASK) * 145 RTE_IPV4_IHL_MULTIPLIER); 146 } 147 148 /** 149 * @internal Calculate a sum of all words in the buffer. 150 * Helper routine for the rte_raw_cksum(). 151 * 152 * @param buf 153 * Pointer to the buffer. 154 * @param len 155 * Length of the buffer. 156 * @param sum 157 * Initial value of the sum. 158 * @return 159 * sum += Sum of all words in the buffer. 160 */ 161 static inline uint32_t 162 __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) 163 { 164 const void *end; 165 166 for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t))); 167 buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { 168 uint16_t v; 169 170 memcpy(&v, buf, sizeof(uint16_t)); 171 sum += v; 172 } 173 174 /* if length is odd, keeping it byte order independent */ 175 if (unlikely(len % 2)) { 176 uint16_t left = 0; 177 178 memcpy(&left, end, 1); 179 sum += left; 180 } 181 182 return sum; 183 } 184 185 /** 186 * @internal Reduce a sum to the non-complemented checksum. 187 * Helper routine for the rte_raw_cksum(). 188 * 189 * @param sum 190 * Value of the sum. 191 * @return 192 * The non-complemented checksum. 193 */ 194 static inline uint16_t 195 __rte_raw_cksum_reduce(uint32_t sum) 196 { 197 sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); 198 sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); 199 return (uint16_t)sum; 200 } 201 202 /** 203 * Process the non-complemented checksum of a buffer. 204 * 205 * @param buf 206 * Pointer to the buffer. 207 * @param len 208 * Length of the buffer. 209 * @return 210 * The non-complemented checksum. 211 */ 212 static inline uint16_t 213 rte_raw_cksum(const void *buf, size_t len) 214 { 215 uint32_t sum; 216 217 sum = __rte_raw_cksum(buf, len, 0); 218 return __rte_raw_cksum_reduce(sum); 219 } 220 221 /** 222 * Compute the raw (non complemented) checksum of a packet. 223 * 224 * @param m 225 * The pointer to the mbuf. 226 * @param off 227 * The offset in bytes to start the checksum. 228 * @param len 229 * The length in bytes of the data to checksum. 230 * @param cksum 231 * A pointer to the checksum, filled on success. 232 * @return 233 * 0 on success, -1 on error (bad length or offset). 234 */ 235 static inline int 236 rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len, 237 uint16_t *cksum) 238 { 239 const struct rte_mbuf *seg; 240 const char *buf; 241 uint32_t sum, tmp; 242 uint32_t seglen, done; 243 244 /* easy case: all data in the first segment */ 245 if (off + len <= rte_pktmbuf_data_len(m)) { 246 *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m, 247 const char *, off), len); 248 return 0; 249 } 250 251 if (unlikely(off + len > rte_pktmbuf_pkt_len(m))) 252 return -1; /* invalid params, return a dummy value */ 253 254 /* else browse the segment to find offset */ 255 seglen = 0; 256 for (seg = m; seg != NULL; seg = seg->next) { 257 seglen = rte_pktmbuf_data_len(seg); 258 if (off < seglen) 259 break; 260 off -= seglen; 261 } 262 RTE_ASSERT(seg != NULL); 263 if (seg == NULL) 264 return -1; 265 seglen -= off; 266 buf = rte_pktmbuf_mtod_offset(seg, const char *, off); 267 if (seglen >= len) { 268 /* all in one segment */ 269 *cksum = rte_raw_cksum(buf, len); 270 return 0; 271 } 272 273 /* hard case: process checksum of several segments */ 274 sum = 0; 275 done = 0; 276 for (;;) { 277 tmp = __rte_raw_cksum(buf, seglen, 0); 278 if (done & 1) 279 tmp = rte_bswap16((uint16_t)tmp); 280 sum += tmp; 281 done += seglen; 282 if (done == len) 283 break; 284 seg = seg->next; 285 buf = rte_pktmbuf_mtod(seg, const char *); 286 seglen = rte_pktmbuf_data_len(seg); 287 if (seglen > len - done) 288 seglen = len - done; 289 } 290 291 *cksum = __rte_raw_cksum_reduce(sum); 292 return 0; 293 } 294 295 /** 296 * Process the IPv4 checksum of an IPv4 header. 297 * 298 * The checksum field must be set to 0 by the caller. 299 * 300 * @param ipv4_hdr 301 * The pointer to the contiguous IPv4 header. 302 * @return 303 * The complemented checksum to set in the IP packet. 304 */ 305 static inline uint16_t 306 rte_ipv4_cksum(const struct rte_ipv4_hdr *ipv4_hdr) 307 { 308 uint16_t cksum; 309 cksum = rte_raw_cksum(ipv4_hdr, rte_ipv4_hdr_len(ipv4_hdr)); 310 return (uint16_t)~cksum; 311 } 312 313 /** 314 * Process the pseudo-header checksum of an IPv4 header. 315 * 316 * The checksum field must be set to 0 by the caller. 317 * 318 * Depending on the ol_flags, the pseudo-header checksum expected by the 319 * drivers is not the same. For instance, when TSO is enabled, the IP 320 * payload length must not be included in the packet. 321 * 322 * When ol_flags is 0, it computes the standard pseudo-header checksum. 323 * 324 * @param ipv4_hdr 325 * The pointer to the contiguous IPv4 header. 326 * @param ol_flags 327 * The ol_flags of the associated mbuf. 328 * @return 329 * The non-complemented checksum to set in the L4 header. 330 */ 331 static inline uint16_t 332 rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) 333 { 334 struct ipv4_psd_header { 335 uint32_t src_addr; /* IP address of source host. */ 336 uint32_t dst_addr; /* IP address of destination host. */ 337 uint8_t zero; /* zero. */ 338 uint8_t proto; /* L4 protocol type. */ 339 uint16_t len; /* L4 length. */ 340 } psd_hdr; 341 342 uint32_t l3_len; 343 344 psd_hdr.src_addr = ipv4_hdr->src_addr; 345 psd_hdr.dst_addr = ipv4_hdr->dst_addr; 346 psd_hdr.zero = 0; 347 psd_hdr.proto = ipv4_hdr->next_proto_id; 348 if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 349 psd_hdr.len = 0; 350 } else { 351 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 352 psd_hdr.len = rte_cpu_to_be_16((uint16_t)(l3_len - 353 rte_ipv4_hdr_len(ipv4_hdr))); 354 } 355 return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); 356 } 357 358 /** 359 * @internal Calculate the non-complemented IPv4 L4 checksum 360 */ 361 static inline uint16_t 362 __rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 363 { 364 uint32_t cksum; 365 uint32_t l3_len, l4_len; 366 uint8_t ip_hdr_len; 367 368 ip_hdr_len = rte_ipv4_hdr_len(ipv4_hdr); 369 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 370 if (l3_len < ip_hdr_len) 371 return 0; 372 373 l4_len = l3_len - ip_hdr_len; 374 375 cksum = rte_raw_cksum(l4_hdr, l4_len); 376 cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0); 377 378 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 379 380 return (uint16_t)cksum; 381 } 382 383 /** 384 * Process the IPv4 UDP or TCP checksum. 385 * 386 * The layer 4 checksum must be set to 0 in the L4 header by the caller. 387 * 388 * @param ipv4_hdr 389 * The pointer to the contiguous IPv4 header. 390 * @param l4_hdr 391 * The pointer to the beginning of the L4 header. 392 * @return 393 * The complemented checksum to set in the L4 header. 394 */ 395 static inline uint16_t 396 rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 397 { 398 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 399 400 cksum = ~cksum; 401 402 /* 403 * Per RFC 768: If the computed checksum is zero for UDP, 404 * it is transmitted as all ones 405 * (the equivalent in one's complement arithmetic). 406 */ 407 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 408 cksum = 0xffff; 409 410 return cksum; 411 } 412 413 /** 414 * @internal Calculate the non-complemented IPv4 L4 checksum of a packet 415 */ 416 static inline uint16_t 417 __rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 418 const struct rte_ipv4_hdr *ipv4_hdr, 419 uint16_t l4_off) 420 { 421 uint16_t raw_cksum; 422 uint32_t cksum; 423 424 if (l4_off > m->pkt_len) 425 return 0; 426 427 if (rte_raw_cksum_mbuf(m, l4_off, m->pkt_len - l4_off, &raw_cksum)) 428 return 0; 429 430 cksum = raw_cksum + rte_ipv4_phdr_cksum(ipv4_hdr, 0); 431 432 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 433 434 return (uint16_t)cksum; 435 } 436 437 /** 438 * @warning 439 * @b EXPERIMENTAL: this API may change without prior notice. 440 * 441 * Compute the IPv4 UDP/TCP checksum of a packet. 442 * 443 * @param m 444 * The pointer to the mbuf. 445 * @param ipv4_hdr 446 * The pointer to the contiguous IPv4 header. 447 * @param l4_off 448 * The offset in bytes to start L4 checksum. 449 * @return 450 * The complemented checksum to set in the L4 header. 451 */ 452 __rte_experimental 453 static inline uint16_t 454 rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 455 const struct rte_ipv4_hdr *ipv4_hdr, uint16_t l4_off) 456 { 457 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 458 459 cksum = ~cksum; 460 461 /* 462 * Per RFC 768: If the computed checksum is zero for UDP, 463 * it is transmitted as all ones 464 * (the equivalent in one's complement arithmetic). 465 */ 466 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 467 cksum = 0xffff; 468 469 return cksum; 470 } 471 472 /** 473 * Validate the IPv4 UDP or TCP checksum. 474 * 475 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 476 * (i.e. no checksum). 477 * 478 * @param ipv4_hdr 479 * The pointer to the contiguous IPv4 header. 480 * @param l4_hdr 481 * The pointer to the beginning of the L4 header. 482 * @return 483 * Return 0 if the checksum is correct, else -1. 484 */ 485 __rte_experimental 486 static inline int 487 rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr, 488 const void *l4_hdr) 489 { 490 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 491 492 if (cksum != 0xffff) 493 return -1; 494 495 return 0; 496 } 497 498 /** 499 * @warning 500 * @b EXPERIMENTAL: this API may change without prior notice. 501 * 502 * Verify the IPv4 UDP/TCP checksum of a packet. 503 * 504 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 505 * (i.e. no checksum). 506 * 507 * @param m 508 * The pointer to the mbuf. 509 * @param ipv4_hdr 510 * The pointer to the contiguous IPv4 header. 511 * @param l4_off 512 * The offset in bytes to start L4 checksum. 513 * @return 514 * Return 0 if the checksum is correct, else -1. 515 */ 516 __rte_experimental 517 static inline uint16_t 518 rte_ipv4_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, 519 const struct rte_ipv4_hdr *ipv4_hdr, 520 uint16_t l4_off) 521 { 522 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 523 524 if (cksum != 0xffff) 525 return -1; 526 527 return 0; 528 } 529 530 /** 531 * IPv6 Header 532 */ 533 struct rte_ipv6_hdr { 534 rte_be32_t vtc_flow; /**< IP version, traffic class & flow label. */ 535 rte_be16_t payload_len; /**< IP payload size, including ext. headers */ 536 uint8_t proto; /**< Protocol, next header. */ 537 uint8_t hop_limits; /**< Hop limits. */ 538 uint8_t src_addr[16]; /**< IP address of source host. */ 539 uint8_t dst_addr[16]; /**< IP address of destination host(s). */ 540 } __rte_packed; 541 542 /** 543 * IPv6 Routing Extension Header 544 */ 545 struct rte_ipv6_routing_ext { 546 uint8_t next_hdr; /**< Protocol, next header. */ 547 uint8_t hdr_len; /**< Header length. */ 548 uint8_t type; /**< Extension header type. */ 549 uint8_t segments_left; /**< Valid segments number. */ 550 __extension__ 551 union { 552 rte_be32_t flags; /**< Packet control data per type. */ 553 struct { 554 uint8_t last_entry; /**< The last_entry field of SRH */ 555 uint8_t flag; /**< Packet flag. */ 556 rte_be16_t tag; /**< Packet tag. */ 557 }; 558 }; 559 /* Next are 128-bit IPv6 address fields to describe segments. */ 560 } __rte_packed; 561 562 /* IPv6 vtc_flow: IPv / TC / flow_label */ 563 #define RTE_IPV6_HDR_FL_SHIFT 0 564 #define RTE_IPV6_HDR_TC_SHIFT 20 565 #define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1) 566 #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT) 567 #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT) 568 #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT) 569 #define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK 570 571 #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */ 572 573 /** 574 * Process the pseudo-header checksum of an IPv6 header. 575 * 576 * Depending on the ol_flags, the pseudo-header checksum expected by the 577 * drivers is not the same. For instance, when TSO is enabled, the IPv6 578 * payload length must not be included in the packet. 579 * 580 * When ol_flags is 0, it computes the standard pseudo-header checksum. 581 * 582 * @param ipv6_hdr 583 * The pointer to the contiguous IPv6 header. 584 * @param ol_flags 585 * The ol_flags of the associated mbuf. 586 * @return 587 * The non-complemented checksum to set in the L4 header. 588 */ 589 static inline uint16_t 590 rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags) 591 { 592 uint32_t sum; 593 struct { 594 rte_be32_t len; /* L4 length. */ 595 rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */ 596 } psd_hdr; 597 598 psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24); 599 if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 600 psd_hdr.len = 0; 601 } else { 602 psd_hdr.len = ipv6_hdr->payload_len; 603 } 604 605 sum = __rte_raw_cksum(ipv6_hdr->src_addr, 606 sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr), 607 0); 608 sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum); 609 return __rte_raw_cksum_reduce(sum); 610 } 611 612 /** 613 * @internal Calculate the non-complemented IPv6 L4 checksum 614 */ 615 static inline uint16_t 616 __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr) 617 { 618 uint32_t cksum; 619 uint32_t l4_len; 620 621 l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len); 622 623 cksum = rte_raw_cksum(l4_hdr, l4_len); 624 cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0); 625 626 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 627 628 return (uint16_t)cksum; 629 } 630 631 /** 632 * Process the IPv6 UDP or TCP checksum. 633 * 634 * The IPv6 header must not be followed by extension headers. The layer 4 635 * checksum must be set to 0 in the L4 header by the caller. 636 * 637 * @param ipv6_hdr 638 * The pointer to the contiguous IPv6 header. 639 * @param l4_hdr 640 * The pointer to the beginning of the L4 header. 641 * @return 642 * The complemented checksum to set in the L4 header. 643 */ 644 static inline uint16_t 645 rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr) 646 { 647 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 648 649 cksum = ~cksum; 650 651 /* 652 * Per RFC 768: If the computed checksum is zero for UDP, 653 * it is transmitted as all ones 654 * (the equivalent in one's complement arithmetic). 655 */ 656 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP) 657 cksum = 0xffff; 658 659 return cksum; 660 } 661 662 /** 663 * @internal Calculate the non-complemented IPv6 L4 checksum of a packet 664 */ 665 static inline uint16_t 666 __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m, 667 const struct rte_ipv6_hdr *ipv6_hdr, 668 uint16_t l4_off) 669 { 670 uint16_t raw_cksum; 671 uint32_t cksum; 672 673 if (l4_off > m->pkt_len) 674 return 0; 675 676 if (rte_raw_cksum_mbuf(m, l4_off, m->pkt_len - l4_off, &raw_cksum)) 677 return 0; 678 679 cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0); 680 681 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 682 683 return (uint16_t)cksum; 684 } 685 686 /** 687 * @warning 688 * @b EXPERIMENTAL: this API may change without prior notice. 689 * 690 * Process the IPv6 UDP or TCP checksum of a packet. 691 * 692 * The IPv6 header must not be followed by extension headers. The layer 4 693 * checksum must be set to 0 in the L4 header by the caller. 694 * 695 * @param m 696 * The pointer to the mbuf. 697 * @param ipv6_hdr 698 * The pointer to the contiguous IPv6 header. 699 * @param l4_off 700 * The offset in bytes to start L4 checksum. 701 * @return 702 * The complemented checksum to set in the L4 header. 703 */ 704 __rte_experimental 705 static inline uint16_t 706 rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m, 707 const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off) 708 { 709 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off); 710 711 cksum = ~cksum; 712 713 /* 714 * Per RFC 768: If the computed checksum is zero for UDP, 715 * it is transmitted as all ones 716 * (the equivalent in one's complement arithmetic). 717 */ 718 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP) 719 cksum = 0xffff; 720 721 return cksum; 722 } 723 724 /** 725 * Validate the IPv6 UDP or TCP checksum. 726 * 727 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0: 728 * this is either invalid or means no checksum in some situations. See 8.1 729 * (Upper-Layer Checksums) in RFC 8200. 730 * 731 * @param ipv6_hdr 732 * The pointer to the contiguous IPv6 header. 733 * @param l4_hdr 734 * The pointer to the beginning of the L4 header. 735 * @return 736 * Return 0 if the checksum is correct, else -1. 737 */ 738 __rte_experimental 739 static inline int 740 rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr, 741 const void *l4_hdr) 742 { 743 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 744 745 if (cksum != 0xffff) 746 return -1; 747 748 return 0; 749 } 750 751 /** 752 * @warning 753 * @b EXPERIMENTAL: this API may change without prior notice. 754 * 755 * Validate the IPv6 UDP or TCP checksum of a packet. 756 * 757 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0: 758 * this is either invalid or means no checksum in some situations. See 8.1 759 * (Upper-Layer Checksums) in RFC 8200. 760 * 761 * @param m 762 * The pointer to the mbuf. 763 * @param ipv6_hdr 764 * The pointer to the contiguous IPv6 header. 765 * @param l4_off 766 * The offset in bytes to start L4 checksum. 767 * @return 768 * Return 0 if the checksum is correct, else -1. 769 */ 770 __rte_experimental 771 static inline int 772 rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, 773 const struct rte_ipv6_hdr *ipv6_hdr, 774 uint16_t l4_off) 775 { 776 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off); 777 778 if (cksum != 0xffff) 779 return -1; 780 781 return 0; 782 } 783 784 /** IPv6 fragment extension header. */ 785 #define RTE_IPV6_EHDR_MF_SHIFT 0 786 #define RTE_IPV6_EHDR_MF_MASK 1 787 #define RTE_IPV6_EHDR_FO_SHIFT 3 788 #define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1)) 789 #define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT) 790 791 #define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK) 792 793 #define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK) 794 #define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT) 795 796 #define RTE_IPV6_SET_FRAG_DATA(fo, mf) \ 797 (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK)) 798 799 struct rte_ipv6_fragment_ext { 800 uint8_t next_header; /**< Next header type */ 801 uint8_t reserved; /**< Reserved */ 802 rte_be16_t frag_data; /**< All fragmentation data */ 803 rte_be32_t id; /**< Packet ID */ 804 } __rte_packed; 805 806 /* IPv6 fragment extension header size */ 807 #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext) 808 809 /** 810 * Parse next IPv6 header extension 811 * 812 * This function checks if proto number is an IPv6 extensions and parses its 813 * data if so, providing information on next header and extension length. 814 * 815 * @param p 816 * Pointer to an extension raw data. 817 * @param proto 818 * Protocol number extracted from the "next header" field from 819 * the IPv6 header or the previous extension. 820 * @param ext_len 821 * Extension data length. 822 * @return 823 * next protocol number if proto is an IPv6 extension, -EINVAL otherwise 824 */ 825 __rte_experimental 826 static inline int 827 rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len) 828 { 829 int next_proto; 830 831 switch (proto) { 832 case IPPROTO_AH: 833 next_proto = *p++; 834 *ext_len = (*p + 2) * sizeof(uint32_t); 835 break; 836 837 case IPPROTO_HOPOPTS: 838 case IPPROTO_ROUTING: 839 case IPPROTO_DSTOPTS: 840 next_proto = *p++; 841 *ext_len = (*p + 1) * sizeof(uint64_t); 842 break; 843 844 case IPPROTO_FRAGMENT: 845 next_proto = *p; 846 *ext_len = RTE_IPV6_FRAG_HDR_SIZE; 847 break; 848 849 default: 850 return -EINVAL; 851 } 852 853 return next_proto; 854 } 855 856 #ifdef __cplusplus 857 } 858 #endif 859 860 #endif /* _RTE_IP_H_ */ 861