From 24bbaf6a38f52ef7e942fb4cea36529091af2a0c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Mar 2014 23:35:18 +0000 Subject: [PATCH] [lotest] Allow loopback testing on shared networks Allow for extraneous packets to be received during loopback testing, and so permit loopback tests to be performed when ports are connected to a switch (rather than requiring ports to be directly connected with a loopback cable). Signed-off-by: Michael Brown --- src/usr/lotest.c | 89 ++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/src/usr/lotest.c b/src/usr/lotest.c index 51d1a5d6..9e2ac331 100644 --- a/src/usr/lotest.c +++ b/src/usr/lotest.c @@ -39,6 +39,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Loopback testing in progress flag */ +static int lotest_active; + +/** Loopback testing received packets */ +static LIST_HEAD ( lotest_queue ); + /** * Process received packet * @@ -54,8 +60,32 @@ static int lotest_rx ( struct io_buffer *iobuf, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused ) { - free_iob ( iobuf ); - return -ENOTSUP; + + /* Add to received packet queue if currently performing a test */ + if ( lotest_active ) { + list_add_tail ( &iobuf->list, &lotest_queue ); + } else { + free_iob ( iobuf ); + } + + return 0; +} + +/** + * Dequeue received packet + * + * @ret iobuf I/O buffer, or NULL + */ +static struct io_buffer * lotest_dequeue ( void ) { + struct io_buffer *iobuf; + + /* Remove first packet (if any) from received packet queue */ + iobuf = list_first_entry ( &lotest_queue, struct io_buffer, list ); + if ( ! iobuf ) + return NULL; + list_del ( &iobuf->list ); + + return iobuf; } /** @@ -83,23 +113,26 @@ static struct net_protocol lotest_protocol __net_protocol = { .net_addr_len = 0, }; +/** + * Discard all received loopback test packets + * + */ +static void lotest_flush ( void ) { + struct io_buffer *iobuf; + + while ( ( iobuf = lotest_dequeue() ) != NULL ) + free_iob ( iobuf ); +} + /** * Wait for packet to be received * - * @v receiver Receiving network device* * @v data Expected data * @v len Expected data length * @ret rc Return status code */ -static int loopback_wait ( struct net_device *receiver, void *data, - size_t len ) { - struct ll_protocol *ll_protocol = receiver->ll_protocol; +static int loopback_wait ( void *data, size_t len ) { struct io_buffer *iobuf; - const void *ll_dest; - const void *ll_source; - uint16_t net_proto; - unsigned int flags; - int rc; /* Poll until packet arrives */ while ( 1 ) { @@ -112,28 +145,10 @@ static int loopback_wait ( struct net_device *receiver, void *data, net_poll(); /* Dequeue packet, if available */ - iobuf = netdev_rx_dequeue ( receiver ); + iobuf = lotest_dequeue(); if ( ! iobuf ) continue; - /* Strip link-layer header */ - if ( ( rc = ll_protocol->pull ( receiver, iobuf, &ll_dest, - &ll_source, &net_proto, - &flags ) ) != 0 ) { - printf ( "\nFailed to strip link-layer header: %s", - strerror ( rc ) ); - free_iob ( iob_disown ( iobuf ) ); - return rc; - } - - /* Ignore non-loopback packets */ - if ( net_proto != lotest_protocol.net_proto ) { - printf ( "\nReceived spurious packet type %04x\n", - ntohs ( net_proto ) ); - free_iob ( iob_disown ( iobuf ) ); - continue; - } - /* Check packet length */ if ( iob_len ( iobuf ) != len ) { printf ( "\nLength mismatch: sent %zd, received %zd", @@ -206,10 +221,9 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, ifstat ( sender ); ifstat ( receiver ); - /* Freeze receive queue processing on the receiver, so that we - * can extract all received packets. - */ - netdev_rx_freeze ( receiver ); + /* Start loopback test */ + lotest_flush(); + lotest_active = 1; /* Perform loopback test */ for ( successes = 0 ; ; successes++ ) { @@ -240,12 +254,15 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, } /* Wait for received packet */ - if ( ( rc = loopback_wait ( receiver, buf, mtu ) ) != 0 ) + if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 ) break; } printf ( "\n"); - netdev_rx_unfreeze ( receiver ); + + /* Stop loopback testing */ + lotest_active = 0; + lotest_flush(); /* Dump final statistics */ ifstat ( sender );