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