1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009-2011 Spectra Logic Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14 * substantially similar to the "NO WARRANTY" disclaimer below
15 * ("Disclaimer") and any redistribution must be conditioned upon
16 * including a substantially similar Disclaimer requirement for further
17 * binary redistribution.
18 *
19 * NO WARRANTY
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGES.
31 *
32 * Authors: Justin T. Gibbs (Spectra Logic Corporation)
33 * Alan Somers (Spectra Logic Corporation)
34 * John Suykerbuyk (Spectra Logic Corporation)
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 /**
41 * \file netback_unit_tests.c
42 *
43 * \brief Unit tests for the Xen netback driver.
44 *
45 * Due to the driver's use of static functions, these tests cannot be compiled
46 * standalone; they must be #include'd from the driver's .c file.
47 */
48
49 /** Helper macro used to snprintf to a buffer and update the buffer pointer */
50 #define SNCATF(buffer, buflen, ...) do { \
51 size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__); \
52 buffer += new_chars; \
53 /* be careful; snprintf's return value can be > buflen */ \
54 buflen -= MIN(buflen, new_chars); \
55 } while (0)
56
57 /* STRINGIFY and TOSTRING are used only to help turn __LINE__ into a string */
58 #define STRINGIFY(x) #x
59 #define TOSTRING(x) STRINGIFY(x)
60
61 /**
62 * Writes an error message to buffer if cond is false
63 * Note the implied parameters buffer and
64 * buflen
65 */
66 #define XNB_ASSERT(cond) ({ \
67 int passed = (cond); \
68 char *_buffer = (buffer); \
69 size_t _buflen = (buflen); \
70 if (! passed) { \
71 strlcat(_buffer, __func__, _buflen); \
72 strlcat(_buffer, ":" TOSTRING(__LINE__) \
73 " Assertion Error: " #cond "\n", _buflen); \
74 } \
75 })
76
77 /**
78 * The signature used by all testcases. If the test writes anything
79 * to buffer, then it will be considered a failure
80 * \param buffer Return storage for error messages
81 * \param buflen The space available in the buffer
82 */
83 typedef void testcase_t(char *buffer, size_t buflen);
84
85 /**
86 * Signature used by setup functions
87 * \return nonzero on error
88 */
89 typedef int setup_t(void);
90
91 typedef void teardown_t(void);
92
93 /** A simple test fixture comprising setup, teardown, and test */
94 struct test_fixture {
95 /** Will be run before the test to allocate and initialize variables */
96 setup_t *setup;
97
98 /** Will be run if setup succeeds */
99 testcase_t *test;
100
101 /** Cleans up test data whether or not the setup succeeded */
102 teardown_t *teardown;
103 };
104
105 typedef struct test_fixture test_fixture_t;
106
107 static int xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags);
108 static int xnb_unit_test_runner(test_fixture_t const tests[], int ntests,
109 char *buffer, size_t buflen);
110
111 static int __unused
112 null_setup(void) { return 0; }
113
114 static void __unused
115 null_teardown(void) { }
116
117 static setup_t setup_pvt_data;
118 static teardown_t teardown_pvt_data;
119 static testcase_t xnb_ring2pkt_emptyring;
120 static testcase_t xnb_ring2pkt_1req;
121 static testcase_t xnb_ring2pkt_2req;
122 static testcase_t xnb_ring2pkt_3req;
123 static testcase_t xnb_ring2pkt_extra;
124 static testcase_t xnb_ring2pkt_partial;
125 static testcase_t xnb_ring2pkt_wraps;
126 static testcase_t xnb_txpkt2rsp_emptypkt;
127 static testcase_t xnb_txpkt2rsp_1req;
128 static testcase_t xnb_txpkt2rsp_extra;
129 static testcase_t xnb_txpkt2rsp_long;
130 static testcase_t xnb_txpkt2rsp_invalid;
131 static testcase_t xnb_txpkt2rsp_error;
132 static testcase_t xnb_txpkt2rsp_wraps;
133 static testcase_t xnb_pkt2mbufc_empty;
134 static testcase_t xnb_pkt2mbufc_short;
135 static testcase_t xnb_pkt2mbufc_csum;
136 static testcase_t xnb_pkt2mbufc_1cluster;
137 static testcase_t xnb_pkt2mbufc_largecluster;
138 static testcase_t xnb_pkt2mbufc_2cluster;
139 static testcase_t xnb_txpkt2gnttab_empty;
140 static testcase_t xnb_txpkt2gnttab_short;
141 static testcase_t xnb_txpkt2gnttab_2req;
142 static testcase_t xnb_txpkt2gnttab_2cluster;
143 static testcase_t xnb_update_mbufc_short;
144 static testcase_t xnb_update_mbufc_2req;
145 static testcase_t xnb_update_mbufc_2cluster;
146 static testcase_t xnb_mbufc2pkt_empty;
147 static testcase_t xnb_mbufc2pkt_short;
148 static testcase_t xnb_mbufc2pkt_1cluster;
149 static testcase_t xnb_mbufc2pkt_2short;
150 static testcase_t xnb_mbufc2pkt_long;
151 static testcase_t xnb_mbufc2pkt_extra;
152 static testcase_t xnb_mbufc2pkt_nospace;
153 static testcase_t xnb_rxpkt2gnttab_empty;
154 static testcase_t xnb_rxpkt2gnttab_short;
155 static testcase_t xnb_rxpkt2gnttab_2req;
156 static testcase_t xnb_rxpkt2rsp_empty;
157 static testcase_t xnb_rxpkt2rsp_short;
158 static testcase_t xnb_rxpkt2rsp_extra;
159 static testcase_t xnb_rxpkt2rsp_2short;
160 static testcase_t xnb_rxpkt2rsp_2slots;
161 static testcase_t xnb_rxpkt2rsp_copyerror;
162 static testcase_t xnb_sscanf_llu;
163 static testcase_t xnb_sscanf_lld;
164 static testcase_t xnb_sscanf_hhu;
165 static testcase_t xnb_sscanf_hhd;
166 static testcase_t xnb_sscanf_hhn;
167
168 #if defined(INET) || defined(INET6)
169 /* TODO: add test cases for xnb_add_mbuf_cksum for IPV6 tcp and udp */
170 static testcase_t xnb_add_mbuf_cksum_arp;
171 static testcase_t xnb_add_mbuf_cksum_tcp;
172 static testcase_t xnb_add_mbuf_cksum_udp;
173 static testcase_t xnb_add_mbuf_cksum_icmp;
174 static testcase_t xnb_add_mbuf_cksum_tcp_swcksum;
175 static void xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len,
176 uint16_t ip_id, uint16_t ip_p,
177 uint16_t ip_off, uint16_t ip_sum);
178 static void xnb_fill_tcp(struct mbuf *m);
179 #endif /* INET || INET6 */
180
181 /** Private data used by unit tests */
182 static struct {
183 gnttab_copy_table gnttab;
184 netif_rx_back_ring_t rxb;
185 netif_rx_front_ring_t rxf;
186 netif_tx_back_ring_t txb;
187 netif_tx_front_ring_t txf;
188 struct ifnet* ifp;
189 netif_rx_sring_t* rxs;
190 netif_tx_sring_t* txs;
191 } xnb_unit_pvt;
192
193 static inline void safe_m_freem(struct mbuf **ppMbuf) {
194 if (*ppMbuf != NULL) {
195 m_freem(*ppMbuf);
196 *ppMbuf = NULL;
197 }
198 }
199
200 /**
201 * The unit test runner. It will run every supplied test and return an
202 * output message as a string
203 * \param tests An array of tests. Every test will be attempted.
204 * \param ntests The length of tests
205 * \param buffer Return storage for the result string
206 * \param buflen The length of buffer
207 * \return The number of tests that failed
208 */
209 static int
210 xnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer,
211 size_t buflen)
212 {
213 int i;
214 int n_passes;
215 int n_failures = 0;
216
217 for (i = 0; i < ntests; i++) {
218 int error = tests[i].setup();
219 if (error != 0) {
220 SNCATF(buffer, buflen,
221 "Setup failed for test idx %d\n", i);
222 n_failures++;
223 } else {
224 size_t new_chars;
225
226 tests[i].test(buffer, buflen);
227 new_chars = strnlen(buffer, buflen);
228 buffer += new_chars;
229 buflen -= new_chars;
230
231 if (new_chars > 0) {
232 n_failures++;
233 }
234 }
235 tests[i].teardown();
236 }
237
238 n_passes = ntests - n_failures;
239 if (n_passes > 0) {
240 SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes);
241 }
242 if (n_failures > 0) {
243 SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures);
244 }
245
246 return n_failures;
247 }
248
249 /** Number of unit tests. Must match the length of the tests array below */
250 #define TOTAL_TESTS (53)
251 /**
252 * Max memory available for returning results. 400 chars/test should give
253 * enough space for a five line error message for every test
254 */
255 #define TOTAL_BUFLEN (400 * TOTAL_TESTS + 2)
256
257 /**
258 * Called from userspace by a sysctl. Runs all internal unit tests, and
259 * returns the results to userspace as a string
260 * \param oidp unused
261 * \param arg1 pointer to an xnb_softc for a specific xnb device
262 * \param arg2 unused
263 * \param req sysctl access structure
264 * \return a string via the special SYSCTL_OUT macro.
265 */
266
267 static int
268 xnb_unit_test_main(SYSCTL_HANDLER_ARGS) {
269 test_fixture_t const tests[TOTAL_TESTS] = {
270 {setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data},
271 {setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data},
272 {setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data},
273 {setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data},
274 {setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data},
275 {setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data},
276 {setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data},
277 {setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data},
278 {setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data},
279 {setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data},
280 {setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data},
281 {setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data},
282 {setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data},
283 {setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data},
284 {setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data},
285 {setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data},
286 {setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data},
287 {setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data},
288 {setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data},
289 {setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data},
290 {setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data},
291 {setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data},
292 {setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data},
293 {setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data},
294 {setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data},
295 {setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data},
296 {setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data},
297 {setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data},
298 {setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data},
299 {setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data},
300 {setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data},
301 {setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data},
302 {setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data},
303 {setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data},
304 {setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data},
305 {setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data},
306 {setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data},
307 {setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data},
308 {setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data},
309 {setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data},
310 {setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data},
311 {setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data},
312 {setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data},
313 #if defined(INET) || defined(INET6)
314 {null_setup, xnb_add_mbuf_cksum_arp, null_teardown},
315 {null_setup, xnb_add_mbuf_cksum_icmp, null_teardown},
316 {null_setup, xnb_add_mbuf_cksum_tcp, null_teardown},
317 {null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown},
318 {null_setup, xnb_add_mbuf_cksum_udp, null_teardown},
319 #endif
320 {null_setup, xnb_sscanf_hhd, null_teardown},
321 {null_setup, xnb_sscanf_hhu, null_teardown},
322 {null_setup, xnb_sscanf_lld, null_teardown},
323 {null_setup, xnb_sscanf_llu, null_teardown},
324 {null_setup, xnb_sscanf_hhn, null_teardown},
325 };
326 /**
327 * results is static so that the data will persist after this function
328 * returns. The sysctl code expects us to return a constant string.
329 * \todo: the static variable is not thread safe. Put a mutex around
330 * it.
331 */
332 static char results[TOTAL_BUFLEN];
333
334 /* empty the result strings */
335 results[0] = 0;
336 xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN);
337
338 return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN)));
339 }
340
341 static int
342 setup_pvt_data(void)
343 {
344 int error = 0;
345
346 bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab));
347
348 xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
349 if (xnb_unit_pvt.txs != NULL) {
350 SHARED_RING_INIT(xnb_unit_pvt.txs);
351 BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE);
352 FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE);
353 } else {
354 error = 1;
355 }
356
357 xnb_unit_pvt.ifp = if_alloc(IFT_ETHER);
358 if (xnb_unit_pvt.ifp == NULL) {
359 error = 1;
360 }
361
362 xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
363 if (xnb_unit_pvt.rxs != NULL) {
364 SHARED_RING_INIT(xnb_unit_pvt.rxs);
365 BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE);
366 FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE);
367 } else {
368 error = 1;
369 }
370
371 return error;
372 }
373
374 static void
375 teardown_pvt_data(void)
376 {
377 if (xnb_unit_pvt.txs != NULL) {
378 free(xnb_unit_pvt.txs, M_XENNETBACK);
379 }
380 if (xnb_unit_pvt.rxs != NULL) {
381 free(xnb_unit_pvt.rxs, M_XENNETBACK);
382 }
383 if (xnb_unit_pvt.ifp != NULL) {
384 if_free(xnb_unit_pvt.ifp);
385 }
386 }
387
388 /**
389 * Verify that xnb_ring2pkt will not consume any requests from an empty ring
390 */
391 static void
392 xnb_ring2pkt_emptyring(char *buffer, size_t buflen)
393 {
394 struct xnb_pkt pkt;
395 int num_consumed;
396
397 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
398 xnb_unit_pvt.txb.req_cons);
399 XNB_ASSERT(num_consumed == 0);
400 }
401
402 /**
403 * Verify that xnb_ring2pkt can convert a single request packet correctly
404 */
405 static void
406 xnb_ring2pkt_1req(char *buffer, size_t buflen)
407 {
408 struct xnb_pkt pkt;
409 int num_consumed;
410 struct netif_tx_request *req;
411
412 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
413 xnb_unit_pvt.txf.req_prod_pvt);
414
415 req->flags = 0;
416 req->size = 69; /* arbitrary number for test */
417 xnb_unit_pvt.txf.req_prod_pvt++;
418
419 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
420
421 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
422 xnb_unit_pvt.txb.req_cons);
423 XNB_ASSERT(num_consumed == 1);
424 XNB_ASSERT(pkt.size == 69);
425 XNB_ASSERT(pkt.car_size == 69);
426 XNB_ASSERT(pkt.flags == 0);
427 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
428 XNB_ASSERT(pkt.list_len == 1);
429 XNB_ASSERT(pkt.car == 0);
430 }
431
432 /**
433 * Verify that xnb_ring2pkt can convert a two request packet correctly.
434 * This tests handling of the MORE_DATA flag and cdr
435 */
436 static void
437 xnb_ring2pkt_2req(char *buffer, size_t buflen)
438 {
439 struct xnb_pkt pkt;
440 int num_consumed;
441 struct netif_tx_request *req;
442 RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
443
444 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
445 xnb_unit_pvt.txf.req_prod_pvt);
446 req->flags = NETTXF_more_data;
447 req->size = 100;
448 xnb_unit_pvt.txf.req_prod_pvt++;
449
450 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
451 xnb_unit_pvt.txf.req_prod_pvt);
452 req->flags = 0;
453 req->size = 40;
454 xnb_unit_pvt.txf.req_prod_pvt++;
455
456 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
457
458 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
459 xnb_unit_pvt.txb.req_cons);
460 XNB_ASSERT(num_consumed == 2);
461 XNB_ASSERT(pkt.size == 100);
462 XNB_ASSERT(pkt.car_size == 60);
463 XNB_ASSERT(pkt.flags == 0);
464 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
465 XNB_ASSERT(pkt.list_len == 2);
466 XNB_ASSERT(pkt.car == start_idx);
467 XNB_ASSERT(pkt.cdr == start_idx + 1);
468 }
469
470 /**
471 * Verify that xnb_ring2pkt can convert a three request packet correctly
472 */
473 static void
474 xnb_ring2pkt_3req(char *buffer, size_t buflen)
475 {
476 struct xnb_pkt pkt;
477 int num_consumed;
478 struct netif_tx_request *req;
479 RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
480
481 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
482 xnb_unit_pvt.txf.req_prod_pvt);
483 req->flags = NETTXF_more_data;
484 req->size = 200;
485 xnb_unit_pvt.txf.req_prod_pvt++;
486
487 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
488 xnb_unit_pvt.txf.req_prod_pvt);
489 req->flags = NETTXF_more_data;
490 req->size = 40;
491 xnb_unit_pvt.txf.req_prod_pvt++;
492
493 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
494 xnb_unit_pvt.txf.req_prod_pvt);
495 req->flags = 0;
496 req->size = 50;
497 xnb_unit_pvt.txf.req_prod_pvt++;
498
499 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
500
501 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
502 xnb_unit_pvt.txb.req_cons);
503 XNB_ASSERT(num_consumed == 3);
504 XNB_ASSERT(pkt.size == 200);
505 XNB_ASSERT(pkt.car_size == 110);
506 XNB_ASSERT(pkt.flags == 0);
507 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
508 XNB_ASSERT(pkt.list_len == 3);
509 XNB_ASSERT(pkt.car == start_idx);
510 XNB_ASSERT(pkt.cdr == start_idx + 1);
511 XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
512 }
513
514 /**
515 * Verify that xnb_ring2pkt can read extra inf
516 */
517 static void
518 xnb_ring2pkt_extra(char *buffer, size_t buflen)
519 {
520 struct xnb_pkt pkt;
521 int num_consumed;
522 struct netif_tx_request *req;
523 struct netif_extra_info *ext;
524 RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
525
526 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
527 xnb_unit_pvt.txf.req_prod_pvt);
528 req->flags = NETTXF_extra_info | NETTXF_more_data;
529 req->size = 150;
530 xnb_unit_pvt.txf.req_prod_pvt++;
531
532 ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
533 xnb_unit_pvt.txf.req_prod_pvt);
534 ext->flags = 0;
535 ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
536 ext->u.gso.size = 250;
537 ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
538 ext->u.gso.features = 0;
539 xnb_unit_pvt.txf.req_prod_pvt++;
540
541 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
542 xnb_unit_pvt.txf.req_prod_pvt);
543 req->flags = 0;
544 req->size = 50;
545 xnb_unit_pvt.txf.req_prod_pvt++;
546
547 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
548
549 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
550 xnb_unit_pvt.txb.req_cons);
551 XNB_ASSERT(num_consumed == 3);
552 XNB_ASSERT(pkt.extra.flags == 0);
553 XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
554 XNB_ASSERT(pkt.extra.u.gso.size == 250);
555 XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4);
556 XNB_ASSERT(pkt.size == 150);
557 XNB_ASSERT(pkt.car_size == 100);
558 XNB_ASSERT(pkt.flags == NETTXF_extra_info);
559 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
560 XNB_ASSERT(pkt.list_len == 2);
561 XNB_ASSERT(pkt.car == start_idx);
562 XNB_ASSERT(pkt.cdr == start_idx + 2);
563 XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req);
564 }
565
566 /**
567 * Verify that xnb_ring2pkt will consume no requests if the entire packet is
568 * not yet in the ring
569 */
570 static void
571 xnb_ring2pkt_partial(char *buffer, size_t buflen)
572 {
573 struct xnb_pkt pkt;
574 int num_consumed;
575 struct netif_tx_request *req;
576
577 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
578 xnb_unit_pvt.txf.req_prod_pvt);
579 req->flags = NETTXF_more_data;
580 req->size = 150;
581 xnb_unit_pvt.txf.req_prod_pvt++;
582
583 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
584
585 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
586 xnb_unit_pvt.txb.req_cons);
587 XNB_ASSERT(num_consumed == 0);
588 XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
589 }
590
591 /**
592 * Verity that xnb_ring2pkt can read a packet whose requests wrap around
593 * the end of the ring
594 */
595 static void
596 xnb_ring2pkt_wraps(char *buffer, size_t buflen)
597 {
598 struct xnb_pkt pkt;
599 int num_consumed;
600 struct netif_tx_request *req;
601 unsigned int rsize;
602
603 /*
604 * Manually tweak the ring indices to create a ring with no responses
605 * and the next request slot at position 2 from the end
606 */
607 rsize = RING_SIZE(&xnb_unit_pvt.txf);
608 xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
609 xnb_unit_pvt.txf.rsp_cons = rsize - 2;
610 xnb_unit_pvt.txs->req_prod = rsize - 2;
611 xnb_unit_pvt.txs->req_event = rsize - 1;
612 xnb_unit_pvt.txs->rsp_prod = rsize - 2;
613 xnb_unit_pvt.txs->rsp_event = rsize - 1;
614 xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
615 xnb_unit_pvt.txb.req_cons = rsize - 2;
616
617 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
618 xnb_unit_pvt.txf.req_prod_pvt);
619 req->flags = NETTXF_more_data;
620 req->size = 550;
621 xnb_unit_pvt.txf.req_prod_pvt++;
622
623 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
624 xnb_unit_pvt.txf.req_prod_pvt);
625 req->flags = NETTXF_more_data;
626 req->size = 100;
627 xnb_unit_pvt.txf.req_prod_pvt++;
628
629 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
630 xnb_unit_pvt.txf.req_prod_pvt);
631 req->flags = 0;
632 req->size = 50;
633 xnb_unit_pvt.txf.req_prod_pvt++;
634
635 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
636
637 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
638 xnb_unit_pvt.txb.req_cons);
639 XNB_ASSERT(num_consumed == 3);
640 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
641 XNB_ASSERT(pkt.list_len == 3);
642 XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
643 }
644
645 /**
646 * xnb_txpkt2rsp should do nothing for an empty packet
647 */
648 static void
649 xnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen)
650 {
651 struct xnb_pkt pkt;
652 netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb;
653 netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs;
654 pkt.list_len = 0;
655
656 /* must call xnb_ring2pkt just to intialize pkt */
657 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
658 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
659 XNB_ASSERT(
660 memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0);
661 XNB_ASSERT(
662 memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0);
663 }
664
665 /**
666 * xnb_txpkt2rsp responding to one request
667 */
668 static void
669 xnb_txpkt2rsp_1req(char *buffer, size_t buflen)
670 {
671 uint16_t num_consumed;
672 struct xnb_pkt pkt;
673 struct netif_tx_request *req;
674 struct netif_tx_response *rsp;
675
676 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
677 xnb_unit_pvt.txf.req_prod_pvt);
678 req->size = 1000;
679 req->flags = 0;
680 xnb_unit_pvt.txf.req_prod_pvt++;
681
682 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
683
684 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
685 xnb_unit_pvt.txb.req_cons);
686 xnb_unit_pvt.txb.req_cons += num_consumed;
687
688 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
689 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
690
691 XNB_ASSERT(
692 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
693 XNB_ASSERT(rsp->id == req->id);
694 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
695 };
696
697 /**
698 * xnb_txpkt2rsp responding to 1 data request and 1 extra info
699 */
700 static void
701 xnb_txpkt2rsp_extra(char *buffer, size_t buflen)
702 {
703 uint16_t num_consumed;
704 struct xnb_pkt pkt;
705 struct netif_tx_request *req;
706 netif_extra_info_t *ext;
707 struct netif_tx_response *rsp;
708
709 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
710 xnb_unit_pvt.txf.req_prod_pvt);
711 req->size = 1000;
712 req->flags = NETTXF_extra_info;
713 req->id = 69;
714 xnb_unit_pvt.txf.req_prod_pvt++;
715
716 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
717 xnb_unit_pvt.txf.req_prod_pvt);
718 ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
719 ext->flags = 0;
720 xnb_unit_pvt.txf.req_prod_pvt++;
721
722 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
723
724 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
725 xnb_unit_pvt.txb.req_cons);
726 xnb_unit_pvt.txb.req_cons += num_consumed;
727
728 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
729
730 XNB_ASSERT(
731 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
732
733 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
734 XNB_ASSERT(rsp->id == req->id);
735 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
736
737 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
738 xnb_unit_pvt.txf.rsp_cons + 1);
739 XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
740 };
741
742 /**
743 * xnb_pkg2rsp responding to 3 data requests and 1 extra info
744 */
745 static void
746 xnb_txpkt2rsp_long(char *buffer, size_t buflen)
747 {
748 uint16_t num_consumed;
749 struct xnb_pkt pkt;
750 struct netif_tx_request *req;
751 netif_extra_info_t *ext;
752 struct netif_tx_response *rsp;
753
754 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
755 xnb_unit_pvt.txf.req_prod_pvt);
756 req->size = 1000;
757 req->flags = NETTXF_extra_info | NETTXF_more_data;
758 req->id = 254;
759 xnb_unit_pvt.txf.req_prod_pvt++;
760
761 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
762 xnb_unit_pvt.txf.req_prod_pvt);
763 ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
764 ext->flags = 0;
765 xnb_unit_pvt.txf.req_prod_pvt++;
766
767 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
768 xnb_unit_pvt.txf.req_prod_pvt);
769 req->size = 300;
770 req->flags = NETTXF_more_data;
771 req->id = 1034;
772 xnb_unit_pvt.txf.req_prod_pvt++;
773
774 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
775 xnb_unit_pvt.txf.req_prod_pvt);
776 req->size = 400;
777 req->flags = 0;
778 req->id = 34;
779 xnb_unit_pvt.txf.req_prod_pvt++;
780
781 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
782
783 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
784 xnb_unit_pvt.txb.req_cons);
785 xnb_unit_pvt.txb.req_cons += num_consumed;
786
787 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
788
789 XNB_ASSERT(
790 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
791
792 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
793 XNB_ASSERT(rsp->id ==
794 RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id);
795 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
796
797 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
798 xnb_unit_pvt.txf.rsp_cons + 1);
799 XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
800
801 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
802 xnb_unit_pvt.txf.rsp_cons + 2);
803 XNB_ASSERT(rsp->id ==
804 RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id);
805 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
806
807 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
808 xnb_unit_pvt.txf.rsp_cons + 3);
809 XNB_ASSERT(rsp->id ==
810 RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id);
811 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
812 }
813
814 /**
815 * xnb_txpkt2rsp responding to an invalid packet.
816 * Note: this test will result in an error message being printed to the console
817 * such as:
818 * xnb(xnb_ring2pkt:1306): Unknown extra info type 255. Discarding packet
819 */
820 static void
821 xnb_txpkt2rsp_invalid(char *buffer, size_t buflen)
822 {
823 uint16_t num_consumed;
824 struct xnb_pkt pkt;
825 struct netif_tx_request *req;
826 netif_extra_info_t *ext;
827 struct netif_tx_response *rsp;
828
829 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
830 xnb_unit_pvt.txf.req_prod_pvt);
831 req->size = 1000;
832 req->flags = NETTXF_extra_info;
833 req->id = 69;
834 xnb_unit_pvt.txf.req_prod_pvt++;
835
836 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
837 xnb_unit_pvt.txf.req_prod_pvt);
838 ext->type = 0xFF; /* Invalid extra type */
839 ext->flags = 0;
840 xnb_unit_pvt.txf.req_prod_pvt++;
841
842 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
843
844 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
845 xnb_unit_pvt.txb.req_cons);
846 xnb_unit_pvt.txb.req_cons += num_consumed;
847 XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
848
849 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
850
851 XNB_ASSERT(
852 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
853
854 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
855 XNB_ASSERT(rsp->id == req->id);
856 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
857
858 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
859 xnb_unit_pvt.txf.rsp_cons + 1);
860 XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
861 };
862
863 /**
864 * xnb_txpkt2rsp responding to one request which caused an error
865 */
866 static void
867 xnb_txpkt2rsp_error(char *buffer, size_t buflen)
868 {
869 uint16_t num_consumed;
870 struct xnb_pkt pkt;
871 struct netif_tx_request *req;
872 struct netif_tx_response *rsp;
873
874 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
875 xnb_unit_pvt.txf.req_prod_pvt);
876 req->size = 1000;
877 req->flags = 0;
878 xnb_unit_pvt.txf.req_prod_pvt++;
879
880 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
881
882 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
883 xnb_unit_pvt.txb.req_cons);
884 xnb_unit_pvt.txb.req_cons += num_consumed;
885
886 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1);
887 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
888
889 XNB_ASSERT(
890 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
891 XNB_ASSERT(rsp->id == req->id);
892 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
893 };
894
895 /**
896 * xnb_txpkt2rsp's responses wrap around the end of the ring
897 */
898 static void
899 xnb_txpkt2rsp_wraps(char *buffer, size_t buflen)
900 {
901 struct xnb_pkt pkt;
902 struct netif_tx_request *req;
903 struct netif_tx_response *rsp;
904 unsigned int rsize;
905
906 /*
907 * Manually tweak the ring indices to create a ring with no responses
908 * and the next request slot at position 2 from the end
909 */
910 rsize = RING_SIZE(&xnb_unit_pvt.txf);
911 xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
912 xnb_unit_pvt.txf.rsp_cons = rsize - 2;
913 xnb_unit_pvt.txs->req_prod = rsize - 2;
914 xnb_unit_pvt.txs->req_event = rsize - 1;
915 xnb_unit_pvt.txs->rsp_prod = rsize - 2;
916 xnb_unit_pvt.txs->rsp_event = rsize - 1;
917 xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
918 xnb_unit_pvt.txb.req_cons = rsize - 2;
919
920 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
921 xnb_unit_pvt.txf.req_prod_pvt);
922 req->flags = NETTXF_more_data;
923 req->size = 550;
924 req->id = 1;
925 xnb_unit_pvt.txf.req_prod_pvt++;
926
927 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
928 xnb_unit_pvt.txf.req_prod_pvt);
929 req->flags = NETTXF_more_data;
930 req->size = 100;
931 req->id = 2;
932 xnb_unit_pvt.txf.req_prod_pvt++;
933
934 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
935 xnb_unit_pvt.txf.req_prod_pvt);
936 req->flags = 0;
937 req->size = 50;
938 req->id = 3;
939 xnb_unit_pvt.txf.req_prod_pvt++;
940
941 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
942
943 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
944
945 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
946
947 XNB_ASSERT(
948 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
949 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
950 xnb_unit_pvt.txf.rsp_cons + 2);
951 XNB_ASSERT(rsp->id == req->id);
952 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
953 }
954
955 /**
956 * Helper function used to setup pkt2mbufc tests
957 * \param size size in bytes of the single request to push to the ring
958 * \param flags optional flags to put in the netif request
959 * \param[out] pkt the returned packet object
960 * \return number of requests consumed from the ring
961 */
962 static int
963 xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags)
964 {
965 struct netif_tx_request *req;
966
967 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
968 xnb_unit_pvt.txf.req_prod_pvt);
969 req->flags = flags;
970 req->size = size;
971 xnb_unit_pvt.txf.req_prod_pvt++;
972
973 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
974
975 return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb,
976 xnb_unit_pvt.txb.req_cons);
977 }
978
979 /**
980 * xnb_pkt2mbufc on an empty packet
981 */
982 static void
983 xnb_pkt2mbufc_empty(char *buffer, size_t buflen)
984 {
985 struct xnb_pkt pkt;
986 struct mbuf *pMbuf;
987 pkt.list_len = 0;
988
989 /* must call xnb_ring2pkt just to intialize pkt */
990 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
991 pkt.size = 0;
992 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
993 safe_m_freem(&pMbuf);
994 }
995
996 /**
997 * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer
998 */
999 static void
1000 xnb_pkt2mbufc_short(char *buffer, size_t buflen)
1001 {
1002 const size_t size = MINCLSIZE - 1;
1003 struct xnb_pkt pkt;
1004 struct mbuf *pMbuf;
1005
1006 xnb_get1pkt(&pkt, size, 0);
1007
1008 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1009 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1010 safe_m_freem(&pMbuf);
1011 }
1012
1013 /**
1014 * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron
1015 */
1016 static void
1017 xnb_pkt2mbufc_csum(char *buffer, size_t buflen)
1018 {
1019 const size_t size = MINCLSIZE - 1;
1020 struct xnb_pkt pkt;
1021 struct mbuf *pMbuf;
1022
1023 xnb_get1pkt(&pkt, size, NETTXF_data_validated);
1024
1025 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1026 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1027 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED);
1028 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID);
1029 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID);
1030 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR);
1031 safe_m_freem(&pMbuf);
1032 }
1033
1034 /**
1035 * xnb_pkt2mbufc on packet that can fit in one cluster
1036 */
1037 static void
1038 xnb_pkt2mbufc_1cluster(char *buffer, size_t buflen)
1039 {
1040 const size_t size = MINCLSIZE;
1041 struct xnb_pkt pkt;
1042 struct mbuf *pMbuf;
1043
1044 xnb_get1pkt(&pkt, size, 0);
1045
1046 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1047 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1048 safe_m_freem(&pMbuf);
1049 }
1050
1051 /**
1052 * xnb_pkt2mbufc on packet that cannot fit in one regular cluster
1053 */
1054 static void
1055 xnb_pkt2mbufc_largecluster(char *buffer, size_t buflen)
1056 {
1057 const size_t size = MCLBYTES + 1;
1058 struct xnb_pkt pkt;
1059 struct mbuf *pMbuf;
1060
1061 xnb_get1pkt(&pkt, size, 0);
1062
1063 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1064 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1065 safe_m_freem(&pMbuf);
1066 }
1067
1068 /**
1069 * xnb_pkt2mbufc on packet that cannot fit in one clusters
1070 */
1071 static void
1072 xnb_pkt2mbufc_2cluster(char *buffer, size_t buflen)
1073 {
1074 const size_t size = 2 * MCLBYTES + 1;
1075 size_t space = 0;
1076 struct xnb_pkt pkt;
1077 struct mbuf *pMbuf;
1078 struct mbuf *m;
1079
1080 xnb_get1pkt(&pkt, size, 0);
1081
1082 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1083
1084 for (m = pMbuf; m != NULL; m = m->m_next) {
1085 space += M_TRAILINGSPACE(m);
1086 }
1087 XNB_ASSERT(space >= size);
1088 safe_m_freem(&pMbuf);
1089 }
1090
1091 /**
1092 * xnb_txpkt2gnttab on an empty packet. Should return empty gnttab
1093 */
1094 static void
1095 xnb_txpkt2gnttab_empty(char *buffer, size_t buflen)
1096 {
1097 int n_entries;
1098 struct xnb_pkt pkt;
1099 struct mbuf *pMbuf;
1100 pkt.list_len = 0;
1101
1102 /* must call xnb_ring2pkt just to intialize pkt */
1103 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1104 pkt.size = 0;
1105 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1106 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1107 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1108 XNB_ASSERT(n_entries == 0);
1109 safe_m_freem(&pMbuf);
1110 }
1111
1112 /**
1113 * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer
1114 * and has one request
1115 */
1116 static void
1117 xnb_txpkt2gnttab_short(char *buffer, size_t buflen)
1118 {
1119 const size_t size = MINCLSIZE - 1;
1120 int n_entries;
1121 struct xnb_pkt pkt;
1122 struct mbuf *pMbuf;
1123
1124 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1125 xnb_unit_pvt.txf.req_prod_pvt);
1126 req->flags = 0;
1127 req->size = size;
1128 req->gref = 7;
1129 req->offset = 17;
1130 xnb_unit_pvt.txf.req_prod_pvt++;
1131
1132 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1133
1134 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1135
1136 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1137 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1138 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1139 XNB_ASSERT(n_entries == 1);
1140 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1141 /* flags should indicate gref's for source */
1142 XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref);
1143 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset);
1144 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1145 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1146 mtod(pMbuf, vm_offset_t)));
1147 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn ==
1148 virt_to_mfn(mtod(pMbuf, vm_offset_t)));
1149 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1150 safe_m_freem(&pMbuf);
1151 }
1152
1153 /**
1154 * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single
1155 * mbuf cluster
1156 */
1157 static void
1158 xnb_txpkt2gnttab_2req(char *buffer, size_t buflen)
1159 {
1160 int n_entries;
1161 struct xnb_pkt pkt;
1162 struct mbuf *pMbuf;
1163
1164 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1165 xnb_unit_pvt.txf.req_prod_pvt);
1166 req->flags = NETTXF_more_data;
1167 req->size = 1900;
1168 req->gref = 7;
1169 req->offset = 0;
1170 xnb_unit_pvt.txf.req_prod_pvt++;
1171
1172 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1173 xnb_unit_pvt.txf.req_prod_pvt);
1174 req->flags = 0;
1175 req->size = 500;
1176 req->gref = 8;
1177 req->offset = 0;
1178 xnb_unit_pvt.txf.req_prod_pvt++;
1179
1180 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1181
1182 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1183
1184 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1185 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1186 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1187
1188 XNB_ASSERT(n_entries == 2);
1189 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400);
1190 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1191 mtod(pMbuf, vm_offset_t)));
1192
1193 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500);
1194 XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1195 mtod(pMbuf, vm_offset_t) + 1400));
1196 safe_m_freem(&pMbuf);
1197 }
1198
1199 /**
1200 * xnb_txpkt2gnttab on a single request that spans two mbuf clusters
1201 */
1202 static void
1203 xnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen)
1204 {
1205 int n_entries;
1206 struct xnb_pkt pkt;
1207 struct mbuf *pMbuf;
1208 const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1209
1210 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1211 xnb_unit_pvt.txf.req_prod_pvt);
1212 req->flags = 0;
1213 req->size = data_this_transaction;
1214 req->gref = 8;
1215 req->offset = 0;
1216 xnb_unit_pvt.txf.req_prod_pvt++;
1217
1218 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1219 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1220
1221 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1222 XNB_ASSERT(pMbuf != NULL);
1223 if (pMbuf == NULL)
1224 return;
1225
1226 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1227 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1228
1229 if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) {
1230 /* there should be three mbufs and three gnttab entries */
1231 XNB_ASSERT(n_entries == 3);
1232 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES);
1233 XNB_ASSERT(
1234 xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1235 mtod(pMbuf, vm_offset_t)));
1236 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1237
1238 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES);
1239 XNB_ASSERT(
1240 xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1241 mtod(pMbuf->m_next, vm_offset_t)));
1242 XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES);
1243
1244 XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1);
1245 XNB_ASSERT(
1246 xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset(
1247 mtod(pMbuf->m_next, vm_offset_t)));
1248 XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 *
1249 MCLBYTES);
1250 } else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) {
1251 /* there should be two mbufs and two gnttab entries */
1252 XNB_ASSERT(n_entries == 2);
1253 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES);
1254 XNB_ASSERT(
1255 xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1256 mtod(pMbuf, vm_offset_t)));
1257 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1258
1259 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1);
1260 XNB_ASSERT(
1261 xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1262 mtod(pMbuf->m_next, vm_offset_t)));
1263 XNB_ASSERT(
1264 xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES);
1265
1266 } else {
1267 /* should never get here */
1268 XNB_ASSERT(0);
1269 }
1270 m_freem(pMbuf);
1271 }
1272
1273 /**
1274 * xnb_update_mbufc on a short packet that only has one gnttab entry
1275 */
1276 static void
1277 xnb_update_mbufc_short(char *buffer, size_t buflen)
1278 {
1279 const size_t size = MINCLSIZE - 1;
1280 int n_entries;
1281 struct xnb_pkt pkt;
1282 struct mbuf *pMbuf;
1283
1284 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1285 xnb_unit_pvt.txf.req_prod_pvt);
1286 req->flags = 0;
1287 req->size = size;
1288 req->gref = 7;
1289 req->offset = 17;
1290 xnb_unit_pvt.txf.req_prod_pvt++;
1291
1292 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1293
1294 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1295
1296 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1297 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1298 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1299
1300 /* Update grant table's status fields as the hypervisor call would */
1301 xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1302
1303 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1304 XNB_ASSERT(pMbuf->m_len == size);
1305 XNB_ASSERT(pMbuf->m_pkthdr.len == size);
1306 safe_m_freem(&pMbuf);
1307 }
1308
1309 /**
1310 * xnb_update_mbufc on a packet with two requests, that can fit into a single
1311 * mbuf cluster
1312 */
1313 static void
1314 xnb_update_mbufc_2req(char *buffer, size_t buflen)
1315 {
1316 int n_entries;
1317 struct xnb_pkt pkt;
1318 struct mbuf *pMbuf;
1319
1320 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1321 xnb_unit_pvt.txf.req_prod_pvt);
1322 req->flags = NETTXF_more_data;
1323 req->size = 1900;
1324 req->gref = 7;
1325 req->offset = 0;
1326 xnb_unit_pvt.txf.req_prod_pvt++;
1327
1328 req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1329 xnb_unit_pvt.txf.req_prod_pvt);
1330 req->flags = 0;
1331 req->size = 500;
1332 req->gref = 8;
1333 req->offset = 0;
1334 xnb_unit_pvt.txf.req_prod_pvt++;
1335
1336 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1337
1338 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1339
1340 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1341 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1342 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1343
1344 /* Update grant table's status fields as the hypervisor call would */
1345 xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1346 xnb_unit_pvt.gnttab[1].status = GNTST_okay;
1347
1348 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1349 XNB_ASSERT(n_entries == 2);
1350 XNB_ASSERT(pMbuf->m_pkthdr.len == 1900);
1351 XNB_ASSERT(pMbuf->m_len == 1900);
1352
1353 safe_m_freem(&pMbuf);
1354 }
1355
1356 /**
1357 * xnb_update_mbufc on a single request that spans two mbuf clusters
1358 */
1359 static void
1360 xnb_update_mbufc_2cluster(char *buffer, size_t buflen)
1361 {
1362 int i;
1363 int n_entries;
1364 struct xnb_pkt pkt;
1365 struct mbuf *pMbuf;
1366 const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1367
1368 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1369 xnb_unit_pvt.txf.req_prod_pvt);
1370 req->flags = 0;
1371 req->size = data_this_transaction;
1372 req->gref = 8;
1373 req->offset = 0;
1374 xnb_unit_pvt.txf.req_prod_pvt++;
1375
1376 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1377 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1378
1379 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1380 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1381 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1382
1383 /* Update grant table's status fields */
1384 for (i = 0; i < n_entries; i++) {
1385 xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1386 }
1387 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1388
1389 if (n_entries == 3) {
1390 /* there should be three mbufs and three gnttab entries */
1391 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1392 XNB_ASSERT(pMbuf->m_len == MCLBYTES);
1393 XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES);
1394 XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1);
1395 } else if (n_entries == 2) {
1396 /* there should be two mbufs and two gnttab entries */
1397 XNB_ASSERT(n_entries == 2);
1398 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1399 XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES);
1400 XNB_ASSERT(pMbuf->m_next->m_len == 1);
1401 } else {
1402 /* should never get here */
1403 XNB_ASSERT(0);
1404 }
1405 safe_m_freem(&pMbuf);
1406 }
1407
1408 /** xnb_mbufc2pkt on an empty mbufc */
1409 static void
1410 xnb_mbufc2pkt_empty(char *buffer, size_t buflen) {
1411 struct xnb_pkt pkt;
1412 int free_slots = 64;
1413 struct mbuf *mbuf;
1414
1415 mbuf = m_get(M_WAITOK, MT_DATA);
1416 /*
1417 * note: it is illegal to set M_PKTHDR on a mbuf with no data. Doing so
1418 * will cause m_freem to segfault
1419 */
1420 XNB_ASSERT(mbuf->m_len == 0);
1421
1422 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1423 XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1424
1425 safe_m_freem(&mbuf);
1426 }
1427
1428 /** xnb_mbufc2pkt on a short mbufc */
1429 static void
1430 xnb_mbufc2pkt_short(char *buffer, size_t buflen) {
1431 struct xnb_pkt pkt;
1432 size_t size = 128;
1433 int free_slots = 64;
1434 RING_IDX start = 9;
1435 struct mbuf *mbuf;
1436
1437 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1438 mbuf->m_flags |= M_PKTHDR;
1439 mbuf->m_pkthdr.len = size;
1440 mbuf->m_len = size;
1441
1442 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1443 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1444 XNB_ASSERT(pkt.size == size);
1445 XNB_ASSERT(pkt.car_size == size);
1446 XNB_ASSERT(! (pkt.flags &
1447 (NETRXF_more_data | NETRXF_extra_info)));
1448 XNB_ASSERT(pkt.list_len == 1);
1449 XNB_ASSERT(pkt.car == start);
1450
1451 safe_m_freem(&mbuf);
1452 }
1453
1454 /** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */
1455 static void
1456 xnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) {
1457 struct xnb_pkt pkt;
1458 size_t size = MCLBYTES;
1459 int free_slots = 32;
1460 RING_IDX start = 12;
1461 struct mbuf *mbuf;
1462
1463 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1464 mbuf->m_flags |= M_PKTHDR;
1465 mbuf->m_pkthdr.len = size;
1466 mbuf->m_len = size;
1467
1468 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1469 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1470 XNB_ASSERT(pkt.size == size);
1471 XNB_ASSERT(pkt.car_size == size);
1472 XNB_ASSERT(! (pkt.flags &
1473 (NETRXF_more_data | NETRXF_extra_info)));
1474 XNB_ASSERT(pkt.list_len == 1);
1475 XNB_ASSERT(pkt.car == start);
1476
1477 safe_m_freem(&mbuf);
1478 }
1479
1480 /** xnb_mbufc2pkt on a two-mbuf chain with short data regions */
1481 static void
1482 xnb_mbufc2pkt_2short(char *buffer, size_t buflen) {
1483 struct xnb_pkt pkt;
1484 size_t size1 = MHLEN - 5;
1485 size_t size2 = MHLEN - 15;
1486 int free_slots = 32;
1487 RING_IDX start = 14;
1488 struct mbuf *mbufc, *mbufc2;
1489
1490 mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1491 XNB_ASSERT(mbufc != NULL);
1492 if (mbufc == NULL)
1493 return;
1494 mbufc->m_flags |= M_PKTHDR;
1495
1496 mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1497 XNB_ASSERT(mbufc2 != NULL);
1498 if (mbufc2 == NULL) {
1499 safe_m_freem(&mbufc);
1500 return;
1501 }
1502 mbufc2->m_pkthdr.len = size1 + size2;
1503 mbufc2->m_len = size1;
1504
1505 xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots);
1506 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1507 XNB_ASSERT(pkt.size == size1 + size2);
1508 XNB_ASSERT(pkt.car == start);
1509 /*
1510 * The second m_getm may allocate a new mbuf and append
1511 * it to the chain, or it may simply extend the first mbuf.
1512 */
1513 if (mbufc2->m_next != NULL) {
1514 XNB_ASSERT(pkt.car_size == size1);
1515 XNB_ASSERT(pkt.list_len == 1);
1516 XNB_ASSERT(pkt.cdr == start + 1);
1517 }
1518
1519 safe_m_freem(&mbufc2);
1520 }
1521
1522 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */
1523 static void
1524 xnb_mbufc2pkt_long(char *buffer, size_t buflen) {
1525 struct xnb_pkt pkt;
1526 size_t size = 14 * MCLBYTES / 3;
1527 size_t size_remaining;
1528 int free_slots = 15;
1529 RING_IDX start = 3;
1530 struct mbuf *mbufc, *m;
1531
1532 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1533 XNB_ASSERT(mbufc != NULL);
1534 if (mbufc == NULL)
1535 return;
1536 mbufc->m_flags |= M_PKTHDR;
1537
1538 mbufc->m_pkthdr.len = size;
1539 size_remaining = size;
1540 for (m = mbufc; m != NULL; m = m->m_next) {
1541 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1542 size_remaining -= m->m_len;
1543 }
1544
1545 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1546 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1547 XNB_ASSERT(pkt.size == size);
1548 XNB_ASSERT(pkt.car == start);
1549 XNB_ASSERT(pkt.car_size = mbufc->m_len);
1550 /*
1551 * There should be >1 response in the packet, and there is no
1552 * extra info.
1553 */
1554 XNB_ASSERT(! (pkt.flags & NETRXF_extra_info));
1555 XNB_ASSERT(pkt.cdr == pkt.car + 1);
1556
1557 safe_m_freem(&mbufc);
1558 }
1559
1560 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */
1561 static void
1562 xnb_mbufc2pkt_extra(char *buffer, size_t buflen) {
1563 struct xnb_pkt pkt;
1564 size_t size = 14 * MCLBYTES / 3;
1565 size_t size_remaining;
1566 int free_slots = 15;
1567 RING_IDX start = 3;
1568 struct mbuf *mbufc, *m;
1569
1570 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1571 XNB_ASSERT(mbufc != NULL);
1572 if (mbufc == NULL)
1573 return;
1574
1575 mbufc->m_flags |= M_PKTHDR;
1576 mbufc->m_pkthdr.len = size;
1577 mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1578 mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40;
1579 size_remaining = size;
1580 for (m = mbufc; m != NULL; m = m->m_next) {
1581 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1582 size_remaining -= m->m_len;
1583 }
1584
1585 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1586 XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1587 XNB_ASSERT(pkt.size == size);
1588 XNB_ASSERT(pkt.car == start);
1589 XNB_ASSERT(pkt.car_size = mbufc->m_len);
1590 /* There should be >1 response in the packet, there is extra info */
1591 XNB_ASSERT(pkt.flags & NETRXF_extra_info);
1592 XNB_ASSERT(pkt.flags & NETRXF_data_validated);
1593 XNB_ASSERT(pkt.cdr == pkt.car + 2);
1594 XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz);
1595 XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
1596 XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE));
1597
1598 safe_m_freem(&mbufc);
1599 }
1600
1601 /** xnb_mbufc2pkt with insufficient space in the ring */
1602 static void
1603 xnb_mbufc2pkt_nospace(char *buffer, size_t buflen) {
1604 struct xnb_pkt pkt;
1605 size_t size = 14 * MCLBYTES / 3;
1606 size_t size_remaining;
1607 int free_slots = 2;
1608 RING_IDX start = 3;
1609 struct mbuf *mbufc, *m;
1610 int error;
1611
1612 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1613 XNB_ASSERT(mbufc != NULL);
1614 if (mbufc == NULL)
1615 return;
1616 mbufc->m_flags |= M_PKTHDR;
1617
1618 mbufc->m_pkthdr.len = size;
1619 size_remaining = size;
1620 for (m = mbufc; m != NULL; m = m->m_next) {
1621 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1622 size_remaining -= m->m_len;
1623 }
1624
1625 error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1626 XNB_ASSERT(error == EAGAIN);
1627 XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1628
1629 safe_m_freem(&mbufc);
1630 }
1631
1632 /**
1633 * xnb_rxpkt2gnttab on an empty packet. Should return empty gnttab
1634 */
1635 static void
1636 xnb_rxpkt2gnttab_empty(char *buffer, size_t buflen)
1637 {
1638 struct xnb_pkt pkt;
1639 int nr_entries;
1640 int free_slots = 60;
1641 struct mbuf *mbuf;
1642
1643 mbuf = m_get(M_WAITOK, MT_DATA);
1644
1645 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1646 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1647 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1648
1649 XNB_ASSERT(nr_entries == 0);
1650
1651 safe_m_freem(&mbuf);
1652 }
1653
1654 /** xnb_rxpkt2gnttab on a short packet without extra data */
1655 static void
1656 xnb_rxpkt2gnttab_short(char *buffer, size_t buflen) {
1657 struct xnb_pkt pkt;
1658 int nr_entries;
1659 size_t size = 128;
1660 int free_slots = 60;
1661 RING_IDX start = 9;
1662 struct netif_rx_request *req;
1663 struct mbuf *mbuf;
1664
1665 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1666 mbuf->m_flags |= M_PKTHDR;
1667 mbuf->m_pkthdr.len = size;
1668 mbuf->m_len = size;
1669
1670 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1671 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1672 xnb_unit_pvt.txf.req_prod_pvt);
1673 req->gref = 7;
1674
1675 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1676 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1677
1678 XNB_ASSERT(nr_entries == 1);
1679 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1680 /* flags should indicate gref's for dest */
1681 XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref);
1682 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0);
1683 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1684 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset(
1685 mtod(mbuf, vm_offset_t)));
1686 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn ==
1687 virt_to_mfn(mtod(mbuf, vm_offset_t)));
1688 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1689
1690 safe_m_freem(&mbuf);
1691 }
1692
1693 /**
1694 * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai
1695 */
1696 static void
1697 xnb_rxpkt2gnttab_2req(char *buffer, size_t buflen)
1698 {
1699 struct xnb_pkt pkt;
1700 int nr_entries;
1701 int i, num_mbufs;
1702 size_t total_granted_size = 0;
1703 size_t size = MJUMPAGESIZE + 1;
1704 int free_slots = 60;
1705 RING_IDX start = 11;
1706 struct netif_rx_request *req;
1707 struct mbuf *mbuf, *m;
1708
1709 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1710 mbuf->m_flags |= M_PKTHDR;
1711 mbuf->m_pkthdr.len = size;
1712 mbuf->m_len = size;
1713
1714 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1715
1716 for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) {
1717 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1718 xnb_unit_pvt.txf.req_prod_pvt);
1719 req->gref = i;
1720 req->id = 5;
1721 }
1722 num_mbufs = i;
1723
1724 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1725 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1726
1727 XNB_ASSERT(nr_entries >= num_mbufs);
1728 for (i = 0; i < nr_entries; i++) {
1729 int end_offset = xnb_unit_pvt.gnttab[i].len +
1730 xnb_unit_pvt.gnttab[i].dest.offset;
1731 XNB_ASSERT(end_offset <= PAGE_SIZE);
1732 total_granted_size += xnb_unit_pvt.gnttab[i].len;
1733 }
1734 XNB_ASSERT(total_granted_size == size);
1735 }
1736
1737 /**
1738 * xnb_rxpkt2rsp on an empty packet. Shouldn't make any response
1739 */
1740 static void
1741 xnb_rxpkt2rsp_empty(char *buffer, size_t buflen)
1742 {
1743 struct xnb_pkt pkt;
1744 int nr_entries;
1745 int nr_reqs;
1746 int free_slots = 60;
1747 netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb;
1748 netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs;
1749 struct mbuf *mbuf;
1750
1751 mbuf = m_get(M_WAITOK, MT_DATA);
1752
1753 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1754 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1755 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1756
1757 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1758 &xnb_unit_pvt.rxb);
1759 XNB_ASSERT(nr_reqs == 0);
1760 XNB_ASSERT(
1761 memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0);
1762 XNB_ASSERT(
1763 memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0);
1764
1765 safe_m_freem(&mbuf);
1766 }
1767
1768 /**
1769 * xnb_rxpkt2rsp on a short packet with no extras
1770 */
1771 static void
1772 xnb_rxpkt2rsp_short(char *buffer, size_t buflen)
1773 {
1774 struct xnb_pkt pkt;
1775 int nr_entries, nr_reqs;
1776 size_t size = 128;
1777 int free_slots = 60;
1778 RING_IDX start = 5;
1779 struct netif_rx_request *req;
1780 struct netif_rx_response *rsp;
1781 struct mbuf *mbuf;
1782
1783 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1784 mbuf->m_flags |= M_PKTHDR;
1785 mbuf->m_pkthdr.len = size;
1786 mbuf->m_len = size;
1787
1788 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1789 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1790 req->gref = 7;
1791 xnb_unit_pvt.rxb.req_cons = start;
1792 xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1793 xnb_unit_pvt.rxs->req_prod = start + 1;
1794 xnb_unit_pvt.rxs->rsp_prod = start;
1795
1796 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1797 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1798
1799 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1800 &xnb_unit_pvt.rxb);
1801
1802 XNB_ASSERT(nr_reqs == 1);
1803 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
1804 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1805 XNB_ASSERT(rsp->id == req->id);
1806 XNB_ASSERT(rsp->offset == 0);
1807 XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0);
1808 XNB_ASSERT(rsp->status == size);
1809
1810 safe_m_freem(&mbuf);
1811 }
1812
1813 /**
1814 * xnb_rxpkt2rsp with extra data
1815 */
1816 static void
1817 xnb_rxpkt2rsp_extra(char *buffer, size_t buflen)
1818 {
1819 struct xnb_pkt pkt;
1820 int nr_entries, nr_reqs;
1821 size_t size = 14;
1822 int free_slots = 15;
1823 RING_IDX start = 3;
1824 uint16_t id = 49;
1825 uint16_t gref = 65;
1826 uint16_t mss = TCP_MSS - 40;
1827 struct mbuf *mbufc;
1828 struct netif_rx_request *req;
1829 struct netif_rx_response *rsp;
1830 struct netif_extra_info *ext;
1831
1832 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1833 XNB_ASSERT(mbufc != NULL);
1834 if (mbufc == NULL)
1835 return;
1836
1837 mbufc->m_flags |= M_PKTHDR;
1838 mbufc->m_pkthdr.len = size;
1839 mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1840 mbufc->m_pkthdr.tso_segsz = mss;
1841 mbufc->m_len = size;
1842
1843 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1844 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1845 req->id = id;
1846 req->gref = gref;
1847 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1848 req->id = id + 1;
1849 req->gref = gref + 1;
1850 xnb_unit_pvt.rxb.req_cons = start;
1851 xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1852 xnb_unit_pvt.rxs->req_prod = start + 2;
1853 xnb_unit_pvt.rxs->rsp_prod = start;
1854
1855 nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1856 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1857
1858 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1859 &xnb_unit_pvt.rxb);
1860
1861 XNB_ASSERT(nr_reqs == 2);
1862 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1863 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1864 XNB_ASSERT(rsp->id == id);
1865 XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0);
1866 XNB_ASSERT((rsp->flags & NETRXF_extra_info));
1867 XNB_ASSERT((rsp->flags & NETRXF_data_validated));
1868 XNB_ASSERT((rsp->flags & NETRXF_csum_blank));
1869 XNB_ASSERT(rsp->status == size);
1870
1871 ext = (struct netif_extra_info*)
1872 RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1873 XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO);
1874 XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE));
1875 XNB_ASSERT(ext->u.gso.size == mss);
1876 XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO);
1877
1878 safe_m_freem(&mbufc);
1879 }
1880
1881 /**
1882 * xnb_rxpkt2rsp on a packet with more than a pages's worth of data. It should
1883 * generate two response slot
1884 */
1885 static void
1886 xnb_rxpkt2rsp_2slots(char *buffer, size_t buflen)
1887 {
1888 struct xnb_pkt pkt;
1889 int nr_entries, nr_reqs;
1890 size_t size = PAGE_SIZE + 100;
1891 int free_slots = 3;
1892 uint16_t id1 = 17;
1893 uint16_t id2 = 37;
1894 uint16_t gref1 = 24;
1895 uint16_t gref2 = 34;
1896 RING_IDX start = 15;
1897 struct netif_rx_request *req;
1898 struct netif_rx_response *rsp;
1899 struct mbuf *mbuf;
1900
1901 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1902 mbuf->m_flags |= M_PKTHDR;
1903 mbuf->m_pkthdr.len = size;
1904 if (mbuf->m_next != NULL) {
1905 size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size);
1906 mbuf->m_len = first_len;
1907 mbuf->m_next->m_len = size - first_len;
1908
1909 } else {
1910 mbuf->m_len = size;
1911 }
1912
1913 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1914 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1915 req->gref = gref1;
1916 req->id = id1;
1917 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1918 req->gref = gref2;
1919 req->id = id2;
1920 xnb_unit_pvt.rxb.req_cons = start;
1921 xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1922 xnb_unit_pvt.rxs->req_prod = start + 2;
1923 xnb_unit_pvt.rxs->rsp_prod = start;
1924
1925 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1926 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1927
1928 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1929 &xnb_unit_pvt.rxb);
1930
1931 XNB_ASSERT(nr_reqs == 2);
1932 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1933 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1934 XNB_ASSERT(rsp->id == id1);
1935 XNB_ASSERT(rsp->offset == 0);
1936 XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1937 XNB_ASSERT(rsp->flags & NETRXF_more_data);
1938 XNB_ASSERT(rsp->status == PAGE_SIZE);
1939
1940 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1941 XNB_ASSERT(rsp->id == id2);
1942 XNB_ASSERT(rsp->offset == 0);
1943 XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1944 XNB_ASSERT(! (rsp->flags & NETRXF_more_data));
1945 XNB_ASSERT(rsp->status == size - PAGE_SIZE);
1946
1947 safe_m_freem(&mbuf);
1948 }
1949
1950 /** xnb_rxpkt2rsp on a grant table with two sub-page entries */
1951 static void
1952 xnb_rxpkt2rsp_2short(char *buffer, size_t buflen) {
1953 struct xnb_pkt pkt;
1954 int nr_reqs, nr_entries;
1955 size_t size1 = MHLEN - 5;
1956 size_t size2 = MHLEN - 15;
1957 int free_slots = 32;
1958 RING_IDX start = 14;
1959 uint16_t id = 47;
1960 uint16_t gref = 54;
1961 struct netif_rx_request *req;
1962 struct netif_rx_response *rsp;
1963 struct mbuf *mbufc;
1964
1965 mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1966 XNB_ASSERT(mbufc != NULL);
1967 if (mbufc == NULL)
1968 return;
1969 mbufc->m_flags |= M_PKTHDR;
1970
1971 m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1972 XNB_ASSERT(mbufc->m_next != NULL);
1973 mbufc->m_pkthdr.len = size1 + size2;
1974 mbufc->m_len = size1;
1975 mbufc->m_next->m_len = size2;
1976
1977 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1978
1979 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1980 req->gref = gref;
1981 req->id = id;
1982 xnb_unit_pvt.rxb.req_cons = start;
1983 xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1984 xnb_unit_pvt.rxs->req_prod = start + 1;
1985 xnb_unit_pvt.rxs->rsp_prod = start;
1986
1987 nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1988 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1989
1990 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1991 &xnb_unit_pvt.rxb);
1992
1993 XNB_ASSERT(nr_entries == 2);
1994 XNB_ASSERT(nr_reqs == 1);
1995 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1996 XNB_ASSERT(rsp->id == id);
1997 XNB_ASSERT(rsp->status == size1 + size2);
1998 XNB_ASSERT(rsp->offset == 0);
1999 XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info)));
2000
2001 safe_m_freem(&mbufc);
2002 }
2003
2004 /**
2005 * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error
2006 * Note: this test will result in an error message being printed to the console
2007 * such as:
2008 * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status
2009 */
2010 static void
2011 xnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen)
2012 {
2013 struct xnb_pkt pkt;
2014 int nr_entries, nr_reqs;
2015 int id = 7;
2016 int gref = 42;
2017 uint16_t canary = 6859;
2018 size_t size = 7 * MCLBYTES;
2019 int free_slots = 9;
2020 RING_IDX start = 2;
2021 struct netif_rx_request *req;
2022 struct netif_rx_response *rsp;
2023 struct mbuf *mbuf;
2024
2025 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
2026 mbuf->m_flags |= M_PKTHDR;
2027 mbuf->m_pkthdr.len = size;
2028 mbuf->m_len = size;
2029
2030 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
2031 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
2032 req->gref = gref;
2033 req->id = id;
2034 xnb_unit_pvt.rxb.req_cons = start;
2035 xnb_unit_pvt.rxb.rsp_prod_pvt = start;
2036 xnb_unit_pvt.rxs->req_prod = start + 1;
2037 xnb_unit_pvt.rxs->rsp_prod = start;
2038 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2039 req->gref = canary;
2040 req->id = canary;
2041
2042 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
2043 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
2044 /* Inject the error*/
2045 xnb_unit_pvt.gnttab[2].status = GNTST_general_error;
2046
2047 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
2048 &xnb_unit_pvt.rxb);
2049
2050 XNB_ASSERT(nr_reqs == 1);
2051 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
2052 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
2053 XNB_ASSERT(rsp->id == id);
2054 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
2055 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2056 XNB_ASSERT(req->gref == canary);
2057 XNB_ASSERT(req->id == canary);
2058
2059 safe_m_freem(&mbuf);
2060 }
2061
2062 #if defined(INET) || defined(INET6)
2063 /**
2064 * xnb_add_mbuf_cksum on an ARP request packet
2065 */
2066 static void
2067 xnb_add_mbuf_cksum_arp(char *buffer, size_t buflen)
2068 {
2069 const size_t pkt_len = sizeof(struct ether_header) +
2070 sizeof(struct ether_arp);
2071 struct mbuf *mbufc;
2072 struct ether_header *eh;
2073 struct ether_arp *ep;
2074 unsigned char pkt_orig[pkt_len];
2075
2076 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2077 /* Fill in an example arp request */
2078 eh = mtod(mbufc, struct ether_header*);
2079 eh->ether_dhost[0] = 0xff;
2080 eh->ether_dhost[1] = 0xff;
2081 eh->ether_dhost[2] = 0xff;
2082 eh->ether_dhost[3] = 0xff;
2083 eh->ether_dhost[4] = 0xff;
2084 eh->ether_dhost[5] = 0xff;
2085 eh->ether_shost[0] = 0x00;
2086 eh->ether_shost[1] = 0x15;
2087 eh->ether_shost[2] = 0x17;
2088 eh->ether_shost[3] = 0xe9;
2089 eh->ether_shost[4] = 0x30;
2090 eh->ether_shost[5] = 0x68;
2091 eh->ether_type = htons(ETHERTYPE_ARP);
2092 ep = (struct ether_arp*)(eh + 1);
2093 ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
2094 ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
2095 ep->ea_hdr.ar_hln = 6;
2096 ep->ea_hdr.ar_pln = 4;
2097 ep->ea_hdr.ar_op = htons(ARPOP_REQUEST);
2098 ep->arp_sha[0] = 0x00;
2099 ep->arp_sha[1] = 0x15;
2100 ep->arp_sha[2] = 0x17;
2101 ep->arp_sha[3] = 0xe9;
2102 ep->arp_sha[4] = 0x30;
2103 ep->arp_sha[5] = 0x68;
2104 ep->arp_spa[0] = 0xc0;
2105 ep->arp_spa[1] = 0xa8;
2106 ep->arp_spa[2] = 0x0a;
2107 ep->arp_spa[3] = 0x04;
2108 bzero(&(ep->arp_tha), ETHER_ADDR_LEN);
2109 ep->arp_tpa[0] = 0xc0;
2110 ep->arp_tpa[1] = 0xa8;
2111 ep->arp_tpa[2] = 0x0a;
2112 ep->arp_tpa[3] = 0x06;
2113
2114 /* fill in the length field */
2115 mbufc->m_len = pkt_len;
2116 mbufc->m_pkthdr.len = pkt_len;
2117 /* indicate that the netfront uses hw-assisted checksums */
2118 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
2119 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2120
2121 /* Make a backup copy of the packet */
2122 bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len);
2123
2124 /* Function under test */
2125 xnb_add_mbuf_cksum(mbufc);
2126
2127 /* Verify that the packet's data did not change */
2128 XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0);
2129 m_freem(mbufc);
2130 }
2131
2132 /**
2133 * Helper function that populates the ethernet header and IP header used by
2134 * some of the xnb_add_mbuf_cksum unit tests. m must already be allocated
2135 * and must be large enough
2136 */
2137 static void
2138 xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id,
2139 uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum)
2140 {
2141 struct ether_header *eh;
2142 struct ip *iph;
2143
2144 eh = mtod(m, struct ether_header*);
2145 eh->ether_dhost[0] = 0x00;
2146 eh->ether_dhost[1] = 0x16;
2147 eh->ether_dhost[2] = 0x3e;
2148 eh->ether_dhost[3] = 0x23;
2149 eh->ether_dhost[4] = 0x50;
2150 eh->ether_dhost[5] = 0x0b;
2151 eh->ether_shost[0] = 0x00;
2152 eh->ether_shost[1] = 0x16;
2153 eh->ether_shost[2] = 0x30;
2154 eh->ether_shost[3] = 0x00;
2155 eh->ether_shost[4] = 0x00;
2156 eh->ether_shost[5] = 0x00;
2157 eh->ether_type = htons(ETHERTYPE_IP);
2158 iph = (struct ip*)(eh + 1);
2159 iph->ip_hl = 0x5; /* 5 dwords == 20 bytes */
2160 iph->ip_v = 4; /* IP v4 */
2161 iph->ip_tos = 0;
2162 iph->ip_len = htons(ip_len);
2163 iph->ip_id = htons(ip_id);
2164 iph->ip_off = htons(ip_off);
2165 iph->ip_ttl = 64;
2166 iph->ip_p = ip_p;
2167 iph->ip_sum = htons(ip_sum);
2168 iph->ip_src.s_addr = htonl(0xc0a80a04);
2169 iph->ip_dst.s_addr = htonl(0xc0a80a05);
2170 }
2171
2172 /**
2173 * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual
2174 * ICMP packet
2175 */
2176 static void
2177 xnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen)
2178 {
2179 const size_t icmp_len = 64; /* set by ping(1) */
2180 const size_t pkt_len = sizeof(struct ether_header) +
2181 sizeof(struct ip) + icmp_len;
2182 struct mbuf *mbufc;
2183 struct ether_header *eh;
2184 struct ip *iph;
2185 struct icmp *icmph;
2186 unsigned char pkt_orig[icmp_len];
2187 uint32_t *tv_field;
2188 uint8_t *data_payload;
2189 int i;
2190 const uint16_t ICMP_CSUM = 0xaed7;
2191 const uint16_t IP_CSUM = 0xe533;
2192
2193 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2194 /* Fill in an example ICMP ping request */
2195 eh = mtod(mbufc, struct ether_header*);
2196 xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0);
2197 iph = (struct ip*)(eh + 1);
2198 icmph = (struct icmp*)(iph + 1);
2199 icmph->icmp_type = ICMP_ECHO;
2200 icmph->icmp_code = 0;
2201 icmph->icmp_cksum = htons(ICMP_CSUM);
2202 icmph->icmp_id = htons(31492);
2203 icmph->icmp_seq = htons(0);
2204 /*
2205 * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq.
2206 * For this test, we will set the bytes individually for portability.
2207 */
2208 tv_field = (uint32_t*)(&(icmph->icmp_hun));
2209 tv_field[0] = 0x4f02cfac;
2210 tv_field[1] = 0x0007c46a;
2211 /*
2212 * Remainder of packet is an incrmenting 8 bit integer, starting with 8
2213 */
2214 data_payload = (uint8_t*)(&tv_field[2]);
2215 for (i = 8; i < 37; i++) {
2216 *data_payload++ = i;
2217 }
2218
2219 /* fill in the length field */
2220 mbufc->m_len = pkt_len;
2221 mbufc->m_pkthdr.len = pkt_len;
2222 /* indicate that the netfront uses hw-assisted checksums */
2223 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
2224 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2225
2226 bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len);
2227 /* Function under test */
2228 xnb_add_mbuf_cksum(mbufc);
2229
2230 /* Check the IP checksum */
2231 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2232
2233 /* Check that the ICMP packet did not change */
2234 XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len));
2235 m_freem(mbufc);
2236 }
2237
2238 /**
2239 * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual
2240 * UDP packet
2241 */
2242 static void
2243 xnb_add_mbuf_cksum_udp(char *buffer, size_t buflen)
2244 {
2245 const size_t udp_len = 16;
2246 const size_t pkt_len = sizeof(struct ether_header) +
2247 sizeof(struct ip) + udp_len;
2248 struct mbuf *mbufc;
2249 struct ether_header *eh;
2250 struct ip *iph;
2251 struct udphdr *udp;
2252 uint8_t *data_payload;
2253 const uint16_t IP_CSUM = 0xe56b;
2254 const uint16_t UDP_CSUM = 0xdde2;
2255
2256 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2257 /* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */
2258 eh = mtod(mbufc, struct ether_header*);
2259 xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad);
2260 iph = (struct ip*)(eh + 1);
2261 udp = (struct udphdr*)(iph + 1);
2262 udp->uh_sport = htons(0x51ae);
2263 udp->uh_dport = htons(0x08ae);
2264 udp->uh_ulen = htons(udp_len);
2265 udp->uh_sum = htons(0xbaad); /* xnb_add_mbuf_cksum will fill this in */
2266 data_payload = (uint8_t*)(udp + 1);
2267 data_payload[0] = 'F';
2268 data_payload[1] = 'r';
2269 data_payload[2] = 'e';
2270 data_payload[3] = 'e';
2271 data_payload[4] = 'B';
2272 data_payload[5] = 'S';
2273 data_payload[6] = 'D';
2274 data_payload[7] = '\n';
2275
2276 /* fill in the length field */
2277 mbufc->m_len = pkt_len;
2278 mbufc->m_pkthdr.len = pkt_len;
2279 /* indicate that the netfront uses hw-assisted checksums */
2280 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
2281 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2282
2283 /* Function under test */
2284 xnb_add_mbuf_cksum(mbufc);
2285
2286 /* Check the checksums */
2287 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2288 XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM));
2289
2290 m_freem(mbufc);
2291 }
2292
2293 /**
2294 * Helper function that populates a TCP packet used by all of the
2295 * xnb_add_mbuf_cksum tcp unit tests. m must already be allocated and must be
2296 * large enough
2297 */
2298 static void
2299 xnb_fill_tcp(struct mbuf *m)
2300 {
2301 struct ether_header *eh;
2302 struct ip *iph;
2303 struct tcphdr *tcp;
2304 uint32_t *options;
2305 uint8_t *data_payload;
2306
2307 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2308 eh = mtod(m, struct ether_header*);
2309 xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0);
2310 iph = (struct ip*)(eh + 1);
2311 tcp = (struct tcphdr*)(iph + 1);
2312 tcp->th_sport = htons(0x9cd9);
2313 tcp->th_dport = htons(2222);
2314 tcp->th_seq = htonl(0x00f72b10);
2315 tcp->th_ack = htonl(0x7f37ba6c);
2316 tcp->th_x2 = 0;
2317 tcp->th_off = 8;
2318 tcp->th_flags = 0x18;
2319 tcp->th_win = htons(0x410);
2320 /* th_sum is incorrect; will be inserted by function under test */
2321 tcp->th_sum = htons(0xbaad);
2322 tcp->th_urp = htons(0);
2323 /*
2324 * The following 12 bytes of options encode:
2325 * [nop, nop, TS val 33247 ecr 3457687679]
2326 */
2327 options = (uint32_t*)(tcp + 1);
2328 options[0] = htonl(0x0101080a);
2329 options[1] = htonl(0x000081df);
2330 options[2] = htonl(0xce18207f);
2331 data_payload = (uint8_t*)(&options[3]);
2332 data_payload[0] = 'F';
2333 data_payload[1] = 'r';
2334 data_payload[2] = 'e';
2335 data_payload[3] = 'e';
2336 data_payload[4] = 'B';
2337 data_payload[5] = 'S';
2338 data_payload[6] = 'D';
2339 data_payload[7] = '\n';
2340 }
2341
2342 /**
2343 * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP
2344 * packet
2345 */
2346 static void
2347 xnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen)
2348 {
2349 const size_t payload_len = 8;
2350 const size_t tcp_options_len = 12;
2351 const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2352 sizeof(struct tcphdr) + tcp_options_len + payload_len;
2353 struct mbuf *mbufc;
2354 struct ether_header *eh;
2355 struct ip *iph;
2356 struct tcphdr *tcp;
2357 const uint16_t IP_CSUM = 0xa55a;
2358 const uint16_t TCP_CSUM = 0x2f64;
2359
2360 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2361 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2362 xnb_fill_tcp(mbufc);
2363 eh = mtod(mbufc, struct ether_header*);
2364 iph = (struct ip*)(eh + 1);
2365 tcp = (struct tcphdr*)(iph + 1);
2366
2367 /* fill in the length field */
2368 mbufc->m_len = pkt_len;
2369 mbufc->m_pkthdr.len = pkt_len;
2370 /* indicate that the netfront uses hw-assisted checksums */
2371 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
2372 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2373
2374 /* Function under test */
2375 xnb_add_mbuf_cksum(mbufc);
2376
2377 /* Check the checksums */
2378 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2379 XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2380
2381 m_freem(mbufc);
2382 }
2383
2384 /**
2385 * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums
2386 */
2387 static void
2388 xnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen)
2389 {
2390 const size_t payload_len = 8;
2391 const size_t tcp_options_len = 12;
2392 const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2393 sizeof(struct tcphdr) + tcp_options_len + payload_len;
2394 struct mbuf *mbufc;
2395 struct ether_header *eh;
2396 struct ip *iph;
2397 struct tcphdr *tcp;
2398 /* Use deliberately bad checksums, and verify that they don't get */
2399 /* corrected by xnb_add_mbuf_cksum */
2400 const uint16_t IP_CSUM = 0xdead;
2401 const uint16_t TCP_CSUM = 0xbeef;
2402
2403 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2404 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2405 xnb_fill_tcp(mbufc);
2406 eh = mtod(mbufc, struct ether_header*);
2407 iph = (struct ip*)(eh + 1);
2408 iph->ip_sum = htons(IP_CSUM);
2409 tcp = (struct tcphdr*)(iph + 1);
2410 tcp->th_sum = htons(TCP_CSUM);
2411
2412 /* fill in the length field */
2413 mbufc->m_len = pkt_len;
2414 mbufc->m_pkthdr.len = pkt_len;
2415 /* indicate that the netfront does not use hw-assisted checksums */
2416 mbufc->m_pkthdr.csum_flags = 0;
2417
2418 /* Function under test */
2419 xnb_add_mbuf_cksum(mbufc);
2420
2421 /* Check that the checksums didn't change */
2422 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2423 XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2424
2425 m_freem(mbufc);
2426 }
2427 #endif /* INET || INET6 */
2428
2429 /**
2430 * sscanf on unsigned chars
2431 */
2432 static void
2433 xnb_sscanf_hhu(char *buffer, size_t buflen)
2434 {
2435 const char mystr[] = "137";
2436 uint8_t dest[12];
2437 int i;
2438
2439 for (i = 0; i < 12; i++)
2440 dest[i] = 'X';
2441
2442 XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1);
2443 for (i = 0; i < 12; i++)
2444 XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X'));
2445 }
2446
2447 /**
2448 * sscanf on signed chars
2449 */
2450 static void
2451 xnb_sscanf_hhd(char *buffer, size_t buflen)
2452 {
2453 const char mystr[] = "-27";
2454 int8_t dest[12];
2455 int i;
2456
2457 for (i = 0; i < 12; i++)
2458 dest[i] = 'X';
2459
2460 XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1);
2461 for (i = 0; i < 12; i++)
2462 XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X'));
2463 }
2464
2465 /**
2466 * sscanf on signed long longs
2467 */
2468 static void
2469 xnb_sscanf_lld(char *buffer, size_t buflen)
2470 {
2471 const char mystr[] = "-123456789012345"; /* about -2**47 */
2472 long long dest[3];
2473 int i;
2474
2475 for (i = 0; i < 3; i++)
2476 dest[i] = (long long)0xdeadbeefdeadbeef;
2477
2478 XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1);
2479 for (i = 0; i < 3; i++)
2480 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2481 -123456789012345));
2482 }
2483
2484 /**
2485 * sscanf on unsigned long longs
2486 */
2487 static void
2488 xnb_sscanf_llu(char *buffer, size_t buflen)
2489 {
2490 const char mystr[] = "12802747070103273189";
2491 unsigned long long dest[3];
2492 int i;
2493
2494 for (i = 0; i < 3; i++)
2495 dest[i] = (long long)0xdeadbeefdeadbeef;
2496
2497 XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1);
2498 for (i = 0; i < 3; i++)
2499 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2500 12802747070103273189ull));
2501 }
2502
2503 /**
2504 * sscanf on unsigned short short n's
2505 */
2506 static void
2507 xnb_sscanf_hhn(char *buffer, size_t buflen)
2508 {
2509 const char mystr[] =
2510 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2511 "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2512 "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f";
2513 unsigned char dest[12];
2514 int i;
2515
2516 for (i = 0; i < 12; i++)
2517 dest[i] = (unsigned char)'X';
2518
2519 XNB_ASSERT(sscanf(mystr,
2520 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2521 "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2522 "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0);
2523 for (i = 0; i < 12; i++)
2524 XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X'));
2525 }
Cache object: 1258fc616e52177d5ce06687971d9c46
|