#include <sys/cdefs.h>
#include <netinet/tcp.h>
#define SNCATF(buffer, buflen, ...) do { \
size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__); \
buffer += new_chars; \
\
buflen -= MIN(buflen, new_chars); \
} while (0)
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define XNB_ASSERT(cond) ({ \
int passed = (cond); \
char *_buffer = (buffer); \
size_t _buflen = (buflen); \
if (! passed) { \
strlcat(_buffer, __func__, _buflen); \
strlcat(_buffer, ":" TOSTRING(__LINE__) \
" Assertion Error: " #cond "\n", _buflen); \
} \
})
typedef void testcase_t(char *buffer, size_t buflen);
typedef int setup_t(void);
typedef void teardown_t(void);
struct test_fixture {
setup_t *setup;
testcase_t *test;
teardown_t *teardown;
};
typedef struct test_fixture test_fixture_t;
static int xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags);
static int xnb_unit_test_runner(test_fixture_t const tests[], int ntests,
char *buffer, size_t buflen);
static int __unused
null_setup(void) { return 0; }
static void __unused
null_teardown(void) { }
static setup_t setup_pvt_data;
static teardown_t teardown_pvt_data;
static testcase_t xnb_ring2pkt_emptyring;
static testcase_t xnb_ring2pkt_1req;
static testcase_t xnb_ring2pkt_2req;
static testcase_t xnb_ring2pkt_3req;
static testcase_t xnb_ring2pkt_extra;
static testcase_t xnb_ring2pkt_partial;
static testcase_t xnb_ring2pkt_wraps;
static testcase_t xnb_txpkt2rsp_emptypkt;
static testcase_t xnb_txpkt2rsp_1req;
static testcase_t xnb_txpkt2rsp_extra;
static testcase_t xnb_txpkt2rsp_long;
static testcase_t xnb_txpkt2rsp_invalid;
static testcase_t xnb_txpkt2rsp_error;
static testcase_t xnb_txpkt2rsp_wraps;
static testcase_t xnb_pkt2mbufc_empty;
static testcase_t xnb_pkt2mbufc_short;
static testcase_t xnb_pkt2mbufc_csum;
static testcase_t xnb_pkt2mbufc_1cluster;
static testcase_t xnb_pkt2mbufc_largecluster;
static testcase_t xnb_pkt2mbufc_2cluster;
static testcase_t xnb_txpkt2gnttab_empty;
static testcase_t xnb_txpkt2gnttab_short;
static testcase_t xnb_txpkt2gnttab_2req;
static testcase_t xnb_txpkt2gnttab_2cluster;
static testcase_t xnb_update_mbufc_short;
static testcase_t xnb_update_mbufc_2req;
static testcase_t xnb_update_mbufc_2cluster;
static testcase_t xnb_mbufc2pkt_empty;
static testcase_t xnb_mbufc2pkt_short;
static testcase_t xnb_mbufc2pkt_1cluster;
static testcase_t xnb_mbufc2pkt_2short;
static testcase_t xnb_mbufc2pkt_long;
static testcase_t xnb_mbufc2pkt_extra;
static testcase_t xnb_mbufc2pkt_nospace;
static testcase_t xnb_rxpkt2gnttab_empty;
static testcase_t xnb_rxpkt2gnttab_short;
static testcase_t xnb_rxpkt2gnttab_2req;
static testcase_t xnb_rxpkt2rsp_empty;
static testcase_t xnb_rxpkt2rsp_short;
static testcase_t xnb_rxpkt2rsp_extra;
static testcase_t xnb_rxpkt2rsp_2short;
static testcase_t xnb_rxpkt2rsp_2slots;
static testcase_t xnb_rxpkt2rsp_copyerror;
static testcase_t xnb_sscanf_llu;
static testcase_t xnb_sscanf_lld;
static testcase_t xnb_sscanf_hhu;
static testcase_t xnb_sscanf_hhd;
static testcase_t xnb_sscanf_hhn;
#if defined(INET) || defined(INET6)
static testcase_t xnb_add_mbuf_cksum_arp;
static testcase_t xnb_add_mbuf_cksum_tcp;
static testcase_t xnb_add_mbuf_cksum_udp;
static testcase_t xnb_add_mbuf_cksum_icmp;
static testcase_t xnb_add_mbuf_cksum_tcp_swcksum;
static void xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len,
uint16_t ip_id, uint16_t ip_p,
uint16_t ip_off, uint16_t ip_sum);
static void xnb_fill_tcp(struct mbuf *m);
#endif
static struct {
gnttab_copy_table gnttab;
netif_rx_back_ring_t rxb;
netif_rx_front_ring_t rxf;
netif_tx_back_ring_t txb;
netif_tx_front_ring_t txf;
struct ifnet* ifp;
netif_rx_sring_t* rxs;
netif_tx_sring_t* txs;
} xnb_unit_pvt;
static inline void safe_m_freem(struct mbuf **ppMbuf) {
if (*ppMbuf != NULL) {
m_freem(*ppMbuf);
*ppMbuf = NULL;
}
}
static int
xnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer,
size_t buflen)
{
int i;
int n_passes;
int n_failures = 0;
for (i = 0; i < ntests; i++) {
int error = tests[i].setup();
if (error != 0) {
SNCATF(buffer, buflen,
"Setup failed for test idx %d\n", i);
n_failures++;
} else {
size_t new_chars;
tests[i].test(buffer, buflen);
new_chars = strnlen(buffer, buflen);
buffer += new_chars;
buflen -= new_chars;
if (new_chars > 0) {
n_failures++;
}
}
tests[i].teardown();
}
n_passes = ntests - n_failures;
if (n_passes > 0) {
SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes);
}
if (n_failures > 0) {
SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures);
}
return n_failures;
}
#define TOTAL_TESTS (53)
#define TOTAL_BUFLEN (400 * TOTAL_TESTS + 2)
static int
xnb_unit_test_main(SYSCTL_HANDLER_ARGS) {
test_fixture_t const tests[TOTAL_TESTS] = {
{setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data},
{setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data},
{setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data},
{setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data},
{setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data},
{setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data},
{setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data},
{setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data},
{setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data},
#if defined(INET) || defined(INET6)
{null_setup, xnb_add_mbuf_cksum_arp, null_teardown},
{null_setup, xnb_add_mbuf_cksum_icmp, null_teardown},
{null_setup, xnb_add_mbuf_cksum_tcp, null_teardown},
{null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown},
{null_setup, xnb_add_mbuf_cksum_udp, null_teardown},
#endif
{null_setup, xnb_sscanf_hhd, null_teardown},
{null_setup, xnb_sscanf_hhu, null_teardown},
{null_setup, xnb_sscanf_lld, null_teardown},
{null_setup, xnb_sscanf_llu, null_teardown},
{null_setup, xnb_sscanf_hhn, null_teardown},
};
static char results[TOTAL_BUFLEN];
results[0] = 0;
xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN);
return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN)));
}
static int
setup_pvt_data(void)
{
int error = 0;
bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab));
xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
if (xnb_unit_pvt.txs != NULL) {
SHARED_RING_INIT(xnb_unit_pvt.txs);
BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE);
FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE);
} else {
error = 1;
}
xnb_unit_pvt.ifp = if_alloc(IFT_ETHER);
if (xnb_unit_pvt.ifp == NULL) {
error = 1;
}
xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
if (xnb_unit_pvt.rxs != NULL) {
SHARED_RING_INIT(xnb_unit_pvt.rxs);
BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE);
FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE);
} else {
error = 1;
}
return error;
}
static void
teardown_pvt_data(void)
{
if (xnb_unit_pvt.txs != NULL) {
free(xnb_unit_pvt.txs, M_XENNETBACK);
}
if (xnb_unit_pvt.rxs != NULL) {
free(xnb_unit_pvt.rxs, M_XENNETBACK);
}
if (xnb_unit_pvt.ifp != NULL) {
if_free(xnb_unit_pvt.ifp);
}
}
static void
xnb_ring2pkt_emptyring(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 0);
}
static void
xnb_ring2pkt_1req(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 69;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 1);
XNB_ASSERT(pkt.size == 69);
XNB_ASSERT(pkt.car_size == 69);
XNB_ASSERT(pkt.flags == 0);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.list_len == 1);
XNB_ASSERT(pkt.car == 0);
}
static void
xnb_ring2pkt_2req(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 100;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 40;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 2);
XNB_ASSERT(pkt.size == 100);
XNB_ASSERT(pkt.car_size == 60);
XNB_ASSERT(pkt.flags == 0);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.list_len == 2);
XNB_ASSERT(pkt.car == start_idx);
XNB_ASSERT(pkt.cdr == start_idx + 1);
}
static void
xnb_ring2pkt_3req(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 200;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 40;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 50;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 3);
XNB_ASSERT(pkt.size == 200);
XNB_ASSERT(pkt.car_size == 110);
XNB_ASSERT(pkt.flags == 0);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.list_len == 3);
XNB_ASSERT(pkt.car == start_idx);
XNB_ASSERT(pkt.cdr == start_idx + 1);
XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
}
static void
xnb_ring2pkt_extra(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
struct netif_extra_info *ext;
RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_extra_info | NETTXF_more_data;
req->size = 150;
xnb_unit_pvt.txf.req_prod_pvt++;
ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
ext->flags = 0;
ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
ext->u.gso.size = 250;
ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
ext->u.gso.features = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 50;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 3);
XNB_ASSERT(pkt.extra.flags == 0);
XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
XNB_ASSERT(pkt.extra.u.gso.size == 250);
XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4);
XNB_ASSERT(pkt.size == 150);
XNB_ASSERT(pkt.car_size == 100);
XNB_ASSERT(pkt.flags == NETTXF_extra_info);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.list_len == 2);
XNB_ASSERT(pkt.car == start_idx);
XNB_ASSERT(pkt.cdr == start_idx + 2);
XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req);
}
static void
xnb_ring2pkt_partial(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 150;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 0);
XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
}
static void
xnb_ring2pkt_wraps(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int num_consumed;
struct netif_tx_request *req;
unsigned int rsize;
rsize = RING_SIZE(&xnb_unit_pvt.txf);
xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
xnb_unit_pvt.txf.rsp_cons = rsize - 2;
xnb_unit_pvt.txs->req_prod = rsize - 2;
xnb_unit_pvt.txs->req_event = rsize - 1;
xnb_unit_pvt.txs->rsp_prod = rsize - 2;
xnb_unit_pvt.txs->rsp_event = rsize - 1;
xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
xnb_unit_pvt.txb.req_cons = rsize - 2;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 550;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 100;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 50;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
XNB_ASSERT(num_consumed == 3);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.list_len == 3);
XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
}
static void
xnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb;
netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs;
pkt.list_len = 0;
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
XNB_ASSERT(
memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0);
XNB_ASSERT(
memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0);
}
static void
xnb_txpkt2rsp_1req(char *buffer, size_t buflen)
{
uint16_t num_consumed;
struct xnb_pkt pkt;
struct netif_tx_request *req;
struct netif_tx_response *rsp;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 1000;
req->flags = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
xnb_unit_pvt.txb.req_cons += num_consumed;
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
};
static void
xnb_txpkt2rsp_extra(char *buffer, size_t buflen)
{
uint16_t num_consumed;
struct xnb_pkt pkt;
struct netif_tx_request *req;
netif_extra_info_t *ext;
struct netif_tx_response *rsp;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 1000;
req->flags = NETTXF_extra_info;
req->id = 69;
xnb_unit_pvt.txf.req_prod_pvt++;
ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
ext->flags = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
xnb_unit_pvt.txb.req_cons += num_consumed;
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 1);
XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
};
static void
xnb_txpkt2rsp_long(char *buffer, size_t buflen)
{
uint16_t num_consumed;
struct xnb_pkt pkt;
struct netif_tx_request *req;
netif_extra_info_t *ext;
struct netif_tx_response *rsp;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 1000;
req->flags = NETTXF_extra_info | NETTXF_more_data;
req->id = 254;
xnb_unit_pvt.txf.req_prod_pvt++;
ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
ext->flags = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 300;
req->flags = NETTXF_more_data;
req->id = 1034;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 400;
req->flags = 0;
req->id = 34;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
xnb_unit_pvt.txb.req_cons += num_consumed;
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
XNB_ASSERT(rsp->id ==
RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 1);
XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 2);
XNB_ASSERT(rsp->id ==
RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 3);
XNB_ASSERT(rsp->id ==
RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
}
static void
xnb_txpkt2rsp_invalid(char *buffer, size_t buflen)
{
uint16_t num_consumed;
struct xnb_pkt pkt;
struct netif_tx_request *req;
netif_extra_info_t *ext;
struct netif_tx_response *rsp;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 1000;
req->flags = NETTXF_extra_info;
req->id = 69;
xnb_unit_pvt.txf.req_prod_pvt++;
ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
ext->type = 0xFF;
ext->flags = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
xnb_unit_pvt.txb.req_cons += num_consumed;
XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 1);
XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
};
static void
xnb_txpkt2rsp_error(char *buffer, size_t buflen)
{
uint16_t num_consumed;
struct xnb_pkt pkt;
struct netif_tx_request *req;
struct netif_tx_response *rsp;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->size = 1000;
req->flags = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
xnb_unit_pvt.txb.req_cons += num_consumed;
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
};
static void
xnb_txpkt2rsp_wraps(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
struct netif_tx_request *req;
struct netif_tx_response *rsp;
unsigned int rsize;
rsize = RING_SIZE(&xnb_unit_pvt.txf);
xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
xnb_unit_pvt.txf.rsp_cons = rsize - 2;
xnb_unit_pvt.txs->req_prod = rsize - 2;
xnb_unit_pvt.txs->req_event = rsize - 1;
xnb_unit_pvt.txs->rsp_prod = rsize - 2;
xnb_unit_pvt.txs->rsp_event = rsize - 1;
xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
xnb_unit_pvt.txb.req_cons = rsize - 2;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 550;
req->id = 1;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 100;
req->id = 2;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 50;
req->id = 3;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
XNB_ASSERT(
xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
xnb_unit_pvt.txf.rsp_cons + 2);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
}
static int
xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags)
{
struct netif_tx_request *req;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = flags;
req->size = size;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb,
xnb_unit_pvt.txb.req_cons);
}
static void
xnb_pkt2mbufc_empty(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
struct mbuf *pMbuf;
pkt.list_len = 0;
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pkt.size = 0;
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
safe_m_freem(&pMbuf);
}
static void
xnb_pkt2mbufc_short(char *buffer, size_t buflen)
{
const size_t size = MINCLSIZE - 1;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
xnb_get1pkt(&pkt, size, 0);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
safe_m_freem(&pMbuf);
}
static void
xnb_pkt2mbufc_csum(char *buffer, size_t buflen)
{
const size_t size = MINCLSIZE - 1;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
xnb_get1pkt(&pkt, size, NETTXF_data_validated);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED);
XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID);
XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID);
XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR);
safe_m_freem(&pMbuf);
}
static void
xnb_pkt2mbufc_1cluster(char *buffer, size_t buflen)
{
const size_t size = MINCLSIZE;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
xnb_get1pkt(&pkt, size, 0);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
safe_m_freem(&pMbuf);
}
static void
xnb_pkt2mbufc_largecluster(char *buffer, size_t buflen)
{
const size_t size = MCLBYTES + 1;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
xnb_get1pkt(&pkt, size, 0);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
safe_m_freem(&pMbuf);
}
static void
xnb_pkt2mbufc_2cluster(char *buffer, size_t buflen)
{
const size_t size = 2 * MCLBYTES + 1;
size_t space = 0;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
struct mbuf *m;
xnb_get1pkt(&pkt, size, 0);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
for (m = pMbuf; m != NULL; m = m->m_next) {
space += M_TRAILINGSPACE(m);
}
XNB_ASSERT(space >= size);
safe_m_freem(&pMbuf);
}
static void
xnb_txpkt2gnttab_empty(char *buffer, size_t buflen)
{
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
pkt.list_len = 0;
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pkt.size = 0;
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
XNB_ASSERT(n_entries == 0);
safe_m_freem(&pMbuf);
}
static void
xnb_txpkt2gnttab_short(char *buffer, size_t buflen)
{
const size_t size = MINCLSIZE - 1;
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = size;
req->gref = 7;
req->offset = 17;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
XNB_ASSERT(n_entries == 1);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
mtod(pMbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn ==
virt_to_mfn(mtod(pMbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
safe_m_freem(&pMbuf);
}
static void
xnb_txpkt2gnttab_2req(char *buffer, size_t buflen)
{
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 1900;
req->gref = 7;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 500;
req->gref = 8;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
XNB_ASSERT(n_entries == 2);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
mtod(pMbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500);
XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
mtod(pMbuf, vm_offset_t) + 1400));
safe_m_freem(&pMbuf);
}
static void
xnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen)
{
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = data_this_transaction;
req->gref = 8;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
XNB_ASSERT(pMbuf != NULL);
if (pMbuf == NULL)
return;
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) {
XNB_ASSERT(n_entries == 3);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES);
XNB_ASSERT(
xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
mtod(pMbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES);
XNB_ASSERT(
xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
mtod(pMbuf->m_next, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES);
XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1);
XNB_ASSERT(
xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset(
mtod(pMbuf->m_next, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 *
MCLBYTES);
} else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) {
XNB_ASSERT(n_entries == 2);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES);
XNB_ASSERT(
xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
mtod(pMbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1);
XNB_ASSERT(
xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
mtod(pMbuf->m_next, vm_offset_t)));
XNB_ASSERT(
xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES);
} else {
XNB_ASSERT(0);
}
m_freem(pMbuf);
}
static void
xnb_update_mbufc_short(char *buffer, size_t buflen)
{
const size_t size = MINCLSIZE - 1;
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = size;
req->gref = 7;
req->offset = 17;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
xnb_unit_pvt.gnttab[0].status = GNTST_okay;
xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
XNB_ASSERT(pMbuf->m_len == size);
XNB_ASSERT(pMbuf->m_pkthdr.len == size);
safe_m_freem(&pMbuf);
}
static void
xnb_update_mbufc_2req(char *buffer, size_t buflen)
{
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = NETTXF_more_data;
req->size = 1900;
req->gref = 7;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = 500;
req->gref = 8;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
xnb_unit_pvt.gnttab[0].status = GNTST_okay;
xnb_unit_pvt.gnttab[1].status = GNTST_okay;
xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
XNB_ASSERT(n_entries == 2);
XNB_ASSERT(pMbuf->m_pkthdr.len == 1900);
XNB_ASSERT(pMbuf->m_len == 1900);
safe_m_freem(&pMbuf);
}
static void
xnb_update_mbufc_2cluster(char *buffer, size_t buflen)
{
int i;
int n_entries;
struct xnb_pkt pkt;
struct mbuf *pMbuf;
const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
xnb_unit_pvt.txf.req_prod_pvt);
req->flags = 0;
req->size = data_this_transaction;
req->gref = 8;
req->offset = 0;
xnb_unit_pvt.txf.req_prod_pvt++;
RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
for (i = 0; i < n_entries; i++) {
xnb_unit_pvt.gnttab[0].status = GNTST_okay;
}
xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
if (n_entries == 3) {
XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
XNB_ASSERT(pMbuf->m_len == MCLBYTES);
XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES);
XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1);
} else if (n_entries == 2) {
XNB_ASSERT(n_entries == 2);
XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES);
XNB_ASSERT(pMbuf->m_next->m_len == 1);
} else {
XNB_ASSERT(0);
}
safe_m_freem(&pMbuf);
}
static void
xnb_mbufc2pkt_empty(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
int free_slots = 64;
struct mbuf *mbuf;
mbuf = m_get(M_WAITOK, MT_DATA);
XNB_ASSERT(mbuf->m_len == 0);
xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
safe_m_freem(&mbuf);
}
static void
xnb_mbufc2pkt_short(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size = 128;
int free_slots = 64;
RING_IDX start = 9;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.size == size);
XNB_ASSERT(pkt.car_size == size);
XNB_ASSERT(! (pkt.flags &
(NETRXF_more_data | NETRXF_extra_info)));
XNB_ASSERT(pkt.list_len == 1);
XNB_ASSERT(pkt.car == start);
safe_m_freem(&mbuf);
}
static void
xnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size = MCLBYTES;
int free_slots = 32;
RING_IDX start = 12;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.size == size);
XNB_ASSERT(pkt.car_size == size);
XNB_ASSERT(! (pkt.flags &
(NETRXF_more_data | NETRXF_extra_info)));
XNB_ASSERT(pkt.list_len == 1);
XNB_ASSERT(pkt.car == start);
safe_m_freem(&mbuf);
}
static void
xnb_mbufc2pkt_2short(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size1 = MHLEN - 5;
size_t size2 = MHLEN - 15;
int free_slots = 32;
RING_IDX start = 14;
struct mbuf *mbufc, *mbufc2;
mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc2 != NULL);
if (mbufc2 == NULL) {
safe_m_freem(&mbufc);
return;
}
mbufc2->m_pkthdr.len = size1 + size2;
mbufc2->m_len = size1;
xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.size == size1 + size2);
XNB_ASSERT(pkt.car == start);
if (mbufc2->m_next != NULL) {
XNB_ASSERT(pkt.car_size == size1);
XNB_ASSERT(pkt.list_len == 1);
XNB_ASSERT(pkt.cdr == start + 1);
}
safe_m_freem(&mbufc2);
}
static void
xnb_mbufc2pkt_long(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size = 14 * MCLBYTES / 3;
size_t size_remaining;
int free_slots = 15;
RING_IDX start = 3;
struct mbuf *mbufc, *m;
mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
mbufc->m_pkthdr.len = size;
size_remaining = size;
for (m = mbufc; m != NULL; m = m->m_next) {
m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
size_remaining -= m->m_len;
}
xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.size == size);
XNB_ASSERT(pkt.car == start);
XNB_ASSERT(pkt.car_size = mbufc->m_len);
XNB_ASSERT(! (pkt.flags & NETRXF_extra_info));
XNB_ASSERT(pkt.cdr == pkt.car + 1);
safe_m_freem(&mbufc);
}
static void
xnb_mbufc2pkt_extra(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size = 14 * MCLBYTES / 3;
size_t size_remaining;
int free_slots = 15;
RING_IDX start = 3;
struct mbuf *mbufc, *m;
mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
mbufc->m_pkthdr.len = size;
mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40;
size_remaining = size;
for (m = mbufc; m != NULL; m = m->m_next) {
m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
size_remaining -= m->m_len;
}
xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
XNB_ASSERT(xnb_pkt_is_valid(&pkt));
XNB_ASSERT(pkt.size == size);
XNB_ASSERT(pkt.car == start);
XNB_ASSERT(pkt.car_size = mbufc->m_len);
XNB_ASSERT(pkt.flags & NETRXF_extra_info);
XNB_ASSERT(pkt.flags & NETRXF_data_validated);
XNB_ASSERT(pkt.cdr == pkt.car + 2);
XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz);
XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE));
safe_m_freem(&mbufc);
}
static void
xnb_mbufc2pkt_nospace(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
size_t size = 14 * MCLBYTES / 3;
size_t size_remaining;
int free_slots = 2;
RING_IDX start = 3;
struct mbuf *mbufc, *m;
int error;
mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
mbufc->m_pkthdr.len = size;
size_remaining = size;
for (m = mbufc; m != NULL; m = m->m_next) {
m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
size_remaining -= m->m_len;
}
error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
XNB_ASSERT(error == EAGAIN);
XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
safe_m_freem(&mbufc);
}
static void
xnb_rxpkt2gnttab_empty(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries;
int free_slots = 60;
struct mbuf *mbuf;
mbuf = m_get(M_WAITOK, MT_DATA);
xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
XNB_ASSERT(nr_entries == 0);
safe_m_freem(&mbuf);
}
static void
xnb_rxpkt2gnttab_short(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
int nr_entries;
size_t size = 128;
int free_slots = 60;
RING_IDX start = 9;
struct netif_rx_request *req;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
xnb_unit_pvt.txf.req_prod_pvt);
req->gref = 7;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
XNB_ASSERT(nr_entries == 1);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset(
mtod(mbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn ==
virt_to_mfn(mtod(mbuf, vm_offset_t)));
XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
safe_m_freem(&mbuf);
}
static void
xnb_rxpkt2gnttab_2req(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries;
int i, num_mbufs;
size_t total_granted_size = 0;
size_t size = MJUMPAGESIZE + 1;
int free_slots = 60;
RING_IDX start = 11;
struct netif_rx_request *req;
struct mbuf *mbuf, *m;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) {
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
xnb_unit_pvt.txf.req_prod_pvt);
req->gref = i;
req->id = 5;
}
num_mbufs = i;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
XNB_ASSERT(nr_entries >= num_mbufs);
for (i = 0; i < nr_entries; i++) {
int end_offset = xnb_unit_pvt.gnttab[i].len +
xnb_unit_pvt.gnttab[i].dest.offset;
XNB_ASSERT(end_offset <= PAGE_SIZE);
total_granted_size += xnb_unit_pvt.gnttab[i].len;
}
XNB_ASSERT(total_granted_size == size);
}
static void
xnb_rxpkt2rsp_empty(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries;
int nr_reqs;
int free_slots = 60;
netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb;
netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs;
struct mbuf *mbuf;
mbuf = m_get(M_WAITOK, MT_DATA);
xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_reqs == 0);
XNB_ASSERT(
memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0);
XNB_ASSERT(
memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0);
safe_m_freem(&mbuf);
}
static void
xnb_rxpkt2rsp_short(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries, nr_reqs;
size_t size = 128;
int free_slots = 60;
RING_IDX start = 5;
struct netif_rx_request *req;
struct netif_rx_response *rsp;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
req->gref = 7;
xnb_unit_pvt.rxb.req_cons = start;
xnb_unit_pvt.rxb.rsp_prod_pvt = start;
xnb_unit_pvt.rxs->req_prod = start + 1;
xnb_unit_pvt.rxs->rsp_prod = start;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_reqs == 1);
XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
XNB_ASSERT(rsp->id == req->id);
XNB_ASSERT(rsp->offset == 0);
XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0);
XNB_ASSERT(rsp->status == size);
safe_m_freem(&mbuf);
}
static void
xnb_rxpkt2rsp_extra(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries, nr_reqs;
size_t size = 14;
int free_slots = 15;
RING_IDX start = 3;
uint16_t id = 49;
uint16_t gref = 65;
uint16_t mss = TCP_MSS - 40;
struct mbuf *mbufc;
struct netif_rx_request *req;
struct netif_rx_response *rsp;
struct netif_extra_info *ext;
mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
mbufc->m_pkthdr.len = size;
mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
mbufc->m_pkthdr.tso_segsz = mss;
mbufc->m_len = size;
xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
req->id = id;
req->gref = gref;
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
req->id = id + 1;
req->gref = gref + 1;
xnb_unit_pvt.rxb.req_cons = start;
xnb_unit_pvt.rxb.rsp_prod_pvt = start;
xnb_unit_pvt.rxs->req_prod = start + 2;
xnb_unit_pvt.rxs->rsp_prod = start;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_reqs == 2);
XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
XNB_ASSERT(rsp->id == id);
XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0);
XNB_ASSERT((rsp->flags & NETRXF_extra_info));
XNB_ASSERT((rsp->flags & NETRXF_data_validated));
XNB_ASSERT((rsp->flags & NETRXF_csum_blank));
XNB_ASSERT(rsp->status == size);
ext = (struct netif_extra_info*)
RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO);
XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE));
XNB_ASSERT(ext->u.gso.size == mss);
XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO);
safe_m_freem(&mbufc);
}
static void
xnb_rxpkt2rsp_2slots(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries, nr_reqs;
size_t size = PAGE_SIZE + 100;
int free_slots = 3;
uint16_t id1 = 17;
uint16_t id2 = 37;
uint16_t gref1 = 24;
uint16_t gref2 = 34;
RING_IDX start = 15;
struct netif_rx_request *req;
struct netif_rx_response *rsp;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
if (mbuf->m_next != NULL) {
size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size);
mbuf->m_len = first_len;
mbuf->m_next->m_len = size - first_len;
} else {
mbuf->m_len = size;
}
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
req->gref = gref1;
req->id = id1;
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
req->gref = gref2;
req->id = id2;
xnb_unit_pvt.rxb.req_cons = start;
xnb_unit_pvt.rxb.rsp_prod_pvt = start;
xnb_unit_pvt.rxs->req_prod = start + 2;
xnb_unit_pvt.rxs->rsp_prod = start;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_reqs == 2);
XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
XNB_ASSERT(rsp->id == id1);
XNB_ASSERT(rsp->offset == 0);
XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
XNB_ASSERT(rsp->flags & NETRXF_more_data);
XNB_ASSERT(rsp->status == PAGE_SIZE);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
XNB_ASSERT(rsp->id == id2);
XNB_ASSERT(rsp->offset == 0);
XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
XNB_ASSERT(! (rsp->flags & NETRXF_more_data));
XNB_ASSERT(rsp->status == size - PAGE_SIZE);
safe_m_freem(&mbuf);
}
static void
xnb_rxpkt2rsp_2short(char *buffer, size_t buflen) {
struct xnb_pkt pkt;
int nr_reqs, nr_entries;
size_t size1 = MHLEN - 5;
size_t size2 = MHLEN - 15;
int free_slots = 32;
RING_IDX start = 14;
uint16_t id = 47;
uint16_t gref = 54;
struct netif_rx_request *req;
struct netif_rx_response *rsp;
struct mbuf *mbufc;
mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc != NULL);
if (mbufc == NULL)
return;
mbufc->m_flags |= M_PKTHDR;
m_getm(mbufc, size2, M_WAITOK, MT_DATA);
XNB_ASSERT(mbufc->m_next != NULL);
mbufc->m_pkthdr.len = size1 + size2;
mbufc->m_len = size1;
mbufc->m_next->m_len = size2;
xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
req->gref = gref;
req->id = id;
xnb_unit_pvt.rxb.req_cons = start;
xnb_unit_pvt.rxb.rsp_prod_pvt = start;
xnb_unit_pvt.rxs->req_prod = start + 1;
xnb_unit_pvt.rxs->rsp_prod = start;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_entries == 2);
XNB_ASSERT(nr_reqs == 1);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
XNB_ASSERT(rsp->id == id);
XNB_ASSERT(rsp->status == size1 + size2);
XNB_ASSERT(rsp->offset == 0);
XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info)));
safe_m_freem(&mbufc);
}
static void
xnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen)
{
struct xnb_pkt pkt;
int nr_entries, nr_reqs;
int id = 7;
int gref = 42;
uint16_t canary = 6859;
size_t size = 7 * MCLBYTES;
int free_slots = 9;
RING_IDX start = 2;
struct netif_rx_request *req;
struct netif_rx_response *rsp;
struct mbuf *mbuf;
mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
mbuf->m_flags |= M_PKTHDR;
mbuf->m_pkthdr.len = size;
mbuf->m_len = size;
xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
req->gref = gref;
req->id = id;
xnb_unit_pvt.rxb.req_cons = start;
xnb_unit_pvt.rxb.rsp_prod_pvt = start;
xnb_unit_pvt.rxs->req_prod = start + 1;
xnb_unit_pvt.rxs->rsp_prod = start;
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
req->gref = canary;
req->id = canary;
nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
xnb_unit_pvt.gnttab[2].status = GNTST_general_error;
nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
&xnb_unit_pvt.rxb);
XNB_ASSERT(nr_reqs == 1);
XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
XNB_ASSERT(rsp->id == id);
XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
XNB_ASSERT(req->gref == canary);
XNB_ASSERT(req->id == canary);
safe_m_freem(&mbuf);
}
#if defined(INET) || defined(INET6)
static void
xnb_add_mbuf_cksum_arp(char *buffer, size_t buflen)
{
const size_t pkt_len = sizeof(struct ether_header) +
sizeof(struct ether_arp);
struct mbuf *mbufc;
struct ether_header *eh;
struct ether_arp *ep;
unsigned char pkt_orig[pkt_len];
mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
eh = mtod(mbufc, struct ether_header*);
eh->ether_dhost[0] = 0xff;
eh->ether_dhost[1] = 0xff;
eh->ether_dhost[2] = 0xff;
eh->ether_dhost[3] = 0xff;
eh->ether_dhost[4] = 0xff;
eh->ether_dhost[5] = 0xff;
eh->ether_shost[0] = 0x00;
eh->ether_shost[1] = 0x15;
eh->ether_shost[2] = 0x17;
eh->ether_shost[3] = 0xe9;
eh->ether_shost[4] = 0x30;
eh->ether_shost[5] = 0x68;
eh->ether_type = htons(ETHERTYPE_ARP);
ep = (struct ether_arp*)(eh + 1);
ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
ep->ea_hdr.ar_hln = 6;
ep->ea_hdr.ar_pln = 4;
ep->ea_hdr.ar_op = htons(ARPOP_REQUEST);
ep->arp_sha[0] = 0x00;
ep->arp_sha[1] = 0x15;
ep->arp_sha[2] = 0x17;
ep->arp_sha[3] = 0xe9;
ep->arp_sha[4] = 0x30;
ep->arp_sha[5] = 0x68;
ep->arp_spa[0] = 0xc0;
ep->arp_spa[1] = 0xa8;
ep->arp_spa[2] = 0x0a;
ep->arp_spa[3] = 0x04;
bzero(&(ep->arp_tha), ETHER_ADDR_LEN);
ep->arp_tpa[0] = 0xc0;
ep->arp_tpa[1] = 0xa8;
ep->arp_tpa[2] = 0x0a;
ep->arp_tpa[3] = 0x06;
mbufc->m_len = pkt_len;
mbufc->m_pkthdr.len = pkt_len;
mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len);
xnb_add_mbuf_cksum(mbufc);
XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0);
m_freem(mbufc);
}
static void
xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id,
uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum)
{
struct ether_header *eh;
struct ip *iph;
eh = mtod(m, struct ether_header*);
eh->ether_dhost[0] = 0x00;
eh->ether_dhost[1] = 0x16;
eh->ether_dhost[2] = 0x3e;
eh->ether_dhost[3] = 0x23;
eh->ether_dhost[4] = 0x50;
eh->ether_dhost[5] = 0x0b;
eh->ether_shost[0] = 0x00;
eh->ether_shost[1] = 0x16;
eh->ether_shost[2] = 0x30;
eh->ether_shost[3] = 0x00;
eh->ether_shost[4] = 0x00;
eh->ether_shost[5] = 0x00;
eh->ether_type = htons(ETHERTYPE_IP);
iph = (struct ip*)(eh + 1);
iph->ip_hl = 0x5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = htons(ip_len);
iph->ip_id = htons(ip_id);
iph->ip_off = htons(ip_off);
iph->ip_ttl = 64;
iph->ip_p = ip_p;
iph->ip_sum = htons(ip_sum);
iph->ip_src.s_addr = htonl(0xc0a80a04);
iph->ip_dst.s_addr = htonl(0xc0a80a05);
}
static void
xnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen)
{
const size_t icmp_len = 64;
const size_t pkt_len = sizeof(struct ether_header) +
sizeof(struct ip) + icmp_len;
struct mbuf *mbufc;
struct ether_header *eh;
struct ip *iph;
struct icmp *icmph;
unsigned char pkt_orig[icmp_len];
uint32_t *tv_field;
uint8_t *data_payload;
int i;
const uint16_t ICMP_CSUM = 0xaed7;
const uint16_t IP_CSUM = 0xe533;
mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
eh = mtod(mbufc, struct ether_header*);
xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0);
iph = (struct ip*)(eh + 1);
icmph = (struct icmp*)(iph + 1);
icmph->icmp_type = ICMP_ECHO;
icmph->icmp_code = 0;
icmph->icmp_cksum = htons(ICMP_CSUM);
icmph->icmp_id = htons(31492);
icmph->icmp_seq = htons(0);
tv_field = (uint32_t*)(&(icmph->icmp_hun));
tv_field[0] = 0x4f02cfac;
tv_field[1] = 0x0007c46a;
data_payload = (uint8_t*)(&tv_field[2]);
for (i = 8; i < 37; i++) {
*data_payload++ = i;
}
mbufc->m_len = pkt_len;
mbufc->m_pkthdr.len = pkt_len;
mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len);
xnb_add_mbuf_cksum(mbufc);
XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len));
m_freem(mbufc);
}
static void
xnb_add_mbuf_cksum_udp(char *buffer, size_t buflen)
{
const size_t udp_len = 16;
const size_t pkt_len = sizeof(struct ether_header) +
sizeof(struct ip) + udp_len;
struct mbuf *mbufc;
struct ether_header *eh;
struct ip *iph;
struct udphdr *udp;
uint8_t *data_payload;
const uint16_t IP_CSUM = 0xe56b;
const uint16_t UDP_CSUM = 0xdde2;
mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
eh = mtod(mbufc, struct ether_header*);
xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad);
iph = (struct ip*)(eh + 1);
udp = (struct udphdr*)(iph + 1);
udp->uh_sport = htons(0x51ae);
udp->uh_dport = htons(0x08ae);
udp->uh_ulen = htons(udp_len);
udp->uh_sum = htons(0xbaad);
data_payload = (uint8_t*)(udp + 1);
data_payload[0] = 'F';
data_payload[1] = 'r';
data_payload[2] = 'e';
data_payload[3] = 'e';
data_payload[4] = 'B';
data_payload[5] = 'S';
data_payload[6] = 'D';
data_payload[7] = '\n';
mbufc->m_len = pkt_len;
mbufc->m_pkthdr.len = pkt_len;
mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
xnb_add_mbuf_cksum(mbufc);
XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM));
m_freem(mbufc);
}
static void
xnb_fill_tcp(struct mbuf *m)
{
struct ether_header *eh;
struct ip *iph;
struct tcphdr *tcp;
uint32_t *options;
uint8_t *data_payload;
eh = mtod(m, struct ether_header*);
xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0);
iph = (struct ip*)(eh + 1);
tcp = (struct tcphdr*)(iph + 1);
tcp->th_sport = htons(0x9cd9);
tcp->th_dport = htons(2222);
tcp->th_seq = htonl(0x00f72b10);
tcp->th_ack = htonl(0x7f37ba6c);
tcp_set_flags(tcp, TH_ACK | TH_PUSH);
tcp->th_off = 8;
tcp->th_win = htons(0x410);
tcp->th_sum = htons(0xbaad);
tcp->th_urp = htons(0);
options = (uint32_t*)(tcp + 1);
options[0] = htonl(0x0101080a);
options[1] = htonl(0x000081df);
options[2] = htonl(0xce18207f);
data_payload = (uint8_t*)(&options[3]);
data_payload[0] = 'F';
data_payload[1] = 'r';
data_payload[2] = 'e';
data_payload[3] = 'e';
data_payload[4] = 'B';
data_payload[5] = 'S';
data_payload[6] = 'D';
data_payload[7] = '\n';
}
static void
xnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen)
{
const size_t payload_len = 8;
const size_t tcp_options_len = 12;
const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
sizeof(struct tcphdr) + tcp_options_len + payload_len;
struct mbuf *mbufc;
struct ether_header *eh;
struct ip *iph;
struct tcphdr *tcp;
const uint16_t IP_CSUM = 0xa55a;
const uint16_t TCP_CSUM = 0x2f64;
mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
xnb_fill_tcp(mbufc);
eh = mtod(mbufc, struct ether_header*);
iph = (struct ip*)(eh + 1);
tcp = (struct tcphdr*)(iph + 1);
mbufc->m_len = pkt_len;
mbufc->m_pkthdr.len = pkt_len;
mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
xnb_add_mbuf_cksum(mbufc);
XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
m_freem(mbufc);
}
static void
xnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen)
{
const size_t payload_len = 8;
const size_t tcp_options_len = 12;
const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
sizeof(struct tcphdr) + tcp_options_len + payload_len;
struct mbuf *mbufc;
struct ether_header *eh;
struct ip *iph;
struct tcphdr *tcp;
const uint16_t IP_CSUM = 0xdead;
const uint16_t TCP_CSUM = 0xbeef;
mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
xnb_fill_tcp(mbufc);
eh = mtod(mbufc, struct ether_header*);
iph = (struct ip*)(eh + 1);
iph->ip_sum = htons(IP_CSUM);
tcp = (struct tcphdr*)(iph + 1);
tcp->th_sum = htons(TCP_CSUM);
mbufc->m_len = pkt_len;
mbufc->m_pkthdr.len = pkt_len;
mbufc->m_pkthdr.csum_flags = 0;
xnb_add_mbuf_cksum(mbufc);
XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
m_freem(mbufc);
}
#endif
static void
xnb_sscanf_hhu(char *buffer, size_t buflen)
{
const char mystr[] = "137";
uint8_t dest[12];
int i;
for (i = 0; i < 12; i++)
dest[i] = 'X';
XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1);
for (i = 0; i < 12; i++)
XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X'));
}
static void
xnb_sscanf_hhd(char *buffer, size_t buflen)
{
const char mystr[] = "-27";
int8_t dest[12];
int i;
for (i = 0; i < 12; i++)
dest[i] = 'X';
XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1);
for (i = 0; i < 12; i++)
XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X'));
}
static void
xnb_sscanf_lld(char *buffer, size_t buflen)
{
const char mystr[] = "-123456789012345";
long long dest[3];
int i;
for (i = 0; i < 3; i++)
dest[i] = (long long)0xdeadbeefdeadbeef;
XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1);
for (i = 0; i < 3; i++)
XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
-123456789012345));
}
static void
xnb_sscanf_llu(char *buffer, size_t buflen)
{
const char mystr[] = "12802747070103273189";
unsigned long long dest[3];
int i;
for (i = 0; i < 3; i++)
dest[i] = (long long)0xdeadbeefdeadbeef;
XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1);
for (i = 0; i < 3; i++)
XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
12802747070103273189ull));
}
static void
xnb_sscanf_hhn(char *buffer, size_t buflen)
{
const char mystr[] =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f";
unsigned char dest[12];
int i;
for (i = 0; i < 12; i++)
dest[i] = (unsigned char)'X';
XNB_ASSERT(sscanf(mystr,
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0);
for (i = 0; i < 12; i++)
XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X'));
}