1230587Sken/*- 2230587Sken * Copyright (c) 2009-2011 Spectra Logic Corporation 3230587Sken * All rights reserved. 4230587Sken * 5230587Sken * Redistribution and use in source and binary forms, with or without 6230587Sken * modification, are permitted provided that the following conditions 7230587Sken * are met: 8230587Sken * 1. Redistributions of source code must retain the above copyright 9230587Sken * notice, this list of conditions, and the following disclaimer, 10230587Sken * without modification. 11230587Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12230587Sken * substantially similar to the "NO WARRANTY" disclaimer below 13230587Sken * ("Disclaimer") and any redistribution must be conditioned upon 14230587Sken * including a substantially similar Disclaimer requirement for further 15230587Sken * binary redistribution. 16230587Sken * 17230587Sken * NO WARRANTY 18230587Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19230587Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20230587Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21230587Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22230587Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23230587Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24230587Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25230587Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26230587Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27230587Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28230587Sken * POSSIBILITY OF SUCH DAMAGES. 29230587Sken * 30230587Sken * Authors: Justin T. Gibbs (Spectra Logic Corporation) 31230587Sken * Alan Somers (Spectra Logic Corporation) 32230587Sken * John Suykerbuyk (Spectra Logic Corporation) 33230587Sken */ 34230587Sken 35230587Sken#include <sys/cdefs.h> 36230587Sken__FBSDID("$FreeBSD: stable/11/sys/dev/xen/netback/netback_unit_tests.c 316362 2017-04-01 16:51:49Z asomers $"); 37230587Sken 38230587Sken/** 39230587Sken * \file netback_unit_tests.c 40230587Sken * 41230587Sken * \brief Unit tests for the Xen netback driver. 42230587Sken * 43230587Sken * Due to the driver's use of static functions, these tests cannot be compiled 44230587Sken * standalone; they must be #include'd from the driver's .c file. 45230587Sken */ 46230587Sken 47230587Sken 48230587Sken/** Helper macro used to snprintf to a buffer and update the buffer pointer */ 49230587Sken#define SNCATF(buffer, buflen, ...) do { \ 50230587Sken size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__); \ 51230587Sken buffer += new_chars; \ 52230587Sken /* be careful; snprintf's return value can be > buflen */ \ 53230587Sken buflen -= MIN(buflen, new_chars); \ 54230587Sken} while (0) 55230587Sken 56230587Sken/* STRINGIFY and TOSTRING are used only to help turn __LINE__ into a string */ 57230587Sken#define STRINGIFY(x) #x 58230587Sken#define TOSTRING(x) STRINGIFY(x) 59230587Sken 60230587Sken/** 61242934Sdim * Writes an error message to buffer if cond is false 62242934Sdim * Note the implied parameters buffer and 63230587Sken * buflen 64230587Sken */ 65242934Sdim#define XNB_ASSERT(cond) ({ \ 66230587Sken int passed = (cond); \ 67230587Sken char *_buffer = (buffer); \ 68230587Sken size_t _buflen = (buflen); \ 69230587Sken if (! passed) { \ 70230587Sken strlcat(_buffer, __func__, _buflen); \ 71230587Sken strlcat(_buffer, ":" TOSTRING(__LINE__) \ 72230587Sken " Assertion Error: " #cond "\n", _buflen); \ 73230587Sken } \ 74242934Sdim }) 75230587Sken 76230587Sken 77230587Sken/** 78230587Sken * The signature used by all testcases. If the test writes anything 79230587Sken * to buffer, then it will be considered a failure 80230587Sken * \param buffer Return storage for error messages 81230587Sken * \param buflen The space available in the buffer 82230587Sken */ 83230587Skentypedef void testcase_t(char *buffer, size_t buflen); 84230587Sken 85230587Sken/** 86230587Sken * Signature used by setup functions 87230587Sken * \return nonzero on error 88230587Sken */ 89230587Skentypedef int setup_t(void); 90230587Sken 91230587Skentypedef void teardown_t(void); 92230587Sken 93230587Sken/** A simple test fixture comprising setup, teardown, and test */ 94230587Skenstruct test_fixture { 95230587Sken /** Will be run before the test to allocate and initialize variables */ 96230587Sken setup_t *setup; 97230587Sken 98230587Sken /** Will be run if setup succeeds */ 99230587Sken testcase_t *test; 100230587Sken 101298955Spfg /** Cleans up test data whether or not the setup succeeded */ 102230587Sken teardown_t *teardown; 103230587Sken}; 104230587Sken 105230587Skentypedef struct test_fixture test_fixture_t; 106230587Sken 107230587Skenstatic int xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags); 108230587Skenstatic int xnb_unit_test_runner(test_fixture_t const tests[], int ntests, 109230587Sken char *buffer, size_t buflen); 110230587Sken 111230587Skenstatic int __unused 112230587Skennull_setup(void) { return 0; } 113230587Sken 114230587Skenstatic void __unused 115230587Skennull_teardown(void) { } 116230587Sken 117230587Skenstatic setup_t setup_pvt_data; 118230587Skenstatic teardown_t teardown_pvt_data; 119230587Skenstatic testcase_t xnb_ring2pkt_emptyring; 120230587Skenstatic testcase_t xnb_ring2pkt_1req; 121230587Skenstatic testcase_t xnb_ring2pkt_2req; 122230587Skenstatic testcase_t xnb_ring2pkt_3req; 123230587Skenstatic testcase_t xnb_ring2pkt_extra; 124230587Skenstatic testcase_t xnb_ring2pkt_partial; 125230587Skenstatic testcase_t xnb_ring2pkt_wraps; 126230587Skenstatic testcase_t xnb_txpkt2rsp_emptypkt; 127230587Skenstatic testcase_t xnb_txpkt2rsp_1req; 128230587Skenstatic testcase_t xnb_txpkt2rsp_extra; 129230587Skenstatic testcase_t xnb_txpkt2rsp_long; 130230587Skenstatic testcase_t xnb_txpkt2rsp_invalid; 131230587Skenstatic testcase_t xnb_txpkt2rsp_error; 132230587Skenstatic testcase_t xnb_txpkt2rsp_wraps; 133230587Skenstatic testcase_t xnb_pkt2mbufc_empty; 134230587Skenstatic testcase_t xnb_pkt2mbufc_short; 135230587Skenstatic testcase_t xnb_pkt2mbufc_csum; 136230587Skenstatic testcase_t xnb_pkt2mbufc_1cluster; 137230587Skenstatic testcase_t xnb_pkt2mbufc_largecluster; 138230587Skenstatic testcase_t xnb_pkt2mbufc_2cluster; 139230587Skenstatic testcase_t xnb_txpkt2gnttab_empty; 140230587Skenstatic testcase_t xnb_txpkt2gnttab_short; 141230587Skenstatic testcase_t xnb_txpkt2gnttab_2req; 142230587Skenstatic testcase_t xnb_txpkt2gnttab_2cluster; 143230587Skenstatic testcase_t xnb_update_mbufc_short; 144230587Skenstatic testcase_t xnb_update_mbufc_2req; 145230587Skenstatic testcase_t xnb_update_mbufc_2cluster; 146230587Skenstatic testcase_t xnb_mbufc2pkt_empty; 147230587Skenstatic testcase_t xnb_mbufc2pkt_short; 148230587Skenstatic testcase_t xnb_mbufc2pkt_1cluster; 149230587Skenstatic testcase_t xnb_mbufc2pkt_2short; 150230587Skenstatic testcase_t xnb_mbufc2pkt_long; 151230587Skenstatic testcase_t xnb_mbufc2pkt_extra; 152230587Skenstatic testcase_t xnb_mbufc2pkt_nospace; 153230587Skenstatic testcase_t xnb_rxpkt2gnttab_empty; 154230587Skenstatic testcase_t xnb_rxpkt2gnttab_short; 155230587Skenstatic testcase_t xnb_rxpkt2gnttab_2req; 156230587Skenstatic testcase_t xnb_rxpkt2rsp_empty; 157230587Skenstatic testcase_t xnb_rxpkt2rsp_short; 158230587Skenstatic testcase_t xnb_rxpkt2rsp_extra; 159230587Skenstatic testcase_t xnb_rxpkt2rsp_2short; 160230587Skenstatic testcase_t xnb_rxpkt2rsp_2slots; 161230587Skenstatic testcase_t xnb_rxpkt2rsp_copyerror; 162257515Sglebiusstatic testcase_t xnb_sscanf_llu; 163257515Sglebiusstatic testcase_t xnb_sscanf_lld; 164257515Sglebiusstatic testcase_t xnb_sscanf_hhu; 165257515Sglebiusstatic testcase_t xnb_sscanf_hhd; 166257515Sglebiusstatic testcase_t xnb_sscanf_hhn; 167257515Sglebius 168257515Sglebius#if defined(INET) || defined(INET6) 169230587Sken/* TODO: add test cases for xnb_add_mbuf_cksum for IPV6 tcp and udp */ 170230587Skenstatic testcase_t xnb_add_mbuf_cksum_arp; 171230587Skenstatic testcase_t xnb_add_mbuf_cksum_tcp; 172230587Skenstatic testcase_t xnb_add_mbuf_cksum_udp; 173230587Skenstatic testcase_t xnb_add_mbuf_cksum_icmp; 174230587Skenstatic testcase_t xnb_add_mbuf_cksum_tcp_swcksum; 175257515Sglebiusstatic void xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, 176257515Sglebius uint16_t ip_id, uint16_t ip_p, 177257515Sglebius uint16_t ip_off, uint16_t ip_sum); 178257515Sglebiusstatic void xnb_fill_tcp(struct mbuf *m); 179257515Sglebius#endif /* INET || INET6 */ 180230587Sken 181230587Sken/** Private data used by unit tests */ 182230587Skenstatic struct { 183230587Sken gnttab_copy_table gnttab; 184230587Sken netif_rx_back_ring_t rxb; 185230587Sken netif_rx_front_ring_t rxf; 186230587Sken netif_tx_back_ring_t txb; 187230587Sken netif_tx_front_ring_t txf; 188230587Sken struct ifnet* ifp; 189230587Sken netif_rx_sring_t* rxs; 190230587Sken netif_tx_sring_t* txs; 191230587Sken} xnb_unit_pvt; 192230587Sken 193230587Skenstatic inline void safe_m_freem(struct mbuf **ppMbuf) { 194230587Sken if (*ppMbuf != NULL) { 195230587Sken m_freem(*ppMbuf); 196230587Sken *ppMbuf = NULL; 197230587Sken } 198230587Sken} 199230587Sken 200230587Sken/** 201230587Sken * The unit test runner. It will run every supplied test and return an 202230587Sken * output message as a string 203230587Sken * \param tests An array of tests. Every test will be attempted. 204230587Sken * \param ntests The length of tests 205230587Sken * \param buffer Return storage for the result string 206230587Sken * \param buflen The length of buffer 207230587Sken * \return The number of tests that failed 208230587Sken */ 209230587Skenstatic int 210230587Skenxnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer, 211230587Sken size_t buflen) 212230587Sken{ 213230587Sken int i; 214230587Sken int n_passes; 215230587Sken int n_failures = 0; 216230587Sken 217230587Sken for (i = 0; i < ntests; i++) { 218230587Sken int error = tests[i].setup(); 219230587Sken if (error != 0) { 220230587Sken SNCATF(buffer, buflen, 221230587Sken "Setup failed for test idx %d\n", i); 222230587Sken n_failures++; 223230587Sken } else { 224230587Sken size_t new_chars; 225230587Sken 226230587Sken tests[i].test(buffer, buflen); 227230587Sken new_chars = strnlen(buffer, buflen); 228230587Sken buffer += new_chars; 229230587Sken buflen -= new_chars; 230230587Sken 231230587Sken if (new_chars > 0) { 232230587Sken n_failures++; 233230587Sken } 234230587Sken } 235230587Sken tests[i].teardown(); 236230587Sken } 237230587Sken 238230587Sken n_passes = ntests - n_failures; 239230587Sken if (n_passes > 0) { 240230587Sken SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes); 241230587Sken } 242230587Sken if (n_failures > 0) { 243230587Sken SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures); 244230587Sken } 245230587Sken 246230587Sken return n_failures; 247230587Sken} 248230587Sken 249230587Sken/** Number of unit tests. Must match the length of the tests array below */ 250230587Sken#define TOTAL_TESTS (53) 251230587Sken/** 252230587Sken * Max memory available for returning results. 400 chars/test should give 253230587Sken * enough space for a five line error message for every test 254230587Sken */ 255230587Sken#define TOTAL_BUFLEN (400 * TOTAL_TESTS + 2) 256230587Sken 257230587Sken/** 258230587Sken * Called from userspace by a sysctl. Runs all internal unit tests, and 259230587Sken * returns the results to userspace as a string 260230587Sken * \param oidp unused 261230587Sken * \param arg1 pointer to an xnb_softc for a specific xnb device 262230587Sken * \param arg2 unused 263230587Sken * \param req sysctl access structure 264230587Sken * \return a string via the special SYSCTL_OUT macro. 265230587Sken */ 266230587Sken 267230587Skenstatic int 268230587Skenxnb_unit_test_main(SYSCTL_HANDLER_ARGS) { 269230587Sken test_fixture_t const tests[TOTAL_TESTS] = { 270230587Sken {setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data}, 271230587Sken {setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data}, 272230587Sken {setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data}, 273230587Sken {setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data}, 274230587Sken {setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data}, 275230587Sken {setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data}, 276230587Sken {setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data}, 277230587Sken {setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data}, 278230587Sken {setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data}, 279230587Sken {setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data}, 280230587Sken {setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data}, 281230587Sken {setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data}, 282230587Sken {setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data}, 283230587Sken {setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data}, 284230587Sken {setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data}, 285230587Sken {setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data}, 286230587Sken {setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data}, 287230587Sken {setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data}, 288230587Sken {setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data}, 289230587Sken {setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data}, 290230587Sken {setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data}, 291230587Sken {setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data}, 292230587Sken {setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data}, 293230587Sken {setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data}, 294230587Sken {setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data}, 295230587Sken {setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data}, 296230587Sken {setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data}, 297230587Sken {setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data}, 298230587Sken {setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data}, 299230587Sken {setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data}, 300230587Sken {setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data}, 301230587Sken {setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data}, 302230587Sken {setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data}, 303230587Sken {setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data}, 304230587Sken {setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data}, 305230587Sken {setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data}, 306230587Sken {setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data}, 307230587Sken {setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data}, 308230587Sken {setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data}, 309230587Sken {setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data}, 310230587Sken {setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data}, 311230587Sken {setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data}, 312230587Sken {setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data}, 313257515Sglebius#if defined(INET) || defined(INET6) 314230587Sken {null_setup, xnb_add_mbuf_cksum_arp, null_teardown}, 315230587Sken {null_setup, xnb_add_mbuf_cksum_icmp, null_teardown}, 316230587Sken {null_setup, xnb_add_mbuf_cksum_tcp, null_teardown}, 317230587Sken {null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown}, 318230587Sken {null_setup, xnb_add_mbuf_cksum_udp, null_teardown}, 319257515Sglebius#endif 320230587Sken {null_setup, xnb_sscanf_hhd, null_teardown}, 321230587Sken {null_setup, xnb_sscanf_hhu, null_teardown}, 322230587Sken {null_setup, xnb_sscanf_lld, null_teardown}, 323230587Sken {null_setup, xnb_sscanf_llu, null_teardown}, 324230587Sken {null_setup, xnb_sscanf_hhn, null_teardown}, 325230587Sken }; 326230587Sken /** 327230587Sken * results is static so that the data will persist after this function 328230587Sken * returns. The sysctl code expects us to return a constant string. 329230587Sken * \todo: the static variable is not thread safe. Put a mutex around 330230587Sken * it. 331230587Sken */ 332230587Sken static char results[TOTAL_BUFLEN]; 333230587Sken 334230587Sken /* empty the result strings */ 335230587Sken results[0] = 0; 336230587Sken xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN); 337230587Sken 338230587Sken return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN))); 339230587Sken} 340230587Sken 341230587Skenstatic int 342230587Skensetup_pvt_data(void) 343230587Sken{ 344230587Sken int error = 0; 345230587Sken 346230587Sken bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab)); 347230587Sken 348230587Sken xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO); 349230587Sken if (xnb_unit_pvt.txs != NULL) { 350230587Sken SHARED_RING_INIT(xnb_unit_pvt.txs); 351230587Sken BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE); 352230587Sken FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE); 353230587Sken } else { 354230587Sken error = 1; 355230587Sken } 356230587Sken 357230587Sken xnb_unit_pvt.ifp = if_alloc(IFT_ETHER); 358230587Sken if (xnb_unit_pvt.ifp == NULL) { 359230587Sken error = 1; 360230587Sken } 361230587Sken 362230587Sken xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO); 363230587Sken if (xnb_unit_pvt.rxs != NULL) { 364230587Sken SHARED_RING_INIT(xnb_unit_pvt.rxs); 365230587Sken BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE); 366230587Sken FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE); 367230587Sken } else { 368230587Sken error = 1; 369230587Sken } 370230587Sken 371230587Sken return error; 372230587Sken} 373230587Sken 374230587Skenstatic void 375230587Skenteardown_pvt_data(void) 376230587Sken{ 377230587Sken if (xnb_unit_pvt.txs != NULL) { 378230587Sken free(xnb_unit_pvt.txs, M_XENNETBACK); 379230587Sken } 380230587Sken if (xnb_unit_pvt.rxs != NULL) { 381230587Sken free(xnb_unit_pvt.rxs, M_XENNETBACK); 382230587Sken } 383230587Sken if (xnb_unit_pvt.ifp != NULL) { 384230587Sken if_free(xnb_unit_pvt.ifp); 385230587Sken } 386230587Sken} 387230587Sken 388230587Sken/** 389230587Sken * Verify that xnb_ring2pkt will not consume any requests from an empty ring 390230587Sken */ 391230587Skenstatic void 392230587Skenxnb_ring2pkt_emptyring(char *buffer, size_t buflen) 393230587Sken{ 394230587Sken struct xnb_pkt pkt; 395230587Sken int num_consumed; 396230587Sken 397230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 398230587Sken xnb_unit_pvt.txb.req_cons); 399230587Sken XNB_ASSERT(num_consumed == 0); 400230587Sken} 401230587Sken 402230587Sken/** 403230587Sken * Verify that xnb_ring2pkt can convert a single request packet correctly 404230587Sken */ 405230587Skenstatic void 406230587Skenxnb_ring2pkt_1req(char *buffer, size_t buflen) 407230587Sken{ 408230587Sken struct xnb_pkt pkt; 409230587Sken int num_consumed; 410230587Sken struct netif_tx_request *req; 411230587Sken 412230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 413230587Sken xnb_unit_pvt.txf.req_prod_pvt); 414230587Sken 415230587Sken req->flags = 0; 416230587Sken req->size = 69; /* arbitrary number for test */ 417230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 418230587Sken 419230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 420230587Sken 421230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 422230587Sken xnb_unit_pvt.txb.req_cons); 423230587Sken XNB_ASSERT(num_consumed == 1); 424230587Sken XNB_ASSERT(pkt.size == 69); 425230587Sken XNB_ASSERT(pkt.car_size == 69); 426230587Sken XNB_ASSERT(pkt.flags == 0); 427230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 428230587Sken XNB_ASSERT(pkt.list_len == 1); 429230587Sken XNB_ASSERT(pkt.car == 0); 430230587Sken} 431230587Sken 432230587Sken/** 433230587Sken * Verify that xnb_ring2pkt can convert a two request packet correctly. 434230587Sken * This tests handling of the MORE_DATA flag and cdr 435230587Sken */ 436230587Skenstatic void 437230587Skenxnb_ring2pkt_2req(char *buffer, size_t buflen) 438230587Sken{ 439230587Sken struct xnb_pkt pkt; 440230587Sken int num_consumed; 441230587Sken struct netif_tx_request *req; 442230587Sken RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt; 443230587Sken 444230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 445230587Sken xnb_unit_pvt.txf.req_prod_pvt); 446230587Sken req->flags = NETTXF_more_data; 447230587Sken req->size = 100; 448230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 449230587Sken 450230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 451230587Sken xnb_unit_pvt.txf.req_prod_pvt); 452230587Sken req->flags = 0; 453230587Sken req->size = 40; 454230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 455230587Sken 456230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 457230587Sken 458230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 459230587Sken xnb_unit_pvt.txb.req_cons); 460230587Sken XNB_ASSERT(num_consumed == 2); 461230587Sken XNB_ASSERT(pkt.size == 100); 462230587Sken XNB_ASSERT(pkt.car_size == 60); 463230587Sken XNB_ASSERT(pkt.flags == 0); 464230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 465230587Sken XNB_ASSERT(pkt.list_len == 2); 466230587Sken XNB_ASSERT(pkt.car == start_idx); 467230587Sken XNB_ASSERT(pkt.cdr == start_idx + 1); 468230587Sken} 469230587Sken 470230587Sken/** 471230587Sken * Verify that xnb_ring2pkt can convert a three request packet correctly 472230587Sken */ 473230587Skenstatic void 474230587Skenxnb_ring2pkt_3req(char *buffer, size_t buflen) 475230587Sken{ 476230587Sken struct xnb_pkt pkt; 477230587Sken int num_consumed; 478230587Sken struct netif_tx_request *req; 479230587Sken RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt; 480230587Sken 481230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 482230587Sken xnb_unit_pvt.txf.req_prod_pvt); 483230587Sken req->flags = NETTXF_more_data; 484230587Sken req->size = 200; 485230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 486230587Sken 487230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 488230587Sken xnb_unit_pvt.txf.req_prod_pvt); 489230587Sken req->flags = NETTXF_more_data; 490230587Sken req->size = 40; 491230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 492230587Sken 493230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 494230587Sken xnb_unit_pvt.txf.req_prod_pvt); 495230587Sken req->flags = 0; 496230587Sken req->size = 50; 497230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 498230587Sken 499230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 500230587Sken 501230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 502230587Sken xnb_unit_pvt.txb.req_cons); 503230587Sken XNB_ASSERT(num_consumed == 3); 504230587Sken XNB_ASSERT(pkt.size == 200); 505230587Sken XNB_ASSERT(pkt.car_size == 110); 506230587Sken XNB_ASSERT(pkt.flags == 0); 507230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 508230587Sken XNB_ASSERT(pkt.list_len == 3); 509230587Sken XNB_ASSERT(pkt.car == start_idx); 510230587Sken XNB_ASSERT(pkt.cdr == start_idx + 1); 511230587Sken XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req); 512230587Sken} 513230587Sken 514230587Sken/** 515230587Sken * Verify that xnb_ring2pkt can read extra inf 516230587Sken */ 517230587Skenstatic void 518230587Skenxnb_ring2pkt_extra(char *buffer, size_t buflen) 519230587Sken{ 520230587Sken struct xnb_pkt pkt; 521230587Sken int num_consumed; 522230587Sken struct netif_tx_request *req; 523230587Sken struct netif_extra_info *ext; 524230587Sken RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt; 525230587Sken 526230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 527230587Sken xnb_unit_pvt.txf.req_prod_pvt); 528230587Sken req->flags = NETTXF_extra_info | NETTXF_more_data; 529230587Sken req->size = 150; 530230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 531230587Sken 532230587Sken ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 533230587Sken xnb_unit_pvt.txf.req_prod_pvt); 534230587Sken ext->flags = 0; 535230587Sken ext->type = XEN_NETIF_EXTRA_TYPE_GSO; 536230587Sken ext->u.gso.size = 250; 537230587Sken ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; 538230587Sken ext->u.gso.features = 0; 539230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 540230587Sken 541230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 542230587Sken xnb_unit_pvt.txf.req_prod_pvt); 543230587Sken req->flags = 0; 544230587Sken req->size = 50; 545230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 546230587Sken 547230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 548230587Sken 549230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 550230587Sken xnb_unit_pvt.txb.req_cons); 551230587Sken XNB_ASSERT(num_consumed == 3); 552230587Sken XNB_ASSERT(pkt.extra.flags == 0); 553230587Sken XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO); 554230587Sken XNB_ASSERT(pkt.extra.u.gso.size == 250); 555230587Sken XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4); 556230587Sken XNB_ASSERT(pkt.size == 150); 557230587Sken XNB_ASSERT(pkt.car_size == 100); 558230587Sken XNB_ASSERT(pkt.flags == NETTXF_extra_info); 559230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 560230587Sken XNB_ASSERT(pkt.list_len == 2); 561230587Sken XNB_ASSERT(pkt.car == start_idx); 562230587Sken XNB_ASSERT(pkt.cdr == start_idx + 2); 563230587Sken XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req); 564230587Sken} 565230587Sken 566230587Sken/** 567230587Sken * Verify that xnb_ring2pkt will consume no requests if the entire packet is 568230587Sken * not yet in the ring 569230587Sken */ 570230587Skenstatic void 571230587Skenxnb_ring2pkt_partial(char *buffer, size_t buflen) 572230587Sken{ 573230587Sken struct xnb_pkt pkt; 574230587Sken int num_consumed; 575230587Sken struct netif_tx_request *req; 576230587Sken 577230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 578230587Sken xnb_unit_pvt.txf.req_prod_pvt); 579230587Sken req->flags = NETTXF_more_data; 580230587Sken req->size = 150; 581230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 582230587Sken 583230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 584230587Sken 585230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 586230587Sken xnb_unit_pvt.txb.req_cons); 587230587Sken XNB_ASSERT(num_consumed == 0); 588230587Sken XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 589230587Sken} 590230587Sken 591230587Sken/** 592230587Sken * Verity that xnb_ring2pkt can read a packet whose requests wrap around 593230587Sken * the end of the ring 594230587Sken */ 595230587Skenstatic void 596230587Skenxnb_ring2pkt_wraps(char *buffer, size_t buflen) 597230587Sken{ 598230587Sken struct xnb_pkt pkt; 599230587Sken int num_consumed; 600230587Sken struct netif_tx_request *req; 601230587Sken unsigned int rsize; 602230587Sken 603230587Sken /* 604230587Sken * Manually tweak the ring indices to create a ring with no responses 605230587Sken * and the next request slot at position 2 from the end 606230587Sken */ 607230587Sken rsize = RING_SIZE(&xnb_unit_pvt.txf); 608230587Sken xnb_unit_pvt.txf.req_prod_pvt = rsize - 2; 609230587Sken xnb_unit_pvt.txf.rsp_cons = rsize - 2; 610230587Sken xnb_unit_pvt.txs->req_prod = rsize - 2; 611230587Sken xnb_unit_pvt.txs->req_event = rsize - 1; 612230587Sken xnb_unit_pvt.txs->rsp_prod = rsize - 2; 613230587Sken xnb_unit_pvt.txs->rsp_event = rsize - 1; 614230587Sken xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2; 615230587Sken xnb_unit_pvt.txb.req_cons = rsize - 2; 616230587Sken 617230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 618230587Sken xnb_unit_pvt.txf.req_prod_pvt); 619230587Sken req->flags = NETTXF_more_data; 620230587Sken req->size = 550; 621230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 622230587Sken 623230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 624230587Sken xnb_unit_pvt.txf.req_prod_pvt); 625230587Sken req->flags = NETTXF_more_data; 626230587Sken req->size = 100; 627230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 628230587Sken 629230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 630230587Sken xnb_unit_pvt.txf.req_prod_pvt); 631230587Sken req->flags = 0; 632230587Sken req->size = 50; 633230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 634230587Sken 635230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 636230587Sken 637230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 638230587Sken xnb_unit_pvt.txb.req_cons); 639230587Sken XNB_ASSERT(num_consumed == 3); 640230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 641230587Sken XNB_ASSERT(pkt.list_len == 3); 642230587Sken XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req); 643230587Sken} 644230587Sken 645230587Sken 646230587Sken/** 647230587Sken * xnb_txpkt2rsp should do nothing for an empty packet 648230587Sken */ 649230587Skenstatic void 650230587Skenxnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen) 651230587Sken{ 652230587Sken int num_consumed; 653230587Sken struct xnb_pkt pkt; 654230587Sken netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb; 655230587Sken netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs; 656230587Sken pkt.list_len = 0; 657230587Sken 658230587Sken /* must call xnb_ring2pkt just to intialize pkt */ 659230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 660230587Sken xnb_unit_pvt.txb.req_cons); 661230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 662230587Sken XNB_ASSERT( 663230587Sken memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0); 664230587Sken XNB_ASSERT( 665230587Sken memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0); 666230587Sken} 667230587Sken 668230587Sken/** 669230587Sken * xnb_txpkt2rsp responding to one request 670230587Sken */ 671230587Skenstatic void 672230587Skenxnb_txpkt2rsp_1req(char *buffer, size_t buflen) 673230587Sken{ 674230587Sken uint16_t num_consumed; 675230587Sken struct xnb_pkt pkt; 676230587Sken struct netif_tx_request *req; 677230587Sken struct netif_tx_response *rsp; 678230587Sken 679230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 680230587Sken xnb_unit_pvt.txf.req_prod_pvt); 681230587Sken req->size = 1000; 682230587Sken req->flags = 0; 683230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 684230587Sken 685230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 686230587Sken 687230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 688230587Sken xnb_unit_pvt.txb.req_cons); 689230587Sken xnb_unit_pvt.txb.req_cons += num_consumed; 690230587Sken 691230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 692230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 693230587Sken 694230587Sken XNB_ASSERT( 695230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 696230587Sken XNB_ASSERT(rsp->id == req->id); 697230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 698230587Sken}; 699230587Sken 700230587Sken/** 701230587Sken * xnb_txpkt2rsp responding to 1 data request and 1 extra info 702230587Sken */ 703230587Skenstatic void 704230587Skenxnb_txpkt2rsp_extra(char *buffer, size_t buflen) 705230587Sken{ 706230587Sken uint16_t num_consumed; 707230587Sken struct xnb_pkt pkt; 708230587Sken struct netif_tx_request *req; 709230587Sken netif_extra_info_t *ext; 710230587Sken struct netif_tx_response *rsp; 711230587Sken 712230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 713230587Sken xnb_unit_pvt.txf.req_prod_pvt); 714230587Sken req->size = 1000; 715230587Sken req->flags = NETTXF_extra_info; 716230587Sken req->id = 69; 717230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 718230587Sken 719230587Sken ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 720230587Sken xnb_unit_pvt.txf.req_prod_pvt); 721230587Sken ext->type = XEN_NETIF_EXTRA_TYPE_GSO; 722230587Sken ext->flags = 0; 723230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 724230587Sken 725230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 726230587Sken 727230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 728230587Sken xnb_unit_pvt.txb.req_cons); 729230587Sken xnb_unit_pvt.txb.req_cons += num_consumed; 730230587Sken 731230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 732230587Sken 733230587Sken XNB_ASSERT( 734230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 735230587Sken 736230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 737230587Sken XNB_ASSERT(rsp->id == req->id); 738230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 739230587Sken 740230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 741230587Sken xnb_unit_pvt.txf.rsp_cons + 1); 742230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 743230587Sken}; 744230587Sken 745230587Sken/** 746230587Sken * xnb_pkg2rsp responding to 3 data requests and 1 extra info 747230587Sken */ 748230587Skenstatic void 749230587Skenxnb_txpkt2rsp_long(char *buffer, size_t buflen) 750230587Sken{ 751230587Sken uint16_t num_consumed; 752230587Sken struct xnb_pkt pkt; 753230587Sken struct netif_tx_request *req; 754230587Sken netif_extra_info_t *ext; 755230587Sken struct netif_tx_response *rsp; 756230587Sken 757230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 758230587Sken xnb_unit_pvt.txf.req_prod_pvt); 759230587Sken req->size = 1000; 760230587Sken req->flags = NETTXF_extra_info | NETTXF_more_data; 761230587Sken req->id = 254; 762230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 763230587Sken 764230587Sken ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 765230587Sken xnb_unit_pvt.txf.req_prod_pvt); 766230587Sken ext->type = XEN_NETIF_EXTRA_TYPE_GSO; 767230587Sken ext->flags = 0; 768230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 769230587Sken 770230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 771230587Sken xnb_unit_pvt.txf.req_prod_pvt); 772230587Sken req->size = 300; 773230587Sken req->flags = NETTXF_more_data; 774230587Sken req->id = 1034; 775230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 776230587Sken 777230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 778230587Sken xnb_unit_pvt.txf.req_prod_pvt); 779230587Sken req->size = 400; 780230587Sken req->flags = 0; 781230587Sken req->id = 34; 782230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 783230587Sken 784230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 785230587Sken 786230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 787230587Sken xnb_unit_pvt.txb.req_cons); 788230587Sken xnb_unit_pvt.txb.req_cons += num_consumed; 789230587Sken 790230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 791230587Sken 792230587Sken XNB_ASSERT( 793230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 794230587Sken 795230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 796230587Sken XNB_ASSERT(rsp->id == 797230587Sken RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id); 798230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 799230587Sken 800230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 801230587Sken xnb_unit_pvt.txf.rsp_cons + 1); 802230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 803230587Sken 804230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 805230587Sken xnb_unit_pvt.txf.rsp_cons + 2); 806230587Sken XNB_ASSERT(rsp->id == 807230587Sken RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id); 808230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 809230587Sken 810230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 811230587Sken xnb_unit_pvt.txf.rsp_cons + 3); 812230587Sken XNB_ASSERT(rsp->id == 813230587Sken RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id); 814230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 815230587Sken} 816230587Sken 817230587Sken/** 818230587Sken * xnb_txpkt2rsp responding to an invalid packet. 819230587Sken * Note: this test will result in an error message being printed to the console 820230587Sken * such as: 821230587Sken * xnb(xnb_ring2pkt:1306): Unknown extra info type 255. Discarding packet 822230587Sken */ 823230587Skenstatic void 824230587Skenxnb_txpkt2rsp_invalid(char *buffer, size_t buflen) 825230587Sken{ 826230587Sken uint16_t num_consumed; 827230587Sken struct xnb_pkt pkt; 828230587Sken struct netif_tx_request *req; 829230587Sken netif_extra_info_t *ext; 830230587Sken struct netif_tx_response *rsp; 831230587Sken 832230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 833230587Sken xnb_unit_pvt.txf.req_prod_pvt); 834230587Sken req->size = 1000; 835230587Sken req->flags = NETTXF_extra_info; 836230587Sken req->id = 69; 837230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 838230587Sken 839230587Sken ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf, 840230587Sken xnb_unit_pvt.txf.req_prod_pvt); 841230587Sken ext->type = 0xFF; /* Invalid extra type */ 842230587Sken ext->flags = 0; 843230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 844230587Sken 845230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 846230587Sken 847230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 848230587Sken xnb_unit_pvt.txb.req_cons); 849230587Sken xnb_unit_pvt.txb.req_cons += num_consumed; 850230587Sken XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 851230587Sken 852230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 853230587Sken 854230587Sken XNB_ASSERT( 855230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 856230587Sken 857230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 858230587Sken XNB_ASSERT(rsp->id == req->id); 859230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 860230587Sken 861230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 862230587Sken xnb_unit_pvt.txf.rsp_cons + 1); 863230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_NULL); 864230587Sken}; 865230587Sken 866230587Sken/** 867230587Sken * xnb_txpkt2rsp responding to one request which caused an error 868230587Sken */ 869230587Skenstatic void 870230587Skenxnb_txpkt2rsp_error(char *buffer, size_t buflen) 871230587Sken{ 872230587Sken uint16_t num_consumed; 873230587Sken struct xnb_pkt pkt; 874230587Sken struct netif_tx_request *req; 875230587Sken struct netif_tx_response *rsp; 876230587Sken 877230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 878230587Sken xnb_unit_pvt.txf.req_prod_pvt); 879230587Sken req->size = 1000; 880230587Sken req->flags = 0; 881230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 882230587Sken 883230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 884230587Sken 885230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 886230587Sken xnb_unit_pvt.txb.req_cons); 887230587Sken xnb_unit_pvt.txb.req_cons += num_consumed; 888230587Sken 889230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1); 890230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons); 891230587Sken 892230587Sken XNB_ASSERT( 893230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 894230587Sken XNB_ASSERT(rsp->id == req->id); 895230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 896230587Sken}; 897230587Sken 898230587Sken/** 899230587Sken * xnb_txpkt2rsp's responses wrap around the end of the ring 900230587Sken */ 901230587Skenstatic void 902230587Skenxnb_txpkt2rsp_wraps(char *buffer, size_t buflen) 903230587Sken{ 904230587Sken struct xnb_pkt pkt; 905230587Sken int num_consumed; 906230587Sken struct netif_tx_request *req; 907230587Sken struct netif_tx_response *rsp; 908230587Sken unsigned int rsize; 909230587Sken 910230587Sken /* 911230587Sken * Manually tweak the ring indices to create a ring with no responses 912230587Sken * and the next request slot at position 2 from the end 913230587Sken */ 914230587Sken rsize = RING_SIZE(&xnb_unit_pvt.txf); 915230587Sken xnb_unit_pvt.txf.req_prod_pvt = rsize - 2; 916230587Sken xnb_unit_pvt.txf.rsp_cons = rsize - 2; 917230587Sken xnb_unit_pvt.txs->req_prod = rsize - 2; 918230587Sken xnb_unit_pvt.txs->req_event = rsize - 1; 919230587Sken xnb_unit_pvt.txs->rsp_prod = rsize - 2; 920230587Sken xnb_unit_pvt.txs->rsp_event = rsize - 1; 921230587Sken xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2; 922230587Sken xnb_unit_pvt.txb.req_cons = rsize - 2; 923230587Sken 924230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 925230587Sken xnb_unit_pvt.txf.req_prod_pvt); 926230587Sken req->flags = NETTXF_more_data; 927230587Sken req->size = 550; 928230587Sken req->id = 1; 929230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 930230587Sken 931230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 932230587Sken xnb_unit_pvt.txf.req_prod_pvt); 933230587Sken req->flags = NETTXF_more_data; 934230587Sken req->size = 100; 935230587Sken req->id = 2; 936230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 937230587Sken 938230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 939230587Sken xnb_unit_pvt.txf.req_prod_pvt); 940230587Sken req->flags = 0; 941230587Sken req->size = 50; 942230587Sken req->id = 3; 943230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 944230587Sken 945230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 946230587Sken 947230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 948230587Sken xnb_unit_pvt.txb.req_cons); 949230587Sken 950230587Sken xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0); 951230587Sken 952230587Sken XNB_ASSERT( 953230587Sken xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod); 954230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, 955230587Sken xnb_unit_pvt.txf.rsp_cons + 2); 956230587Sken XNB_ASSERT(rsp->id == req->id); 957230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_OKAY); 958230587Sken} 959230587Sken 960230587Sken 961230587Sken/** 962230587Sken * Helper function used to setup pkt2mbufc tests 963230587Sken * \param size size in bytes of the single request to push to the ring 964230587Sken * \param flags optional flags to put in the netif request 965230587Sken * \param[out] pkt the returned packet object 966230587Sken * \return number of requests consumed from the ring 967230587Sken */ 968230587Skenstatic int 969230587Skenxnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags) 970230587Sken{ 971230587Sken struct netif_tx_request *req; 972230587Sken 973230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 974230587Sken xnb_unit_pvt.txf.req_prod_pvt); 975230587Sken req->flags = flags; 976230587Sken req->size = size; 977230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 978230587Sken 979230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 980230587Sken 981230587Sken return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb, 982230587Sken xnb_unit_pvt.txb.req_cons); 983230587Sken} 984230587Sken 985230587Sken/** 986230587Sken * xnb_pkt2mbufc on an empty packet 987230587Sken */ 988230587Skenstatic void 989230587Skenxnb_pkt2mbufc_empty(char *buffer, size_t buflen) 990230587Sken{ 991230587Sken int num_consumed; 992230587Sken struct xnb_pkt pkt; 993230587Sken struct mbuf *pMbuf; 994230587Sken pkt.list_len = 0; 995230587Sken 996230587Sken /* must call xnb_ring2pkt just to intialize pkt */ 997230587Sken num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, 998230587Sken xnb_unit_pvt.txb.req_cons); 999230587Sken pkt.size = 0; 1000230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1001230587Sken safe_m_freem(&pMbuf); 1002230587Sken} 1003230587Sken 1004230587Sken/** 1005230587Sken * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer 1006230587Sken */ 1007230587Skenstatic void 1008230587Skenxnb_pkt2mbufc_short(char *buffer, size_t buflen) 1009230587Sken{ 1010230587Sken const size_t size = MINCLSIZE - 1; 1011230587Sken struct xnb_pkt pkt; 1012230587Sken struct mbuf *pMbuf; 1013230587Sken 1014230587Sken xnb_get1pkt(&pkt, size, 0); 1015230587Sken 1016230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1017230587Sken XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1018230587Sken safe_m_freem(&pMbuf); 1019230587Sken} 1020230587Sken 1021230587Sken/** 1022230587Sken * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron 1023230587Sken */ 1024230587Skenstatic void 1025230587Skenxnb_pkt2mbufc_csum(char *buffer, size_t buflen) 1026230587Sken{ 1027230587Sken const size_t size = MINCLSIZE - 1; 1028230587Sken struct xnb_pkt pkt; 1029230587Sken struct mbuf *pMbuf; 1030230587Sken 1031230587Sken xnb_get1pkt(&pkt, size, NETTXF_data_validated); 1032230587Sken 1033230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1034230587Sken XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1035230587Sken XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED); 1036230587Sken XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID); 1037230587Sken XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID); 1038230587Sken XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR); 1039230587Sken safe_m_freem(&pMbuf); 1040230587Sken} 1041230587Sken 1042230587Sken/** 1043230587Sken * xnb_pkt2mbufc on packet that can fit in one cluster 1044230587Sken */ 1045230587Skenstatic void 1046230587Skenxnb_pkt2mbufc_1cluster(char *buffer, size_t buflen) 1047230587Sken{ 1048230587Sken const size_t size = MINCLSIZE; 1049230587Sken struct xnb_pkt pkt; 1050230587Sken struct mbuf *pMbuf; 1051230587Sken 1052230587Sken xnb_get1pkt(&pkt, size, 0); 1053230587Sken 1054230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1055230587Sken XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1056230587Sken safe_m_freem(&pMbuf); 1057230587Sken} 1058230587Sken 1059230587Sken/** 1060230587Sken * xnb_pkt2mbufc on packet that cannot fit in one regular cluster 1061230587Sken */ 1062230587Skenstatic void 1063230587Skenxnb_pkt2mbufc_largecluster(char *buffer, size_t buflen) 1064230587Sken{ 1065230587Sken const size_t size = MCLBYTES + 1; 1066230587Sken struct xnb_pkt pkt; 1067230587Sken struct mbuf *pMbuf; 1068230587Sken 1069230587Sken xnb_get1pkt(&pkt, size, 0); 1070230587Sken 1071230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1072230587Sken XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size); 1073230587Sken safe_m_freem(&pMbuf); 1074230587Sken} 1075230587Sken 1076230587Sken/** 1077230587Sken * xnb_pkt2mbufc on packet that cannot fit in one clusters 1078230587Sken */ 1079230587Skenstatic void 1080230587Skenxnb_pkt2mbufc_2cluster(char *buffer, size_t buflen) 1081230587Sken{ 1082230587Sken const size_t size = 2 * MCLBYTES + 1; 1083230587Sken size_t space = 0; 1084230587Sken struct xnb_pkt pkt; 1085230587Sken struct mbuf *pMbuf; 1086230587Sken struct mbuf *m; 1087230587Sken 1088230587Sken xnb_get1pkt(&pkt, size, 0); 1089230587Sken 1090230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1091230587Sken 1092230587Sken for (m = pMbuf; m != NULL; m = m->m_next) { 1093230587Sken space += M_TRAILINGSPACE(m); 1094230587Sken } 1095230587Sken XNB_ASSERT(space >= size); 1096230587Sken safe_m_freem(&pMbuf); 1097230587Sken} 1098230587Sken 1099230587Sken/** 1100230587Sken * xnb_txpkt2gnttab on an empty packet. Should return empty gnttab 1101230587Sken */ 1102230587Skenstatic void 1103230587Skenxnb_txpkt2gnttab_empty(char *buffer, size_t buflen) 1104230587Sken{ 1105230587Sken int n_entries; 1106230587Sken struct xnb_pkt pkt; 1107230587Sken struct mbuf *pMbuf; 1108230587Sken pkt.list_len = 0; 1109230587Sken 1110230587Sken /* must call xnb_ring2pkt just to intialize pkt */ 1111230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1112230587Sken pkt.size = 0; 1113230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1114230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1115230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1116230587Sken XNB_ASSERT(n_entries == 0); 1117230587Sken safe_m_freem(&pMbuf); 1118230587Sken} 1119230587Sken 1120230587Sken/** 1121230587Sken * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer 1122230587Sken * and has one request 1123230587Sken */ 1124230587Skenstatic void 1125230587Skenxnb_txpkt2gnttab_short(char *buffer, size_t buflen) 1126230587Sken{ 1127230587Sken const size_t size = MINCLSIZE - 1; 1128230587Sken int n_entries; 1129230587Sken struct xnb_pkt pkt; 1130230587Sken struct mbuf *pMbuf; 1131230587Sken 1132230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1133230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1134230587Sken req->flags = 0; 1135230587Sken req->size = size; 1136230587Sken req->gref = 7; 1137230587Sken req->offset = 17; 1138230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1139230587Sken 1140230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1141230587Sken 1142230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1143230587Sken 1144230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1145230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1146230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1147230587Sken XNB_ASSERT(n_entries == 1); 1148230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size); 1149230587Sken /* flags should indicate gref's for source */ 1150230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref); 1151230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset); 1152230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF); 1153230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1154230587Sken mtod(pMbuf, vm_offset_t))); 1155230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn == 1156230587Sken virt_to_mfn(mtod(pMbuf, vm_offset_t))); 1157230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED); 1158230587Sken safe_m_freem(&pMbuf); 1159230587Sken} 1160230587Sken 1161230587Sken/** 1162230587Sken * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single 1163230587Sken * mbuf cluster 1164230587Sken */ 1165230587Skenstatic void 1166230587Skenxnb_txpkt2gnttab_2req(char *buffer, size_t buflen) 1167230587Sken{ 1168230587Sken int n_entries; 1169230587Sken struct xnb_pkt pkt; 1170230587Sken struct mbuf *pMbuf; 1171230587Sken 1172230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1173230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1174230587Sken req->flags = NETTXF_more_data; 1175230587Sken req->size = 1900; 1176230587Sken req->gref = 7; 1177230587Sken req->offset = 0; 1178230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1179230587Sken 1180230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1181230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1182230587Sken req->flags = 0; 1183230587Sken req->size = 500; 1184230587Sken req->gref = 8; 1185230587Sken req->offset = 0; 1186230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1187230587Sken 1188230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1189230587Sken 1190230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1191230587Sken 1192230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1193230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1194230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1195230587Sken 1196230587Sken XNB_ASSERT(n_entries == 2); 1197230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400); 1198230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1199230587Sken mtod(pMbuf, vm_offset_t))); 1200230587Sken 1201230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500); 1202230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1203230587Sken mtod(pMbuf, vm_offset_t) + 1400)); 1204230587Sken safe_m_freem(&pMbuf); 1205230587Sken} 1206230587Sken 1207230587Sken/** 1208230587Sken * xnb_txpkt2gnttab on a single request that spans two mbuf clusters 1209230587Sken */ 1210230587Skenstatic void 1211230587Skenxnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen) 1212230587Sken{ 1213230587Sken int n_entries; 1214230587Sken struct xnb_pkt pkt; 1215230587Sken struct mbuf *pMbuf; 1216230587Sken const uint16_t data_this_transaction = (MCLBYTES*2) + 1; 1217230587Sken 1218230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1219230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1220230587Sken req->flags = 0; 1221230587Sken req->size = data_this_transaction; 1222230587Sken req->gref = 8; 1223230587Sken req->offset = 0; 1224230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1225230587Sken 1226230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1227230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1228230587Sken 1229230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1230316362Sasomers XNB_ASSERT(pMbuf != NULL); 1231316362Sasomers if (pMbuf == NULL) 1232316362Sasomers return; 1233316362Sasomers 1234230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1235230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1236230587Sken 1237230587Sken if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) { 1238230587Sken /* there should be three mbufs and three gnttab entries */ 1239230587Sken XNB_ASSERT(n_entries == 3); 1240230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES); 1241230587Sken XNB_ASSERT( 1242230587Sken xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1243230587Sken mtod(pMbuf, vm_offset_t))); 1244230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0); 1245230587Sken 1246230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES); 1247230587Sken XNB_ASSERT( 1248230587Sken xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1249230587Sken mtod(pMbuf->m_next, vm_offset_t))); 1250230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES); 1251230587Sken 1252230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1); 1253230587Sken XNB_ASSERT( 1254230587Sken xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset( 1255230587Sken mtod(pMbuf->m_next, vm_offset_t))); 1256230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 * 1257230587Sken MCLBYTES); 1258230587Sken } else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) { 1259230587Sken /* there should be two mbufs and two gnttab entries */ 1260230587Sken XNB_ASSERT(n_entries == 2); 1261230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES); 1262230587Sken XNB_ASSERT( 1263230587Sken xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset( 1264230587Sken mtod(pMbuf, vm_offset_t))); 1265230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0); 1266230587Sken 1267230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1); 1268230587Sken XNB_ASSERT( 1269230587Sken xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset( 1270230587Sken mtod(pMbuf->m_next, vm_offset_t))); 1271230587Sken XNB_ASSERT( 1272230587Sken xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES); 1273230587Sken 1274230587Sken } else { 1275230587Sken /* should never get here */ 1276230587Sken XNB_ASSERT(0); 1277230587Sken } 1278316362Sasomers m_freem(pMbuf); 1279230587Sken} 1280230587Sken 1281230587Sken 1282230587Sken/** 1283230587Sken * xnb_update_mbufc on a short packet that only has one gnttab entry 1284230587Sken */ 1285230587Skenstatic void 1286230587Skenxnb_update_mbufc_short(char *buffer, size_t buflen) 1287230587Sken{ 1288230587Sken const size_t size = MINCLSIZE - 1; 1289230587Sken int n_entries; 1290230587Sken struct xnb_pkt pkt; 1291230587Sken struct mbuf *pMbuf; 1292230587Sken 1293230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1294230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1295230587Sken req->flags = 0; 1296230587Sken req->size = size; 1297230587Sken req->gref = 7; 1298230587Sken req->offset = 17; 1299230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1300230587Sken 1301230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1302230587Sken 1303230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1304230587Sken 1305230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1306230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1307230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1308230587Sken 1309230587Sken /* Update grant table's status fields as the hypervisor call would */ 1310230587Sken xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1311230587Sken 1312230587Sken xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1313230587Sken XNB_ASSERT(pMbuf->m_len == size); 1314230587Sken XNB_ASSERT(pMbuf->m_pkthdr.len == size); 1315230587Sken safe_m_freem(&pMbuf); 1316230587Sken} 1317230587Sken 1318230587Sken/** 1319230587Sken * xnb_update_mbufc on a packet with two requests, that can fit into a single 1320230587Sken * mbuf cluster 1321230587Sken */ 1322230587Skenstatic void 1323230587Skenxnb_update_mbufc_2req(char *buffer, size_t buflen) 1324230587Sken{ 1325230587Sken int n_entries; 1326230587Sken struct xnb_pkt pkt; 1327230587Sken struct mbuf *pMbuf; 1328230587Sken 1329230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1330230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1331230587Sken req->flags = NETTXF_more_data; 1332230587Sken req->size = 1900; 1333230587Sken req->gref = 7; 1334230587Sken req->offset = 0; 1335230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1336230587Sken 1337230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1338230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1339230587Sken req->flags = 0; 1340230587Sken req->size = 500; 1341230587Sken req->gref = 8; 1342230587Sken req->offset = 0; 1343230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1344230587Sken 1345230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1346230587Sken 1347230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1348230587Sken 1349230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1350230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1351230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1352230587Sken 1353230587Sken /* Update grant table's status fields as the hypervisor call would */ 1354230587Sken xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1355230587Sken xnb_unit_pvt.gnttab[1].status = GNTST_okay; 1356230587Sken 1357230587Sken xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1358230587Sken XNB_ASSERT(n_entries == 2); 1359230587Sken XNB_ASSERT(pMbuf->m_pkthdr.len == 1900); 1360230587Sken XNB_ASSERT(pMbuf->m_len == 1900); 1361230587Sken 1362230587Sken safe_m_freem(&pMbuf); 1363230587Sken} 1364230587Sken 1365230587Sken/** 1366230587Sken * xnb_update_mbufc on a single request that spans two mbuf clusters 1367230587Sken */ 1368230587Skenstatic void 1369230587Skenxnb_update_mbufc_2cluster(char *buffer, size_t buflen) 1370230587Sken{ 1371230587Sken int i; 1372230587Sken int n_entries; 1373230587Sken struct xnb_pkt pkt; 1374230587Sken struct mbuf *pMbuf; 1375230587Sken const uint16_t data_this_transaction = (MCLBYTES*2) + 1; 1376230587Sken 1377230587Sken struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf, 1378230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1379230587Sken req->flags = 0; 1380230587Sken req->size = data_this_transaction; 1381230587Sken req->gref = 8; 1382230587Sken req->offset = 0; 1383230587Sken xnb_unit_pvt.txf.req_prod_pvt++; 1384230587Sken 1385230587Sken RING_PUSH_REQUESTS(&xnb_unit_pvt.txf); 1386230587Sken xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons); 1387230587Sken 1388230587Sken pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp); 1389230587Sken n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab, 1390230587Sken &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED); 1391230587Sken 1392230587Sken /* Update grant table's status fields */ 1393230587Sken for (i = 0; i < n_entries; i++) { 1394230587Sken xnb_unit_pvt.gnttab[0].status = GNTST_okay; 1395230587Sken } 1396230587Sken xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries); 1397230587Sken 1398230587Sken if (n_entries == 3) { 1399230587Sken /* there should be three mbufs and three gnttab entries */ 1400230587Sken XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction); 1401230587Sken XNB_ASSERT(pMbuf->m_len == MCLBYTES); 1402230587Sken XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES); 1403230587Sken XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1); 1404230587Sken } else if (n_entries == 2) { 1405230587Sken /* there should be two mbufs and two gnttab entries */ 1406230587Sken XNB_ASSERT(n_entries == 2); 1407230587Sken XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction); 1408230587Sken XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES); 1409230587Sken XNB_ASSERT(pMbuf->m_next->m_len == 1); 1410230587Sken } else { 1411230587Sken /* should never get here */ 1412230587Sken XNB_ASSERT(0); 1413230587Sken } 1414230587Sken safe_m_freem(&pMbuf); 1415230587Sken} 1416230587Sken 1417230587Sken/** xnb_mbufc2pkt on an empty mbufc */ 1418230587Skenstatic void 1419230587Skenxnb_mbufc2pkt_empty(char *buffer, size_t buflen) { 1420230587Sken struct xnb_pkt pkt; 1421230587Sken int free_slots = 64; 1422230587Sken struct mbuf *mbuf; 1423230587Sken 1424230587Sken mbuf = m_get(M_WAITOK, MT_DATA); 1425230587Sken /* 1426230587Sken * note: it is illegal to set M_PKTHDR on a mbuf with no data. Doing so 1427230587Sken * will cause m_freem to segfault 1428230587Sken */ 1429230587Sken XNB_ASSERT(mbuf->m_len == 0); 1430230587Sken 1431230587Sken xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1432230587Sken XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 1433230587Sken 1434230587Sken safe_m_freem(&mbuf); 1435230587Sken} 1436230587Sken 1437230587Sken/** xnb_mbufc2pkt on a short mbufc */ 1438230587Skenstatic void 1439230587Skenxnb_mbufc2pkt_short(char *buffer, size_t buflen) { 1440230587Sken struct xnb_pkt pkt; 1441230587Sken size_t size = 128; 1442230587Sken int free_slots = 64; 1443230587Sken RING_IDX start = 9; 1444230587Sken struct mbuf *mbuf; 1445230587Sken 1446230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1447230587Sken mbuf->m_flags |= M_PKTHDR; 1448230587Sken mbuf->m_pkthdr.len = size; 1449230587Sken mbuf->m_len = size; 1450230587Sken 1451230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1452230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1453230587Sken XNB_ASSERT(pkt.size == size); 1454230587Sken XNB_ASSERT(pkt.car_size == size); 1455230587Sken XNB_ASSERT(! (pkt.flags & 1456230587Sken (NETRXF_more_data | NETRXF_extra_info))); 1457230587Sken XNB_ASSERT(pkt.list_len == 1); 1458230587Sken XNB_ASSERT(pkt.car == start); 1459230587Sken 1460230587Sken safe_m_freem(&mbuf); 1461230587Sken} 1462230587Sken 1463230587Sken/** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */ 1464230587Skenstatic void 1465230587Skenxnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) { 1466230587Sken struct xnb_pkt pkt; 1467230587Sken size_t size = MCLBYTES; 1468230587Sken int free_slots = 32; 1469230587Sken RING_IDX start = 12; 1470230587Sken struct mbuf *mbuf; 1471230587Sken 1472230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1473230587Sken mbuf->m_flags |= M_PKTHDR; 1474230587Sken mbuf->m_pkthdr.len = size; 1475230587Sken mbuf->m_len = size; 1476230587Sken 1477230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1478230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1479230587Sken XNB_ASSERT(pkt.size == size); 1480230587Sken XNB_ASSERT(pkt.car_size == size); 1481230587Sken XNB_ASSERT(! (pkt.flags & 1482230587Sken (NETRXF_more_data | NETRXF_extra_info))); 1483230587Sken XNB_ASSERT(pkt.list_len == 1); 1484230587Sken XNB_ASSERT(pkt.car == start); 1485230587Sken 1486230587Sken safe_m_freem(&mbuf); 1487230587Sken} 1488230587Sken 1489240521Seadler/** xnb_mbufc2pkt on a two-mbuf chain with short data regions */ 1490230587Skenstatic void 1491230587Skenxnb_mbufc2pkt_2short(char *buffer, size_t buflen) { 1492230587Sken struct xnb_pkt pkt; 1493230587Sken size_t size1 = MHLEN - 5; 1494230587Sken size_t size2 = MHLEN - 15; 1495230587Sken int free_slots = 32; 1496230587Sken RING_IDX start = 14; 1497230587Sken struct mbuf *mbufc, *mbufc2; 1498230587Sken 1499230587Sken mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA); 1500316362Sasomers XNB_ASSERT(mbufc != NULL); 1501316362Sasomers if (mbufc == NULL) 1502316362Sasomers return; 1503230587Sken mbufc->m_flags |= M_PKTHDR; 1504230587Sken 1505230587Sken mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA); 1506316362Sasomers XNB_ASSERT(mbufc2 != NULL); 1507230587Sken if (mbufc2 == NULL) { 1508230587Sken safe_m_freem(&mbufc); 1509230587Sken return; 1510230587Sken } 1511230587Sken mbufc2->m_pkthdr.len = size1 + size2; 1512230587Sken mbufc2->m_len = size1; 1513230587Sken 1514230587Sken xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots); 1515230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1516230587Sken XNB_ASSERT(pkt.size == size1 + size2); 1517230587Sken XNB_ASSERT(pkt.car == start); 1518230587Sken /* 1519230587Sken * The second m_getm may allocate a new mbuf and append 1520230587Sken * it to the chain, or it may simply extend the first mbuf. 1521230587Sken */ 1522230587Sken if (mbufc2->m_next != NULL) { 1523230587Sken XNB_ASSERT(pkt.car_size == size1); 1524230587Sken XNB_ASSERT(pkt.list_len == 1); 1525230587Sken XNB_ASSERT(pkt.cdr == start + 1); 1526230587Sken } 1527230587Sken 1528230587Sken safe_m_freem(&mbufc2); 1529230587Sken} 1530230587Sken 1531240521Seadler/** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */ 1532230587Skenstatic void 1533230587Skenxnb_mbufc2pkt_long(char *buffer, size_t buflen) { 1534230587Sken struct xnb_pkt pkt; 1535230587Sken size_t size = 14 * MCLBYTES / 3; 1536230587Sken size_t size_remaining; 1537230587Sken int free_slots = 15; 1538230587Sken RING_IDX start = 3; 1539230587Sken struct mbuf *mbufc, *m; 1540230587Sken 1541230587Sken mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1542316362Sasomers XNB_ASSERT(mbufc != NULL); 1543316362Sasomers if (mbufc == NULL) 1544316362Sasomers return; 1545230587Sken mbufc->m_flags |= M_PKTHDR; 1546230587Sken 1547230587Sken mbufc->m_pkthdr.len = size; 1548230587Sken size_remaining = size; 1549230587Sken for (m = mbufc; m != NULL; m = m->m_next) { 1550230587Sken m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1551230587Sken size_remaining -= m->m_len; 1552230587Sken } 1553230587Sken 1554230587Sken xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1555230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1556230587Sken XNB_ASSERT(pkt.size == size); 1557230587Sken XNB_ASSERT(pkt.car == start); 1558230587Sken XNB_ASSERT(pkt.car_size = mbufc->m_len); 1559230587Sken /* 1560230587Sken * There should be >1 response in the packet, and there is no 1561230587Sken * extra info. 1562230587Sken */ 1563230587Sken XNB_ASSERT(! (pkt.flags & NETRXF_extra_info)); 1564230587Sken XNB_ASSERT(pkt.cdr == pkt.car + 1); 1565230587Sken 1566230587Sken safe_m_freem(&mbufc); 1567230587Sken} 1568230587Sken 1569240521Seadler/** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */ 1570230587Skenstatic void 1571230587Skenxnb_mbufc2pkt_extra(char *buffer, size_t buflen) { 1572230587Sken struct xnb_pkt pkt; 1573230587Sken size_t size = 14 * MCLBYTES / 3; 1574230587Sken size_t size_remaining; 1575230587Sken int free_slots = 15; 1576230587Sken RING_IDX start = 3; 1577230587Sken struct mbuf *mbufc, *m; 1578230587Sken 1579230587Sken mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1580316362Sasomers XNB_ASSERT(mbufc != NULL); 1581316362Sasomers if (mbufc == NULL) 1582230587Sken return; 1583230587Sken 1584230587Sken mbufc->m_flags |= M_PKTHDR; 1585230587Sken mbufc->m_pkthdr.len = size; 1586230587Sken mbufc->m_pkthdr.csum_flags |= CSUM_TSO; 1587230587Sken mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40; 1588230587Sken size_remaining = size; 1589230587Sken for (m = mbufc; m != NULL; m = m->m_next) { 1590230587Sken m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1591230587Sken size_remaining -= m->m_len; 1592230587Sken } 1593230587Sken 1594230587Sken xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1595230587Sken XNB_ASSERT(xnb_pkt_is_valid(&pkt)); 1596230587Sken XNB_ASSERT(pkt.size == size); 1597230587Sken XNB_ASSERT(pkt.car == start); 1598230587Sken XNB_ASSERT(pkt.car_size = mbufc->m_len); 1599230587Sken /* There should be >1 response in the packet, there is extra info */ 1600230587Sken XNB_ASSERT(pkt.flags & NETRXF_extra_info); 1601230587Sken XNB_ASSERT(pkt.flags & NETRXF_data_validated); 1602230587Sken XNB_ASSERT(pkt.cdr == pkt.car + 2); 1603230587Sken XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz); 1604230587Sken XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO); 1605230587Sken XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE)); 1606230587Sken 1607230587Sken safe_m_freem(&mbufc); 1608230587Sken} 1609230587Sken 1610230587Sken/** xnb_mbufc2pkt with insufficient space in the ring */ 1611230587Skenstatic void 1612230587Skenxnb_mbufc2pkt_nospace(char *buffer, size_t buflen) { 1613230587Sken struct xnb_pkt pkt; 1614230587Sken size_t size = 14 * MCLBYTES / 3; 1615230587Sken size_t size_remaining; 1616230587Sken int free_slots = 2; 1617230587Sken RING_IDX start = 3; 1618230587Sken struct mbuf *mbufc, *m; 1619230587Sken int error; 1620230587Sken 1621230587Sken mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1622316362Sasomers XNB_ASSERT(mbufc != NULL); 1623316362Sasomers if (mbufc == NULL) 1624316362Sasomers return; 1625230587Sken mbufc->m_flags |= M_PKTHDR; 1626230587Sken 1627230587Sken mbufc->m_pkthdr.len = size; 1628230587Sken size_remaining = size; 1629230587Sken for (m = mbufc; m != NULL; m = m->m_next) { 1630230587Sken m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining); 1631230587Sken size_remaining -= m->m_len; 1632230587Sken } 1633230587Sken 1634230587Sken error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1635230587Sken XNB_ASSERT(error == EAGAIN); 1636230587Sken XNB_ASSERT(! xnb_pkt_is_valid(&pkt)); 1637230587Sken 1638230587Sken safe_m_freem(&mbufc); 1639230587Sken} 1640230587Sken 1641230587Sken/** 1642230587Sken * xnb_rxpkt2gnttab on an empty packet. Should return empty gnttab 1643230587Sken */ 1644230587Skenstatic void 1645230587Skenxnb_rxpkt2gnttab_empty(char *buffer, size_t buflen) 1646230587Sken{ 1647230587Sken struct xnb_pkt pkt; 1648230587Sken int nr_entries; 1649230587Sken int free_slots = 60; 1650230587Sken struct mbuf *mbuf; 1651230587Sken 1652230587Sken mbuf = m_get(M_WAITOK, MT_DATA); 1653230587Sken 1654230587Sken xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1655230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1656230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1657230587Sken 1658230587Sken XNB_ASSERT(nr_entries == 0); 1659230587Sken 1660230587Sken safe_m_freem(&mbuf); 1661230587Sken} 1662230587Sken 1663230587Sken/** xnb_rxpkt2gnttab on a short packet without extra data */ 1664230587Skenstatic void 1665230587Skenxnb_rxpkt2gnttab_short(char *buffer, size_t buflen) { 1666230587Sken struct xnb_pkt pkt; 1667230587Sken int nr_entries; 1668230587Sken size_t size = 128; 1669230587Sken int free_slots = 60; 1670230587Sken RING_IDX start = 9; 1671230587Sken struct netif_rx_request *req; 1672230587Sken struct mbuf *mbuf; 1673230587Sken 1674230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1675230587Sken mbuf->m_flags |= M_PKTHDR; 1676230587Sken mbuf->m_pkthdr.len = size; 1677230587Sken mbuf->m_len = size; 1678230587Sken 1679230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1680230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, 1681230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1682230587Sken req->gref = 7; 1683230587Sken 1684230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1685230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1686230587Sken 1687230587Sken XNB_ASSERT(nr_entries == 1); 1688230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size); 1689230587Sken /* flags should indicate gref's for dest */ 1690230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref); 1691230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0); 1692230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF); 1693230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset( 1694230587Sken mtod(mbuf, vm_offset_t))); 1695230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn == 1696230587Sken virt_to_mfn(mtod(mbuf, vm_offset_t))); 1697230587Sken XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED); 1698230587Sken 1699230587Sken safe_m_freem(&mbuf); 1700230587Sken} 1701230587Sken 1702230587Sken/** 1703230587Sken * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai 1704230587Sken */ 1705230587Skenstatic void 1706230587Skenxnb_rxpkt2gnttab_2req(char *buffer, size_t buflen) 1707230587Sken{ 1708230587Sken struct xnb_pkt pkt; 1709230587Sken int nr_entries; 1710230587Sken int i, num_mbufs; 1711230587Sken size_t total_granted_size = 0; 1712230587Sken size_t size = MJUMPAGESIZE + 1; 1713230587Sken int free_slots = 60; 1714230587Sken RING_IDX start = 11; 1715230587Sken struct netif_rx_request *req; 1716230587Sken struct mbuf *mbuf, *m; 1717230587Sken 1718230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1719230587Sken mbuf->m_flags |= M_PKTHDR; 1720230587Sken mbuf->m_pkthdr.len = size; 1721230587Sken mbuf->m_len = size; 1722230587Sken 1723230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1724230587Sken 1725230587Sken for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) { 1726230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, 1727230587Sken xnb_unit_pvt.txf.req_prod_pvt); 1728230587Sken req->gref = i; 1729230587Sken req->id = 5; 1730230587Sken } 1731230587Sken num_mbufs = i; 1732230587Sken 1733230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1734230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1735230587Sken 1736230587Sken XNB_ASSERT(nr_entries >= num_mbufs); 1737230587Sken for (i = 0; i < nr_entries; i++) { 1738230587Sken int end_offset = xnb_unit_pvt.gnttab[i].len + 1739230587Sken xnb_unit_pvt.gnttab[i].dest.offset; 1740230587Sken XNB_ASSERT(end_offset <= PAGE_SIZE); 1741230587Sken total_granted_size += xnb_unit_pvt.gnttab[i].len; 1742230587Sken } 1743230587Sken XNB_ASSERT(total_granted_size == size); 1744230587Sken} 1745230587Sken 1746230587Sken/** 1747230587Sken * xnb_rxpkt2rsp on an empty packet. Shouldn't make any response 1748230587Sken */ 1749230587Skenstatic void 1750230587Skenxnb_rxpkt2rsp_empty(char *buffer, size_t buflen) 1751230587Sken{ 1752230587Sken struct xnb_pkt pkt; 1753230587Sken int nr_entries; 1754230587Sken int nr_reqs; 1755230587Sken int free_slots = 60; 1756230587Sken netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb; 1757230587Sken netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs; 1758230587Sken struct mbuf *mbuf; 1759230587Sken 1760230587Sken mbuf = m_get(M_WAITOK, MT_DATA); 1761230587Sken 1762230587Sken xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots); 1763230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1764230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1765230587Sken 1766230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1767230587Sken &xnb_unit_pvt.rxb); 1768230587Sken XNB_ASSERT(nr_reqs == 0); 1769230587Sken XNB_ASSERT( 1770230587Sken memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0); 1771230587Sken XNB_ASSERT( 1772230587Sken memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0); 1773230587Sken 1774230587Sken safe_m_freem(&mbuf); 1775230587Sken} 1776230587Sken 1777230587Sken/** 1778230587Sken * xnb_rxpkt2rsp on a short packet with no extras 1779230587Sken */ 1780230587Skenstatic void 1781230587Skenxnb_rxpkt2rsp_short(char *buffer, size_t buflen) 1782230587Sken{ 1783230587Sken struct xnb_pkt pkt; 1784230587Sken int nr_entries, nr_reqs; 1785230587Sken size_t size = 128; 1786230587Sken int free_slots = 60; 1787230587Sken RING_IDX start = 5; 1788230587Sken struct netif_rx_request *req; 1789230587Sken struct netif_rx_response *rsp; 1790230587Sken struct mbuf *mbuf; 1791230587Sken 1792230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1793230587Sken mbuf->m_flags |= M_PKTHDR; 1794230587Sken mbuf->m_pkthdr.len = size; 1795230587Sken mbuf->m_len = size; 1796230587Sken 1797230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1798230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1799230587Sken req->gref = 7; 1800230587Sken xnb_unit_pvt.rxb.req_cons = start; 1801230587Sken xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1802230587Sken xnb_unit_pvt.rxs->req_prod = start + 1; 1803230587Sken xnb_unit_pvt.rxs->rsp_prod = start; 1804230587Sken 1805230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1806230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1807230587Sken 1808230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1809230587Sken &xnb_unit_pvt.rxb); 1810230587Sken 1811230587Sken XNB_ASSERT(nr_reqs == 1); 1812230587Sken XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1); 1813230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1814230587Sken XNB_ASSERT(rsp->id == req->id); 1815230587Sken XNB_ASSERT(rsp->offset == 0); 1816230587Sken XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0); 1817230587Sken XNB_ASSERT(rsp->status == size); 1818230587Sken 1819230587Sken safe_m_freem(&mbuf); 1820230587Sken} 1821230587Sken 1822230587Sken/** 1823230587Sken * xnb_rxpkt2rsp with extra data 1824230587Sken */ 1825230587Skenstatic void 1826230587Skenxnb_rxpkt2rsp_extra(char *buffer, size_t buflen) 1827230587Sken{ 1828230587Sken struct xnb_pkt pkt; 1829230587Sken int nr_entries, nr_reqs; 1830230587Sken size_t size = 14; 1831230587Sken int free_slots = 15; 1832230587Sken RING_IDX start = 3; 1833230587Sken uint16_t id = 49; 1834230587Sken uint16_t gref = 65; 1835230587Sken uint16_t mss = TCP_MSS - 40; 1836230587Sken struct mbuf *mbufc; 1837230587Sken struct netif_rx_request *req; 1838230587Sken struct netif_rx_response *rsp; 1839230587Sken struct netif_extra_info *ext; 1840230587Sken 1841230587Sken mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA); 1842316362Sasomers XNB_ASSERT(mbufc != NULL); 1843316362Sasomers if (mbufc == NULL) 1844230587Sken return; 1845230587Sken 1846230587Sken mbufc->m_flags |= M_PKTHDR; 1847230587Sken mbufc->m_pkthdr.len = size; 1848230587Sken mbufc->m_pkthdr.csum_flags |= CSUM_TSO; 1849230587Sken mbufc->m_pkthdr.tso_segsz = mss; 1850230587Sken mbufc->m_len = size; 1851230587Sken 1852230587Sken xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1853230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1854230587Sken req->id = id; 1855230587Sken req->gref = gref; 1856230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 1857230587Sken req->id = id + 1; 1858230587Sken req->gref = gref + 1; 1859230587Sken xnb_unit_pvt.rxb.req_cons = start; 1860230587Sken xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1861230587Sken xnb_unit_pvt.rxs->req_prod = start + 2; 1862230587Sken xnb_unit_pvt.rxs->rsp_prod = start; 1863230587Sken 1864230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab, 1865230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1866230587Sken 1867230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1868230587Sken &xnb_unit_pvt.rxb); 1869230587Sken 1870230587Sken XNB_ASSERT(nr_reqs == 2); 1871230587Sken XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2); 1872230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1873230587Sken XNB_ASSERT(rsp->id == id); 1874230587Sken XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0); 1875230587Sken XNB_ASSERT((rsp->flags & NETRXF_extra_info)); 1876230587Sken XNB_ASSERT((rsp->flags & NETRXF_data_validated)); 1877230587Sken XNB_ASSERT((rsp->flags & NETRXF_csum_blank)); 1878230587Sken XNB_ASSERT(rsp->status == size); 1879230587Sken 1880230587Sken ext = (struct netif_extra_info*) 1881230587Sken RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1); 1882230587Sken XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO); 1883230587Sken XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE)); 1884230587Sken XNB_ASSERT(ext->u.gso.size == mss); 1885230587Sken XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO); 1886230587Sken 1887230587Sken safe_m_freem(&mbufc); 1888230587Sken} 1889230587Sken 1890230587Sken/** 1891230587Sken * xnb_rxpkt2rsp on a packet with more than a pages's worth of data. It should 1892230587Sken * generate two response slot 1893230587Sken */ 1894230587Skenstatic void 1895230587Skenxnb_rxpkt2rsp_2slots(char *buffer, size_t buflen) 1896230587Sken{ 1897230587Sken struct xnb_pkt pkt; 1898230587Sken int nr_entries, nr_reqs; 1899230587Sken size_t size = PAGE_SIZE + 100; 1900230587Sken int free_slots = 3; 1901230587Sken uint16_t id1 = 17; 1902230587Sken uint16_t id2 = 37; 1903230587Sken uint16_t gref1 = 24; 1904230587Sken uint16_t gref2 = 34; 1905230587Sken RING_IDX start = 15; 1906230587Sken struct netif_rx_request *req; 1907230587Sken struct netif_rx_response *rsp; 1908230587Sken struct mbuf *mbuf; 1909230587Sken 1910230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 1911230587Sken mbuf->m_flags |= M_PKTHDR; 1912230587Sken mbuf->m_pkthdr.len = size; 1913230587Sken if (mbuf->m_next != NULL) { 1914230587Sken size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size); 1915230587Sken mbuf->m_len = first_len; 1916230587Sken mbuf->m_next->m_len = size - first_len; 1917230587Sken 1918230587Sken } else { 1919230587Sken mbuf->m_len = size; 1920230587Sken } 1921230587Sken 1922230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 1923230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1924230587Sken req->gref = gref1; 1925230587Sken req->id = id1; 1926230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 1927230587Sken req->gref = gref2; 1928230587Sken req->id = id2; 1929230587Sken xnb_unit_pvt.rxb.req_cons = start; 1930230587Sken xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1931230587Sken xnb_unit_pvt.rxs->req_prod = start + 2; 1932230587Sken xnb_unit_pvt.rxs->rsp_prod = start; 1933230587Sken 1934230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 1935230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1936230587Sken 1937230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 1938230587Sken &xnb_unit_pvt.rxb); 1939230587Sken 1940230587Sken XNB_ASSERT(nr_reqs == 2); 1941230587Sken XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2); 1942230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 1943230587Sken XNB_ASSERT(rsp->id == id1); 1944230587Sken XNB_ASSERT(rsp->offset == 0); 1945230587Sken XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0); 1946230587Sken XNB_ASSERT(rsp->flags & NETRXF_more_data); 1947230587Sken XNB_ASSERT(rsp->status == PAGE_SIZE); 1948230587Sken 1949230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1); 1950230587Sken XNB_ASSERT(rsp->id == id2); 1951230587Sken XNB_ASSERT(rsp->offset == 0); 1952230587Sken XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0); 1953230587Sken XNB_ASSERT(! (rsp->flags & NETRXF_more_data)); 1954230587Sken XNB_ASSERT(rsp->status == size - PAGE_SIZE); 1955230587Sken 1956230587Sken safe_m_freem(&mbuf); 1957230587Sken} 1958230587Sken 1959230587Sken/** xnb_rxpkt2rsp on a grant table with two sub-page entries */ 1960230587Skenstatic void 1961230587Skenxnb_rxpkt2rsp_2short(char *buffer, size_t buflen) { 1962230587Sken struct xnb_pkt pkt; 1963230587Sken int nr_reqs, nr_entries; 1964230587Sken size_t size1 = MHLEN - 5; 1965230587Sken size_t size2 = MHLEN - 15; 1966230587Sken int free_slots = 32; 1967230587Sken RING_IDX start = 14; 1968230587Sken uint16_t id = 47; 1969230587Sken uint16_t gref = 54; 1970230587Sken struct netif_rx_request *req; 1971230587Sken struct netif_rx_response *rsp; 1972230587Sken struct mbuf *mbufc; 1973230587Sken 1974230587Sken mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA); 1975316362Sasomers XNB_ASSERT(mbufc != NULL); 1976316362Sasomers if (mbufc == NULL) 1977316362Sasomers return; 1978230587Sken mbufc->m_flags |= M_PKTHDR; 1979230587Sken 1980230587Sken m_getm(mbufc, size2, M_WAITOK, MT_DATA); 1981230587Sken XNB_ASSERT(mbufc->m_next != NULL); 1982230587Sken mbufc->m_pkthdr.len = size1 + size2; 1983230587Sken mbufc->m_len = size1; 1984230587Sken mbufc->m_next->m_len = size2; 1985230587Sken 1986230587Sken xnb_mbufc2pkt(mbufc, &pkt, start, free_slots); 1987230587Sken 1988230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 1989230587Sken req->gref = gref; 1990230587Sken req->id = id; 1991230587Sken xnb_unit_pvt.rxb.req_cons = start; 1992230587Sken xnb_unit_pvt.rxb.rsp_prod_pvt = start; 1993230587Sken xnb_unit_pvt.rxs->req_prod = start + 1; 1994230587Sken xnb_unit_pvt.rxs->rsp_prod = start; 1995230587Sken 1996230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab, 1997230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 1998230587Sken 1999230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 2000230587Sken &xnb_unit_pvt.rxb); 2001230587Sken 2002230587Sken XNB_ASSERT(nr_entries == 2); 2003230587Sken XNB_ASSERT(nr_reqs == 1); 2004230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 2005230587Sken XNB_ASSERT(rsp->id == id); 2006230587Sken XNB_ASSERT(rsp->status == size1 + size2); 2007230587Sken XNB_ASSERT(rsp->offset == 0); 2008230587Sken XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info))); 2009230587Sken 2010230587Sken safe_m_freem(&mbufc); 2011230587Sken} 2012230587Sken 2013230587Sken/** 2014230587Sken * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error 2015230587Sken * Note: this test will result in an error message being printed to the console 2016230587Sken * such as: 2017230587Sken * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status 2018230587Sken */ 2019230587Skenstatic void 2020230587Skenxnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen) 2021230587Sken{ 2022230587Sken struct xnb_pkt pkt; 2023230587Sken int nr_entries, nr_reqs; 2024230587Sken int id = 7; 2025230587Sken int gref = 42; 2026230587Sken uint16_t canary = 6859; 2027230587Sken size_t size = 7 * MCLBYTES; 2028230587Sken int free_slots = 9; 2029230587Sken RING_IDX start = 2; 2030230587Sken struct netif_rx_request *req; 2031230587Sken struct netif_rx_response *rsp; 2032230587Sken struct mbuf *mbuf; 2033230587Sken 2034230587Sken mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA); 2035230587Sken mbuf->m_flags |= M_PKTHDR; 2036230587Sken mbuf->m_pkthdr.len = size; 2037230587Sken mbuf->m_len = size; 2038230587Sken 2039230587Sken xnb_mbufc2pkt(mbuf, &pkt, start, free_slots); 2040230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start); 2041230587Sken req->gref = gref; 2042230587Sken req->id = id; 2043230587Sken xnb_unit_pvt.rxb.req_cons = start; 2044230587Sken xnb_unit_pvt.rxb.rsp_prod_pvt = start; 2045230587Sken xnb_unit_pvt.rxs->req_prod = start + 1; 2046230587Sken xnb_unit_pvt.rxs->rsp_prod = start; 2047230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 2048230587Sken req->gref = canary; 2049230587Sken req->id = canary; 2050230587Sken 2051230587Sken nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab, 2052230587Sken &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED); 2053230587Sken /* Inject the error*/ 2054230587Sken xnb_unit_pvt.gnttab[2].status = GNTST_general_error; 2055230587Sken 2056230587Sken nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries, 2057230587Sken &xnb_unit_pvt.rxb); 2058230587Sken 2059230587Sken XNB_ASSERT(nr_reqs == 1); 2060230587Sken XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1); 2061230587Sken rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start); 2062230587Sken XNB_ASSERT(rsp->id == id); 2063230587Sken XNB_ASSERT(rsp->status == NETIF_RSP_ERROR); 2064230587Sken req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1); 2065230587Sken XNB_ASSERT(req->gref == canary); 2066230587Sken XNB_ASSERT(req->id == canary); 2067230587Sken 2068230587Sken safe_m_freem(&mbuf); 2069230587Sken} 2070230587Sken 2071257515Sglebius#if defined(INET) || defined(INET6) 2072230587Sken/** 2073230587Sken * xnb_add_mbuf_cksum on an ARP request packet 2074230587Sken */ 2075230587Skenstatic void 2076230587Skenxnb_add_mbuf_cksum_arp(char *buffer, size_t buflen) 2077230587Sken{ 2078230587Sken const size_t pkt_len = sizeof(struct ether_header) + 2079230587Sken sizeof(struct ether_arp); 2080230587Sken struct mbuf *mbufc; 2081230587Sken struct ether_header *eh; 2082230587Sken struct ether_arp *ep; 2083230587Sken unsigned char pkt_orig[pkt_len]; 2084230587Sken 2085230587Sken mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2086230587Sken /* Fill in an example arp request */ 2087230587Sken eh = mtod(mbufc, struct ether_header*); 2088230587Sken eh->ether_dhost[0] = 0xff; 2089230587Sken eh->ether_dhost[1] = 0xff; 2090230587Sken eh->ether_dhost[2] = 0xff; 2091230587Sken eh->ether_dhost[3] = 0xff; 2092230587Sken eh->ether_dhost[4] = 0xff; 2093230587Sken eh->ether_dhost[5] = 0xff; 2094230587Sken eh->ether_shost[0] = 0x00; 2095230587Sken eh->ether_shost[1] = 0x15; 2096230587Sken eh->ether_shost[2] = 0x17; 2097230587Sken eh->ether_shost[3] = 0xe9; 2098230587Sken eh->ether_shost[4] = 0x30; 2099230587Sken eh->ether_shost[5] = 0x68; 2100230587Sken eh->ether_type = htons(ETHERTYPE_ARP); 2101230587Sken ep = (struct ether_arp*)(eh + 1); 2102230587Sken ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); 2103230587Sken ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP); 2104230587Sken ep->ea_hdr.ar_hln = 6; 2105230587Sken ep->ea_hdr.ar_pln = 4; 2106230587Sken ep->ea_hdr.ar_op = htons(ARPOP_REQUEST); 2107230587Sken ep->arp_sha[0] = 0x00; 2108230587Sken ep->arp_sha[1] = 0x15; 2109230587Sken ep->arp_sha[2] = 0x17; 2110230587Sken ep->arp_sha[3] = 0xe9; 2111230587Sken ep->arp_sha[4] = 0x30; 2112230587Sken ep->arp_sha[5] = 0x68; 2113230587Sken ep->arp_spa[0] = 0xc0; 2114230587Sken ep->arp_spa[1] = 0xa8; 2115230587Sken ep->arp_spa[2] = 0x0a; 2116230587Sken ep->arp_spa[3] = 0x04; 2117230587Sken bzero(&(ep->arp_tha), ETHER_ADDR_LEN); 2118230587Sken ep->arp_tpa[0] = 0xc0; 2119230587Sken ep->arp_tpa[1] = 0xa8; 2120230587Sken ep->arp_tpa[2] = 0x0a; 2121230587Sken ep->arp_tpa[3] = 0x06; 2122230587Sken 2123230587Sken /* fill in the length field */ 2124230587Sken mbufc->m_len = pkt_len; 2125230587Sken mbufc->m_pkthdr.len = pkt_len; 2126230587Sken /* indicate that the netfront uses hw-assisted checksums */ 2127230587Sken mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2128230587Sken CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2129230587Sken 2130230587Sken /* Make a backup copy of the packet */ 2131230587Sken bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len); 2132230587Sken 2133230587Sken /* Function under test */ 2134230587Sken xnb_add_mbuf_cksum(mbufc); 2135230587Sken 2136230587Sken /* Verify that the packet's data did not change */ 2137230587Sken XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0); 2138230587Sken m_freem(mbufc); 2139230587Sken} 2140230587Sken 2141230587Sken/** 2142230587Sken * Helper function that populates the ethernet header and IP header used by 2143230587Sken * some of the xnb_add_mbuf_cksum unit tests. m must already be allocated 2144230587Sken * and must be large enough 2145230587Sken */ 2146230587Skenstatic void 2147230587Skenxnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id, 2148230587Sken uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum) 2149230587Sken{ 2150230587Sken struct ether_header *eh; 2151230587Sken struct ip *iph; 2152230587Sken 2153230587Sken eh = mtod(m, struct ether_header*); 2154230587Sken eh->ether_dhost[0] = 0x00; 2155230587Sken eh->ether_dhost[1] = 0x16; 2156230587Sken eh->ether_dhost[2] = 0x3e; 2157230587Sken eh->ether_dhost[3] = 0x23; 2158230587Sken eh->ether_dhost[4] = 0x50; 2159230587Sken eh->ether_dhost[5] = 0x0b; 2160230587Sken eh->ether_shost[0] = 0x00; 2161230587Sken eh->ether_shost[1] = 0x16; 2162230587Sken eh->ether_shost[2] = 0x30; 2163230587Sken eh->ether_shost[3] = 0x00; 2164230587Sken eh->ether_shost[4] = 0x00; 2165230587Sken eh->ether_shost[5] = 0x00; 2166230587Sken eh->ether_type = htons(ETHERTYPE_IP); 2167230587Sken iph = (struct ip*)(eh + 1); 2168230587Sken iph->ip_hl = 0x5; /* 5 dwords == 20 bytes */ 2169230587Sken iph->ip_v = 4; /* IP v4 */ 2170230587Sken iph->ip_tos = 0; 2171230587Sken iph->ip_len = htons(ip_len); 2172230587Sken iph->ip_id = htons(ip_id); 2173230587Sken iph->ip_off = htons(ip_off); 2174230587Sken iph->ip_ttl = 64; 2175230587Sken iph->ip_p = ip_p; 2176230587Sken iph->ip_sum = htons(ip_sum); 2177230587Sken iph->ip_src.s_addr = htonl(0xc0a80a04); 2178230587Sken iph->ip_dst.s_addr = htonl(0xc0a80a05); 2179230587Sken} 2180230587Sken 2181230587Sken/** 2182230587Sken * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual 2183230587Sken * ICMP packet 2184230587Sken */ 2185230587Skenstatic void 2186230587Skenxnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen) 2187230587Sken{ 2188230587Sken const size_t icmp_len = 64; /* set by ping(1) */ 2189230587Sken const size_t pkt_len = sizeof(struct ether_header) + 2190230587Sken sizeof(struct ip) + icmp_len; 2191230587Sken struct mbuf *mbufc; 2192230587Sken struct ether_header *eh; 2193230587Sken struct ip *iph; 2194230587Sken struct icmp *icmph; 2195230587Sken unsigned char pkt_orig[icmp_len]; 2196230587Sken uint32_t *tv_field; 2197230587Sken uint8_t *data_payload; 2198230587Sken int i; 2199230587Sken const uint16_t ICMP_CSUM = 0xaed7; 2200230587Sken const uint16_t IP_CSUM = 0xe533; 2201230587Sken 2202230587Sken mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2203230587Sken /* Fill in an example ICMP ping request */ 2204230587Sken eh = mtod(mbufc, struct ether_header*); 2205230587Sken xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0); 2206230587Sken iph = (struct ip*)(eh + 1); 2207230587Sken icmph = (struct icmp*)(iph + 1); 2208230587Sken icmph->icmp_type = ICMP_ECHO; 2209230587Sken icmph->icmp_code = 0; 2210230587Sken icmph->icmp_cksum = htons(ICMP_CSUM); 2211230587Sken icmph->icmp_id = htons(31492); 2212230587Sken icmph->icmp_seq = htons(0); 2213230587Sken /* 2214230587Sken * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq. 2215230587Sken * For this test, we will set the bytes individually for portability. 2216230587Sken */ 2217230587Sken tv_field = (uint32_t*)(&(icmph->icmp_hun)); 2218230587Sken tv_field[0] = 0x4f02cfac; 2219230587Sken tv_field[1] = 0x0007c46a; 2220230587Sken /* 2221230587Sken * Remainder of packet is an incrmenting 8 bit integer, starting with 8 2222230587Sken */ 2223230587Sken data_payload = (uint8_t*)(&tv_field[2]); 2224230587Sken for (i = 8; i < 37; i++) { 2225230587Sken *data_payload++ = i; 2226230587Sken } 2227230587Sken 2228230587Sken /* fill in the length field */ 2229230587Sken mbufc->m_len = pkt_len; 2230230587Sken mbufc->m_pkthdr.len = pkt_len; 2231230587Sken /* indicate that the netfront uses hw-assisted checksums */ 2232230587Sken mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2233230587Sken CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2234230587Sken 2235230587Sken bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len); 2236230587Sken /* Function under test */ 2237230587Sken xnb_add_mbuf_cksum(mbufc); 2238230587Sken 2239230587Sken /* Check the IP checksum */ 2240230587Sken XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2241230587Sken 2242230587Sken /* Check that the ICMP packet did not change */ 2243230587Sken XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len)); 2244230587Sken m_freem(mbufc); 2245230587Sken} 2246230587Sken 2247230587Sken/** 2248230587Sken * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual 2249230587Sken * UDP packet 2250230587Sken */ 2251230587Skenstatic void 2252230587Skenxnb_add_mbuf_cksum_udp(char *buffer, size_t buflen) 2253230587Sken{ 2254230587Sken const size_t udp_len = 16; 2255230587Sken const size_t pkt_len = sizeof(struct ether_header) + 2256230587Sken sizeof(struct ip) + udp_len; 2257230587Sken struct mbuf *mbufc; 2258230587Sken struct ether_header *eh; 2259230587Sken struct ip *iph; 2260230587Sken struct udphdr *udp; 2261230587Sken uint8_t *data_payload; 2262230587Sken const uint16_t IP_CSUM = 0xe56b; 2263230587Sken const uint16_t UDP_CSUM = 0xdde2; 2264230587Sken 2265230587Sken mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2266230587Sken /* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */ 2267230587Sken eh = mtod(mbufc, struct ether_header*); 2268230587Sken xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad); 2269230587Sken iph = (struct ip*)(eh + 1); 2270230587Sken udp = (struct udphdr*)(iph + 1); 2271230587Sken udp->uh_sport = htons(0x51ae); 2272230587Sken udp->uh_dport = htons(0x08ae); 2273230587Sken udp->uh_ulen = htons(udp_len); 2274230587Sken udp->uh_sum = htons(0xbaad); /* xnb_add_mbuf_cksum will fill this in */ 2275230587Sken data_payload = (uint8_t*)(udp + 1); 2276230587Sken data_payload[0] = 'F'; 2277230587Sken data_payload[1] = 'r'; 2278230587Sken data_payload[2] = 'e'; 2279230587Sken data_payload[3] = 'e'; 2280230587Sken data_payload[4] = 'B'; 2281230587Sken data_payload[5] = 'S'; 2282230587Sken data_payload[6] = 'D'; 2283230587Sken data_payload[7] = '\n'; 2284230587Sken 2285230587Sken /* fill in the length field */ 2286230587Sken mbufc->m_len = pkt_len; 2287230587Sken mbufc->m_pkthdr.len = pkt_len; 2288230587Sken /* indicate that the netfront uses hw-assisted checksums */ 2289230587Sken mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2290230587Sken CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2291230587Sken 2292230587Sken /* Function under test */ 2293230587Sken xnb_add_mbuf_cksum(mbufc); 2294230587Sken 2295230587Sken /* Check the checksums */ 2296230587Sken XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2297230587Sken XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM)); 2298230587Sken 2299230587Sken m_freem(mbufc); 2300230587Sken} 2301230587Sken 2302230587Sken/** 2303230587Sken * Helper function that populates a TCP packet used by all of the 2304230587Sken * xnb_add_mbuf_cksum tcp unit tests. m must already be allocated and must be 2305230587Sken * large enough 2306230587Sken */ 2307230587Skenstatic void 2308230587Skenxnb_fill_tcp(struct mbuf *m) 2309230587Sken{ 2310230587Sken struct ether_header *eh; 2311230587Sken struct ip *iph; 2312230587Sken struct tcphdr *tcp; 2313230587Sken uint32_t *options; 2314230587Sken uint8_t *data_payload; 2315230587Sken 2316230587Sken /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2317230587Sken eh = mtod(m, struct ether_header*); 2318230587Sken xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0); 2319230587Sken iph = (struct ip*)(eh + 1); 2320230587Sken tcp = (struct tcphdr*)(iph + 1); 2321230587Sken tcp->th_sport = htons(0x9cd9); 2322230587Sken tcp->th_dport = htons(2222); 2323230587Sken tcp->th_seq = htonl(0x00f72b10); 2324230587Sken tcp->th_ack = htonl(0x7f37ba6c); 2325230587Sken tcp->th_x2 = 0; 2326230587Sken tcp->th_off = 8; 2327230587Sken tcp->th_flags = 0x18; 2328230587Sken tcp->th_win = htons(0x410); 2329230587Sken /* th_sum is incorrect; will be inserted by function under test */ 2330230587Sken tcp->th_sum = htons(0xbaad); 2331230587Sken tcp->th_urp = htons(0); 2332230587Sken /* 2333230587Sken * The following 12 bytes of options encode: 2334230587Sken * [nop, nop, TS val 33247 ecr 3457687679] 2335230587Sken */ 2336230587Sken options = (uint32_t*)(tcp + 1); 2337230587Sken options[0] = htonl(0x0101080a); 2338230587Sken options[1] = htonl(0x000081df); 2339230587Sken options[2] = htonl(0xce18207f); 2340230587Sken data_payload = (uint8_t*)(&options[3]); 2341230587Sken data_payload[0] = 'F'; 2342230587Sken data_payload[1] = 'r'; 2343230587Sken data_payload[2] = 'e'; 2344230587Sken data_payload[3] = 'e'; 2345230587Sken data_payload[4] = 'B'; 2346230587Sken data_payload[5] = 'S'; 2347230587Sken data_payload[6] = 'D'; 2348230587Sken data_payload[7] = '\n'; 2349230587Sken} 2350230587Sken 2351230587Sken/** 2352230587Sken * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP 2353230587Sken * packet 2354230587Sken */ 2355230587Skenstatic void 2356230587Skenxnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen) 2357230587Sken{ 2358230587Sken const size_t payload_len = 8; 2359230587Sken const size_t tcp_options_len = 12; 2360230587Sken const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) + 2361230587Sken sizeof(struct tcphdr) + tcp_options_len + payload_len; 2362230587Sken struct mbuf *mbufc; 2363230587Sken struct ether_header *eh; 2364230587Sken struct ip *iph; 2365230587Sken struct tcphdr *tcp; 2366230587Sken const uint16_t IP_CSUM = 0xa55a; 2367230587Sken const uint16_t TCP_CSUM = 0x2f64; 2368230587Sken 2369230587Sken mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2370230587Sken /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2371230587Sken xnb_fill_tcp(mbufc); 2372230587Sken eh = mtod(mbufc, struct ether_header*); 2373230587Sken iph = (struct ip*)(eh + 1); 2374230587Sken tcp = (struct tcphdr*)(iph + 1); 2375230587Sken 2376230587Sken /* fill in the length field */ 2377230587Sken mbufc->m_len = pkt_len; 2378230587Sken mbufc->m_pkthdr.len = pkt_len; 2379230587Sken /* indicate that the netfront uses hw-assisted checksums */ 2380230587Sken mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 2381230587Sken CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2382230587Sken 2383230587Sken /* Function under test */ 2384230587Sken xnb_add_mbuf_cksum(mbufc); 2385230587Sken 2386230587Sken /* Check the checksums */ 2387230587Sken XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2388230587Sken XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM)); 2389230587Sken 2390230587Sken m_freem(mbufc); 2391230587Sken} 2392230587Sken 2393230587Sken/** 2394230587Sken * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums 2395230587Sken */ 2396230587Skenstatic void 2397230587Skenxnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen) 2398230587Sken{ 2399230587Sken const size_t payload_len = 8; 2400230587Sken const size_t tcp_options_len = 12; 2401230587Sken const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) + 2402230587Sken sizeof(struct tcphdr) + tcp_options_len + payload_len; 2403230587Sken struct mbuf *mbufc; 2404230587Sken struct ether_header *eh; 2405230587Sken struct ip *iph; 2406230587Sken struct tcphdr *tcp; 2407230587Sken /* Use deliberately bad checksums, and verify that they don't get */ 2408230587Sken /* corrected by xnb_add_mbuf_cksum */ 2409230587Sken const uint16_t IP_CSUM = 0xdead; 2410230587Sken const uint16_t TCP_CSUM = 0xbeef; 2411230587Sken 2412230587Sken mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA); 2413230587Sken /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */ 2414230587Sken xnb_fill_tcp(mbufc); 2415230587Sken eh = mtod(mbufc, struct ether_header*); 2416230587Sken iph = (struct ip*)(eh + 1); 2417230587Sken iph->ip_sum = htons(IP_CSUM); 2418230587Sken tcp = (struct tcphdr*)(iph + 1); 2419230587Sken tcp->th_sum = htons(TCP_CSUM); 2420230587Sken 2421230587Sken /* fill in the length field */ 2422230587Sken mbufc->m_len = pkt_len; 2423230587Sken mbufc->m_pkthdr.len = pkt_len; 2424230587Sken /* indicate that the netfront does not use hw-assisted checksums */ 2425230587Sken mbufc->m_pkthdr.csum_flags = 0; 2426230587Sken 2427230587Sken /* Function under test */ 2428230587Sken xnb_add_mbuf_cksum(mbufc); 2429230587Sken 2430230587Sken /* Check that the checksums didn't change */ 2431230587Sken XNB_ASSERT(iph->ip_sum == htons(IP_CSUM)); 2432230587Sken XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM)); 2433230587Sken 2434230587Sken m_freem(mbufc); 2435230587Sken} 2436257515Sglebius#endif /* INET || INET6 */ 2437230587Sken 2438230587Sken/** 2439230587Sken * sscanf on unsigned chars 2440230587Sken */ 2441230587Skenstatic void 2442230587Skenxnb_sscanf_hhu(char *buffer, size_t buflen) 2443230587Sken{ 2444230587Sken const char mystr[] = "137"; 2445230587Sken uint8_t dest[12]; 2446230587Sken int i; 2447230587Sken 2448230587Sken for (i = 0; i < 12; i++) 2449230587Sken dest[i] = 'X'; 2450230587Sken 2451316362Sasomers XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1); 2452230587Sken for (i = 0; i < 12; i++) 2453230587Sken XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X')); 2454230587Sken} 2455230587Sken 2456230587Sken/** 2457230587Sken * sscanf on signed chars 2458230587Sken */ 2459230587Skenstatic void 2460230587Skenxnb_sscanf_hhd(char *buffer, size_t buflen) 2461230587Sken{ 2462230587Sken const char mystr[] = "-27"; 2463230587Sken int8_t dest[12]; 2464230587Sken int i; 2465230587Sken 2466230587Sken for (i = 0; i < 12; i++) 2467230587Sken dest[i] = 'X'; 2468230587Sken 2469316362Sasomers XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1); 2470230587Sken for (i = 0; i < 12; i++) 2471230587Sken XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X')); 2472230587Sken} 2473230587Sken 2474230587Sken/** 2475230587Sken * sscanf on signed long longs 2476230587Sken */ 2477230587Skenstatic void 2478230587Skenxnb_sscanf_lld(char *buffer, size_t buflen) 2479230587Sken{ 2480230587Sken const char mystr[] = "-123456789012345"; /* about -2**47 */ 2481230587Sken long long dest[3]; 2482230587Sken int i; 2483230587Sken 2484230587Sken for (i = 0; i < 3; i++) 2485230587Sken dest[i] = (long long)0xdeadbeefdeadbeef; 2486230587Sken 2487316362Sasomers XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1); 2488230587Sken for (i = 0; i < 3; i++) 2489230587Sken XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef : 2490230587Sken -123456789012345)); 2491230587Sken} 2492230587Sken 2493230587Sken/** 2494230587Sken * sscanf on unsigned long longs 2495230587Sken */ 2496230587Skenstatic void 2497230587Skenxnb_sscanf_llu(char *buffer, size_t buflen) 2498230587Sken{ 2499230587Sken const char mystr[] = "12802747070103273189"; 2500230587Sken unsigned long long dest[3]; 2501230587Sken int i; 2502230587Sken 2503230587Sken for (i = 0; i < 3; i++) 2504230587Sken dest[i] = (long long)0xdeadbeefdeadbeef; 2505230587Sken 2506316362Sasomers XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1); 2507230587Sken for (i = 0; i < 3; i++) 2508230587Sken XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef : 2509230587Sken 12802747070103273189ull)); 2510230587Sken} 2511230587Sken 2512230587Sken/** 2513230587Sken * sscanf on unsigned short short n's 2514230587Sken */ 2515230587Skenstatic void 2516230587Skenxnb_sscanf_hhn(char *buffer, size_t buflen) 2517230587Sken{ 2518230587Sken const char mystr[] = 2519230587Sken "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 2520230587Sken "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 2521230587Sken "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"; 2522230587Sken unsigned char dest[12]; 2523230587Sken int i; 2524230587Sken 2525230587Sken for (i = 0; i < 12; i++) 2526230587Sken dest[i] = (unsigned char)'X'; 2527230587Sken 2528316362Sasomers XNB_ASSERT(sscanf(mystr, 2529230587Sken "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 2530230587Sken "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 2531316362Sasomers "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0); 2532230587Sken for (i = 0; i < 12; i++) 2533230587Sken XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X')); 2534230587Sken} 2535