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 : 0 : __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
44 : : {
45 : 0 : const void *end;
46 : :
47 : 5772 : for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t)));
48 [ + + + + : 63710 : buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) {
+ + + + +
+ ]
49 : 0 : uint16_t v;
50 : :
51 : 0 : memcpy(&v, buf, sizeof(uint16_t));
52 : 57914 : sum += v;
53 : : }
54 : :
55 : : /* if length is odd, keeping it byte order independent */
56 [ + + + + ]: 5780 : if (unlikely(len % 2)) {
57 : 10 : uint16_t left = 0;
58 : :
59 : : memcpy(&left, end, 1);
60 : 10 : sum += left;
61 : : }
62 : :
63 : 0 : 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 : 0 : __rte_raw_cksum_reduce(uint32_t sum)
77 : : {
78 : 5791 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
79 : 5791 : sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
80 : 5791 : return (uint16_t)sum;
81 : : }
82 : :
83 : : /**
84 : : * @internal Reduce a sum to the non-complemented checksum.
85 : : * Helper routine for the rte_raw_cksum_mbuf().
86 : : *
87 : : * @param sum
88 : : * Value of the sum.
89 : : * @return
90 : : * The non-complemented checksum.
91 : : */
92 : : static inline uint16_t
93 : 1 : __rte_raw_cksum_reduce_u64(uint64_t sum)
94 : : {
95 : : uint32_t tmp;
96 : :
97 : 1 : tmp = __rte_raw_cksum_reduce((uint32_t)sum);
98 : 1 : tmp += __rte_raw_cksum_reduce((uint32_t)(sum >> 32));
99 : 1 : return __rte_raw_cksum_reduce(tmp);
100 : : }
101 : :
102 : : /**
103 : : * Process the non-complemented checksum of a buffer.
104 : : *
105 : : * @param buf
106 : : * Pointer to the buffer.
107 : : * @param len
108 : : * Length of the buffer.
109 : : * @return
110 : : * The non-complemented checksum.
111 : : */
112 : : static inline uint16_t
113 : 5777 : rte_raw_cksum(const void *buf, size_t len)
114 : : {
115 : 0 : uint32_t sum;
116 : :
117 : 0 : sum = __rte_raw_cksum(buf, len, 0);
118 : 5777 : return __rte_raw_cksum_reduce(sum);
119 : : }
120 : :
121 : : /**
122 : : * Compute the raw (non complemented) checksum of a packet.
123 : : *
124 : : * @param m
125 : : * The pointer to the mbuf.
126 : : * @param off
127 : : * The offset in bytes to start the checksum.
128 : : * @param len
129 : : * The length in bytes of the data to checksum.
130 : : * @param cksum
131 : : * A pointer to the checksum, filled on success.
132 : : * @return
133 : : * 0 on success, -1 on error (bad length or offset).
134 : : */
135 : : static inline int
136 : 1 : rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
137 : : uint16_t *cksum)
138 : : {
139 : : const struct rte_mbuf *seg;
140 : : const char *buf;
141 : : uint32_t seglen, done, tmp;
142 : : uint64_t sum;
143 : :
144 : : /* easy case: all data in the first segment */
145 [ - + ]: 1 : if (off + len <= rte_pktmbuf_data_len(m)) {
146 : 0 : *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m,
147 : : const char *, off), len);
148 : 0 : return 0;
149 : : }
150 : :
151 [ + - ]: 1 : if (unlikely(off + len > rte_pktmbuf_pkt_len(m)))
152 : : return -1; /* invalid params, return a dummy value */
153 : :
154 : : /* else browse the segment to find offset */
155 : : seglen = 0;
156 [ + - ]: 1 : for (seg = m; seg != NULL; seg = seg->next) {
157 : 1 : seglen = rte_pktmbuf_data_len(seg);
158 [ - + ]: 1 : if (off < seglen)
159 : : break;
160 : 0 : off -= seglen;
161 : : }
162 : : RTE_ASSERT(seg != NULL);
163 [ + - ]: 1 : if (seg == NULL)
164 : : return -1;
165 : 1 : seglen -= off;
166 : 1 : buf = rte_pktmbuf_mtod_offset(seg, const char *, off);
167 [ - + ]: 1 : if (seglen >= len) {
168 : : /* all in one segment */
169 : 0 : *cksum = rte_raw_cksum(buf, len);
170 : 0 : return 0;
171 : : }
172 : :
173 : : /* hard case: process checksum of several segments */
174 : : sum = 0;
175 : : done = 0;
176 : : for (;;) {
177 : 3 : tmp = __rte_raw_cksum(buf, seglen, 0);
178 [ + + ]: 3 : if (done & 1)
179 [ - + ]: 1 : tmp = rte_bswap32(tmp);
180 : 3 : sum += tmp;
181 : 3 : done += seglen;
182 [ + + ]: 3 : if (done == len)
183 : : break;
184 : 2 : seg = seg->next;
185 : 2 : buf = rte_pktmbuf_mtod(seg, const char *);
186 : 2 : seglen = rte_pktmbuf_data_len(seg);
187 : 2 : if (seglen > len - done)
188 : : seglen = len - done;
189 : : }
190 : :
191 : 1 : *cksum = __rte_raw_cksum_reduce_u64(sum);
192 : 1 : return 0;
193 : : }
194 : :
195 : : #ifdef __cplusplus
196 : : }
197 : : #endif
198 : :
199 : : #endif /* _RTE_CKSUM_H_ */
|