Line data Source code
1 : /*
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 :
42 : static ip_csum_t
43 49594200 : _ip_incremental_checksum (ip_csum_t sum, void *_data, uword n_bytes)
44 : {
45 49594200 : uword data = pointer_to_uword (_data);
46 : ip_csum_t sum0, sum1;
47 :
48 49594200 : sum0 = 0;
49 49594200 : sum1 = sum;
50 :
51 : /*
52 : * Align pointer to 64 bits. The ip checksum is a 16-bit
53 : * one's complememt sum. It's impractical to optimize
54 : * the calculation if the incoming address is odd.
55 : */
56 : #define _(t) \
57 : do { \
58 : if (n_bytes >= sizeof (t) \
59 : && sizeof (t) < sizeof (ip_csum_t) \
60 : && (data % (2 * sizeof (t))) != 0) \
61 : { \
62 : sum0 += * uword_to_pointer (data, t *); \
63 : data += sizeof (t); \
64 : n_bytes -= sizeof (t); \
65 : } \
66 : } while (0)
67 :
68 49594200 : if (PREDICT_TRUE ((data & 1) == 0))
69 : {
70 49594200 : _(u16);
71 : if (BITS (ip_csum_t) > 32)
72 49594200 : _(u32);
73 : }
74 : #undef _
75 :
76 : {
77 49594200 : ip_csum_t *d = uword_to_pointer (data, ip_csum_t *);
78 :
79 4198290000 : while (n_bytes >= 2 * sizeof (d[0]))
80 : {
81 4148690000 : sum0 = ip_csum_with_carry (sum0, d[0]);
82 4148690000 : sum1 = ip_csum_with_carry (sum1, d[1]);
83 4148690000 : d += 2;
84 4148690000 : n_bytes -= 2 * sizeof (d[0]);
85 : }
86 :
87 49594200 : data = pointer_to_uword (d);
88 : }
89 :
90 : #define _(t) \
91 : do { \
92 : if (n_bytes >= sizeof (t) && sizeof (t) <= sizeof (ip_csum_t)) \
93 : { \
94 : sum0 = ip_csum_with_carry (sum0, * uword_to_pointer (data, t *)); \
95 : data += sizeof (t); \
96 : n_bytes -= sizeof (t); \
97 : } \
98 : } while (0)
99 :
100 : if (BITS (ip_csum_t) > 32)
101 49594200 : _(u64);
102 49594200 : _(u32);
103 49594200 : _(u16);
104 49594200 : _(u8);
105 :
106 : #undef _
107 :
108 : /* Combine even and odd sums. */
109 49594200 : sum0 = ip_csum_with_carry (sum0, sum1);
110 :
111 49594200 : return sum0;
112 : }
113 :
114 : /*
115 : * Note: the tcp / udp checksum calculation is performance critical
116 : * [e.g. when NIC h/w offload is not available],
117 : * so it's worth producing architecture-dependent code.
118 : *
119 : * ip_incremental_checksum() is an always-inlined static
120 : * function which uses the function pointer we set up in
121 : * ip_checksum_init().
122 : */
123 :
124 : ip_csum_t (*vnet_incremental_checksum_fp) (ip_csum_t, void *, uword);
125 :
126 : clib_error_t *
127 575 : ip_checksum_init (vlib_main_t *vm)
128 : {
129 575 : vnet_incremental_checksum_fp = _ip_incremental_checksum;
130 575 : return 0;
131 : }
132 :
133 44351 : VLIB_INIT_FUNCTION (ip_checksum_init);
134 :
135 : #if CLIB_DEBUG > 0
136 :
137 : static const char test_pkt[] = {
138 : 0x45, 0x00, 0x00, 0x3c, 0x5d, 0x6f, 0x40, 0x00,
139 : 0x40, 0x06, 0x3f, 0x6b, 0x0a, 0x76, 0x72, 0x44,
140 : 0x0a, 0x56, 0x16, 0xd2,
141 : };
142 :
143 : static clib_error_t *
144 0 : test_ip_checksum_fn (vlib_main_t * vm,
145 : unformat_input_t * input, vlib_cli_command_t * cmd)
146 : {
147 : u16 csum;
148 : ip4_header_t *hp;
149 0 : u8 *align_test = 0;
150 : int offset;
151 :
152 0 : vec_validate (align_test, ARRAY_LEN (test_pkt) + 7);
153 :
154 0 : for (offset = 0; offset < 8; offset++)
155 : {
156 0 : memcpy (align_test + offset, test_pkt, ARRAY_LEN (test_pkt));
157 :
158 0 : hp = (ip4_header_t *) (align_test + offset);
159 0 : csum = ip4_header_checksum (hp);
160 :
161 0 : vlib_cli_output (vm, "offset %d checksum %u expected result 27455",
162 : offset, (u32) csum);
163 : }
164 :
165 0 : return 0;
166 : }
167 :
168 : /* *INDENT-OFF* */
169 285289 : VLIB_CLI_COMMAND (test_checksum, static) =
170 : {
171 : .path = "test ip checksum",
172 : .short_help = "test ip checksum",
173 : .function = test_ip_checksum_fn,
174 : };
175 : /* *INDENT-ON* */
176 :
177 : #endif /* CLIB_DEBUG */
178 :
179 : /*
180 : * fd.io coding-style-patch-verification: ON
181 : *
182 : * Local Variables:
183 : * eval: (c-set-style "gnu")
184 : * End:
185 : */
|