Branch data Line data Source code
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_byteorder.h>
32 : : #include <rte_mbuf.h>
33 : :
34 : : #ifdef __cplusplus
35 : : extern "C" {
36 : : #endif
37 : :
38 : : /**
39 : : * IPv4 Header
40 : : */
41 : : struct rte_ipv4_hdr {
42 : : __extension__
43 : : union {
44 : : uint8_t version_ihl; /**< version and header length */
45 : : struct {
46 : : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
47 : : uint8_t ihl:4; /**< header length */
48 : : uint8_t version:4; /**< version */
49 : : #elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
50 : : uint8_t version:4; /**< version */
51 : : uint8_t ihl:4; /**< header length */
52 : : #endif
53 : : };
54 : : };
55 : : uint8_t type_of_service; /**< type of service */
56 : : rte_be16_t total_length; /**< length of packet */
57 : : rte_be16_t packet_id; /**< packet ID */
58 : : rte_be16_t fragment_offset; /**< fragmentation offset */
59 : : uint8_t time_to_live; /**< time to live */
60 : : uint8_t next_proto_id; /**< protocol ID */
61 : : rte_be16_t hdr_checksum; /**< header checksum */
62 : : rte_be32_t src_addr; /**< source address */
63 : : rte_be32_t dst_addr; /**< destination address */
64 : : } __rte_packed;
65 : :
66 : : /** Create IPv4 address */
67 : : #define RTE_IPV4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \
68 : : (((b) & 0xff) << 16) | \
69 : : (((c) & 0xff) << 8) | \
70 : : ((d) & 0xff))
71 : :
72 : : /** Maximal IPv4 packet length (including a header) */
73 : : #define RTE_IPV4_MAX_PKT_LEN 65535
74 : :
75 : : /** Internet header length mask for version_ihl field */
76 : : #define RTE_IPV4_HDR_IHL_MASK (0x0f)
77 : : /**
78 : : * Internet header length field multiplier (IHL field specifies overall header
79 : : * length in number of 4-byte words)
80 : : */
81 : : #define RTE_IPV4_IHL_MULTIPLIER (4)
82 : :
83 : : /* Type of Service fields */
84 : : #define RTE_IPV4_HDR_DSCP_MASK (0xfc)
85 : : #define RTE_IPV4_HDR_ECN_MASK (0x03)
86 : : #define RTE_IPV4_HDR_ECN_CE RTE_IPV4_HDR_ECN_MASK
87 : :
88 : : /* Fragment Offset * Flags. */
89 : : #define RTE_IPV4_HDR_DF_SHIFT 14
90 : : #define RTE_IPV4_HDR_MF_SHIFT 13
91 : : #define RTE_IPV4_HDR_FO_SHIFT 3
92 : :
93 : : #define RTE_IPV4_HDR_DF_FLAG (1 << RTE_IPV4_HDR_DF_SHIFT)
94 : : #define RTE_IPV4_HDR_MF_FLAG (1 << RTE_IPV4_HDR_MF_SHIFT)
95 : :
96 : : #define RTE_IPV4_HDR_OFFSET_MASK ((1 << RTE_IPV4_HDR_MF_SHIFT) - 1)
97 : :
98 : : #define RTE_IPV4_HDR_OFFSET_UNITS 8
99 : :
100 : : /* IPv4 options */
101 : : #define RTE_IPV4_HDR_OPT_EOL 0
102 : : #define RTE_IPV4_HDR_OPT_NOP 1
103 : : #define RTE_IPV4_HDR_OPT_COPIED(v) ((v) & 0x80)
104 : : #define RTE_IPV4_HDR_OPT_MAX_LEN 40
105 : :
106 : : /*
107 : : * IPv4 address types
108 : : */
109 : : #define RTE_IPV4_ANY ((uint32_t)0x00000000) /**< 0.0.0.0 */
110 : : #define RTE_IPV4_LOOPBACK ((uint32_t)0x7f000001) /**< 127.0.0.1 */
111 : : #define RTE_IPV4_BROADCAST ((uint32_t)0xe0000000) /**< 224.0.0.0 */
112 : : #define RTE_IPV4_ALLHOSTS_GROUP ((uint32_t)0xe0000001) /**< 224.0.0.1 */
113 : : #define RTE_IPV4_ALLRTRS_GROUP ((uint32_t)0xe0000002) /**< 224.0.0.2 */
114 : : #define RTE_IPV4_MAX_LOCAL_GROUP ((uint32_t)0xe00000ff) /**< 224.0.0.255 */
115 : :
116 : : /*
117 : : * IPv4 Multicast-related macros
118 : : */
119 : : #define RTE_IPV4_MIN_MCAST \
120 : : RTE_IPV4(224, 0, 0, 0) /**< Minimal IPv4-multicast address */
121 : : #define RTE_IPV4_MAX_MCAST \
122 : : RTE_IPV4(239, 255, 255, 255) /**< Maximum IPv4 multicast address */
123 : :
124 : : #define RTE_IS_IPV4_MCAST(x) \
125 : : ((x) >= RTE_IPV4_MIN_MCAST && (x) <= RTE_IPV4_MAX_MCAST)
126 : : /**< check if IPv4 address is multicast */
127 : :
128 : : /* IPv4 default fields values */
129 : : #define RTE_IPV4_MIN_IHL (0x5)
130 : : #define RTE_IPV4_VHL_DEF ((IPVERSION << 4) | RTE_IPV4_MIN_IHL)
131 : :
132 : : /**
133 : : * Get the length of an IPv4 header.
134 : : *
135 : : * @param ipv4_hdr
136 : : * Pointer to the IPv4 header.
137 : : * @return
138 : : * The length of the IPv4 header (with options if present) in bytes.
139 : : */
140 : : static inline uint8_t
141 : : rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)
142 : : {
143 [ + - - - ]: 25 : return (uint8_t)((ipv4_hdr->version_ihl & RTE_IPV4_HDR_IHL_MASK) *
144 : : RTE_IPV4_IHL_MULTIPLIER);
145 : : }
146 : :
147 : : /**
148 : : * @internal Calculate a sum of all words in the buffer.
149 : : * Helper routine for the rte_raw_cksum().
150 : : *
151 : : * @param buf
152 : : * Pointer to the buffer.
153 : : * @param len
154 : : * Length of the buffer.
155 : : * @param sum
156 : : * Initial value of the sum.
157 : : * @return
158 : : * sum += Sum of all words in the buffer.
159 : : */
160 : : static inline uint32_t
161 : : __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
162 : : {
163 : : const void *end;
164 : :
165 : 12 : for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t)));
166 [ + + + + : 312 : buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) {
+ + + + #
# ]
167 : : uint16_t v;
168 : :
169 : : memcpy(&v, buf, sizeof(uint16_t));
170 : 276 : sum += v;
171 : : }
172 : :
173 : : /* if length is odd, keeping it byte order independent */
174 [ + + # # ]: 21 : if (unlikely(len % 2)) {
175 : 9 : uint16_t left = 0;
176 : :
177 : : memcpy(&left, end, 1);
178 : 9 : sum += left;
179 : : }
180 : :
181 : : return sum;
182 : : }
183 : :
184 : : /**
185 : : * @internal Reduce a sum to the non-complemented checksum.
186 : : * Helper routine for the rte_raw_cksum().
187 : : *
188 : : * @param sum
189 : : * Value of the sum.
190 : : * @return
191 : : * The non-complemented checksum.
192 : : */
193 : : static inline uint16_t
194 : : __rte_raw_cksum_reduce(uint32_t sum)
195 : : {
196 : 33 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
197 : 33 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
198 : 33 : return (uint16_t)sum;
199 : : }
200 : :
201 : : /**
202 : : * Process the non-complemented checksum of a buffer.
203 : : *
204 : : * @param buf
205 : : * Pointer to the buffer.
206 : : * @param len
207 : : * Length of the buffer.
208 : : * @return
209 : : * The non-complemented checksum.
210 : : */
211 : : static inline uint16_t
212 : 21 : rte_raw_cksum(const void *buf, size_t len)
213 : : {
214 : : uint32_t sum;
215 : :
216 : : sum = __rte_raw_cksum(buf, len, 0);
217 : 21 : return __rte_raw_cksum_reduce(sum);
218 : : }
219 : :
220 : : /**
221 : : * Compute the raw (non complemented) checksum of a packet.
222 : : *
223 : : * @param m
224 : : * The pointer to the mbuf.
225 : : * @param off
226 : : * The offset in bytes to start the checksum.
227 : : * @param len
228 : : * The length in bytes of the data to checksum.
229 : : * @param cksum
230 : : * A pointer to the checksum, filled on success.
231 : : * @return
232 : : * 0 on success, -1 on error (bad length or offset).
233 : : */
234 : : static inline int
235 : 0 : rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
236 : : uint16_t *cksum)
237 : : {
238 : : const struct rte_mbuf *seg;
239 : : const char *buf;
240 : : uint32_t sum, tmp;
241 : : uint32_t seglen, done;
242 : :
243 : : /* easy case: all data in the first segment */
244 [ # # ]: 0 : if (off + len <= rte_pktmbuf_data_len(m)) {
245 : 0 : *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m,
246 : : const char *, off), len);
247 : 0 : return 0;
248 : : }
249 : :
250 [ # # ]: 0 : if (unlikely(off + len > rte_pktmbuf_pkt_len(m)))
251 : : return -1; /* invalid params, return a dummy value */
252 : :
253 : : /* else browse the segment to find offset */
254 : : seglen = 0;
255 [ # # ]: 0 : for (seg = m; seg != NULL; seg = seg->next) {
256 : 0 : seglen = rte_pktmbuf_data_len(seg);
257 [ # # ]: 0 : if (off < seglen)
258 : : break;
259 : 0 : off -= seglen;
260 : : }
261 : : RTE_ASSERT(seg != NULL);
262 [ # # ]: 0 : if (seg == NULL)
263 : : return -1;
264 : 0 : seglen -= off;
265 : 0 : buf = rte_pktmbuf_mtod_offset(seg, const char *, off);
266 [ # # ]: 0 : if (seglen >= len) {
267 : : /* all in one segment */
268 : 0 : *cksum = rte_raw_cksum(buf, len);
269 : 0 : return 0;
270 : : }
271 : :
272 : : /* hard case: process checksum of several segments */
273 : : sum = 0;
274 : : done = 0;
275 : : for (;;) {
276 : 0 : tmp = __rte_raw_cksum(buf, seglen, 0);
277 [ # # ]: 0 : if (done & 1)
278 [ # # ]: 0 : tmp = rte_bswap16((uint16_t)tmp);
279 : 0 : sum += tmp;
280 : 0 : done += seglen;
281 [ # # ]: 0 : if (done == len)
282 : : break;
283 : 0 : seg = seg->next;
284 : 0 : buf = rte_pktmbuf_mtod(seg, const char *);
285 : 0 : seglen = rte_pktmbuf_data_len(seg);
286 : 0 : if (seglen > len - done)
287 : : seglen = len - done;
288 : : }
289 : :
290 : 0 : *cksum = __rte_raw_cksum_reduce(sum);
291 : 0 : return 0;
292 : : }
293 : :
294 : : /**
295 : : * Process the IPv4 checksum of an IPv4 header.
296 : : *
297 : : * The checksum field must be set to 0 by the caller.
298 : : *
299 : : * @param ipv4_hdr
300 : : * The pointer to the contiguous IPv4 header.
301 : : * @return
302 : : * The complemented checksum to set in the IP packet.
303 : : */
304 : : static inline uint16_t
305 : 0 : rte_ipv4_cksum(const struct rte_ipv4_hdr *ipv4_hdr)
306 : : {
307 : : uint16_t cksum;
308 [ - + - + ]: 3 : cksum = rte_raw_cksum(ipv4_hdr, rte_ipv4_hdr_len(ipv4_hdr));
309 [ - + # # ]: 3 : return (uint16_t)~cksum;
310 : : }
311 : :
312 : : /**
313 : : * Process the pseudo-header checksum of an IPv4 header.
314 : : *
315 : : * The checksum field must be set to 0 by the caller.
316 : : *
317 : : * Depending on the ol_flags, the pseudo-header checksum expected by the
318 : : * drivers is not the same. For instance, when TSO is enabled, the IP
319 : : * payload length must not be included in the packet.
320 : : *
321 : : * When ol_flags is 0, it computes the standard pseudo-header checksum.
322 : : *
323 : : * @param ipv4_hdr
324 : : * The pointer to the contiguous IPv4 header.
325 : : * @param ol_flags
326 : : * The ol_flags of the associated mbuf.
327 : : * @return
328 : : * The non-complemented checksum to set in the L4 header.
329 : : */
330 : : static inline uint16_t
331 : 9 : rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags)
332 : : {
333 : : struct ipv4_psd_header {
334 : : uint32_t src_addr; /* IP address of source host. */
335 : : uint32_t dst_addr; /* IP address of destination host. */
336 : : uint8_t zero; /* zero. */
337 : : uint8_t proto; /* L4 protocol type. */
338 : : uint16_t len; /* L4 length. */
339 : : } psd_hdr;
340 : :
341 : : uint32_t l3_len;
342 : :
343 : 9 : psd_hdr.src_addr = ipv4_hdr->src_addr;
344 : 9 : psd_hdr.dst_addr = ipv4_hdr->dst_addr;
345 : 9 : psd_hdr.zero = 0;
346 : 9 : psd_hdr.proto = ipv4_hdr->next_proto_id;
347 [ - + ]: 9 : if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
348 : 0 : psd_hdr.len = 0;
349 : : } else {
350 [ - + ]: 18 : l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length);
351 : 9 : psd_hdr.len = rte_cpu_to_be_16((uint16_t)(l3_len -
352 : : rte_ipv4_hdr_len(ipv4_hdr)));
353 : : }
354 : 9 : return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr));
355 : : }
356 : :
357 : : /**
358 : : * @internal Calculate the non-complemented IPv4 L4 checksum
359 : : */
360 : : static inline uint16_t
361 : 9 : __rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr)
362 : : {
363 : : uint32_t cksum;
364 : : uint32_t l3_len, l4_len;
365 : : uint8_t ip_hdr_len;
366 : :
367 : : ip_hdr_len = rte_ipv4_hdr_len(ipv4_hdr);
368 [ - + ]: 18 : l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length);
369 [ + - ]: 9 : if (l3_len < ip_hdr_len)
370 : : return 0;
371 : :
372 : 9 : l4_len = l3_len - ip_hdr_len;
373 : :
374 : 9 : cksum = rte_raw_cksum(l4_hdr, l4_len);
375 : 9 : cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0);
376 : :
377 : 9 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
378 : :
379 : 9 : return (uint16_t)cksum;
380 : : }
381 : :
382 : : /**
383 : : * Process the IPv4 UDP or TCP checksum.
384 : : *
385 : : * The layer 4 checksum must be set to 0 in the L4 header by the caller.
386 : : *
387 : : * @param ipv4_hdr
388 : : * The pointer to the contiguous IPv4 header.
389 : : * @param l4_hdr
390 : : * The pointer to the beginning of the L4 header.
391 : : * @return
392 : : * The complemented checksum to set in the L4 header.
393 : : */
394 : : static inline uint16_t
395 : : rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr)
396 : : {
397 : 3 : uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr);
398 : :
399 : 3 : cksum = ~cksum;
400 : :
401 : : /*
402 : : * Per RFC 768: If the computed checksum is zero for UDP,
403 : : * it is transmitted as all ones
404 : : * (the equivalent in one's complement arithmetic).
405 : : */
406 [ - + - - : 3 : if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP)
- + - - #
# # # ]
407 : : cksum = 0xffff;
408 : :
409 : : return cksum;
410 : : }
411 : :
412 : : /**
413 : : * @internal Calculate the non-complemented IPv4 L4 checksum of a packet
414 : : */
415 : : static inline uint16_t
416 : 0 : __rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m,
417 : : const struct rte_ipv4_hdr *ipv4_hdr,
418 : : uint16_t l4_off)
419 : : {
420 : : uint16_t raw_cksum;
421 : : uint32_t cksum;
422 : : uint16_t len;
423 : :
424 [ # # ]: 0 : if (unlikely(l4_off > m->pkt_len))
425 : : return 0; /* invalid params, return a dummy value */
426 : :
427 [ # # ]: 0 : len = rte_be_to_cpu_16(ipv4_hdr->total_length) - (uint16_t)rte_ipv4_hdr_len(ipv4_hdr);
428 : :
429 [ # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, len, &raw_cksum))
430 : : return 0;
431 : :
432 : 0 : cksum = raw_cksum + rte_ipv4_phdr_cksum(ipv4_hdr, 0);
433 : :
434 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
435 : :
436 : 0 : return (uint16_t)cksum;
437 : : }
438 : :
439 : : /**
440 : : * Compute the IPv4 UDP/TCP checksum of a packet.
441 : : *
442 : : * @param m
443 : : * The pointer to the mbuf.
444 : : * @param ipv4_hdr
445 : : * The pointer to the contiguous IPv4 header.
446 : : * @param l4_off
447 : : * The offset in bytes to start L4 checksum.
448 : : * @return
449 : : * The complemented checksum to set in the L4 header.
450 : : */
451 : : static inline uint16_t
452 : : rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m,
453 : : const struct rte_ipv4_hdr *ipv4_hdr, uint16_t l4_off)
454 : : {
455 : 0 : uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off);
456 : :
457 : 0 : cksum = ~cksum;
458 : :
459 : : /*
460 : : * Per RFC 768: If the computed checksum is zero for UDP,
461 : : * it is transmitted as all ones
462 : : * (the equivalent in one's complement arithmetic).
463 : : */
464 [ # # # # ]: 0 : if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP)
465 : : cksum = 0xffff;
466 : :
467 : : return cksum;
468 : : }
469 : :
470 : : /**
471 : : * Validate the IPv4 UDP or TCP checksum.
472 : : *
473 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0
474 : : * (i.e. no checksum).
475 : : *
476 : : * @param ipv4_hdr
477 : : * The pointer to the contiguous IPv4 header.
478 : : * @param l4_hdr
479 : : * The pointer to the beginning of the L4 header.
480 : : * @return
481 : : * Return 0 if the checksum is correct, else -1.
482 : : */
483 : : static inline int
484 : : rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr,
485 : : const void *l4_hdr)
486 : : {
487 : 6 : uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr);
488 : :
489 [ - + + - : 6 : if (cksum != 0xffff)
+ - ]
490 : 0 : return -1;
491 : :
492 : : return 0;
493 : : }
494 : :
495 : : /**
496 : : * Verify the IPv4 UDP/TCP checksum of a packet.
497 : : *
498 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0
499 : : * (i.e. no checksum).
500 : : *
501 : : * @param m
502 : : * The pointer to the mbuf.
503 : : * @param ipv4_hdr
504 : : * The pointer to the contiguous IPv4 header.
505 : : * @param l4_off
506 : : * The offset in bytes to start L4 checksum.
507 : : * @return
508 : : * Return 0 if the checksum is correct, else -1.
509 : : */
510 : : static inline int
511 : : rte_ipv4_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
512 : : const struct rte_ipv4_hdr *ipv4_hdr,
513 : : uint16_t l4_off)
514 : : {
515 : : uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off);
516 : :
517 : : if (cksum != 0xffff)
518 : : return -1;
519 : :
520 : : return 0;
521 : : }
522 : :
523 : : /**
524 : : * IPv6 Header
525 : : */
526 : : struct rte_ipv6_hdr {
527 : : rte_be32_t vtc_flow; /**< IP version, traffic class & flow label. */
528 : : rte_be16_t payload_len; /**< IP payload size, including ext. headers */
529 : : uint8_t proto; /**< Protocol, next header. */
530 : : uint8_t hop_limits; /**< Hop limits. */
531 : : uint8_t src_addr[16]; /**< IP address of source host. */
532 : : uint8_t dst_addr[16]; /**< IP address of destination host(s). */
533 : : } __rte_packed;
534 : :
535 : : /* IPv6 routing extension type definition. */
536 : : #define RTE_IPV6_SRCRT_TYPE_4 4
537 : :
538 : : /**
539 : : * IPv6 Routing Extension Header
540 : : */
541 : : struct rte_ipv6_routing_ext {
542 : : uint8_t next_hdr; /**< Protocol, next header. */
543 : : uint8_t hdr_len; /**< Header length. */
544 : : uint8_t type; /**< Extension header type. */
545 : : uint8_t segments_left; /**< Valid segments number. */
546 : : __extension__
547 : : union {
548 : : rte_be32_t flags; /**< Packet control data per type. */
549 : : struct {
550 : : uint8_t last_entry; /**< The last_entry field of SRH */
551 : : uint8_t flag; /**< Packet flag. */
552 : : rte_be16_t tag; /**< Packet tag. */
553 : : };
554 : : };
555 : : /* Next are 128-bit IPv6 address fields to describe segments. */
556 : : } __rte_packed;
557 : :
558 : : /* IPv6 vtc_flow: IPv / TC / flow_label */
559 : : #define RTE_IPV6_HDR_FL_SHIFT 0
560 : : #define RTE_IPV6_HDR_TC_SHIFT 20
561 : : #define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1)
562 : : #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT)
563 : : #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT)
564 : : #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT)
565 : : #define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK
566 : :
567 : : #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */
568 : :
569 : : /**
570 : : * Process the pseudo-header checksum of an IPv6 header.
571 : : *
572 : : * Depending on the ol_flags, the pseudo-header checksum expected by the
573 : : * drivers is not the same. For instance, when TSO is enabled, the IPv6
574 : : * payload length must not be included in the packet.
575 : : *
576 : : * When ol_flags is 0, it computes the standard pseudo-header checksum.
577 : : *
578 : : * @param ipv6_hdr
579 : : * The pointer to the contiguous IPv6 header.
580 : : * @param ol_flags
581 : : * The ol_flags of the associated mbuf.
582 : : * @return
583 : : * The non-complemented checksum to set in the L4 header.
584 : : */
585 : : static inline uint16_t
586 : 3 : rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
587 : : {
588 : : uint32_t sum;
589 : : struct {
590 : : rte_be32_t len; /* L4 length. */
591 : : rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
592 : : } psd_hdr;
593 : :
594 : 3 : psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
595 [ - + ]: 3 : if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
596 : 0 : psd_hdr.len = 0;
597 : : } else {
598 : 3 : psd_hdr.len = ipv6_hdr->payload_len;
599 : : }
600 : :
601 : 3 : sum = __rte_raw_cksum(ipv6_hdr->src_addr,
602 : : sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr),
603 : : 0);
604 : : sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum);
605 : 3 : return __rte_raw_cksum_reduce(sum);
606 : : }
607 : :
608 : : /**
609 : : * @internal Calculate the non-complemented IPv6 L4 checksum
610 : : */
611 : : static inline uint16_t
612 : 3 : __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
613 : : {
614 : : uint32_t cksum;
615 : : uint32_t l4_len;
616 : :
617 [ - + ]: 6 : l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
618 : :
619 : 3 : cksum = rte_raw_cksum(l4_hdr, l4_len);
620 : 3 : cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
621 : :
622 : 3 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
623 : :
624 : 3 : return (uint16_t)cksum;
625 : : }
626 : :
627 : : /**
628 : : * Process the IPv6 UDP or TCP checksum.
629 : : *
630 : : * The IPv6 header must not be followed by extension headers. The layer 4
631 : : * checksum must be set to 0 in the L4 header by the caller.
632 : : *
633 : : * @param ipv6_hdr
634 : : * The pointer to the contiguous IPv6 header.
635 : : * @param l4_hdr
636 : : * The pointer to the beginning of the L4 header.
637 : : * @return
638 : : * The complemented checksum to set in the L4 header.
639 : : */
640 : : static inline uint16_t
641 : : rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
642 : : {
643 : 1 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
644 : :
645 : 1 : cksum = ~cksum;
646 : :
647 : : /*
648 : : * Per RFC 768: If the computed checksum is zero for UDP,
649 : : * it is transmitted as all ones
650 : : * (the equivalent in one's complement arithmetic).
651 : : */
652 [ - - - - : 1 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
- + - - #
# # # ]
653 : : cksum = 0xffff;
654 : :
655 : : return cksum;
656 : : }
657 : :
658 : : /**
659 : : * @internal Calculate the non-complemented IPv6 L4 checksum of a packet
660 : : */
661 : : static inline uint16_t
662 : 0 : __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
663 : : const struct rte_ipv6_hdr *ipv6_hdr,
664 : : uint16_t l4_off)
665 : : {
666 : : uint16_t raw_cksum;
667 : : uint32_t cksum;
668 : :
669 [ # # ]: 0 : if (unlikely(l4_off > m->pkt_len))
670 : : return 0; /* invalid params, return a dummy value */
671 : :
672 [ # # # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, rte_be_to_cpu_16(ipv6_hdr->payload_len), &raw_cksum))
673 : : return 0;
674 : :
675 : 0 : cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
676 : :
677 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
678 : :
679 : 0 : return (uint16_t)cksum;
680 : : }
681 : :
682 : : /**
683 : : * Process the IPv6 UDP or TCP checksum of a packet.
684 : : *
685 : : * The IPv6 header must not be followed by extension headers. The layer 4
686 : : * checksum must be set to 0 in the L4 header by the caller.
687 : : *
688 : : * @param m
689 : : * The pointer to the mbuf.
690 : : * @param ipv6_hdr
691 : : * The pointer to the contiguous IPv6 header.
692 : : * @param l4_off
693 : : * The offset in bytes to start L4 checksum.
694 : : * @return
695 : : * The complemented checksum to set in the L4 header.
696 : : */
697 : : static inline uint16_t
698 : : rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
699 : : const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
700 : : {
701 : 0 : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
702 : :
703 : 0 : cksum = ~cksum;
704 : :
705 : : /*
706 : : * Per RFC 768: If the computed checksum is zero for UDP,
707 : : * it is transmitted as all ones
708 : : * (the equivalent in one's complement arithmetic).
709 : : */
710 [ # # # # ]: 0 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
711 : : cksum = 0xffff;
712 : :
713 : : return cksum;
714 : : }
715 : :
716 : : /**
717 : : * Validate the IPv6 UDP or TCP checksum.
718 : : *
719 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
720 : : * this is either invalid or means no checksum in some situations. See 8.1
721 : : * (Upper-Layer Checksums) in RFC 8200.
722 : : *
723 : : * @param ipv6_hdr
724 : : * The pointer to the contiguous IPv6 header.
725 : : * @param l4_hdr
726 : : * The pointer to the beginning of the L4 header.
727 : : * @return
728 : : * Return 0 if the checksum is correct, else -1.
729 : : */
730 : : static inline int
731 : : rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr,
732 : : const void *l4_hdr)
733 : : {
734 : 2 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
735 : :
736 [ - + - - : 2 : if (cksum != 0xffff)
+ - ]
737 : 0 : return -1;
738 : :
739 : : return 0;
740 : : }
741 : :
742 : : /**
743 : : * Validate the IPv6 UDP or TCP checksum of a packet.
744 : : *
745 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
746 : : * this is either invalid or means no checksum in some situations. See 8.1
747 : : * (Upper-Layer Checksums) in RFC 8200.
748 : : *
749 : : * @param m
750 : : * The pointer to the mbuf.
751 : : * @param ipv6_hdr
752 : : * The pointer to the contiguous IPv6 header.
753 : : * @param l4_off
754 : : * The offset in bytes to start L4 checksum.
755 : : * @return
756 : : * Return 0 if the checksum is correct, else -1.
757 : : */
758 : : static inline int
759 : : rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
760 : : const struct rte_ipv6_hdr *ipv6_hdr,
761 : : uint16_t l4_off)
762 : : {
763 : : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
764 : :
765 : : if (cksum != 0xffff)
766 : : return -1;
767 : :
768 : : return 0;
769 : : }
770 : :
771 : : /** IPv6 fragment extension header. */
772 : : #define RTE_IPV6_EHDR_MF_SHIFT 0
773 : : #define RTE_IPV6_EHDR_MF_MASK 1
774 : : #define RTE_IPV6_EHDR_FO_SHIFT 3
775 : : #define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
776 : : #define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT)
777 : :
778 : : #define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
779 : :
780 : : #define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK)
781 : : #define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT)
782 : :
783 : : #define RTE_IPV6_SET_FRAG_DATA(fo, mf) \
784 : : (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
785 : :
786 : : struct rte_ipv6_fragment_ext {
787 : : uint8_t next_header; /**< Next header type */
788 : : uint8_t reserved; /**< Reserved */
789 : : rte_be16_t frag_data; /**< All fragmentation data */
790 : : rte_be32_t id; /**< Packet ID */
791 : : } __rte_packed;
792 : :
793 : : /* IPv6 fragment extension header size */
794 : : #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
795 : :
796 : : /**
797 : : * Parse next IPv6 header extension
798 : : *
799 : : * This function checks if proto number is an IPv6 extensions and parses its
800 : : * data if so, providing information on next header and extension length.
801 : : *
802 : : * @param p
803 : : * Pointer to an extension raw data.
804 : : * @param proto
805 : : * Protocol number extracted from the "next header" field from
806 : : * the IPv6 header or the previous extension.
807 : : * @param ext_len
808 : : * Extension data length.
809 : : * @return
810 : : * next protocol number if proto is an IPv6 extension, -EINVAL otherwise
811 : : */
812 : : static inline int
813 : 0 : rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
814 : : {
815 : : int next_proto;
816 : :
817 [ # # # # ]: 0 : switch (proto) {
818 : 0 : case IPPROTO_AH:
819 : 0 : next_proto = *p++;
820 : 0 : *ext_len = (*p + 2) * sizeof(uint32_t);
821 : 0 : break;
822 : :
823 : 0 : case IPPROTO_HOPOPTS:
824 : : case IPPROTO_ROUTING:
825 : : case IPPROTO_DSTOPTS:
826 : 0 : next_proto = *p++;
827 : 0 : *ext_len = (*p + 1) * sizeof(uint64_t);
828 : 0 : break;
829 : :
830 : 0 : case IPPROTO_FRAGMENT:
831 : 0 : next_proto = *p;
832 : 0 : *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
833 : 0 : break;
834 : :
835 : : default:
836 : : return -EINVAL;
837 : : }
838 : :
839 : : return next_proto;
840 : : }
841 : :
842 : : #ifdef __cplusplus
843 : : }
844 : : #endif
845 : :
846 : : #endif /* _RTE_IP_H_ */
|