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_CKSUM_H_
10 : : #define _RTE_CKSUM_H_
11 : :
12 : : /**
13 : : * @file
14 : : *
15 : : * Protocol independent checksum utilities.
16 : : */
17 : :
18 : : #include <stdint.h>
19 : :
20 : : #include <rte_byteorder.h>
21 : : #include <rte_common.h>
22 : : #include <rte_mbuf.h>
23 : :
24 : : #ifdef __cplusplus
25 : : extern "C" {
26 : : #endif
27 : :
28 : :
29 : : /**
30 : : * @internal Calculate a sum of all words in the buffer.
31 : : * Helper routine for the rte_raw_cksum().
32 : : *
33 : : * @param buf
34 : : * Pointer to the buffer.
35 : : * @param len
36 : : * Length of the buffer.
37 : : * @param sum
38 : : * Initial value of the sum.
39 : : * @return
40 : : * sum += Sum of all words in the buffer.
41 : : */
42 : : static inline uint32_t
43 : : __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
44 : : {
45 : : const void *end;
46 : :
47 : 4144 : for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t)));
48 [ + + + + : 45731 : buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) {
+ + + + #
# ]
49 : : uint16_t v;
50 : :
51 : : memcpy(&v, buf, sizeof(uint16_t));
52 : 41566 : sum += v;
53 : : }
54 : :
55 : : /* if length is odd, keeping it byte order independent */
56 [ + + # # ]: 4150 : if (unlikely(len % 2)) {
57 : 9 : uint16_t left = 0;
58 : :
59 : : memcpy(&left, end, 1);
60 : 9 : sum += left;
61 : : }
62 : :
63 : : return sum;
64 : : }
65 : :
66 : : /**
67 : : * @internal Reduce a sum to the non-complemented checksum.
68 : : * Helper routine for the rte_raw_cksum().
69 : : *
70 : : * @param sum
71 : : * Value of the sum.
72 : : * @return
73 : : * The non-complemented checksum.
74 : : */
75 : : static inline uint16_t
76 : : __rte_raw_cksum_reduce(uint32_t sum)
77 : : {
78 : 4162 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
79 : 4162 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
80 : 4162 : return (uint16_t)sum;
81 : : }
82 : :
83 : : /**
84 : : * Process the non-complemented checksum of a buffer.
85 : : *
86 : : * @param buf
87 : : * Pointer to the buffer.
88 : : * @param len
89 : : * Length of the buffer.
90 : : * @return
91 : : * The non-complemented checksum.
92 : : */
93 : : static inline uint16_t
94 : 4150 : rte_raw_cksum(const void *buf, size_t len)
95 : : {
96 : : uint32_t sum;
97 : :
98 : : sum = __rte_raw_cksum(buf, len, 0);
99 : 4150 : return __rte_raw_cksum_reduce(sum);
100 : : }
101 : :
102 : : /**
103 : : * Compute the raw (non complemented) checksum of a packet.
104 : : *
105 : : * @param m
106 : : * The pointer to the mbuf.
107 : : * @param off
108 : : * The offset in bytes to start the checksum.
109 : : * @param len
110 : : * The length in bytes of the data to checksum.
111 : : * @param cksum
112 : : * A pointer to the checksum, filled on success.
113 : : * @return
114 : : * 0 on success, -1 on error (bad length or offset).
115 : : */
116 : : static inline int
117 : 0 : rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
118 : : uint16_t *cksum)
119 : : {
120 : : const struct rte_mbuf *seg;
121 : : const char *buf;
122 : : uint32_t sum, tmp;
123 : : uint32_t seglen, done;
124 : :
125 : : /* easy case: all data in the first segment */
126 [ # # ]: 0 : if (off + len <= rte_pktmbuf_data_len(m)) {
127 : 0 : *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m,
128 : : const char *, off), len);
129 : 0 : return 0;
130 : : }
131 : :
132 [ # # ]: 0 : if (unlikely(off + len > rte_pktmbuf_pkt_len(m)))
133 : : return -1; /* invalid params, return a dummy value */
134 : :
135 : : /* else browse the segment to find offset */
136 : : seglen = 0;
137 [ # # ]: 0 : for (seg = m; seg != NULL; seg = seg->next) {
138 : 0 : seglen = rte_pktmbuf_data_len(seg);
139 [ # # ]: 0 : if (off < seglen)
140 : : break;
141 : 0 : off -= seglen;
142 : : }
143 : : RTE_ASSERT(seg != NULL);
144 [ # # ]: 0 : if (seg == NULL)
145 : : return -1;
146 : 0 : seglen -= off;
147 : 0 : buf = rte_pktmbuf_mtod_offset(seg, const char *, off);
148 [ # # ]: 0 : if (seglen >= len) {
149 : : /* all in one segment */
150 : 0 : *cksum = rte_raw_cksum(buf, len);
151 : 0 : return 0;
152 : : }
153 : :
154 : : /* hard case: process checksum of several segments */
155 : : sum = 0;
156 : : done = 0;
157 : : for (;;) {
158 : 0 : tmp = __rte_raw_cksum(buf, seglen, 0);
159 [ # # ]: 0 : if (done & 1)
160 [ # # ]: 0 : tmp = rte_bswap16((uint16_t)tmp);
161 : 0 : sum += tmp;
162 : 0 : done += seglen;
163 [ # # ]: 0 : if (done == len)
164 : : break;
165 : 0 : seg = seg->next;
166 : 0 : buf = rte_pktmbuf_mtod(seg, const char *);
167 : 0 : seglen = rte_pktmbuf_data_len(seg);
168 : 0 : if (seglen > len - done)
169 : : seglen = len - done;
170 : : }
171 : :
172 : 0 : *cksum = __rte_raw_cksum_reduce(sum);
173 : 0 : return 0;
174 : : }
175 : :
176 : : #ifdef __cplusplus
177 : : }
178 : : #endif
179 : :
180 : : #endif /* _RTE_CKSUM_H_ */
|