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_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 * Process the pseudo-header checksum of an IPv4 header. 168 * 169 * The checksum field must be set to 0 by the caller. 170 * 171 * Depending on the ol_flags, the pseudo-header checksum expected by the 172 * drivers is not the same. For instance, when TSO is enabled, the IP 173 * payload length must not be included in the packet. 174 * 175 * When ol_flags is 0, it computes the standard pseudo-header checksum. 176 * 177 * @param ipv4_hdr 178 * The pointer to the contiguous IPv4 header. 179 * @param ol_flags 180 * The ol_flags of the associated mbuf. 181 * @return 182 * The non-complemented checksum to set in the L4 header. 183 */ 184 static inline uint16_t 185 rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) 186 { 187 struct ipv4_psd_header { 188 uint32_t src_addr; /* IP address of source host. */ 189 uint32_t dst_addr; /* IP address of destination host. */ 190 uint8_t zero; /* zero. */ 191 uint8_t proto; /* L4 protocol type. */ 192 uint16_t len; /* L4 length. */ 193 } psd_hdr; 194 195 uint32_t l3_len; 196 197 psd_hdr.src_addr = ipv4_hdr->src_addr; 198 psd_hdr.dst_addr = ipv4_hdr->dst_addr; 199 psd_hdr.zero = 0; 200 psd_hdr.proto = ipv4_hdr->next_proto_id; 201 if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { 202 psd_hdr.len = 0; 203 } else { 204 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 205 psd_hdr.len = rte_cpu_to_be_16((uint16_t)(l3_len - 206 rte_ipv4_hdr_len(ipv4_hdr))); 207 } 208 return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); 209 } 210 211 /** 212 * @internal Calculate the non-complemented IPv4 L4 checksum 213 */ 214 static inline uint16_t 215 __rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 216 { 217 uint32_t cksum; 218 uint32_t l3_len, l4_len; 219 uint8_t ip_hdr_len; 220 221 ip_hdr_len = rte_ipv4_hdr_len(ipv4_hdr); 222 l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); 223 if (l3_len < ip_hdr_len) 224 return 0; 225 226 l4_len = l3_len - ip_hdr_len; 227 228 cksum = rte_raw_cksum(l4_hdr, l4_len); 229 cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0); 230 231 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 232 233 return (uint16_t)cksum; 234 } 235 236 /** 237 * Process the IPv4 UDP or TCP checksum. 238 * 239 * The layer 4 checksum must be set to 0 in the L4 header by the caller. 240 * 241 * @param ipv4_hdr 242 * The pointer to the contiguous IPv4 header. 243 * @param l4_hdr 244 * The pointer to the beginning of the L4 header. 245 * @return 246 * The complemented checksum to set in the L4 header. 247 */ 248 static inline uint16_t 249 rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) 250 { 251 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 252 253 cksum = ~cksum; 254 255 /* 256 * Per RFC 768: If the computed checksum is zero for UDP, 257 * it is transmitted as all ones 258 * (the equivalent in one's complement arithmetic). 259 */ 260 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 261 cksum = 0xffff; 262 263 return cksum; 264 } 265 266 /** 267 * @internal Calculate the non-complemented IPv4 L4 checksum of a packet 268 */ 269 static inline uint16_t 270 __rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 271 const struct rte_ipv4_hdr *ipv4_hdr, 272 uint16_t l4_off) 273 { 274 uint16_t raw_cksum; 275 uint32_t cksum; 276 uint16_t len; 277 278 if (unlikely(l4_off > m->pkt_len)) 279 return 0; /* invalid params, return a dummy value */ 280 281 len = rte_be_to_cpu_16(ipv4_hdr->total_length) - (uint16_t)rte_ipv4_hdr_len(ipv4_hdr); 282 283 if (rte_raw_cksum_mbuf(m, l4_off, len, &raw_cksum)) 284 return 0; 285 286 cksum = raw_cksum + rte_ipv4_phdr_cksum(ipv4_hdr, 0); 287 288 cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff); 289 290 return (uint16_t)cksum; 291 } 292 293 /** 294 * Compute the IPv4 UDP/TCP checksum of a packet. 295 * 296 * @param m 297 * The pointer to the mbuf. 298 * @param ipv4_hdr 299 * The pointer to the contiguous IPv4 header. 300 * @param l4_off 301 * The offset in bytes to start L4 checksum. 302 * @return 303 * The complemented checksum to set in the L4 header. 304 */ 305 static inline uint16_t 306 rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m, 307 const struct rte_ipv4_hdr *ipv4_hdr, uint16_t l4_off) 308 { 309 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 310 311 cksum = ~cksum; 312 313 /* 314 * Per RFC 768: If the computed checksum is zero for UDP, 315 * it is transmitted as all ones 316 * (the equivalent in one's complement arithmetic). 317 */ 318 if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP) 319 cksum = 0xffff; 320 321 return cksum; 322 } 323 324 /** 325 * Validate the IPv4 UDP or TCP checksum. 326 * 327 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 328 * (i.e. no checksum). 329 * 330 * @param ipv4_hdr 331 * The pointer to the contiguous IPv4 header. 332 * @param l4_hdr 333 * The pointer to the beginning of the L4 header. 334 * @return 335 * Return 0 if the checksum is correct, else -1. 336 */ 337 static inline int 338 rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr, 339 const void *l4_hdr) 340 { 341 uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr); 342 343 if (cksum != 0xffff) 344 return -1; 345 346 return 0; 347 } 348 349 /** 350 * Verify the IPv4 UDP/TCP checksum of a packet. 351 * 352 * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0 353 * (i.e. no checksum). 354 * 355 * @param m 356 * The pointer to the mbuf. 357 * @param ipv4_hdr 358 * The pointer to the contiguous IPv4 header. 359 * @param l4_off 360 * The offset in bytes to start L4 checksum. 361 * @return 362 * Return 0 if the checksum is correct, else -1. 363 */ 364 static inline int 365 rte_ipv4_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m, 366 const struct rte_ipv4_hdr *ipv4_hdr, 367 uint16_t l4_off) 368 { 369 uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off); 370 371 if (cksum != 0xffff) 372 return -1; 373 374 return 0; 375 } 376 377 #ifdef __cplusplus 378 } 379 #endif 380 381 #endif /* _RTE_IP_H_ */ 382