[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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2014-03-13 23:35:18 +00:00
parent a17ee3610d
commit 24bbaf6a38

View File

@@ -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 * Process received packet
* *
@@ -54,8 +60,32 @@ static int lotest_rx ( struct io_buffer *iobuf,
const void *ll_dest __unused, const void *ll_dest __unused,
const void *ll_source __unused, const void *ll_source __unused,
unsigned int flags __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, .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 * Wait for packet to be received
* *
* @v receiver Receiving network device*
* @v data Expected data * @v data Expected data
* @v len Expected data length * @v len Expected data length
* @ret rc Return status code * @ret rc Return status code
*/ */
static int loopback_wait ( struct net_device *receiver, void *data, static int loopback_wait ( void *data, size_t len ) {
size_t len ) {
struct ll_protocol *ll_protocol = receiver->ll_protocol;
struct io_buffer *iobuf; 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 */ /* Poll until packet arrives */
while ( 1 ) { while ( 1 ) {
@@ -112,28 +145,10 @@ static int loopback_wait ( struct net_device *receiver, void *data,
net_poll(); net_poll();
/* Dequeue packet, if available */ /* Dequeue packet, if available */
iobuf = netdev_rx_dequeue ( receiver ); iobuf = lotest_dequeue();
if ( ! iobuf ) if ( ! iobuf )
continue; 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 */ /* Check packet length */
if ( iob_len ( iobuf ) != len ) { if ( iob_len ( iobuf ) != len ) {
printf ( "\nLength mismatch: sent %zd, received %zd", 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 ( sender );
ifstat ( receiver ); ifstat ( receiver );
/* Freeze receive queue processing on the receiver, so that we /* Start loopback test */
* can extract all received packets. lotest_flush();
*/ lotest_active = 1;
netdev_rx_freeze ( receiver );
/* Perform loopback test */ /* Perform loopback test */
for ( successes = 0 ; ; successes++ ) { for ( successes = 0 ; ; successes++ ) {
@@ -240,12 +254,15 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
} }
/* Wait for received packet */ /* Wait for received packet */
if ( ( rc = loopback_wait ( receiver, buf, mtu ) ) != 0 ) if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 )
break; break;
} }
printf ( "\n"); printf ( "\n");
netdev_rx_unfreeze ( receiver );
/* Stop loopback testing */
lotest_active = 0;
lotest_flush();
/* Dump final statistics */ /* Dump final statistics */
ifstat ( sender ); ifstat ( sender );