blob: 6a9cf657a5c6a20a971713717312a816825aca48 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip4/ip_checksum.c: ip/tcp/udp checksums
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/ip/ip.h>
41
42ip_csum_t
Dave Barachd7cb1b52016-12-09 09:52:16 -050043ip_incremental_checksum (ip_csum_t sum, void *_data, uword n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -070044{
45 uword data = pointer_to_uword (_data);
46 ip_csum_t sum0, sum1;
47
48 sum0 = 0;
49 sum1 = sum;
50
51 /* Align data pointer to 64 bits. */
52#define _(t) \
53do { \
54 if (n_bytes >= sizeof (t) \
55 && sizeof (t) < sizeof (ip_csum_t) \
56 && (data % (2 * sizeof (t))) != 0) \
57 { \
58 sum0 += * uword_to_pointer (data, t *); \
59 data += sizeof (t); \
60 n_bytes -= sizeof (t); \
61 } \
62} while (0)
63
Dave Barachd7cb1b52016-12-09 09:52:16 -050064 _(u8);
65 _(u16);
Ed Warnickecb9cada2015-12-08 15:45:58 -070066 if (BITS (ip_csum_t) > 32)
Dave Barachd7cb1b52016-12-09 09:52:16 -050067 _(u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -070068
69#undef _
70
Dave Barachd7cb1b52016-12-09 09:52:16 -050071 {
72 ip_csum_t *d = uword_to_pointer (data, ip_csum_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073
Dave Barachd7cb1b52016-12-09 09:52:16 -050074 while (n_bytes >= 2 * sizeof (d[0]))
75 {
76 sum0 = ip_csum_with_carry (sum0, d[0]);
77 sum1 = ip_csum_with_carry (sum1, d[1]);
78 d += 2;
79 n_bytes -= 2 * sizeof (d[0]);
80 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070081
Dave Barachd7cb1b52016-12-09 09:52:16 -050082 data = pointer_to_uword (d);
83 }
84
Ed Warnickecb9cada2015-12-08 15:45:58 -070085#define _(t) \
86do { \
87 if (n_bytes >= sizeof (t) && sizeof (t) <= sizeof (ip_csum_t)) \
88 { \
89 sum0 = ip_csum_with_carry (sum0, * uword_to_pointer (data, t *)); \
90 data += sizeof (t); \
91 n_bytes -= sizeof (t); \
92 } \
93} while (0)
94
Dave Barachd7cb1b52016-12-09 09:52:16 -050095 if (BITS (ip_csum_t) > 32)
96 _(u64);
97 _(u32);
98 _(u16);
99 _(u8);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
101#undef _
102
Dave Barachd7cb1b52016-12-09 09:52:16 -0500103 /* Combine even and odd sums. */
104 sum0 = ip_csum_with_carry (sum0, sum1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
Dave Barachd7cb1b52016-12-09 09:52:16 -0500106 return sum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107}
108
109ip_csum_t
Dave Barachd7cb1b52016-12-09 09:52:16 -0500110ip_csum_and_memcpy (ip_csum_t sum, void *dst, void *src, uword n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111{
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800112 uword n_left;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 ip_csum_t sum0 = sum, sum1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 n_left = n_bytes;
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800115
Dave Barachd7cb1b52016-12-09 09:52:16 -0500116 if (n_left && (pointer_to_uword (dst) & sizeof (u8)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500118 u8 *d8, val;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800120 d8 = dst;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121 val = ((u8 *) src)[0];
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800122 d8[0] = val;
123 dst += 1;
124 src += 1;
125 n_left -= 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500126 sum0 =
127 ip_csum_with_carry (sum0, val << (8 * CLIB_ARCH_IS_LITTLE_ENDIAN));
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800128 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130 while ((n_left >= sizeof (u16))
131 && (pointer_to_uword (dst) & (sizeof (sum) - sizeof (u16))))
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800132 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500133 u16 *d16, *s16;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800135 d16 = dst;
136 s16 = src;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500137
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800138 d16[0] = clib_mem_unaligned (&s16[0], u16);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800140 sum0 = ip_csum_with_carry (sum0, d16[0]);
141 dst += sizeof (u16);
142 src += sizeof (u16);
143 n_left -= sizeof (u16);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144 }
145
146 sum1 = 0;
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800147 while (n_left >= 2 * sizeof (sum))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148 {
149 ip_csum_t dst0, dst1;
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800150 ip_csum_t *dst_even, *src_even;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800152 dst_even = dst;
153 src_even = src;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 dst0 = clib_mem_unaligned (&src_even[0], ip_csum_t);
155 dst1 = clib_mem_unaligned (&src_even[1], ip_csum_t);
156
157 dst_even[0] = dst0;
158 dst_even[1] = dst1;
159
Dave Barachd7cb1b52016-12-09 09:52:16 -0500160 dst += 2 * sizeof (dst_even[0]);
161 src += 2 * sizeof (dst_even[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162 n_left -= 2 * sizeof (dst_even[0]);
163
164 sum0 = ip_csum_with_carry (sum0, dst0);
165 sum1 = ip_csum_with_carry (sum1, dst1);
166 }
167
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800168 sum0 = ip_csum_with_carry (sum0, sum1);
169 while (n_left >= 1 * sizeof (sum))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 {
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800171 ip_csum_t dst0, *dst_even, *src_even;
172
173 dst_even = dst;
174 src_even = src;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175
176 dst0 = clib_mem_unaligned (&src_even[0], ip_csum_t);
177
178 dst_even[0] = dst0;
179
Dave Barachd7cb1b52016-12-09 09:52:16 -0500180 dst += 1 * sizeof (sum);
181 src += 1 * sizeof (sum);
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800182 n_left -= 1 * sizeof (sum);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183
184 sum0 = ip_csum_with_carry (sum0, dst0);
185 }
186
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800187 while (n_left >= sizeof (u16))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 {
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800189 u16 dst0, *dst_short, *src_short;
190
191 dst_short = dst;
192 src_short = src;
193
194 dst0 = clib_mem_unaligned (&src_short[0], u16);
195
196 dst_short[0] = dst0;
197
198 sum0 = ip_csum_with_carry (sum0, dst_short[0]);
199 dst += 1 * sizeof (dst0);
200 src += 1 * sizeof (dst0);
201 n_left -= 1 * sizeof (dst0);
202
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 }
204
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800205 if (n_left == 1)
206 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500207 u8 *d8, *s8, val;
Kevin Paul Herbertcf121e32015-12-08 19:53:45 -0800208
209 d8 = dst;
210 s8 = src;
211
212 d8[0] = val = s8[0];
213 d8 += 1;
214 s8 += 1;
215 n_left -= 1;
216 sum0 = ip_csum_with_carry (sum0, val << (8 * CLIB_ARCH_IS_BIG_ENDIAN));
217 }
218
219 return sum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220}
Dave Barachd7cb1b52016-12-09 09:52:16 -0500221
222/*
223 * fd.io coding-style-patch-verification: ON
224 *
225 * Local Variables:
226 * eval: (c-set-style "gnu")
227 * End:
228 */