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 : :
423 [ # # ]: 0 : if (l4_off > m->pkt_len)
424 : : return 0;
425 : :
426 [ # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, m->pkt_len - l4_off, &raw_cksum))
427 : : return 0;
428 : :
429 : 0 : cksum = raw_cksum + rte_ipv4_phdr_cksum(ipv4_hdr, 0);
430 : :
431 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
432 : :
433 : 0 : return (uint16_t)cksum;
434 : : }
435 : :
436 : : /**
437 : : * Compute the IPv4 UDP/TCP checksum of a packet.
438 : : *
439 : : * @param m
440 : : * The pointer to the mbuf.
441 : : * @param ipv4_hdr
442 : : * The pointer to the contiguous IPv4 header.
443 : : * @param l4_off
444 : : * The offset in bytes to start L4 checksum.
445 : : * @return
446 : : * The complemented checksum to set in the L4 header.
447 : : */
448 : : static inline uint16_t
449 : : rte_ipv4_udptcp_cksum_mbuf(const struct rte_mbuf *m,
450 : : const struct rte_ipv4_hdr *ipv4_hdr, uint16_t l4_off)
451 : : {
452 : 0 : uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off);
453 : :
454 : 0 : cksum = ~cksum;
455 : :
456 : : /*
457 : : * Per RFC 768: If the computed checksum is zero for UDP,
458 : : * it is transmitted as all ones
459 : : * (the equivalent in one's complement arithmetic).
460 : : */
461 [ # # # # ]: 0 : if (cksum == 0 && ipv4_hdr->next_proto_id == IPPROTO_UDP)
462 : : cksum = 0xffff;
463 : :
464 : : return cksum;
465 : : }
466 : :
467 : : /**
468 : : * Validate the IPv4 UDP or TCP checksum.
469 : : *
470 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0
471 : : * (i.e. no checksum).
472 : : *
473 : : * @param ipv4_hdr
474 : : * The pointer to the contiguous IPv4 header.
475 : : * @param l4_hdr
476 : : * The pointer to the beginning of the L4 header.
477 : : * @return
478 : : * Return 0 if the checksum is correct, else -1.
479 : : */
480 : : static inline int
481 : : rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr,
482 : : const void *l4_hdr)
483 : : {
484 : 6 : uint16_t cksum = __rte_ipv4_udptcp_cksum(ipv4_hdr, l4_hdr);
485 : :
486 [ - + + - : 6 : if (cksum != 0xffff)
+ - ]
487 : 0 : return -1;
488 : :
489 : : return 0;
490 : : }
491 : :
492 : : /**
493 : : * Verify the IPv4 UDP/TCP checksum of a packet.
494 : : *
495 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0
496 : : * (i.e. no checksum).
497 : : *
498 : : * @param m
499 : : * The pointer to the mbuf.
500 : : * @param ipv4_hdr
501 : : * The pointer to the contiguous IPv4 header.
502 : : * @param l4_off
503 : : * The offset in bytes to start L4 checksum.
504 : : * @return
505 : : * Return 0 if the checksum is correct, else -1.
506 : : */
507 : : static inline int
508 : : rte_ipv4_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
509 : : const struct rte_ipv4_hdr *ipv4_hdr,
510 : : uint16_t l4_off)
511 : : {
512 : : uint16_t cksum = __rte_ipv4_udptcp_cksum_mbuf(m, ipv4_hdr, l4_off);
513 : :
514 : : if (cksum != 0xffff)
515 : : return -1;
516 : :
517 : : return 0;
518 : : }
519 : :
520 : : /**
521 : : * IPv6 Header
522 : : */
523 : : struct rte_ipv6_hdr {
524 : : rte_be32_t vtc_flow; /**< IP version, traffic class & flow label. */
525 : : rte_be16_t payload_len; /**< IP payload size, including ext. headers */
526 : : uint8_t proto; /**< Protocol, next header. */
527 : : uint8_t hop_limits; /**< Hop limits. */
528 : : uint8_t src_addr[16]; /**< IP address of source host. */
529 : : uint8_t dst_addr[16]; /**< IP address of destination host(s). */
530 : : } __rte_packed;
531 : :
532 : : /* IPv6 routing extension type definition. */
533 : : #define RTE_IPV6_SRCRT_TYPE_4 4
534 : :
535 : : /**
536 : : * IPv6 Routing Extension Header
537 : : */
538 : : struct rte_ipv6_routing_ext {
539 : : uint8_t next_hdr; /**< Protocol, next header. */
540 : : uint8_t hdr_len; /**< Header length. */
541 : : uint8_t type; /**< Extension header type. */
542 : : uint8_t segments_left; /**< Valid segments number. */
543 : : __extension__
544 : : union {
545 : : rte_be32_t flags; /**< Packet control data per type. */
546 : : struct {
547 : : uint8_t last_entry; /**< The last_entry field of SRH */
548 : : uint8_t flag; /**< Packet flag. */
549 : : rte_be16_t tag; /**< Packet tag. */
550 : : };
551 : : };
552 : : /* Next are 128-bit IPv6 address fields to describe segments. */
553 : : } __rte_packed;
554 : :
555 : : /* IPv6 vtc_flow: IPv / TC / flow_label */
556 : : #define RTE_IPV6_HDR_FL_SHIFT 0
557 : : #define RTE_IPV6_HDR_TC_SHIFT 20
558 : : #define RTE_IPV6_HDR_FL_MASK ((1u << RTE_IPV6_HDR_TC_SHIFT) - 1)
559 : : #define RTE_IPV6_HDR_TC_MASK (0xff << RTE_IPV6_HDR_TC_SHIFT)
560 : : #define RTE_IPV6_HDR_DSCP_MASK (0xfc << RTE_IPV6_HDR_TC_SHIFT)
561 : : #define RTE_IPV6_HDR_ECN_MASK (0x03 << RTE_IPV6_HDR_TC_SHIFT)
562 : : #define RTE_IPV6_HDR_ECN_CE RTE_IPV6_HDR_ECN_MASK
563 : :
564 : : #define RTE_IPV6_MIN_MTU 1280 /**< Minimum MTU for IPv6, see RFC 8200. */
565 : :
566 : : /**
567 : : * Process the pseudo-header checksum of an IPv6 header.
568 : : *
569 : : * Depending on the ol_flags, the pseudo-header checksum expected by the
570 : : * drivers is not the same. For instance, when TSO is enabled, the IPv6
571 : : * payload length must not be included in the packet.
572 : : *
573 : : * When ol_flags is 0, it computes the standard pseudo-header checksum.
574 : : *
575 : : * @param ipv6_hdr
576 : : * The pointer to the contiguous IPv6 header.
577 : : * @param ol_flags
578 : : * The ol_flags of the associated mbuf.
579 : : * @return
580 : : * The non-complemented checksum to set in the L4 header.
581 : : */
582 : : static inline uint16_t
583 : 3 : rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
584 : : {
585 : : uint32_t sum;
586 : : struct {
587 : : rte_be32_t len; /* L4 length. */
588 : : rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
589 : : } psd_hdr;
590 : :
591 : 3 : psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
592 [ - + ]: 3 : if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
593 : 0 : psd_hdr.len = 0;
594 : : } else {
595 : 3 : psd_hdr.len = ipv6_hdr->payload_len;
596 : : }
597 : :
598 : 3 : sum = __rte_raw_cksum(ipv6_hdr->src_addr,
599 : : sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr),
600 : : 0);
601 : : sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum);
602 : 3 : return __rte_raw_cksum_reduce(sum);
603 : : }
604 : :
605 : : /**
606 : : * @internal Calculate the non-complemented IPv6 L4 checksum
607 : : */
608 : : static inline uint16_t
609 : 3 : __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
610 : : {
611 : : uint32_t cksum;
612 : : uint32_t l4_len;
613 : :
614 [ - + ]: 6 : l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
615 : :
616 : 3 : cksum = rte_raw_cksum(l4_hdr, l4_len);
617 : 3 : cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
618 : :
619 : 3 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
620 : :
621 : 3 : return (uint16_t)cksum;
622 : : }
623 : :
624 : : /**
625 : : * Process the IPv6 UDP or TCP checksum.
626 : : *
627 : : * The IPv6 header must not be followed by extension headers. The layer 4
628 : : * checksum must be set to 0 in the L4 header by the caller.
629 : : *
630 : : * @param ipv6_hdr
631 : : * The pointer to the contiguous IPv6 header.
632 : : * @param l4_hdr
633 : : * The pointer to the beginning of the L4 header.
634 : : * @return
635 : : * The complemented checksum to set in the L4 header.
636 : : */
637 : : static inline uint16_t
638 : : rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void *l4_hdr)
639 : : {
640 : 1 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
641 : :
642 : 1 : cksum = ~cksum;
643 : :
644 : : /*
645 : : * Per RFC 768: If the computed checksum is zero for UDP,
646 : : * it is transmitted as all ones
647 : : * (the equivalent in one's complement arithmetic).
648 : : */
649 [ - - - - : 1 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
- + - - #
# # # ]
650 : : cksum = 0xffff;
651 : :
652 : : return cksum;
653 : : }
654 : :
655 : : /**
656 : : * @internal Calculate the non-complemented IPv6 L4 checksum of a packet
657 : : */
658 : : static inline uint16_t
659 : 0 : __rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
660 : : const struct rte_ipv6_hdr *ipv6_hdr,
661 : : uint16_t l4_off)
662 : : {
663 : : uint16_t raw_cksum;
664 : : uint32_t cksum;
665 : :
666 [ # # ]: 0 : if (l4_off > m->pkt_len)
667 : : return 0;
668 : :
669 [ # # ]: 0 : if (rte_raw_cksum_mbuf(m, l4_off, m->pkt_len - l4_off, &raw_cksum))
670 : : return 0;
671 : :
672 : 0 : cksum = raw_cksum + rte_ipv6_phdr_cksum(ipv6_hdr, 0);
673 : :
674 : 0 : cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
675 : :
676 : 0 : return (uint16_t)cksum;
677 : : }
678 : :
679 : : /**
680 : : * Process the IPv6 UDP or TCP checksum of a packet.
681 : : *
682 : : * The IPv6 header must not be followed by extension headers. The layer 4
683 : : * checksum must be set to 0 in the L4 header by the caller.
684 : : *
685 : : * @param m
686 : : * The pointer to the mbuf.
687 : : * @param ipv6_hdr
688 : : * The pointer to the contiguous IPv6 header.
689 : : * @param l4_off
690 : : * The offset in bytes to start L4 checksum.
691 : : * @return
692 : : * The complemented checksum to set in the L4 header.
693 : : */
694 : : static inline uint16_t
695 : : rte_ipv6_udptcp_cksum_mbuf(const struct rte_mbuf *m,
696 : : const struct rte_ipv6_hdr *ipv6_hdr, uint16_t l4_off)
697 : : {
698 : 0 : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
699 : :
700 : 0 : cksum = ~cksum;
701 : :
702 : : /*
703 : : * Per RFC 768: If the computed checksum is zero for UDP,
704 : : * it is transmitted as all ones
705 : : * (the equivalent in one's complement arithmetic).
706 : : */
707 [ # # # # ]: 0 : if (cksum == 0 && ipv6_hdr->proto == IPPROTO_UDP)
708 : : cksum = 0xffff;
709 : :
710 : : return cksum;
711 : : }
712 : :
713 : : /**
714 : : * Validate the IPv6 UDP or TCP checksum.
715 : : *
716 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
717 : : * this is either invalid or means no checksum in some situations. See 8.1
718 : : * (Upper-Layer Checksums) in RFC 8200.
719 : : *
720 : : * @param ipv6_hdr
721 : : * The pointer to the contiguous IPv6 header.
722 : : * @param l4_hdr
723 : : * The pointer to the beginning of the L4 header.
724 : : * @return
725 : : * Return 0 if the checksum is correct, else -1.
726 : : */
727 : : static inline int
728 : : rte_ipv6_udptcp_cksum_verify(const struct rte_ipv6_hdr *ipv6_hdr,
729 : : const void *l4_hdr)
730 : : {
731 : 2 : uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr);
732 : :
733 [ - + - - : 2 : if (cksum != 0xffff)
+ - ]
734 : 0 : return -1;
735 : :
736 : : return 0;
737 : : }
738 : :
739 : : /**
740 : : * Validate the IPv6 UDP or TCP checksum of a packet.
741 : : *
742 : : * In case of UDP, the caller must first check if udp_hdr->dgram_cksum is 0:
743 : : * this is either invalid or means no checksum in some situations. See 8.1
744 : : * (Upper-Layer Checksums) in RFC 8200.
745 : : *
746 : : * @param m
747 : : * The pointer to the mbuf.
748 : : * @param ipv6_hdr
749 : : * The pointer to the contiguous IPv6 header.
750 : : * @param l4_off
751 : : * The offset in bytes to start L4 checksum.
752 : : * @return
753 : : * Return 0 if the checksum is correct, else -1.
754 : : */
755 : : static inline int
756 : : rte_ipv6_udptcp_cksum_mbuf_verify(const struct rte_mbuf *m,
757 : : const struct rte_ipv6_hdr *ipv6_hdr,
758 : : uint16_t l4_off)
759 : : {
760 : : uint16_t cksum = __rte_ipv6_udptcp_cksum_mbuf(m, ipv6_hdr, l4_off);
761 : :
762 : : if (cksum != 0xffff)
763 : : return -1;
764 : :
765 : : return 0;
766 : : }
767 : :
768 : : /** IPv6 fragment extension header. */
769 : : #define RTE_IPV6_EHDR_MF_SHIFT 0
770 : : #define RTE_IPV6_EHDR_MF_MASK 1
771 : : #define RTE_IPV6_EHDR_FO_SHIFT 3
772 : : #define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
773 : : #define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT)
774 : :
775 : : #define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
776 : :
777 : : #define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK)
778 : : #define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT)
779 : :
780 : : #define RTE_IPV6_SET_FRAG_DATA(fo, mf) \
781 : : (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
782 : :
783 : : struct rte_ipv6_fragment_ext {
784 : : uint8_t next_header; /**< Next header type */
785 : : uint8_t reserved; /**< Reserved */
786 : : rte_be16_t frag_data; /**< All fragmentation data */
787 : : rte_be32_t id; /**< Packet ID */
788 : : } __rte_packed;
789 : :
790 : : /* IPv6 fragment extension header size */
791 : : #define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
792 : :
793 : : /**
794 : : * Parse next IPv6 header extension
795 : : *
796 : : * This function checks if proto number is an IPv6 extensions and parses its
797 : : * data if so, providing information on next header and extension length.
798 : : *
799 : : * @param p
800 : : * Pointer to an extension raw data.
801 : : * @param proto
802 : : * Protocol number extracted from the "next header" field from
803 : : * the IPv6 header or the previous extension.
804 : : * @param ext_len
805 : : * Extension data length.
806 : : * @return
807 : : * next protocol number if proto is an IPv6 extension, -EINVAL otherwise
808 : : */
809 : : static inline int
810 : 0 : rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
811 : : {
812 : : int next_proto;
813 : :
814 [ # # # # ]: 0 : switch (proto) {
815 : 0 : case IPPROTO_AH:
816 : 0 : next_proto = *p++;
817 : 0 : *ext_len = (*p + 2) * sizeof(uint32_t);
818 : 0 : break;
819 : :
820 : 0 : case IPPROTO_HOPOPTS:
821 : : case IPPROTO_ROUTING:
822 : : case IPPROTO_DSTOPTS:
823 : 0 : next_proto = *p++;
824 : 0 : *ext_len = (*p + 1) * sizeof(uint64_t);
825 : 0 : break;
826 : :
827 : 0 : case IPPROTO_FRAGMENT:
828 : 0 : next_proto = *p;
829 : 0 : *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
830 : 0 : break;
831 : :
832 : : default:
833 : : return -EINVAL;
834 : : }
835 : :
836 : : return next_proto;
837 : : }
838 : :
839 : : #ifdef __cplusplus
840 : : }
841 : : #endif
842 : :
843 : : #endif /* _RTE_IP_H_ */
|