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 | RTE_MBUF_F_TX_UDP_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 int 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 /* IPv6 routing extension type definition. */ 543 #define RTE_IPV6_SRCRT_TYPE_4 4 544 545 /** 546 * IPv6 Routing Extension Header 547 */ 548 struct rte_ipv6_routing_ext { 549 uint8_t next_hdr; /**< Protocol, next header. */ 550 uint8_t hdr_len; /**< Header length. */ 551 uint8_t type; /**< Extension header type. */ 552 uint8_t segments_left; /**< Valid segments number. */ 553 __extension__ 554 union { 555 rte_be32_t flags; /**< Packet control data per type. */ 556 struct { 557 uint8_t last_entry; /**< The last_entry field of SRH */ 558 uint8_t flag; /**< Packet flag. */ 559 rte_be16_t tag; /**< Packet tag. */ 560 }; 561 }; 562 /* Next are 128-bit IPv6 address fields to describe segments. */ 563 } __rte_packed; 564 565 /* IPv6 vtc_flow: IPv / TC / flow_label */ 566 #define RTE_IPV6_HDR_FL_SHIFT 0 567 #define RTE_IPV6_HDR_TC_SHIFT 20 568 #define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1) 569 #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT) 570 #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT) 571 #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT) 572 #define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK 573 574 #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */ 575 576 /** 577 * Process the pseudo-header checksum of an IPv6 header. 578 * 579 * Depending on the ol_flags, the pseudo-header checksum expected by the 580 * drivers is not the same. For instance, when TSO is enabled, the IPv6 581 * payload length must not be included in the packet. 582 * 583 * When ol_flags is 0, it computes the standard pseudo-header checksum. 584 * 585 * @param ipv6_hdr 586 * The pointer to the contiguous IPv6 header. 587 * @param ol_flags 588 * The ol_flags of the associated mbuf. 589 * @return 590 * The non-complemented checksum to set in the L4 header. 591 */ 592 static inline uint16_t 593 rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags) 594 { 595 uint32_t sum; 596 struct { 597 rte_be32_t len; /* L4 length. */ 598 rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */ 599 } psd_hdr; 600 601 psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24); 602 if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { 603 psd_hdr.len = 0; 604 } else { 605 psd_hdr.len = ipv6_hdr->payload_len; 606 } 607 608 sum = __rte_raw_cksum(ipv6_hdr->src_addr, 609 sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr), 610 0); 611 sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum); 612 return __rte_raw_cksum_reduce(sum); 613 } 614 615 /** 616 * @internal Calculate the non-complemented IPv6 L4 checksum 617 */ 618 static inline uint16_t 619 __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr) 620 { 621 uint32_t cksum; 622 uint32_t l4_len; 623 624 l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len); 625 626 cksum = rte_raw_cksum(l4_hdr, l4_len); 627 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. 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 ipv6_hdr 641 * The pointer to the contiguous IPv6 header. 642 * @param l4_hdr 643 * The pointer to the beginning of the L4 header. 644 * @return 645 * The complemented checksum to set in the L4 header. 646 */ 647 static inline uint16_t 648 rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr) 649 { 650 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 651 652 cksum = ~cksum; 653 654 /* 655 * Per RFC 768: If the computed checksum is zero for UDP, 656 * it is transmitted as all ones 657 * (the equivalent in one's complement arithmetic). 658 */ 659 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP) 660 cksum = 0xffff; 661 662 return cksum; 663 } 664 665 /** 666 * @internal Calculate the non-complemented IPv6 L4 checksum of a packet 667 */ 668 static inline uint16_t 669 __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m, 670 const struct rte_ipv6_hdr *ipv6_hdr, 671 uint16_t l4_off) 672 { 673 uint16_t raw_cksum; 674 uint32_t cksum; 675 676 if (l4_off > m->pkt_len) 677 return 0; 678 679 if (rte_raw_cksum_mbuf(m, l4_off, m->pkt_len - l4_off, &raw_cksum)) 680 return 0; 681 682 cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0); 683 684 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 685 686 return (uint16_t)cksum; 687 } 688 689 /** 690 * @warning 691 * @b EXPERIMENTAL: this API may change without prior notice. 692 * 693 * Process the IPv6 UDP or TCP checksum of a packet. 694 * 695 * The IPv6 header must not be followed by extension headers. The layer 4 696 * checksum must be set to 0 in the L4 header by the caller. 697 * 698 * @param m 699 * The pointer to the mbuf. 700 * @param ipv6_hdr 701 * The pointer to the contiguous IPv6 header. 702 * @param l4_off 703 * The offset in bytes to start L4 checksum. 704 * @return 705 * The complemented checksum to set in the L4 header. 706 */ 707 __rte_experimental 708 static inline uint16_t 709 rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m, 710 const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off) 711 { 712 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off); 713 714 cksum = ~cksum; 715 716 /* 717 * Per RFC 768: If the computed checksum is zero for UDP, 718 * it is transmitted as all ones 719 * (the equivalent in one's complement arithmetic). 720 */ 721 if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP) 722 cksum = 0xffff; 723 724 return cksum; 725 } 726 727 /** 728 * Validate the IPv6 UDP or TCP checksum. 729 * 730 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0: 731 * this is either invalid or means no checksum in some situations. See 8.1 732 * (Upper-Layer Checksums) in RFC 8200. 733 * 734 * @param ipv6_hdr 735 * The pointer to the contiguous IPv6 header. 736 * @param l4_hdr 737 * The pointer to the beginning of the L4 header. 738 * @return 739 * Return 0 if the checksum is correct, else -1. 740 */ 741 __rte_experimental 742 static inline int 743 rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr, 744 const void *l4_hdr) 745 { 746 uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 747 748 if (cksum != 0xffff) 749 return -1; 750 751 return 0; 752 } 753 754 /** 755 * @warning 756 * @b EXPERIMENTAL: this API may change without prior notice. 757 * 758 * Validate the IPv6 UDP or TCP checksum of a packet. 759 * 760 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0: 761 * this is either invalid or means no checksum in some situations. See 8.1 762 * (Upper-Layer Checksums) in RFC 8200. 763 * 764 * @param m 765 * The pointer to the mbuf. 766 * @param ipv6_hdr 767 * The pointer to the contiguous IPv6 header. 768 * @param l4_off 769 * The offset in bytes to start L4 checksum. 770 * @return 771 * Return 0 if the checksum is correct, else -1. 772 */ 773 __rte_experimental 774 static inline int 775 rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, 776 const struct rte_ipv6_hdr *ipv6_hdr, 777 uint16_t l4_off) 778 { 779 uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off); 780 781 if (cksum != 0xffff) 782 return -1; 783 784 return 0; 785 } 786 787 /** IPv6 fragment extension header. */ 788 #define RTE_IPV6_EHDR_MF_SHIFT 0 789 #define RTE_IPV6_EHDR_MF_MASK 1 790 #define RTE_IPV6_EHDR_FO_SHIFT 3 791 #define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1)) 792 #define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT) 793 794 #define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK) 795 796 #define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK) 797 #define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT) 798 799 #define RTE_IPV6_SET_FRAG_DATA(fo, mf) \ 800 (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK)) 801 802 struct rte_ipv6_fragment_ext { 803 uint8_t next_header; /**< Next header type */ 804 uint8_t reserved; /**< Reserved */ 805 rte_be16_t frag_data; /**< All fragmentation data */ 806 rte_be32_t id; /**< Packet ID */ 807 } __rte_packed; 808 809 /* IPv6 fragment extension header size */ 810 #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext) 811 812 /** 813 * Parse next IPv6 header extension 814 * 815 * This function checks if proto number is an IPv6 extensions and parses its 816 * data if so, providing information on next header and extension length. 817 * 818 * @param p 819 * Pointer to an extension raw data. 820 * @param proto 821 * Protocol number extracted from the "next header" field from 822 * the IPv6 header or the previous extension. 823 * @param ext_len 824 * Extension data length. 825 * @return 826 * next protocol number if proto is an IPv6 extension, -EINVAL otherwise 827 */ 828 __rte_experimental 829 static inline int 830 rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len) 831 { 832 int next_proto; 833 834 switch (proto) { 835 case IPPROTO_AH: 836 next_proto = *p++; 837 *ext_len = (*p + 2) * sizeof(uint32_t); 838 break; 839 840 case IPPROTO_HOPOPTS: 841 case IPPROTO_ROUTING: 842 case IPPROTO_DSTOPTS: 843 next_proto = *p++; 844 *ext_len = (*p + 1) * sizeof(uint64_t); 845 break; 846 847 case IPPROTO_FRAGMENT: 848 next_proto = *p; 849 *ext_len = RTE_IPV6_FRAG_HDR_SIZE; 850 break; 851 852 default: 853 return -EINVAL; 854 } 855 856 return next_proto; 857 } 858 859 #ifdef __cplusplus 860 } 861 #endif 862 863 #endif /* _RTE_IP_H_ */ 864