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_IP4_H_ 10 #define _RTE_IP4_H_ 11 12 /** 13 * @file 14 * 15 * IPv4-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_byteorder.h> 32 #include <rte_cksum.h> 33 #include <rte_mbuf.h> 34 35 #ifdef __cplusplus 36 extern "C" { 37 #endif 38 39 /** 40 * IPv4 Header 41 */ 42 struct __rte_aligned(2) 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 * Process the IPv4 checksum of an IPv4 header. 150 * 151 * The checksum field must be set to 0 by the caller. 152 * 153 * @param ipv4_hdr 154 * The pointer to the contiguous IPv4 header. 155 * @return 156 * The complemented checksum to set in the IP packet. 157 */ 158 static inline uint16_t 159 rte_ipv4_cksum(const struct rte_ipv4_hdr *ipv4_hdr) 160 { 161 uint16_t cksum; 162 cksum = rte_raw_cksum(ipv4_hdr, rte_ipv4_hdr_len(ipv4_hdr)); 163 return (uint16_t)~cksum; 164 } 165 166 /** 167 * @warning 168 * @b EXPERIMENTAL: this API may change without prior notice. 169 * 170 * Process the IPv4 checksum of an IPv4 header without any extensions. 171 * 172 * The checksum field does NOT have to be set by the caller, the field 173 * is skipped by the calculation. 174 * 175 * @param ipv4_hdr 176 * The pointer to the contiguous IPv4 header. 177 * @return 178 * The complemented checksum to set in the IP packet. 179 */ 180 __rte_experimental 181 static inline uint16_t 182 rte_ipv4_cksum_simple(const struct rte_ipv4_hdr *ipv4_hdr) 183 { 184 const uint16_t *v16_h; 185 uint32_t ip_cksum; 186 187 /* 188 * Compute the sum of successive 16-bit words of the IPv4 header, 189 * skipping the checksum field of the header. 190 */ 191 v16_h = (const uint16_t *)ipv4_hdr; 192 ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] + 193 v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9]; 194 195 /* reduce 32 bit checksum to 16 bits and complement it */ 196 ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16); 197 ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16); 198 return (uint16_t)(~ip_cksum); 199 } 200 201 /** 202 * Process the pseudo-header checksum of an IPv4 header. 203 * 204 * The checksum field must be set to 0 by the caller. 205 * 206 * Depending on the ol_flags, the pseudo-header checksum expected by the 207 * drivers is not the same. For instance, when TSO is enabled, the IP 208 * payload length must not be included in the packet. 209 * 210 * When ol_flags is 0, it computes the standard pseudo-header checksum. 211 * 212 * @param ipv4_hdr 213 * The pointer to the contiguous IPv4 header. 214 * @param ol_flags 215 * The ol_flags of the associated mbuf. 216 * @return 217 * The non-complemented checksum to set in the L4 header. 218 */ 219 static inline uint16_t 220 rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) 221 { 222 struct ipv4_psd_header { 223 uint32_t src_addr; /* IP address of source host. */ 224 uint32_t dst_addr; /* IP address of destination host. */ 225 uint8_t zero; /* zero. */ 226 uint8_t proto; /* L4 protocol type. */ 227 uint16_t len; /* L4 length. */ 228 } psd_hdr; 229 230 uint32_t l3_len; 231 232 psd_hdr.src_addr = ipv4_hdr->src_addr; 233 psd_hdr.dst_addr = ipv4_hdr->dst_addr; 234 psd_hdr.zero = 0; 235 psd_hdr.proto = ipv4_hdr->next_proto_id; 236 if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { 237 psd_hdr.len = 0; 238 } else { 239 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 240 psd_hdr.len = rte_cpu_to_be_16((uint16_t)(l3_len - 241 rte_ipv4_hdr_len(ipv4_hdr))); 242 } 243 return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); 244 } 245 246 /** 247 * @internal Calculate the non-complemented IPv4 L4 checksum 248 */ 249 static inline uint16_t 250 __rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 251 { 252 uint32_t cksum; 253 uint32_t l3_len, l4_len; 254 uint8_t ip_hdr_len; 255 256 ip_hdr_len = rte_ipv4_hdr_len(ipv4_hdr); 257 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 258 if (l3_len < ip_hdr_len) 259 return 0; 260 261 l4_len = l3_len - ip_hdr_len; 262 263 cksum = rte_raw_cksum(l4_hdr, l4_len); 264 cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0); 265 266 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 267 268 return (uint16_t)cksum; 269 } 270 271 /** 272 * Process the IPv4 UDP or TCP checksum. 273 * 274 * The layer 4 checksum must be set to 0 in the L4 header by the caller. 275 * 276 * @param ipv4_hdr 277 * The pointer to the contiguous IPv4 header. 278 * @param l4_hdr 279 * The pointer to the beginning of the L4 header. 280 * @return 281 * The complemented checksum to set in the L4 header. 282 */ 283 static inline uint16_t 284 rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 285 { 286 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 287 288 cksum = ~cksum; 289 290 /* 291 * Per RFC 768: If the computed checksum is zero for UDP, 292 * it is transmitted as all ones 293 * (the equivalent in one's complement arithmetic). 294 */ 295 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 296 cksum = 0xffff; 297 298 return cksum; 299 } 300 301 /** 302 * @internal Calculate the non-complemented IPv4 L4 checksum of a packet 303 */ 304 static inline uint16_t 305 __rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 306 const struct rte_ipv4_hdr *ipv4_hdr, 307 uint16_t l4_off) 308 { 309 uint16_t raw_cksum; 310 uint32_t cksum; 311 uint16_t len; 312 313 if (unlikely(l4_off > m->pkt_len)) 314 return 0; /* invalid params, return a dummy value */ 315 316 len = rte_be_to_cpu_16(ipv4_hdr->total_length) - (uint16_t)rte_ipv4_hdr_len(ipv4_hdr); 317 318 if (rte_raw_cksum_mbuf(m, l4_off, len, &raw_cksum)) 319 return 0; 320 321 cksum = raw_cksum + rte_ipv4_phdr_cksum(ipv4_hdr, 0); 322 323 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 324 325 return (uint16_t)cksum; 326 } 327 328 /** 329 * Compute the IPv4 UDP/TCP checksum of a packet. 330 * 331 * @param m 332 * The pointer to the mbuf. 333 * @param ipv4_hdr 334 * The pointer to the contiguous IPv4 header. 335 * @param l4_off 336 * The offset in bytes to start L4 checksum. 337 * @return 338 * The complemented checksum to set in the L4 header. 339 */ 340 static inline uint16_t 341 rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 342 const struct rte_ipv4_hdr *ipv4_hdr, uint16_t l4_off) 343 { 344 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 345 346 cksum = ~cksum; 347 348 /* 349 * Per RFC 768: If the computed checksum is zero for UDP, 350 * it is transmitted as all ones 351 * (the equivalent in one's complement arithmetic). 352 */ 353 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 354 cksum = 0xffff; 355 356 return cksum; 357 } 358 359 /** 360 * Validate the IPv4 UDP or TCP checksum. 361 * 362 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 363 * (i.e. no checksum). 364 * 365 * @param ipv4_hdr 366 * The pointer to the contiguous IPv4 header. 367 * @param l4_hdr 368 * The pointer to the beginning of the L4 header. 369 * @return 370 * Return 0 if the checksum is correct, else -1. 371 */ 372 static inline int 373 rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr, 374 const void *l4_hdr) 375 { 376 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 377 378 if (cksum != 0xffff) 379 return -1; 380 381 return 0; 382 } 383 384 /** 385 * Verify the IPv4 UDP/TCP checksum of a packet. 386 * 387 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 388 * (i.e. no checksum). 389 * 390 * @param m 391 * The pointer to the mbuf. 392 * @param ipv4_hdr 393 * The pointer to the contiguous IPv4 header. 394 * @param l4_off 395 * The offset in bytes to start L4 checksum. 396 * @return 397 * Return 0 if the checksum is correct, else -1. 398 */ 399 static inline int 400 rte_ipv4_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, 401 const struct rte_ipv4_hdr *ipv4_hdr, 402 uint16_t l4_off) 403 { 404 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 405 406 if (cksum != 0xffff) 407 return -1; 408 409 return 0; 410 } 411 412 #ifdef __cplusplus 413 } 414 #endif 415 416 #endif /* _RTE_IP_H_ */ 417