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 int num_consumed; 652 struct xnb_pkt pkt; 653 netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb; 654 netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs; 655 pkt.list_len = 0; 656 657 /* must call xnb_ring2pkt just to intialize pkt */ 658 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 659 xnb_unit_pvt.txb.req_cons); 660 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 661 XNB_ASSERT( 662 memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0); 663 XNB_ASSERT( 664 memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0); 665 } 666 667 /** 668 * xnb_txpkt2rsp responding to one request 669 */ 670 static void 671 xnb_txpkt2rsp_1req(char *buffer, size_t buflen) 672 { 673 uint16_t num_consumed; 674 struct xnb_pkt pkt; 675 struct netif_tx_request *req; 676 struct netif_tx_response *rsp; 677 678 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 679 xnb_unit_pvt.txf.req_prod_pvt); 680 req->size = 1000; 681 req->flags = 0; 682 xnb_unit_pvt.txf.req_prod_pvt++; 683 684 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 685 686 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 687 xnb_unit_pvt.txb.req_cons); 688 xnb_unit_pvt.txb.req_cons += num_consumed; 689 690 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 691 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 692 693 XNB_ASSERT( 694 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 695 XNB_ASSERT(rsp->id == req->id); 696 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 697 }; 698 699 /** 700 * xnb_txpkt2rsp responding to 1 data request and 1 extra info 701 */ 702 static void 703 xnb_txpkt2rsp_extra(char *buffer, size_t buflen) 704 { 705 uint16_t num_consumed; 706 struct xnb_pkt pkt; 707 struct netif_tx_request *req; 708 netif_extra_info_t *ext; 709 struct netif_tx_response *rsp; 710 711 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 712 xnb_unit_pvt.txf.req_prod_pvt); 713 req->size = 1000; 714 req->flags = NETTXF_extra_info; 715 req->id = 69; 716 xnb_unit_pvt.txf.req_prod_pvt++; 717 718 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 719 xnb_unit_pvt.txf.req_prod_pvt); 720 ext->type = XEN_NETIF_EXTRA_TYPE_GSO; 721 ext->flags = 0; 722 xnb_unit_pvt.txf.req_prod_pvt++; 723 724 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 725 726 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 727 xnb_unit_pvt.txb.req_cons); 728 xnb_unit_pvt.txb.req_cons += num_consumed; 729 730 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 731 732 XNB_ASSERT( 733 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 734 735 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 736 XNB_ASSERT(rsp->id == req->id); 737 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 738 739 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 740 xnb_unit_pvt.txf.rsp_cons + 1); 741 XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 742 }; 743 744 /** 745 * xnb_pkg2rsp responding to 3 data requests and 1 extra info 746 */ 747 static void 748 xnb_txpkt2rsp_long(char *buffer, size_t buflen) 749 { 750 uint16_t num_consumed; 751 struct xnb_pkt pkt; 752 struct netif_tx_request *req; 753 netif_extra_info_t *ext; 754 struct netif_tx_response *rsp; 755 756 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 757 xnb_unit_pvt.txf.req_prod_pvt); 758 req->size = 1000; 759 req->flags = NETTXF_extra_info | NETTXF_more_data; 760 req->id = 254; 761 xnb_unit_pvt.txf.req_prod_pvt++; 762 763 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 764 xnb_unit_pvt.txf.req_prod_pvt); 765 ext->type = XEN_NETIF_EXTRA_TYPE_GSO; 766 ext->flags = 0; 767 xnb_unit_pvt.txf.req_prod_pvt++; 768 769 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 770 xnb_unit_pvt.txf.req_prod_pvt); 771 req->size = 300; 772 req->flags = NETTXF_more_data; 773 req->id = 1034; 774 xnb_unit_pvt.txf.req_prod_pvt++; 775 776 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 777 xnb_unit_pvt.txf.req_prod_pvt); 778 req->size = 400; 779 req->flags = 0; 780 req->id = 34; 781 xnb_unit_pvt.txf.req_prod_pvt++; 782 783 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 784 785 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 786 xnb_unit_pvt.txb.req_cons); 787 xnb_unit_pvt.txb.req_cons += num_consumed; 788 789 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 790 791 XNB_ASSERT( 792 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 793 794 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 795 XNB_ASSERT(rsp->id == 796 RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id); 797 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 798 799 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 800 xnb_unit_pvt.txf.rsp_cons + 1); 801 XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 802 803 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 804 xnb_unit_pvt.txf.rsp_cons + 2); 805 XNB_ASSERT(rsp->id == 806 RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id); 807 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 808 809 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 810 xnb_unit_pvt.txf.rsp_cons + 3); 811 XNB_ASSERT(rsp->id == 812 RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id); 813 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 814 } 815 816 /** 817 * xnb_txpkt2rsp responding to an invalid packet. 818 * Note: this test will result in an error message being printed to the console 819 * such as: 820 * xnb(xnb_ring2pkt:1306): Unknown extra info type 255. Discarding packet 821 */ 822 static void 823 xnb_txpkt2rsp_invalid(char *buffer, size_t buflen) 824 { 825 uint16_t num_consumed; 826 struct xnb_pkt pkt; 827 struct netif_tx_request *req; 828 netif_extra_info_t *ext; 829 struct netif_tx_response *rsp; 830 831 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 832 xnb_unit_pvt.txf.req_prod_pvt); 833 req->size = 1000; 834 req->flags = NETTXF_extra_info; 835 req->id = 69; 836 xnb_unit_pvt.txf.req_prod_pvt++; 837 838 ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 839 xnb_unit_pvt.txf.req_prod_pvt); 840 ext->type = 0xFF; /* Invalid extra type */ 841 ext->flags = 0; 842 xnb_unit_pvt.txf.req_prod_pvt++; 843 844 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 845 846 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 847 xnb_unit_pvt.txb.req_cons); 848 xnb_unit_pvt.txb.req_cons += num_consumed; 849 XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 850 851 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 852 853 XNB_ASSERT( 854 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 855 856 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 857 XNB_ASSERT(rsp->id == req->id); 858 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 859 860 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 861 xnb_unit_pvt.txf.rsp_cons + 1); 862 XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 863 }; 864 865 /** 866 * xnb_txpkt2rsp responding to one request which caused an error 867 */ 868 static void 869 xnb_txpkt2rsp_error(char *buffer, size_t buflen) 870 { 871 uint16_t num_consumed; 872 struct xnb_pkt pkt; 873 struct netif_tx_request *req; 874 struct netif_tx_response *rsp; 875 876 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 877 xnb_unit_pvt.txf.req_prod_pvt); 878 req->size = 1000; 879 req->flags = 0; 880 xnb_unit_pvt.txf.req_prod_pvt++; 881 882 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 883 884 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 885 xnb_unit_pvt.txb.req_cons); 886 xnb_unit_pvt.txb.req_cons += num_consumed; 887 888 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1); 889 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 890 891 XNB_ASSERT( 892 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 893 XNB_ASSERT(rsp->id == req->id); 894 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 895 }; 896 897 /** 898 * xnb_txpkt2rsp's responses wrap around the end of the ring 899 */ 900 static void 901 xnb_txpkt2rsp_wraps(char *buffer, size_t buflen) 902 { 903 struct xnb_pkt pkt; 904 int num_consumed; 905 struct netif_tx_request *req; 906 struct netif_tx_response *rsp; 907 unsigned int rsize; 908 909 /* 910 * Manually tweak the ring indices to create a ring with no responses 911 * and the next request slot at position 2 from the end 912 */ 913 rsize = RING_SIZE(&xnb_unit_pvt.txf); 914 xnb_unit_pvt.txf.req_prod_pvt = rsize - 2; 915 xnb_unit_pvt.txf.rsp_cons = rsize - 2; 916 xnb_unit_pvt.txs->req_prod = rsize - 2; 917 xnb_unit_pvt.txs->req_event = rsize - 1; 918 xnb_unit_pvt.txs->rsp_prod = rsize - 2; 919 xnb_unit_pvt.txs->rsp_event = rsize - 1; 920 xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2; 921 xnb_unit_pvt.txb.req_cons = rsize - 2; 922 923 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 924 xnb_unit_pvt.txf.req_prod_pvt); 925 req->flags = NETTXF_more_data; 926 req->size = 550; 927 req->id = 1; 928 xnb_unit_pvt.txf.req_prod_pvt++; 929 930 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 931 xnb_unit_pvt.txf.req_prod_pvt); 932 req->flags = NETTXF_more_data; 933 req->size = 100; 934 req->id = 2; 935 xnb_unit_pvt.txf.req_prod_pvt++; 936 937 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 938 xnb_unit_pvt.txf.req_prod_pvt); 939 req->flags = 0; 940 req->size = 50; 941 req->id = 3; 942 xnb_unit_pvt.txf.req_prod_pvt++; 943 944 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 945 946 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 947 xnb_unit_pvt.txb.req_cons); 948 949 xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 950 951 XNB_ASSERT( 952 xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 953 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 954 xnb_unit_pvt.txf.rsp_cons + 2); 955 XNB_ASSERT(rsp->id == req->id); 956 XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 957 } 958 959 /** 960 * Helper function used to setup pkt2mbufc tests 961 * \param size size in bytes of the single request to push to the ring 962 * \param flags optional flags to put in the netif request 963 * \param[out] pkt the returned packet object 964 * \return number of requests consumed from the ring 965 */ 966 static int 967 xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags) 968 { 969 struct netif_tx_request *req; 970 971 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 972 xnb_unit_pvt.txf.req_prod_pvt); 973 req->flags = flags; 974 req->size = size; 975 xnb_unit_pvt.txf.req_prod_pvt++; 976 977 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 978 979 return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb, 980 xnb_unit_pvt.txb.req_cons); 981 } 982 983 /** 984 * xnb_pkt2mbufc on an empty packet 985 */ 986 static void 987 xnb_pkt2mbufc_empty(char *buffer, size_t buflen) 988 { 989 int num_consumed; 990 struct xnb_pkt pkt; 991 struct mbuf *pMbuf; 992 pkt.list_len = 0; 993 994 /* must call xnb_ring2pkt just to intialize pkt */ 995 num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 996 xnb_unit_pvt.txb.req_cons); 997 pkt.size = 0; 998 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 999 safe_m_freem(&pMbuf); 1000 } 1001 1002 /** 1003 * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer 1004 */ 1005 static void 1006 xnb_pkt2mbufc_short(char *buffer, size_t buflen) 1007 { 1008 const size_t size = MINCLSIZE - 1; 1009 struct xnb_pkt pkt; 1010 struct mbuf *pMbuf; 1011 1012 xnb_get1pkt(&pkt, size, 0); 1013 1014 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1015 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1016 safe_m_freem(&pMbuf); 1017 } 1018 1019 /** 1020 * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron 1021 */ 1022 static void 1023 xnb_pkt2mbufc_csum(char *buffer, size_t buflen) 1024 { 1025 const size_t size = MINCLSIZE - 1; 1026 struct xnb_pkt pkt; 1027 struct mbuf *pMbuf; 1028 1029 xnb_get1pkt(&pkt, size, NETTXF_data_validated); 1030 1031 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1032 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1033 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED); 1034 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID); 1035 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID); 1036 XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR); 1037 safe_m_freem(&pMbuf); 1038 } 1039 1040 /** 1041 * xnb_pkt2mbufc on packet that can fit in one cluster 1042 */ 1043 static void 1044 xnb_pkt2mbufc_1cluster(char *buffer, size_t buflen) 1045 { 1046 const size_t size = MINCLSIZE; 1047 struct xnb_pkt pkt; 1048 struct mbuf *pMbuf; 1049 1050 xnb_get1pkt(&pkt, size, 0); 1051 1052 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1053 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1054 safe_m_freem(&pMbuf); 1055 } 1056 1057 /** 1058 * xnb_pkt2mbufc on packet that cannot fit in one regular cluster 1059 */ 1060 static void 1061 xnb_pkt2mbufc_largecluster(char *buffer, size_t buflen) 1062 { 1063 const size_t size = MCLBYTES + 1; 1064 struct xnb_pkt pkt; 1065 struct mbuf *pMbuf; 1066 1067 xnb_get1pkt(&pkt, size, 0); 1068 1069 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1070 XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1071 safe_m_freem(&pMbuf); 1072 } 1073 1074 /** 1075 * xnb_pkt2mbufc on packet that cannot fit in one clusters 1076 */ 1077 static void 1078 xnb_pkt2mbufc_2cluster(char *buffer, size_t buflen) 1079 { 1080 const size_t size = 2 * MCLBYTES + 1; 1081 size_t space = 0; 1082 struct xnb_pkt pkt; 1083 struct mbuf *pMbuf; 1084 struct mbuf *m; 1085 1086 xnb_get1pkt(&pkt, size, 0); 1087 1088 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1089 1090 for (m = pMbuf; m != NULL; m = m->m_next) { 1091 space += M_TRAILINGSPACE(m); 1092 } 1093 XNB_ASSERT(space >= size); 1094 safe_m_freem(&pMbuf); 1095 } 1096 1097 /** 1098 * xnb_txpkt2gnttab on an empty packet. Should return empty gnttab 1099 */ 1100 static void 1101 xnb_txpkt2gnttab_empty(char *buffer, size_t buflen) 1102 { 1103 int n_entries; 1104 struct xnb_pkt pkt; 1105 struct mbuf *pMbuf; 1106 pkt.list_len = 0; 1107 1108 /* must call xnb_ring2pkt just to intialize pkt */ 1109 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1110 pkt.size = 0; 1111 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1112 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1113 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1114 XNB_ASSERT(n_entries == 0); 1115 safe_m_freem(&pMbuf); 1116 } 1117 1118 /** 1119 * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer 1120 * and has one request 1121 */ 1122 static void 1123 xnb_txpkt2gnttab_short(char *buffer, size_t buflen) 1124 { 1125 const size_t size = MINCLSIZE - 1; 1126 int n_entries; 1127 struct xnb_pkt pkt; 1128 struct mbuf *pMbuf; 1129 1130 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1131 xnb_unit_pvt.txf.req_prod_pvt); 1132 req->flags = 0; 1133 req->size = size; 1134 req->gref = 7; 1135 req->offset = 17; 1136 xnb_unit_pvt.txf.req_prod_pvt++; 1137 1138 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1139 1140 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1141 1142 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1143 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1144 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1145 XNB_ASSERT(n_entries == 1); 1146 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size); 1147 /* flags should indicate gref's for source */ 1148 XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref); 1149 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset); 1150 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF); 1151 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1152 mtod(pMbuf, vm_offset_t))); 1153 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn == 1154 virt_to_mfn(mtod(pMbuf, vm_offset_t))); 1155 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED); 1156 safe_m_freem(&pMbuf); 1157 } 1158 1159 /** 1160 * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single 1161 * mbuf cluster 1162 */ 1163 static void 1164 xnb_txpkt2gnttab_2req(char *buffer, size_t buflen) 1165 { 1166 int n_entries; 1167 struct xnb_pkt pkt; 1168 struct mbuf *pMbuf; 1169 1170 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1171 xnb_unit_pvt.txf.req_prod_pvt); 1172 req->flags = NETTXF_more_data; 1173 req->size = 1900; 1174 req->gref = 7; 1175 req->offset = 0; 1176 xnb_unit_pvt.txf.req_prod_pvt++; 1177 1178 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1179 xnb_unit_pvt.txf.req_prod_pvt); 1180 req->flags = 0; 1181 req->size = 500; 1182 req->gref = 8; 1183 req->offset = 0; 1184 xnb_unit_pvt.txf.req_prod_pvt++; 1185 1186 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1187 1188 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1189 1190 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1191 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1192 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1193 1194 XNB_ASSERT(n_entries == 2); 1195 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400); 1196 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1197 mtod(pMbuf, vm_offset_t))); 1198 1199 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500); 1200 XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1201 mtod(pMbuf, vm_offset_t) + 1400)); 1202 safe_m_freem(&pMbuf); 1203 } 1204 1205 /** 1206 * xnb_txpkt2gnttab on a single request that spans two mbuf clusters 1207 */ 1208 static void 1209 xnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen) 1210 { 1211 int n_entries; 1212 struct xnb_pkt pkt; 1213 struct mbuf *pMbuf; 1214 const uint16_t data_this_transaction = (MCLBYTES*2) + 1; 1215 1216 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1217 xnb_unit_pvt.txf.req_prod_pvt); 1218 req->flags = 0; 1219 req->size = data_this_transaction; 1220 req->gref = 8; 1221 req->offset = 0; 1222 xnb_unit_pvt.txf.req_prod_pvt++; 1223 1224 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1225 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1226 1227 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1228 XNB_ASSERT(pMbuf != NULL); 1229 if (pMbuf == NULL) 1230 return; 1231 1232 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1233 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1234 1235 if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) { 1236 /* there should be three mbufs and three gnttab entries */ 1237 XNB_ASSERT(n_entries == 3); 1238 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES); 1239 XNB_ASSERT( 1240 xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1241 mtod(pMbuf, vm_offset_t))); 1242 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0); 1243 1244 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES); 1245 XNB_ASSERT( 1246 xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1247 mtod(pMbuf->m_next, vm_offset_t))); 1248 XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES); 1249 1250 XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1); 1251 XNB_ASSERT( 1252 xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset( 1253 mtod(pMbuf->m_next, vm_offset_t))); 1254 XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 * 1255 MCLBYTES); 1256 } else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) { 1257 /* there should be two mbufs and two gnttab entries */ 1258 XNB_ASSERT(n_entries == 2); 1259 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES); 1260 XNB_ASSERT( 1261 xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1262 mtod(pMbuf, vm_offset_t))); 1263 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0); 1264 1265 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1); 1266 XNB_ASSERT( 1267 xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1268 mtod(pMbuf->m_next, vm_offset_t))); 1269 XNB_ASSERT( 1270 xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES); 1271 1272 } else { 1273 /* should never get here */ 1274 XNB_ASSERT(0); 1275 } 1276 m_freem(pMbuf); 1277 } 1278 1279 /** 1280 * xnb_update_mbufc on a short packet that only has one gnttab entry 1281 */ 1282 static void 1283 xnb_update_mbufc_short(char *buffer, size_t buflen) 1284 { 1285 const size_t size = MINCLSIZE - 1; 1286 int n_entries; 1287 struct xnb_pkt pkt; 1288 struct mbuf *pMbuf; 1289 1290 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1291 xnb_unit_pvt.txf.req_prod_pvt); 1292 req->flags = 0; 1293 req->size = size; 1294 req->gref = 7; 1295 req->offset = 17; 1296 xnb_unit_pvt.txf.req_prod_pvt++; 1297 1298 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1299 1300 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1301 1302 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1303 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1304 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1305 1306 /* Update grant table's status fields as the hypervisor call would */ 1307 xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1308 1309 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1310 XNB_ASSERT(pMbuf->m_len == size); 1311 XNB_ASSERT(pMbuf->m_pkthdr.len == size); 1312 safe_m_freem(&pMbuf); 1313 } 1314 1315 /** 1316 * xnb_update_mbufc on a packet with two requests, that can fit into a single 1317 * mbuf cluster 1318 */ 1319 static void 1320 xnb_update_mbufc_2req(char *buffer, size_t buflen) 1321 { 1322 int n_entries; 1323 struct xnb_pkt pkt; 1324 struct mbuf *pMbuf; 1325 1326 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1327 xnb_unit_pvt.txf.req_prod_pvt); 1328 req->flags = NETTXF_more_data; 1329 req->size = 1900; 1330 req->gref = 7; 1331 req->offset = 0; 1332 xnb_unit_pvt.txf.req_prod_pvt++; 1333 1334 req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1335 xnb_unit_pvt.txf.req_prod_pvt); 1336 req->flags = 0; 1337 req->size = 500; 1338 req->gref = 8; 1339 req->offset = 0; 1340 xnb_unit_pvt.txf.req_prod_pvt++; 1341 1342 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1343 1344 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1345 1346 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1347 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1348 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1349 1350 /* Update grant table's status fields as the hypervisor call would */ 1351 xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1352 xnb_unit_pvt.gnttab[1].status = GNTST_okay; 1353 1354 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1355 XNB_ASSERT(n_entries == 2); 1356 XNB_ASSERT(pMbuf->m_pkthdr.len == 1900); 1357 XNB_ASSERT(pMbuf->m_len == 1900); 1358 1359 safe_m_freem(&pMbuf); 1360 } 1361 1362 /** 1363 * xnb_update_mbufc on a single request that spans two mbuf clusters 1364 */ 1365 static void 1366 xnb_update_mbufc_2cluster(char *buffer, size_t buflen) 1367 { 1368 int i; 1369 int n_entries; 1370 struct xnb_pkt pkt; 1371 struct mbuf *pMbuf; 1372 const uint16_t data_this_transaction = (MCLBYTES*2) + 1; 1373 1374 struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1375 xnb_unit_pvt.txf.req_prod_pvt); 1376 req->flags = 0; 1377 req->size = data_this_transaction; 1378 req->gref = 8; 1379 req->offset = 0; 1380 xnb_unit_pvt.txf.req_prod_pvt++; 1381 1382 RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1383 xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1384 1385 pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1386 n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1387 &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1388 1389 /* Update grant table's status fields */ 1390 for (i = 0; i < n_entries; i++) { 1391 xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1392 } 1393 xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1394 1395 if (n_entries == 3) { 1396 /* there should be three mbufs and three gnttab entries */ 1397 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction); 1398 XNB_ASSERT(pMbuf->m_len == MCLBYTES); 1399 XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES); 1400 XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1); 1401 } else if (n_entries == 2) { 1402 /* there should be two mbufs and two gnttab entries */ 1403 XNB_ASSERT(n_entries == 2); 1404 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction); 1405 XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES); 1406 XNB_ASSERT(pMbuf->m_next->m_len == 1); 1407 } else { 1408 /* should never get here */ 1409 XNB_ASSERT(0); 1410 } 1411 safe_m_freem(&pMbuf); 1412 } 1413 1414 /** xnb_mbufc2pkt on an empty mbufc */ 1415 static void 1416 xnb_mbufc2pkt_empty(char *buffer, size_t buflen) { 1417 struct xnb_pkt pkt; 1418 int free_slots = 64; 1419 struct mbuf *mbuf; 1420 1421 mbuf = m_get(M_WAITOK, MT_DATA); 1422 /* 1423 * note: it is illegal to set M_PKTHDR on a mbuf with no data. Doing so 1424 * will cause m_freem to segfault 1425 */ 1426 XNB_ASSERT(mbuf->m_len == 0); 1427 1428 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1429 XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 1430 1431 safe_m_freem(&mbuf); 1432 } 1433 1434 /** xnb_mbufc2pkt on a short mbufc */ 1435 static void 1436 xnb_mbufc2pkt_short(char *buffer, size_t buflen) { 1437 struct xnb_pkt pkt; 1438 size_t size = 128; 1439 int free_slots = 64; 1440 RING_IDX start = 9; 1441 struct mbuf *mbuf; 1442 1443 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1444 mbuf->m_flags |= M_PKTHDR; 1445 mbuf->m_pkthdr.len = size; 1446 mbuf->m_len = size; 1447 1448 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1449 XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1450 XNB_ASSERT(pkt.size == size); 1451 XNB_ASSERT(pkt.car_size == size); 1452 XNB_ASSERT(! (pkt.flags & 1453 (NETRXF_more_data | NETRXF_extra_info))); 1454 XNB_ASSERT(pkt.list_len == 1); 1455 XNB_ASSERT(pkt.car == start); 1456 1457 safe_m_freem(&mbuf); 1458 } 1459 1460 /** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */ 1461 static void 1462 xnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) { 1463 struct xnb_pkt pkt; 1464 size_t size = MCLBYTES; 1465 int free_slots = 32; 1466 RING_IDX start = 12; 1467 struct mbuf *mbuf; 1468 1469 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1470 mbuf->m_flags |= M_PKTHDR; 1471 mbuf->m_pkthdr.len = size; 1472 mbuf->m_len = size; 1473 1474 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1475 XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1476 XNB_ASSERT(pkt.size == size); 1477 XNB_ASSERT(pkt.car_size == size); 1478 XNB_ASSERT(! (pkt.flags & 1479 (NETRXF_more_data | NETRXF_extra_info))); 1480 XNB_ASSERT(pkt.list_len == 1); 1481 XNB_ASSERT(pkt.car == start); 1482 1483 safe_m_freem(&mbuf); 1484 } 1485 1486 /** xnb_mbufc2pkt on a two-mbuf chain with short data regions */ 1487 static void 1488 xnb_mbufc2pkt_2short(char *buffer, size_t buflen) { 1489 struct xnb_pkt pkt; 1490 size_t size1 = MHLEN - 5; 1491 size_t size2 = MHLEN - 15; 1492 int free_slots = 32; 1493 RING_IDX start = 14; 1494 struct mbuf *mbufc, *mbufc2; 1495 1496 mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA); 1497 XNB_ASSERT(mbufc != NULL); 1498 if (mbufc == NULL) 1499 return; 1500 mbufc->m_flags |= M_PKTHDR; 1501 1502 mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA); 1503 XNB_ASSERT(mbufc2 != NULL); 1504 if (mbufc2 == NULL) { 1505 safe_m_freem(&mbufc); 1506 return; 1507 } 1508 mbufc2->m_pkthdr.len = size1 + size2; 1509 mbufc2->m_len = size1; 1510 1511 xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots); 1512 XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1513 XNB_ASSERT(pkt.size == size1 + size2); 1514 XNB_ASSERT(pkt.car == start); 1515 /* 1516 * The second m_getm may allocate a new mbuf and append 1517 * it to the chain, or it may simply extend the first mbuf. 1518 */ 1519 if (mbufc2->m_next != NULL) { 1520 XNB_ASSERT(pkt.car_size == size1); 1521 XNB_ASSERT(pkt.list_len == 1); 1522 XNB_ASSERT(pkt.cdr == start + 1); 1523 } 1524 1525 safe_m_freem(&mbufc2); 1526 } 1527 1528 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */ 1529 static void 1530 xnb_mbufc2pkt_long(char *buffer, size_t buflen) { 1531 struct xnb_pkt pkt; 1532 size_t size = 14 * MCLBYTES / 3; 1533 size_t size_remaining; 1534 int free_slots = 15; 1535 RING_IDX start = 3; 1536 struct mbuf *mbufc, *m; 1537 1538 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1539 XNB_ASSERT(mbufc != NULL); 1540 if (mbufc == NULL) 1541 return; 1542 mbufc->m_flags |= M_PKTHDR; 1543 1544 mbufc->m_pkthdr.len = size; 1545 size_remaining = size; 1546 for (m = mbufc; m != NULL; m = m->m_next) { 1547 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1548 size_remaining -= m->m_len; 1549 } 1550 1551 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1552 XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1553 XNB_ASSERT(pkt.size == size); 1554 XNB_ASSERT(pkt.car == start); 1555 XNB_ASSERT(pkt.car_size = mbufc->m_len); 1556 /* 1557 * There should be >1 response in the packet, and there is no 1558 * extra info. 1559 */ 1560 XNB_ASSERT(! (pkt.flags & NETRXF_extra_info)); 1561 XNB_ASSERT(pkt.cdr == pkt.car + 1); 1562 1563 safe_m_freem(&mbufc); 1564 } 1565 1566 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */ 1567 static void 1568 xnb_mbufc2pkt_extra(char *buffer, size_t buflen) { 1569 struct xnb_pkt pkt; 1570 size_t size = 14 * MCLBYTES / 3; 1571 size_t size_remaining; 1572 int free_slots = 15; 1573 RING_IDX start = 3; 1574 struct mbuf *mbufc, *m; 1575 1576 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1577 XNB_ASSERT(mbufc != NULL); 1578 if (mbufc == NULL) 1579 return; 1580 1581 mbufc->m_flags |= M_PKTHDR; 1582 mbufc->m_pkthdr.len = size; 1583 mbufc->m_pkthdr.csum_flags |= CSUM_TSO; 1584 mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40; 1585 size_remaining = size; 1586 for (m = mbufc; m != NULL; m = m->m_next) { 1587 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1588 size_remaining -= m->m_len; 1589 } 1590 1591 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1592 XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1593 XNB_ASSERT(pkt.size == size); 1594 XNB_ASSERT(pkt.car == start); 1595 XNB_ASSERT(pkt.car_size = mbufc->m_len); 1596 /* There should be >1 response in the packet, there is extra info */ 1597 XNB_ASSERT(pkt.flags & NETRXF_extra_info); 1598 XNB_ASSERT(pkt.flags & NETRXF_data_validated); 1599 XNB_ASSERT(pkt.cdr == pkt.car + 2); 1600 XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz); 1601 XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO); 1602 XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE)); 1603 1604 safe_m_freem(&mbufc); 1605 } 1606 1607 /** xnb_mbufc2pkt with insufficient space in the ring */ 1608 static void 1609 xnb_mbufc2pkt_nospace(char *buffer, size_t buflen) { 1610 struct xnb_pkt pkt; 1611 size_t size = 14 * MCLBYTES / 3; 1612 size_t size_remaining; 1613 int free_slots = 2; 1614 RING_IDX start = 3; 1615 struct mbuf *mbufc, *m; 1616 int error; 1617 1618 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1619 XNB_ASSERT(mbufc != NULL); 1620 if (mbufc == NULL) 1621 return; 1622 mbufc->m_flags |= M_PKTHDR; 1623 1624 mbufc->m_pkthdr.len = size; 1625 size_remaining = size; 1626 for (m = mbufc; m != NULL; m = m->m_next) { 1627 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1628 size_remaining -= m->m_len; 1629 } 1630 1631 error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1632 XNB_ASSERT(error == EAGAIN); 1633 XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 1634 1635 safe_m_freem(&mbufc); 1636 } 1637 1638 /** 1639 * xnb_rxpkt2gnttab on an empty packet. Should return empty gnttab 1640 */ 1641 static void 1642 xnb_rxpkt2gnttab_empty(char *buffer, size_t buflen) 1643 { 1644 struct xnb_pkt pkt; 1645 int nr_entries; 1646 int free_slots = 60; 1647 struct mbuf *mbuf; 1648 1649 mbuf = m_get(M_WAITOK, MT_DATA); 1650 1651 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1652 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1653 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1654 1655 XNB_ASSERT(nr_entries == 0); 1656 1657 safe_m_freem(&mbuf); 1658 } 1659 1660 /** xnb_rxpkt2gnttab on a short packet without extra data */ 1661 static void 1662 xnb_rxpkt2gnttab_short(char *buffer, size_t buflen) { 1663 struct xnb_pkt pkt; 1664 int nr_entries; 1665 size_t size = 128; 1666 int free_slots = 60; 1667 RING_IDX start = 9; 1668 struct netif_rx_request *req; 1669 struct mbuf *mbuf; 1670 1671 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1672 mbuf->m_flags |= M_PKTHDR; 1673 mbuf->m_pkthdr.len = size; 1674 mbuf->m_len = size; 1675 1676 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1677 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, 1678 xnb_unit_pvt.txf.req_prod_pvt); 1679 req->gref = 7; 1680 1681 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1682 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1683 1684 XNB_ASSERT(nr_entries == 1); 1685 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size); 1686 /* flags should indicate gref's for dest */ 1687 XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref); 1688 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0); 1689 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF); 1690 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset( 1691 mtod(mbuf, vm_offset_t))); 1692 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn == 1693 virt_to_mfn(mtod(mbuf, vm_offset_t))); 1694 XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED); 1695 1696 safe_m_freem(&mbuf); 1697 } 1698 1699 /** 1700 * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai 1701 */ 1702 static void 1703 xnb_rxpkt2gnttab_2req(char *buffer, size_t buflen) 1704 { 1705 struct xnb_pkt pkt; 1706 int nr_entries; 1707 int i, num_mbufs; 1708 size_t total_granted_size = 0; 1709 size_t size = MJUMPAGESIZE + 1; 1710 int free_slots = 60; 1711 RING_IDX start = 11; 1712 struct netif_rx_request *req; 1713 struct mbuf *mbuf, *m; 1714 1715 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1716 mbuf->m_flags |= M_PKTHDR; 1717 mbuf->m_pkthdr.len = size; 1718 mbuf->m_len = size; 1719 1720 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1721 1722 for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) { 1723 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, 1724 xnb_unit_pvt.txf.req_prod_pvt); 1725 req->gref = i; 1726 req->id = 5; 1727 } 1728 num_mbufs = i; 1729 1730 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1731 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1732 1733 XNB_ASSERT(nr_entries >= num_mbufs); 1734 for (i = 0; i < nr_entries; i++) { 1735 int end_offset = xnb_unit_pvt.gnttab[i].len + 1736 xnb_unit_pvt.gnttab[i].dest.offset; 1737 XNB_ASSERT(end_offset <= PAGE_SIZE); 1738 total_granted_size += xnb_unit_pvt.gnttab[i].len; 1739 } 1740 XNB_ASSERT(total_granted_size == size); 1741 } 1742 1743 /** 1744 * xnb_rxpkt2rsp on an empty packet. Shouldn't make any response 1745 */ 1746 static void 1747 xnb_rxpkt2rsp_empty(char *buffer, size_t buflen) 1748 { 1749 struct xnb_pkt pkt; 1750 int nr_entries; 1751 int nr_reqs; 1752 int free_slots = 60; 1753 netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb; 1754 netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs; 1755 struct mbuf *mbuf; 1756 1757 mbuf = m_get(M_WAITOK, MT_DATA); 1758 1759 xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1760 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1761 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1762 1763 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1764 &xnb_unit_pvt.rxb); 1765 XNB_ASSERT(nr_reqs == 0); 1766 XNB_ASSERT( 1767 memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0); 1768 XNB_ASSERT( 1769 memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0); 1770 1771 safe_m_freem(&mbuf); 1772 } 1773 1774 /** 1775 * xnb_rxpkt2rsp on a short packet with no extras 1776 */ 1777 static void 1778 xnb_rxpkt2rsp_short(char *buffer, size_t buflen) 1779 { 1780 struct xnb_pkt pkt; 1781 int nr_entries, nr_reqs; 1782 size_t size = 128; 1783 int free_slots = 60; 1784 RING_IDX start = 5; 1785 struct netif_rx_request *req; 1786 struct netif_rx_response *rsp; 1787 struct mbuf *mbuf; 1788 1789 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1790 mbuf->m_flags |= M_PKTHDR; 1791 mbuf->m_pkthdr.len = size; 1792 mbuf->m_len = size; 1793 1794 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1795 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1796 req->gref = 7; 1797 xnb_unit_pvt.rxb.req_cons = start; 1798 xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1799 xnb_unit_pvt.rxs->req_prod = start + 1; 1800 xnb_unit_pvt.rxs->rsp_prod = start; 1801 1802 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1803 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1804 1805 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1806 &xnb_unit_pvt.rxb); 1807 1808 XNB_ASSERT(nr_reqs == 1); 1809 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1); 1810 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1811 XNB_ASSERT(rsp->id == req->id); 1812 XNB_ASSERT(rsp->offset == 0); 1813 XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0); 1814 XNB_ASSERT(rsp->status == size); 1815 1816 safe_m_freem(&mbuf); 1817 } 1818 1819 /** 1820 * xnb_rxpkt2rsp with extra data 1821 */ 1822 static void 1823 xnb_rxpkt2rsp_extra(char *buffer, size_t buflen) 1824 { 1825 struct xnb_pkt pkt; 1826 int nr_entries, nr_reqs; 1827 size_t size = 14; 1828 int free_slots = 15; 1829 RING_IDX start = 3; 1830 uint16_t id = 49; 1831 uint16_t gref = 65; 1832 uint16_t mss = TCP_MSS - 40; 1833 struct mbuf *mbufc; 1834 struct netif_rx_request *req; 1835 struct netif_rx_response *rsp; 1836 struct netif_extra_info *ext; 1837 1838 mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1839 XNB_ASSERT(mbufc != NULL); 1840 if (mbufc == NULL) 1841 return; 1842 1843 mbufc->m_flags |= M_PKTHDR; 1844 mbufc->m_pkthdr.len = size; 1845 mbufc->m_pkthdr.csum_flags |= CSUM_TSO; 1846 mbufc->m_pkthdr.tso_segsz = mss; 1847 mbufc->m_len = size; 1848 1849 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1850 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1851 req->id = id; 1852 req->gref = gref; 1853 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 1854 req->id = id + 1; 1855 req->gref = gref + 1; 1856 xnb_unit_pvt.rxb.req_cons = start; 1857 xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1858 xnb_unit_pvt.rxs->req_prod = start + 2; 1859 xnb_unit_pvt.rxs->rsp_prod = start; 1860 1861 nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab, 1862 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1863 1864 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1865 &xnb_unit_pvt.rxb); 1866 1867 XNB_ASSERT(nr_reqs == 2); 1868 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2); 1869 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1870 XNB_ASSERT(rsp->id == id); 1871 XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0); 1872 XNB_ASSERT((rsp->flags & NETRXF_extra_info)); 1873 XNB_ASSERT((rsp->flags & NETRXF_data_validated)); 1874 XNB_ASSERT((rsp->flags & NETRXF_csum_blank)); 1875 XNB_ASSERT(rsp->status == size); 1876 1877 ext = (struct netif_extra_info*) 1878 RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1); 1879 XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO); 1880 XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE)); 1881 XNB_ASSERT(ext->u.gso.size == mss); 1882 XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO); 1883 1884 safe_m_freem(&mbufc); 1885 } 1886 1887 /** 1888 * xnb_rxpkt2rsp on a packet with more than a pages's worth of data. It should 1889 * generate two response slot 1890 */ 1891 static void 1892 xnb_rxpkt2rsp_2slots(char *buffer, size_t buflen) 1893 { 1894 struct xnb_pkt pkt; 1895 int nr_entries, nr_reqs; 1896 size_t size = PAGE_SIZE + 100; 1897 int free_slots = 3; 1898 uint16_t id1 = 17; 1899 uint16_t id2 = 37; 1900 uint16_t gref1 = 24; 1901 uint16_t gref2 = 34; 1902 RING_IDX start = 15; 1903 struct netif_rx_request *req; 1904 struct netif_rx_response *rsp; 1905 struct mbuf *mbuf; 1906 1907 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1908 mbuf->m_flags |= M_PKTHDR; 1909 mbuf->m_pkthdr.len = size; 1910 if (mbuf->m_next != NULL) { 1911 size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size); 1912 mbuf->m_len = first_len; 1913 mbuf->m_next->m_len = size - first_len; 1914 1915 } else { 1916 mbuf->m_len = size; 1917 } 1918 1919 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1920 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1921 req->gref = gref1; 1922 req->id = id1; 1923 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 1924 req->gref = gref2; 1925 req->id = id2; 1926 xnb_unit_pvt.rxb.req_cons = start; 1927 xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1928 xnb_unit_pvt.rxs->req_prod = start + 2; 1929 xnb_unit_pvt.rxs->rsp_prod = start; 1930 1931 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1932 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1933 1934 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1935 &xnb_unit_pvt.rxb); 1936 1937 XNB_ASSERT(nr_reqs == 2); 1938 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2); 1939 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1940 XNB_ASSERT(rsp->id == id1); 1941 XNB_ASSERT(rsp->offset == 0); 1942 XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0); 1943 XNB_ASSERT(rsp->flags & NETRXF_more_data); 1944 XNB_ASSERT(rsp->status == PAGE_SIZE); 1945 1946 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1); 1947 XNB_ASSERT(rsp->id == id2); 1948 XNB_ASSERT(rsp->offset == 0); 1949 XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0); 1950 XNB_ASSERT(! (rsp->flags & NETRXF_more_data)); 1951 XNB_ASSERT(rsp->status == size - PAGE_SIZE); 1952 1953 safe_m_freem(&mbuf); 1954 } 1955 1956 /** xnb_rxpkt2rsp on a grant table with two sub-page entries */ 1957 static void 1958 xnb_rxpkt2rsp_2short(char *buffer, size_t buflen) { 1959 struct xnb_pkt pkt; 1960 int nr_reqs, nr_entries; 1961 size_t size1 = MHLEN - 5; 1962 size_t size2 = MHLEN - 15; 1963 int free_slots = 32; 1964 RING_IDX start = 14; 1965 uint16_t id = 47; 1966 uint16_t gref = 54; 1967 struct netif_rx_request *req; 1968 struct netif_rx_response *rsp; 1969 struct mbuf *mbufc; 1970 1971 mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA); 1972 XNB_ASSERT(mbufc != NULL); 1973 if (mbufc == NULL) 1974 return; 1975 mbufc->m_flags |= M_PKTHDR; 1976 1977 m_getm(mbufc, size2, M_WAITOK, MT_DATA); 1978 XNB_ASSERT(mbufc->m_next != NULL); 1979 mbufc->m_pkthdr.len = size1 + size2; 1980 mbufc->m_len = size1; 1981 mbufc->m_next->m_len = size2; 1982 1983 xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1984 1985 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1986 req->gref = gref; 1987 req->id = id; 1988 xnb_unit_pvt.rxb.req_cons = start; 1989 xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1990 xnb_unit_pvt.rxs->req_prod = start + 1; 1991 xnb_unit_pvt.rxs->rsp_prod = start; 1992 1993 nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab, 1994 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1995 1996 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1997 &xnb_unit_pvt.rxb); 1998 1999 XNB_ASSERT(nr_entries == 2); 2000 XNB_ASSERT(nr_reqs == 1); 2001 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 2002 XNB_ASSERT(rsp->id == id); 2003 XNB_ASSERT(rsp->status == size1 + size2); 2004 XNB_ASSERT(rsp->offset == 0); 2005 XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info))); 2006 2007 safe_m_freem(&mbufc); 2008 } 2009 2010 /** 2011 * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error 2012 * Note: this test will result in an error message being printed to the console 2013 * such as: 2014 * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status 2015 */ 2016 static void 2017 xnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen) 2018 { 2019 struct xnb_pkt pkt; 2020 int nr_entries, nr_reqs; 2021 int id = 7; 2022 int gref = 42; 2023 uint16_t canary = 6859; 2024 size_t size = 7 * MCLBYTES; 2025 int free_slots = 9; 2026 RING_IDX start = 2; 2027 struct netif_rx_request *req; 2028 struct netif_rx_response *rsp; 2029 struct mbuf *mbuf; 2030 2031 mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 2032 mbuf->m_flags |= M_PKTHDR; 2033 mbuf->m_pkthdr.len = size; 2034 mbuf->m_len = size; 2035 2036 xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 2037 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 2038 req->gref = gref; 2039 req->id = id; 2040 xnb_unit_pvt.rxb.req_cons = start; 2041 xnb_unit_pvt.rxb.rsp_prod_pvt = start; 2042 xnb_unit_pvt.rxs->req_prod = start + 1; 2043 xnb_unit_pvt.rxs->rsp_prod = start; 2044 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 2045 req->gref = canary; 2046 req->id = canary; 2047 2048 nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 2049 &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 2050 /* Inject the error*/ 2051 xnb_unit_pvt.gnttab[2].status = GNTST_general_error; 2052 2053 nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 2054 &xnb_unit_pvt.rxb); 2055 2056 XNB_ASSERT(nr_reqs == 1); 2057 XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1); 2058 rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 2059 XNB_ASSERT(rsp->id == id); 2060 XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 2061 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 2062 XNB_ASSERT(req->gref == canary); 2063 XNB_ASSERT(req->id == canary); 2064 2065 safe_m_freem(&mbuf); 2066 } 2067 2068 #if defined(INET) || defined(INET6) 2069 /** 2070 * xnb_add_mbuf_cksum on an ARP request packet 2071 */ 2072 static void 2073 xnb_add_mbuf_cksum_arp(char *buffer, size_t buflen) 2074 { 2075 const size_t pkt_len = sizeof(struct ether_header) + 2076 sizeof(struct ether_arp); 2077 struct mbuf *mbufc; 2078 struct ether_header *eh; 2079 struct ether_arp *ep; 2080 unsigned char pkt_orig[pkt_len]; 2081 2082 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2083 /* Fill in an example arp request */ 2084 eh = mtod(mbufc, struct ether_header*); 2085 eh->ether_dhost[0] = 0xff; 2086 eh->ether_dhost[1] = 0xff; 2087 eh->ether_dhost[2] = 0xff; 2088 eh->ether_dhost[3] = 0xff; 2089 eh->ether_dhost[4] = 0xff; 2090 eh->ether_dhost[5] = 0xff; 2091 eh->ether_shost[0] = 0x00; 2092 eh->ether_shost[1] = 0x15; 2093 eh->ether_shost[2] = 0x17; 2094 eh->ether_shost[3] = 0xe9; 2095 eh->ether_shost[4] = 0x30; 2096 eh->ether_shost[5] = 0x68; 2097 eh->ether_type = htons(ETHERTYPE_ARP); 2098 ep = (struct ether_arp*)(eh + 1); 2099 ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); 2100 ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP); 2101 ep->ea_hdr.ar_hln = 6; 2102 ep->ea_hdr.ar_pln = 4; 2103 ep->ea_hdr.ar_op = htons(ARPOP_REQUEST); 2104 ep->arp_sha[0] = 0x00; 2105 ep->arp_sha[1] = 0x15; 2106 ep->arp_sha[2] = 0x17; 2107 ep->arp_sha[3] = 0xe9; 2108 ep->arp_sha[4] = 0x30; 2109 ep->arp_sha[5] = 0x68; 2110 ep->arp_spa[0] = 0xc0; 2111 ep->arp_spa[1] = 0xa8; 2112 ep->arp_spa[2] = 0x0a; 2113 ep->arp_spa[3] = 0x04; 2114 bzero(&(ep->arp_tha), ETHER_ADDR_LEN); 2115 ep->arp_tpa[0] = 0xc0; 2116 ep->arp_tpa[1] = 0xa8; 2117 ep->arp_tpa[2] = 0x0a; 2118 ep->arp_tpa[3] = 0x06; 2119 2120 /* fill in the length field */ 2121 mbufc->m_len = pkt_len; 2122 mbufc->m_pkthdr.len = pkt_len; 2123 /* indicate that the netfront uses hw-assisted checksums */ 2124 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2125 CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2126 2127 /* Make a backup copy of the packet */ 2128 bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len); 2129 2130 /* Function under test */ 2131 xnb_add_mbuf_cksum(mbufc); 2132 2133 /* Verify that the packet's data did not change */ 2134 XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0); 2135 m_freem(mbufc); 2136 } 2137 2138 /** 2139 * Helper function that populates the ethernet header and IP header used by 2140 * some of the xnb_add_mbuf_cksum unit tests. m must already be allocated 2141 * and must be large enough 2142 */ 2143 static void 2144 xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id, 2145 uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum) 2146 { 2147 struct ether_header *eh; 2148 struct ip *iph; 2149 2150 eh = mtod(m, struct ether_header*); 2151 eh->ether_dhost[0] = 0x00; 2152 eh->ether_dhost[1] = 0x16; 2153 eh->ether_dhost[2] = 0x3e; 2154 eh->ether_dhost[3] = 0x23; 2155 eh->ether_dhost[4] = 0x50; 2156 eh->ether_dhost[5] = 0x0b; 2157 eh->ether_shost[0] = 0x00; 2158 eh->ether_shost[1] = 0x16; 2159 eh->ether_shost[2] = 0x30; 2160 eh->ether_shost[3] = 0x00; 2161 eh->ether_shost[4] = 0x00; 2162 eh->ether_shost[5] = 0x00; 2163 eh->ether_type = htons(ETHERTYPE_IP); 2164 iph = (struct ip*)(eh + 1); 2165 iph->ip_hl = 0x5; /* 5 dwords == 20 bytes */ 2166 iph->ip_v = 4; /* IP v4 */ 2167 iph->ip_tos = 0; 2168 iph->ip_len = htons(ip_len); 2169 iph->ip_id = htons(ip_id); 2170 iph->ip_off = htons(ip_off); 2171 iph->ip_ttl = 64; 2172 iph->ip_p = ip_p; 2173 iph->ip_sum = htons(ip_sum); 2174 iph->ip_src.s_addr = htonl(0xc0a80a04); 2175 iph->ip_dst.s_addr = htonl(0xc0a80a05); 2176 } 2177 2178 /** 2179 * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual 2180 * ICMP packet 2181 */ 2182 static void 2183 xnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen) 2184 { 2185 const size_t icmp_len = 64; /* set by ping(1) */ 2186 const size_t pkt_len = sizeof(struct ether_header) + 2187 sizeof(struct ip) + icmp_len; 2188 struct mbuf *mbufc; 2189 struct ether_header *eh; 2190 struct ip *iph; 2191 struct icmp *icmph; 2192 unsigned char pkt_orig[icmp_len]; 2193 uint32_t *tv_field; 2194 uint8_t *data_payload; 2195 int i; 2196 const uint16_t ICMP_CSUM = 0xaed7; 2197 const uint16_t IP_CSUM = 0xe533; 2198 2199 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2200 /* Fill in an example ICMP ping request */ 2201 eh = mtod(mbufc, struct ether_header*); 2202 xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0); 2203 iph = (struct ip*)(eh + 1); 2204 icmph = (struct icmp*)(iph + 1); 2205 icmph->icmp_type = ICMP_ECHO; 2206 icmph->icmp_code = 0; 2207 icmph->icmp_cksum = htons(ICMP_CSUM); 2208 icmph->icmp_id = htons(31492); 2209 icmph->icmp_seq = htons(0); 2210 /* 2211 * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq. 2212 * For this test, we will set the bytes individually for portability. 2213 */ 2214 tv_field = (uint32_t*)(&(icmph->icmp_hun)); 2215 tv_field[0] = 0x4f02cfac; 2216 tv_field[1] = 0x0007c46a; 2217 /* 2218 * Remainder of packet is an incrmenting 8 bit integer, starting with 8 2219 */ 2220 data_payload = (uint8_t*)(&tv_field[2]); 2221 for (i = 8; i < 37; i++) { 2222 *data_payload++ = i; 2223 } 2224 2225 /* fill in the length field */ 2226 mbufc->m_len = pkt_len; 2227 mbufc->m_pkthdr.len = pkt_len; 2228 /* indicate that the netfront uses hw-assisted checksums */ 2229 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2230 CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2231 2232 bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len); 2233 /* Function under test */ 2234 xnb_add_mbuf_cksum(mbufc); 2235 2236 /* Check the IP checksum */ 2237 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2238 2239 /* Check that the ICMP packet did not change */ 2240 XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len)); 2241 m_freem(mbufc); 2242 } 2243 2244 /** 2245 * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual 2246 * UDP packet 2247 */ 2248 static void 2249 xnb_add_mbuf_cksum_udp(char *buffer, size_t buflen) 2250 { 2251 const size_t udp_len = 16; 2252 const size_t pkt_len = sizeof(struct ether_header) + 2253 sizeof(struct ip) + udp_len; 2254 struct mbuf *mbufc; 2255 struct ether_header *eh; 2256 struct ip *iph; 2257 struct udphdr *udp; 2258 uint8_t *data_payload; 2259 const uint16_t IP_CSUM = 0xe56b; 2260 const uint16_t UDP_CSUM = 0xdde2; 2261 2262 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2263 /* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */ 2264 eh = mtod(mbufc, struct ether_header*); 2265 xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad); 2266 iph = (struct ip*)(eh + 1); 2267 udp = (struct udphdr*)(iph + 1); 2268 udp->uh_sport = htons(0x51ae); 2269 udp->uh_dport = htons(0x08ae); 2270 udp->uh_ulen = htons(udp_len); 2271 udp->uh_sum = htons(0xbaad); /* xnb_add_mbuf_cksum will fill this in */ 2272 data_payload = (uint8_t*)(udp + 1); 2273 data_payload[0] = 'F'; 2274 data_payload[1] = 'r'; 2275 data_payload[2] = 'e'; 2276 data_payload[3] = 'e'; 2277 data_payload[4] = 'B'; 2278 data_payload[5] = 'S'; 2279 data_payload[6] = 'D'; 2280 data_payload[7] = '\n'; 2281 2282 /* fill in the length field */ 2283 mbufc->m_len = pkt_len; 2284 mbufc->m_pkthdr.len = pkt_len; 2285 /* indicate that the netfront uses hw-assisted checksums */ 2286 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2287 CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2288 2289 /* Function under test */ 2290 xnb_add_mbuf_cksum(mbufc); 2291 2292 /* Check the checksums */ 2293 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2294 XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM)); 2295 2296 m_freem(mbufc); 2297 } 2298 2299 /** 2300 * Helper function that populates a TCP packet used by all of the 2301 * xnb_add_mbuf_cksum tcp unit tests. m must already be allocated and must be 2302 * large enough 2303 */ 2304 static void 2305 xnb_fill_tcp(struct mbuf *m) 2306 { 2307 struct ether_header *eh; 2308 struct ip *iph; 2309 struct tcphdr *tcp; 2310 uint32_t *options; 2311 uint8_t *data_payload; 2312 2313 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2314 eh = mtod(m, struct ether_header*); 2315 xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0); 2316 iph = (struct ip*)(eh + 1); 2317 tcp = (struct tcphdr*)(iph + 1); 2318 tcp->th_sport = htons(0x9cd9); 2319 tcp->th_dport = htons(2222); 2320 tcp->th_seq = htonl(0x00f72b10); 2321 tcp->th_ack = htonl(0x7f37ba6c); 2322 tcp->th_x2 = 0; 2323 tcp->th_off = 8; 2324 tcp->th_flags = 0x18; 2325 tcp->th_win = htons(0x410); 2326 /* th_sum is incorrect; will be inserted by function under test */ 2327 tcp->th_sum = htons(0xbaad); 2328 tcp->th_urp = htons(0); 2329 /* 2330 * The following 12 bytes of options encode: 2331 * [nop, nop, TS val 33247 ecr 3457687679] 2332 */ 2333 options = (uint32_t*)(tcp + 1); 2334 options[0] = htonl(0x0101080a); 2335 options[1] = htonl(0x000081df); 2336 options[2] = htonl(0xce18207f); 2337 data_payload = (uint8_t*)(&options[3]); 2338 data_payload[0] = 'F'; 2339 data_payload[1] = 'r'; 2340 data_payload[2] = 'e'; 2341 data_payload[3] = 'e'; 2342 data_payload[4] = 'B'; 2343 data_payload[5] = 'S'; 2344 data_payload[6] = 'D'; 2345 data_payload[7] = '\n'; 2346 } 2347 2348 /** 2349 * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP 2350 * packet 2351 */ 2352 static void 2353 xnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen) 2354 { 2355 const size_t payload_len = 8; 2356 const size_t tcp_options_len = 12; 2357 const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) + 2358 sizeof(struct tcphdr) + tcp_options_len + payload_len; 2359 struct mbuf *mbufc; 2360 struct ether_header *eh; 2361 struct ip *iph; 2362 struct tcphdr *tcp; 2363 const uint16_t IP_CSUM = 0xa55a; 2364 const uint16_t TCP_CSUM = 0x2f64; 2365 2366 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2367 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2368 xnb_fill_tcp(mbufc); 2369 eh = mtod(mbufc, struct ether_header*); 2370 iph = (struct ip*)(eh + 1); 2371 tcp = (struct tcphdr*)(iph + 1); 2372 2373 /* fill in the length field */ 2374 mbufc->m_len = pkt_len; 2375 mbufc->m_pkthdr.len = pkt_len; 2376 /* indicate that the netfront uses hw-assisted checksums */ 2377 mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2378 CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2379 2380 /* Function under test */ 2381 xnb_add_mbuf_cksum(mbufc); 2382 2383 /* Check the checksums */ 2384 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2385 XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM)); 2386 2387 m_freem(mbufc); 2388 } 2389 2390 /** 2391 * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums 2392 */ 2393 static void 2394 xnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen) 2395 { 2396 const size_t payload_len = 8; 2397 const size_t tcp_options_len = 12; 2398 const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) + 2399 sizeof(struct tcphdr) + tcp_options_len + payload_len; 2400 struct mbuf *mbufc; 2401 struct ether_header *eh; 2402 struct ip *iph; 2403 struct tcphdr *tcp; 2404 /* Use deliberately bad checksums, and verify that they don't get */ 2405 /* corrected by xnb_add_mbuf_cksum */ 2406 const uint16_t IP_CSUM = 0xdead; 2407 const uint16_t TCP_CSUM = 0xbeef; 2408 2409 mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2410 /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2411 xnb_fill_tcp(mbufc); 2412 eh = mtod(mbufc, struct ether_header*); 2413 iph = (struct ip*)(eh + 1); 2414 iph->ip_sum = htons(IP_CSUM); 2415 tcp = (struct tcphdr*)(iph + 1); 2416 tcp->th_sum = htons(TCP_CSUM); 2417 2418 /* fill in the length field */ 2419 mbufc->m_len = pkt_len; 2420 mbufc->m_pkthdr.len = pkt_len; 2421 /* indicate that the netfront does not use hw-assisted checksums */ 2422 mbufc->m_pkthdr.csum_flags = 0; 2423 2424 /* Function under test */ 2425 xnb_add_mbuf_cksum(mbufc); 2426 2427 /* Check that the checksums didn't change */ 2428 XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2429 XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM)); 2430 2431 m_freem(mbufc); 2432 } 2433 #endif /* INET || INET6 */ 2434 2435 /** 2436 * sscanf on unsigned chars 2437 */ 2438 static void 2439 xnb_sscanf_hhu(char *buffer, size_t buflen) 2440 { 2441 const char mystr[] = "137"; 2442 uint8_t dest[12]; 2443 int i; 2444 2445 for (i = 0; i < 12; i++) 2446 dest[i] = 'X'; 2447 2448 XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1); 2449 for (i = 0; i < 12; i++) 2450 XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X')); 2451 } 2452 2453 /** 2454 * sscanf on signed chars 2455 */ 2456 static void 2457 xnb_sscanf_hhd(char *buffer, size_t buflen) 2458 { 2459 const char mystr[] = "-27"; 2460 int8_t dest[12]; 2461 int i; 2462 2463 for (i = 0; i < 12; i++) 2464 dest[i] = 'X'; 2465 2466 XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1); 2467 for (i = 0; i < 12; i++) 2468 XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X')); 2469 } 2470 2471 /** 2472 * sscanf on signed long longs 2473 */ 2474 static void 2475 xnb_sscanf_lld(char *buffer, size_t buflen) 2476 { 2477 const char mystr[] = "-123456789012345"; /* about -2**47 */ 2478 long long dest[3]; 2479 int i; 2480 2481 for (i = 0; i < 3; i++) 2482 dest[i] = (long long)0xdeadbeefdeadbeef; 2483 2484 XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1); 2485 for (i = 0; i < 3; i++) 2486 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef : 2487 -123456789012345)); 2488 } 2489 2490 /** 2491 * sscanf on unsigned long longs 2492 */ 2493 static void 2494 xnb_sscanf_llu(char *buffer, size_t buflen) 2495 { 2496 const char mystr[] = "12802747070103273189"; 2497 unsigned long long dest[3]; 2498 int i; 2499 2500 for (i = 0; i < 3; i++) 2501 dest[i] = (long long)0xdeadbeefdeadbeef; 2502 2503 XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1); 2504 for (i = 0; i < 3; i++) 2505 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef : 2506 12802747070103273189ull)); 2507 } 2508 2509 /** 2510 * sscanf on unsigned short short n's 2511 */ 2512 static void 2513 xnb_sscanf_hhn(char *buffer, size_t buflen) 2514 { 2515 const char mystr[] = 2516 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 2517 "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 2518 "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"; 2519 unsigned char dest[12]; 2520 int i; 2521 2522 for (i = 0; i < 12; i++) 2523 dest[i] = (unsigned char)'X'; 2524 2525 XNB_ASSERT(sscanf(mystr, 2526 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 2527 "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 2528 "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0); 2529 for (i = 0; i < 12; i++) 2530 XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X')); 2531 } 2532