xref: /dpdk/lib/net/rte_ip4.h (revision 21a66096bb44a4468353782c36fc85913520dc6c)
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