Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2021 6WIND S.A.
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <stdint.h>
9 : :
10 : : #include <rte_net.h>
11 : : #include <rte_mbuf.h>
12 : : #include <rte_ip.h>
13 : :
14 : : #include "test.h"
15 : :
16 : : #define MEMPOOL_CACHE_SIZE 0
17 : : #define MBUF_DATA_SIZE 256
18 : : #define NB_MBUF 128
19 : :
20 : : /*
21 : : * Test L3/L4 checksum API.
22 : : */
23 : :
24 : : #define GOTO_FAIL(str, ...) do { \
25 : : printf("cksum test FAILED (l.%d): <" str ">\n", \
26 : : __LINE__, ##__VA_ARGS__); \
27 : : goto fail; \
28 : : } while (0)
29 : :
30 : : /* generated in scapy with Ether()/IP()/TCP())) */
31 : : static const char test_cksum_ipv4_tcp[] = {
32 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
33 : : 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
34 : : 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
35 : : 0x7c, 0xcd, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
36 : : 0x00, 0x01, 0x00, 0x14, 0x00, 0x50, 0x00, 0x00,
37 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
38 : : 0x20, 0x00, 0x91, 0x7c, 0x00, 0x00,
39 : :
40 : : };
41 : :
42 : : /* generated in scapy with Ether()/IPv6()/TCP()) */
43 : : static const char test_cksum_ipv6_tcp[] = {
44 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
45 : : 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x60, 0x00,
46 : : 0x00, 0x00, 0x00, 0x14, 0x06, 0x40, 0x00, 0x00,
47 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
49 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14,
51 : : 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 : : 0x00, 0x00, 0x50, 0x02, 0x20, 0x00, 0x8f, 0x7d,
53 : : 0x00, 0x00,
54 : : };
55 : :
56 : : /* generated in scapy with Ether()/IP()/UDP()/Raw('x')) */
57 : : static const char test_cksum_ipv4_udp[] = {
58 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
59 : : 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
60 : : 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
61 : : 0x7c, 0xcd, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
62 : : 0x00, 0x01, 0x00, 0x35, 0x00, 0x35, 0x00, 0x09,
63 : : 0x89, 0x6f, 0x78,
64 : : };
65 : :
66 : : /* generated in scapy with Ether()/IPv6()/UDP()/Raw('x')) */
67 : : static const char test_cksum_ipv6_udp[] = {
68 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
69 : : 0x00, 0x00, 0x00, 0x00, 0x86, 0xdd, 0x60, 0x00,
70 : : 0x00, 0x00, 0x00, 0x09, 0x11, 0x40, 0x00, 0x00,
71 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
73 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x35,
75 : : 0x00, 0x35, 0x00, 0x09, 0x87, 0x70, 0x78,
76 : : };
77 : :
78 : : /* generated in scapy with Ether()/IP(options='\x00')/UDP()/Raw('x')) */
79 : : static const char test_cksum_ipv4_opts_udp[] = {
80 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
81 : : 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x46, 0x00,
82 : : 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
83 : : 0x7b, 0xc9, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
84 : : 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35,
85 : : 0x00, 0x35, 0x00, 0x09, 0x89, 0x6f, 0x78,
86 : : };
87 : :
88 : : /*
89 : : * generated in scapy with
90 : : * Ether()/IP()/TCP(options=[NOP,NOP,Timestamps])/os.urandom(113))
91 : : */
92 : : static const char test_cksum_ipv4_tcp_multi_segs[] = {
93 : : 0x00, 0x16, 0x3e, 0x0b, 0x6b, 0xd2, 0xee, 0xff,
94 : : 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x45, 0x00,
95 : : 0x00, 0xa5, 0x46, 0x10, 0x40, 0x00, 0x40, 0x06,
96 : : 0x80, 0xb5, 0xc0, 0xa8, 0xf9, 0x1d, 0xc0, 0xa8,
97 : : 0xf9, 0x1e, 0xdc, 0xa2, 0x14, 0x51, 0xbb, 0x8f,
98 : : 0xa0, 0x00, 0xe4, 0x7c, 0xe4, 0xb8, 0x80, 0x10,
99 : : 0x02, 0x00, 0x4b, 0xc1, 0x00, 0x00, 0x01, 0x01,
100 : : 0x08, 0x0a, 0x90, 0x60, 0xf4, 0xff, 0x03, 0xc5,
101 : : 0xb4, 0x19, 0x77, 0x34, 0xd4, 0xdc, 0x84, 0x86,
102 : : 0xff, 0x44, 0x09, 0x63, 0x36, 0x2e, 0x26, 0x9b,
103 : : 0x90, 0x70, 0xf2, 0xed, 0xc8, 0x5b, 0x87, 0xaa,
104 : : 0xb4, 0x67, 0x6b, 0x32, 0x3d, 0xc4, 0xbf, 0x15,
105 : : 0xa9, 0x16, 0x6c, 0x2a, 0x9d, 0xb2, 0xb7, 0x6b,
106 : : 0x58, 0x44, 0x58, 0x12, 0x4b, 0x8f, 0xe5, 0x12,
107 : : 0x11, 0x90, 0x94, 0x68, 0x37, 0xad, 0x0a, 0x9b,
108 : : 0xd6, 0x79, 0xf2, 0xb7, 0x31, 0xcf, 0x44, 0x22,
109 : : 0xc8, 0x99, 0x3f, 0xe5, 0xe7, 0xac, 0xc7, 0x0b,
110 : : 0x86, 0xdf, 0xda, 0xed, 0x0a, 0x0f, 0x86, 0xd7,
111 : : 0x48, 0xe2, 0xf1, 0xc2, 0x43, 0xed, 0x47, 0x3a,
112 : : 0xea, 0x25, 0x2d, 0xd6, 0x60, 0x38, 0x30, 0x07,
113 : : 0x28, 0xdd, 0x1f, 0x0c, 0xdd, 0x7b, 0x7c, 0xd9,
114 : : 0x35, 0x9d, 0x14, 0xaa, 0xc6, 0x35, 0xd1, 0x03,
115 : : 0x38, 0xb1, 0xf5,
116 : : };
117 : :
118 : : static const uint8_t test_cksum_ipv4_tcp_multi_segs_len[] = {
119 : : 66, /* the first seg contains all headers, including L2 to L4 */
120 : : 61, /* the second seg length is odd, test byte order independent */
121 : : 52, /* three segs are sufficient to test the most complex scenarios */
122 : : };
123 : :
124 : : /* test l3/l4 checksum api */
125 : : static int
126 : 5 : test_l4_cksum(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len)
127 : : {
128 : : struct rte_net_hdr_lens hdr_lens;
129 : : struct rte_mbuf *m = NULL;
130 : : uint32_t packet_type;
131 : : uint16_t prev_cksum;
132 : : void *l3_hdr;
133 : : void *l4_hdr;
134 : : uint32_t l3;
135 : : uint32_t l4;
136 : : char *data;
137 : :
138 : 5 : m = rte_pktmbuf_alloc(pktmbuf_pool);
139 [ - + ]: 5 : if (m == NULL)
140 : 0 : GOTO_FAIL("Cannot allocate mbuf");
141 : :
142 : 5 : data = rte_pktmbuf_append(m, len);
143 [ - + ]: 5 : if (data == NULL)
144 : 0 : GOTO_FAIL("Cannot append data");
145 : :
146 : : memcpy(data, pktdata, len);
147 : :
148 : 5 : packet_type = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
149 : 5 : l3 = packet_type & RTE_PTYPE_L3_MASK;
150 : 5 : l4 = packet_type & RTE_PTYPE_L4_MASK;
151 : :
152 : 5 : l3_hdr = rte_pktmbuf_mtod_offset(m, void *, hdr_lens.l2_len);
153 : 5 : l4_hdr = rte_pktmbuf_mtod_offset(m, void *,
154 : : hdr_lens.l2_len + hdr_lens.l3_len);
155 : :
156 [ + + ]: 5 : if (l3 == RTE_PTYPE_L3_IPV4 || l3 == RTE_PTYPE_L3_IPV4_EXT) {
157 : : struct rte_ipv4_hdr *ip = l3_hdr;
158 : :
159 : : /* verify IPv4 checksum */
160 : : if (rte_ipv4_cksum(l3_hdr) != 0)
161 : 0 : GOTO_FAIL("invalid IPv4 checksum verification");
162 : :
163 : : /* verify bad IPv4 checksum */
164 [ - + ]: 3 : ip->hdr_checksum++;
165 [ - + ]: 3 : if (rte_ipv4_cksum(l3_hdr) == 0)
166 : 0 : GOTO_FAIL("invalid IPv4 bad checksum verification");
167 : : ip->hdr_checksum--;
168 : :
169 : : /* recalculate IPv4 checksum */
170 : : prev_cksum = ip->hdr_checksum;
171 [ - + ]: 3 : ip->hdr_checksum = 0;
172 : 3 : ip->hdr_checksum = rte_ipv4_cksum(ip);
173 [ - + ]: 3 : if (ip->hdr_checksum != prev_cksum)
174 : 0 : GOTO_FAIL("invalid IPv4 checksum calculation");
175 : :
176 : : /* verify L4 checksum */
177 : : if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) != 0)
178 : 0 : GOTO_FAIL("invalid L4 checksum verification");
179 : :
180 [ + + ]: 3 : if (l4 == RTE_PTYPE_L4_TCP) {
181 : : struct rte_tcp_hdr *tcp = l4_hdr;
182 : :
183 : : /* verify bad TCP checksum */
184 : 1 : tcp->cksum++;
185 : : if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
186 : 0 : GOTO_FAIL("invalid bad TCP checksum verification");
187 : : tcp->cksum--;
188 : :
189 : : /* recalculate TCP checksum */
190 : : prev_cksum = tcp->cksum;
191 : 1 : tcp->cksum = 0;
192 : 1 : tcp->cksum = rte_ipv4_udptcp_cksum(l3_hdr, l4_hdr);
193 [ - + ]: 1 : if (tcp->cksum != prev_cksum)
194 : 0 : GOTO_FAIL("invalid TCP checksum calculation");
195 : :
196 [ + - ]: 2 : } else if (l4 == RTE_PTYPE_L4_UDP) {
197 : : struct rte_udp_hdr *udp = l4_hdr;
198 : :
199 : : /* verify bad UDP checksum */
200 : 2 : udp->dgram_cksum++;
201 : : if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
202 : 0 : GOTO_FAIL("invalid bad UDP checksum verification");
203 : : udp->dgram_cksum--;
204 : :
205 : : /* recalculate UDP checksum */
206 : : prev_cksum = udp->dgram_cksum;
207 : 2 : udp->dgram_cksum = 0;
208 : 2 : udp->dgram_cksum = rte_ipv4_udptcp_cksum(l3_hdr,
209 : : l4_hdr);
210 [ - + ]: 2 : if (udp->dgram_cksum != prev_cksum)
211 : 0 : GOTO_FAIL("invalid TCP checksum calculation");
212 : : }
213 [ + + ]: 2 : } else if (l3 == RTE_PTYPE_L3_IPV6 || l3 == RTE_PTYPE_L3_IPV6_EXT) {
214 : : if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) != 0)
215 : 0 : GOTO_FAIL("invalid L4 checksum verification");
216 : :
217 [ - + ]: 1 : if (l4 == RTE_PTYPE_L4_TCP) {
218 : : struct rte_tcp_hdr *tcp = l4_hdr;
219 : :
220 : : /* verify bad TCP checksum */
221 : 0 : tcp->cksum++;
222 : : if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
223 : 0 : GOTO_FAIL("invalid bad TCP checksum verification");
224 : : tcp->cksum--;
225 : :
226 : : /* recalculate TCP checksum */
227 : : prev_cksum = tcp->cksum;
228 : 0 : tcp->cksum = 0;
229 : 0 : tcp->cksum = rte_ipv6_udptcp_cksum(l3_hdr, l4_hdr);
230 [ # # ]: 0 : if (tcp->cksum != prev_cksum)
231 : 0 : GOTO_FAIL("invalid TCP checksum calculation");
232 : :
233 [ + - ]: 1 : } else if (l4 == RTE_PTYPE_L4_UDP) {
234 : : struct rte_udp_hdr *udp = l4_hdr;
235 : :
236 : : /* verify bad UDP checksum */
237 : 1 : udp->dgram_cksum++;
238 : : if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
239 : 0 : GOTO_FAIL("invalid bad UDP checksum verification");
240 : : udp->dgram_cksum--;
241 : :
242 : : /* recalculate UDP checksum */
243 : : prev_cksum = udp->dgram_cksum;
244 : 1 : udp->dgram_cksum = 0;
245 : 1 : udp->dgram_cksum = rte_ipv6_udptcp_cksum(l3_hdr,
246 : : l4_hdr);
247 [ - + ]: 1 : if (udp->dgram_cksum != prev_cksum)
248 : 0 : GOTO_FAIL("invalid TCP checksum calculation");
249 : : }
250 : : }
251 : :
252 : 5 : rte_pktmbuf_free(m);
253 : :
254 : 5 : return 0;
255 : :
256 : 0 : fail:
257 : 0 : rte_pktmbuf_free(m);
258 : :
259 : 0 : return -1;
260 : : }
261 : :
262 : : /* test l4 checksum api for a packet with mbuf chain */
263 : : static int
264 : 1 : test_l4_cksum_mbuf_chain(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len,
265 : : const uint8_t *segs, size_t segs_len)
266 : : {
267 : : struct rte_mbuf *m[NB_MBUF] = {0};
268 : : struct rte_mbuf *m_hdr = NULL;
269 : : struct rte_net_hdr_lens hdr_lens;
270 : : size_t i, off = 0;
271 : : uint32_t packet_type, l3;
272 : : void *l3_hdr;
273 : : char *data;
274 : :
275 [ + + ]: 4 : for (i = 0; i < segs_len; i++) {
276 : 3 : m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
277 [ - + ]: 3 : if (m[i] == NULL)
278 : 0 : GOTO_FAIL("Cannot allocate mbuf");
279 : :
280 : 3 : data = rte_pktmbuf_append(m[i], segs[i]);
281 [ - + ]: 3 : if (data == NULL) {
282 : 0 : rte_pktmbuf_free(m[i]);
283 : : m[i] = NULL;
284 : 0 : GOTO_FAIL("Cannot append data");
285 : : }
286 : :
287 [ + + ]: 3 : memcpy(data, pktdata + off, segs[i]);
288 : 3 : off += segs[i];
289 : :
290 [ + + ]: 3 : if (m_hdr) {
291 : : if (rte_pktmbuf_chain(m_hdr, m[i])) {
292 : 0 : rte_pktmbuf_free(m[i]);
293 : : m[i] = NULL;
294 : 0 : GOTO_FAIL("Cannot chain mbuf");
295 : : }
296 : : } else {
297 : : m_hdr = m[i];
298 : : }
299 : : }
300 : :
301 [ - + ]: 1 : if (off != len)
302 : 0 : GOTO_FAIL("Invalid segs");
303 : :
304 : 1 : packet_type = rte_net_get_ptype(m_hdr, &hdr_lens, RTE_PTYPE_ALL_MASK);
305 : 1 : l3 = packet_type & RTE_PTYPE_L3_MASK;
306 : :
307 : 1 : l3_hdr = rte_pktmbuf_mtod_offset(m_hdr, void *, hdr_lens.l2_len);
308 : 1 : off = hdr_lens.l2_len + hdr_lens.l3_len;
309 : :
310 [ + - ]: 1 : if (l3 == RTE_PTYPE_L3_IPV4 || l3 == RTE_PTYPE_L3_IPV4_EXT) {
311 : 1 : if (rte_ipv4_udptcp_cksum_mbuf_verify(m_hdr, l3_hdr, off) != 0)
312 : 0 : GOTO_FAIL("Invalid L4 checksum verification for mbuf chain");
313 [ # # ]: 0 : } else if (l3 == RTE_PTYPE_L3_IPV6 || l3 == RTE_PTYPE_L3_IPV6_EXT) {
314 : 0 : if (rte_ipv6_udptcp_cksum_mbuf_verify(m_hdr, l3_hdr, off) != 0)
315 : 0 : GOTO_FAIL("Invalid L4 checksum verification for mbuf chain");
316 : : }
317 : :
318 : 1 : rte_pktmbuf_free(m_hdr);
319 : :
320 : 1 : return 0;
321 : :
322 : 0 : fail:
323 [ # # ]: 0 : if (m_hdr)
324 : 0 : rte_pktmbuf_free(m_hdr);
325 : :
326 : : return -1;
327 : : }
328 : :
329 : : static int
330 : 1 : test_cksum(void)
331 : : {
332 : : struct rte_mempool *pktmbuf_pool = NULL;
333 : :
334 : : /* create pktmbuf pool if it does not exist */
335 : 1 : pktmbuf_pool = rte_pktmbuf_pool_create("test_cksum_mbuf_pool",
336 : : NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
337 : : SOCKET_ID_ANY);
338 : :
339 [ - + ]: 1 : if (pktmbuf_pool == NULL)
340 : 0 : GOTO_FAIL("cannot allocate mbuf pool");
341 : :
342 [ - + ]: 1 : if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_tcp,
343 : : sizeof(test_cksum_ipv4_tcp)) < 0)
344 : 0 : GOTO_FAIL("checksum error on ipv4_tcp");
345 : :
346 [ - + ]: 1 : if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv6_tcp,
347 : : sizeof(test_cksum_ipv6_tcp)) < 0)
348 : 0 : GOTO_FAIL("checksum error on ipv6_tcp");
349 : :
350 [ - + ]: 1 : if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_udp,
351 : : sizeof(test_cksum_ipv4_udp)) < 0)
352 : 0 : GOTO_FAIL("checksum error on ipv4_udp");
353 : :
354 [ - + ]: 1 : if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv6_udp,
355 : : sizeof(test_cksum_ipv6_udp)) < 0)
356 : 0 : GOTO_FAIL("checksum error on ipv6_udp");
357 : :
358 [ - + ]: 1 : if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_opts_udp,
359 : : sizeof(test_cksum_ipv4_opts_udp)) < 0)
360 : 0 : GOTO_FAIL("checksum error on ipv4_opts_udp");
361 : :
362 [ - + ]: 1 : if (test_l4_cksum_mbuf_chain(pktmbuf_pool, test_cksum_ipv4_tcp_multi_segs,
363 : : sizeof(test_cksum_ipv4_tcp_multi_segs),
364 : : test_cksum_ipv4_tcp_multi_segs_len,
365 : : sizeof(test_cksum_ipv4_tcp_multi_segs_len)) < 0)
366 : 0 : GOTO_FAIL("checksum error on mbuf chain check");
367 : :
368 : 1 : rte_mempool_free(pktmbuf_pool);
369 : :
370 : 1 : return 0;
371 : :
372 : 0 : fail:
373 : 0 : rte_mempool_free(pktmbuf_pool);
374 : :
375 : 0 : return -1;
376 : : }
377 : : #undef GOTO_FAIL
378 : :
379 : 302 : REGISTER_FAST_TEST(cksum_autotest, NOHUGE_OK, ASAN_OK, test_cksum);
|