[dpdk-dev,1/1] app/test: create ring and ethdevs in pmd_ring_autotest

Message ID 1448292046-22682-1-git-send-email-bernard.iremonger@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Iremonger, Bernard Nov. 23, 2015, 3:20 p.m. UTC
  Use command line option --vdev=eth_ring0 to create port 0.
Create two rings and five ethdevs in test_pmd_ring for ports 1 to 5.
Improve test output by adding the port number to printf statements,
and adding a printf describing each test.

revise ring-based PMD doc to match latest ring PMD code.

Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
 app/test/test_pmd_ring.c      | 360 +++++++++++++++++++++++++-----------------
 doc/guides/nics/pcap_ring.rst |  28 ++--
 2 files changed, 235 insertions(+), 153 deletions(-)
  

Comments

Bruce Richardson Nov. 24, 2015, 4:14 p.m. UTC | #1
On Mon, Nov 23, 2015 at 03:20:46PM +0000, Bernard Iremonger wrote:
> Use command line option --vdev=eth_ring0 to create port 0.
> Create two rings and five ethdevs in test_pmd_ring for ports 1 to 5.
> Improve test output by adding the port number to printf statements,
> and adding a printf describing each test.
> 
> revise ring-based PMD doc to match latest ring PMD code.
> 
> Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>

The doc changes are not relevant to the unit test fixes, so should be in a 
separate patch. The test changes themselves are good though, and actually makes
the test runable without having to find a very specific command-line incantation
to make things work right.

Subject to this being split into two:
Acked-by: Bruce Richardson <bruce.richardson@intel.com>


> ---
>  app/test/test_pmd_ring.c      | 360 +++++++++++++++++++++++++-----------------
>  doc/guides/nics/pcap_ring.rst |  28 ++--
>  2 files changed, 235 insertions(+), 153 deletions(-)
> 
> diff --git a/app/test/test_pmd_ring.c b/app/test/test_pmd_ring.c
> index a555db8..5568759 100644
> --- a/app/test/test_pmd_ring.c
> +++ b/app/test/test_pmd_ring.c
> @@ -1,7 +1,7 @@
>  /*-
>   *   BSD LICENSE
>   *
> - *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
>   *   All rights reserved.
>   *
>   *   Redistribution and use in source and binary forms, with or without
> @@ -38,108 +38,104 @@
>  #include <rte_ethdev.h>
>  
>  static struct rte_mempool *mp;
> +static int tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte;
>  
> -#define TX_PORT 0
> -#define RX_PORT 1
> -#define RXTX_PORT 2
> -#define RXTX_PORT2 3
> -#define RXTX_PORT3 4
>  #define SOCKET0 0
> -
>  #define RING_SIZE 256
> +#define NUM_RINGS 2
> +#define NB_MBUF 512
>  
> -#define NB_MBUF   512
>  
>  static int
> -test_ethdev_configure(void)
> +test_ethdev_configure_port(int port)
>  {
>  	struct rte_eth_conf null_conf;
>  	struct rte_eth_link link;
>  
>  	memset(&null_conf, 0, sizeof(struct rte_eth_conf));
>  
> -	if ((TX_PORT >= RTE_MAX_ETHPORTS) || (RX_PORT >= RTE_MAX_ETHPORTS)\
> -		|| (RXTX_PORT >= RTE_MAX_ETHPORTS)) {
> -		printf(" TX/RX port exceed max eth ports\n");
> -		return -1;
> -	}
> -	if (rte_eth_dev_configure(TX_PORT, 1, 2, &null_conf) < 0) {
> -		printf("Configure failed for TX port\n");
> +	if (rte_eth_dev_configure(port, 1, 2, &null_conf) < 0) {
> +		printf("Configure failed for port %d\n", port);
>  		return -1;
>  	}
>  
>  	/* Test queue release */
> -	if (rte_eth_dev_configure(TX_PORT, 1, 1, &null_conf) < 0) {
> -		printf("Configure failed for TX port\n");
> -		return -1;
> -	}
> -	if (rte_eth_dev_configure(RX_PORT, 1, 1, &null_conf) < 0) {
> -		printf("Configure failed for RX port\n");
> -		return -1;
> -	}
> -	if (rte_eth_dev_configure(RXTX_PORT, 1, 1, &null_conf) < 0) {
> -		printf("Configure failed for RXTX port\n");
> +	if (rte_eth_dev_configure(port, 1, 1, &null_conf) < 0) {
> +		printf("Configure failed for port %d\n", port);
>  		return -1;
>  	}
>  
> -	if (rte_eth_tx_queue_setup(TX_PORT, 0, RING_SIZE, SOCKET0, NULL) < 0) {
> -		printf("TX queue setup failed\n");
> -		return -1;
> -	}
> -	if (rte_eth_rx_queue_setup(RX_PORT, 0, RING_SIZE, SOCKET0,
> -			NULL, mp) < 0) {
> -		printf("RX queue setup failed\n");
> -		return -1;
> -	}
> -	if (rte_eth_tx_queue_setup(RXTX_PORT, 0, RING_SIZE, SOCKET0, NULL) < 0) {
> -		printf("TX queue setup failed\n");
> +	if (rte_eth_tx_queue_setup(port, 0, RING_SIZE, SOCKET0, NULL) < 0) {
> +		printf("TX queue setup failed port %d\n", port);
>  		return -1;
>  	}
> -	if (rte_eth_rx_queue_setup(RXTX_PORT, 0, RING_SIZE, SOCKET0,
> +
> +	if (rte_eth_rx_queue_setup(port, 0, RING_SIZE, SOCKET0,
>  			NULL, mp) < 0) {
> -		printf("RX queue setup failed\n");
> +		printf("RX queue setup failed port %d\n", port);
>  		return -1;
>  	}
>  
> -	if (rte_eth_dev_start(TX_PORT) < 0) {
> -		printf("Error starting TX port\n");
> +	if (rte_eth_dev_start(port) < 0) {
> +		printf("Error starting port %d\n", port);
>  		return -1;
>  	}
> -	if (rte_eth_dev_start(RX_PORT) < 0) {
> -		printf("Error starting RX port\n");
> +
> +	rte_eth_link_get(port, &link);
> +
> +	return 0;
> +}
> +
> +static int
> +test_send_basic_packets(void)
> +{
> +	struct rte_mbuf  bufs[RING_SIZE];
> +	struct rte_mbuf *pbufs[RING_SIZE];
> +	int i;
> +
> +	printf("Testing send and receive RING_SIZE/2 packets (tx_porta -> rx_portb)\n");
> +
> +	for (i = 0; i < RING_SIZE/2; i++)
> +		pbufs[i] = &bufs[i];
> +
> +	if (rte_eth_tx_burst(tx_porta, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
> +		printf("Failed to transmit packet burst port %d\n", tx_porta);
>  		return -1;
>  	}
> -	if (rte_eth_dev_start(RXTX_PORT) < 0) {
> -		printf("Error starting RX port\n");
> +
> +	if (rte_eth_rx_burst(rx_portb, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
> +		printf("Failed to receive packet burst on port %d\n", rx_portb);
>  		return -1;
>  	}
>  
> -	rte_eth_link_get(TX_PORT, &link);
> -	rte_eth_link_get(RX_PORT, &link);
> -	rte_eth_link_get(RXTX_PORT, &link);
> +	for (i = 0; i < RING_SIZE/2; i++)
> +		if (pbufs[i] != &bufs[i]) {
> +			printf("Error: received data does not match that transmitted\n");
> +			return -1;
> +		}
>  
>  	return 0;
>  }
>  
>  static int
> -test_send_basic_packets(void)
> +test_send_basic_packets_port(int port)
>  {
>  	struct rte_mbuf  bufs[RING_SIZE];
>  	struct rte_mbuf *pbufs[RING_SIZE];
>  	int i;
>  
> -	printf("Testing ring pmd RX/TX\n");
> +	printf("Testing send and receive RING_SIZE/2 packets (cmdl_port0 -> cmdl_port0)\n");
>  
>  	for (i = 0; i < RING_SIZE/2; i++)
>  		pbufs[i] = &bufs[i];
>  
> -	if (rte_eth_tx_burst(TX_PORT, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
> -		printf("Failed to transmit packet burst\n");
> +	if (rte_eth_tx_burst(port, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
> +		printf("Failed to transmit packet burst port %d\n", port);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RX_PORT, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
> -		printf("Failed to receive packet burst\n");
> +	if (rte_eth_rx_burst(port, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
> +		printf("Failed to receive packet burst on port %d\n", port);
>  		return -1;
>  	}
>  
> @@ -152,89 +148,92 @@ test_send_basic_packets(void)
>  	return 0;
>  }
>  
> +
>  static int
> -test_get_stats(void)
> +test_get_stats(int port)
>  {
>  	struct rte_eth_stats stats;
>  	struct rte_mbuf buf, *pbuf = &buf;
>  
> -	printf("Testing ring PMD stats\n");
> +	printf("Testing ring PMD stats_get port %d\n", port);
>  
>  	/* check stats of RXTX port, should all be zero */
> -	rte_eth_stats_get(RXTX_PORT, &stats);
> +
> +	rte_eth_stats_get(port, &stats);
>  	if (stats.ipackets != 0 || stats.opackets != 0 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not zero\n");
> +		printf("Error: port %d stats are not zero\n", port);
>  		return -1;
>  	}
>  
>  	/* send and receive 1 packet and check for stats update */
> -	if (rte_eth_tx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", port);
>  		return -1;
>  	}
> -	if (rte_eth_rx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +
> +	if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", port);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT, &stats);
> +	rte_eth_stats_get(port, &stats);
>  	if (stats.ipackets != 1 || stats.opackets != 1 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", port);
>  		return -1;
>  	}
>  	return 0;
>  }
>  
>  static int
> -test_stats_reset(void)
> +test_stats_reset(int port)
>  {
>  	struct rte_eth_stats stats;
>  	struct rte_mbuf buf, *pbuf = &buf;
>  
> -	printf("Testing ring PMD stats reset\n");
> +	printf("Testing ring PMD stats_reset port %d\n", port);
>  
> -	rte_eth_stats_reset(RXTX_PORT);
> +	rte_eth_stats_reset(port);
>  
>  	/* check stats of RXTX port, should all be zero */
> -	rte_eth_stats_get(RXTX_PORT, &stats);
> +	rte_eth_stats_get(port, &stats);
>  	if (stats.ipackets != 0 || stats.opackets != 0 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not zero\n");
> +		printf("Error: port %d stats are not zero\n", port);
>  		return -1;
>  	}
>  
>  	/* send and receive 1 packet and check for stats update */
> -	if (rte_eth_tx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", port);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +	if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", port);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT, &stats);
> +	rte_eth_stats_get(port, &stats);
>  	if (stats.ipackets != 1 || stats.opackets != 1 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", port);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_reset(RXTX_PORT);
> +	rte_eth_stats_reset(port);
>  
>  	/* check stats of RXTX port, should all be zero */
> -	rte_eth_stats_get(RXTX_PORT, &stats);
> +	rte_eth_stats_get(port, &stats);
>  	if (stats.ipackets != 0 || stats.opackets != 0 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not zero\n");
> +		printf("Error: port %d stats are not zero\n", port);
>  		return -1;
>  	}
>  
> @@ -242,162 +241,182 @@ test_stats_reset(void)
>  }
>  
>  static int
> -test_pmd_ring_pair_create_attach(void)
> +test_pmd_ring_pair_create_attach(int portd, int porte)
>  {
>  	struct rte_eth_stats stats, stats2;
>  	struct rte_mbuf buf, *pbuf = &buf;
>  	struct rte_eth_conf null_conf;
>  
> -	if ((RXTX_PORT2 >= RTE_MAX_ETHPORTS) || (RXTX_PORT3 >= RTE_MAX_ETHPORTS)) {
> -		printf(" TX/RX port exceed max eth ports\n");
> -		return -1;
> -	}
> -	if ((rte_eth_dev_configure(RXTX_PORT2, 1, 1, &null_conf) < 0)
> -		|| (rte_eth_dev_configure(RXTX_PORT3, 1, 1, &null_conf) < 0)) {
> -		printf("Configure failed for RXTX port\n");
> +	if ((rte_eth_dev_configure(portd, 1, 1, &null_conf) < 0)
> +		|| (rte_eth_dev_configure(porte, 1, 1, &null_conf) < 0)) {
> +		printf("Configure failed for port\n");
>  		return -1;
>  	}
>  
> -	if ((rte_eth_tx_queue_setup(RXTX_PORT2, 0, RING_SIZE, SOCKET0, NULL) < 0)
> -		|| (rte_eth_tx_queue_setup(RXTX_PORT3, 0, RING_SIZE, SOCKET0, NULL) < 0)) {
> +	if ((rte_eth_tx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL) < 0)
> +		|| (rte_eth_tx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL) < 0)) {
>  		printf("TX queue setup failed\n");
>  		return -1;
>  	}
>  
> -	if ((rte_eth_rx_queue_setup(RXTX_PORT2, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)
> -		|| (rte_eth_rx_queue_setup(RXTX_PORT3, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)) {
> +	if ((rte_eth_rx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)
> +		|| (rte_eth_rx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)) {
>  		printf("RX queue setup failed\n");
>  		return -1;
>  	}
>  
> -	if ((rte_eth_dev_start(RXTX_PORT2) < 0)
> -		|| (rte_eth_dev_start(RXTX_PORT3) < 0)) {
> -		printf("Error starting RXTX port\n");
> +	if ((rte_eth_dev_start(portd) < 0)
> +		|| (rte_eth_dev_start(porte) < 0)) {
> +		printf("Error starting port\n");
> +		return -1;
> +	}
> +
> +	rte_eth_stats_reset(portd);
> +	/* check stats of port, should all be zero */
> +	rte_eth_stats_get(portd, &stats);
> +	if (stats.ipackets != 0 || stats.opackets != 0 ||
> +			stats.ibytes != 0 || stats.obytes != 0 ||
> +			stats.ierrors != 0 || stats.oerrors != 0) {
> +		printf("Error: port %d stats are not zero\n", portd);
> +		return -1;
> +	}
> +
> +	rte_eth_stats_reset(porte);
> +	/* check stats of port, should all be zero */
> +	rte_eth_stats_get(porte, &stats2);
> +	if (stats2.ipackets != 0 || stats2.opackets != 0 ||
> +			stats2.ibytes != 0 || stats2.obytes != 0 ||
> +			stats2.ierrors != 0 || stats2.oerrors != 0) {
> +		printf("Error: port %d stats are not zero\n", porte);
>  		return -1;
>  	}
>  
>  	/*
> -	 * send and receive 1 packet (RXTX_PORT2 -> RXTX_PORT3)
> +	 * send and receive 1 packet (portd -> porte)
>  	 * and check for stats update
>  	 */
> -	if (rte_eth_tx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	printf("Testing send and receive 1 packet (portd -> porte)\n");
> +	if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", portd);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +	if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", porte);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT2, &stats);
> -	rte_eth_stats_get(RXTX_PORT3, &stats2);
> +	rte_eth_stats_get(portd, &stats);
> +	rte_eth_stats_get(porte, &stats2);
>  	if (stats.ipackets != 0 || stats.opackets != 1 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", portd);
>  		return -1;
>  	}
>  
>  	if (stats2.ipackets != 1 || stats2.opackets != 0 ||
>  			stats2.ibytes != 0 || stats2.obytes != 0 ||
>  			stats2.ierrors != 0 || stats2.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", porte);
>  		return -1;
>  	}
>  
>  	/*
> -	 * send and receive 1 packet (RXTX_PORT3 -> RXTX_PORT2)
> +	 * send and receive 1 packet (porte -> portd)
>  	 * and check for stats update
>  	 */
> -	if (rte_eth_tx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	printf("Testing send and receive 1 packet (porte -> portd)\n");
> +	if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", porte);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +	if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", portd);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT2, &stats);
> -	rte_eth_stats_get(RXTX_PORT3, &stats2);
> +	rte_eth_stats_get(portd, &stats);
> +	rte_eth_stats_get(porte, &stats2);
>  	if (stats.ipackets != 1 || stats.opackets != 1 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", portd);
>  		return -1;
>  	}
>  
>  	if (stats2.ipackets != 1 || stats2.opackets != 1 ||
>  			stats2.ibytes != 0 || stats2.obytes != 0 ||
>  			stats2.ierrors != 0 || stats2.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", porte);
>  		return -1;
>  	}
>  
>  	/*
> -	 * send and receive 1 packet (RXTX_PORT2 -> RXTX_PORT2)
> +	 * send and receive 1 packet (portd -> portd)
>  	 * and check for stats update
>  	 */
> -	if (rte_eth_tx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	printf("Testing send and receive 1 packet (portd -> portd)\n");
> +	if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", portd);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +	if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", porte);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT2, &stats);
> -	rte_eth_stats_get(RXTX_PORT3, &stats2);
> +	rte_eth_stats_get(portd, &stats);
> +	rte_eth_stats_get(porte, &stats2);
>  	if (stats.ipackets != 2 || stats.opackets != 2 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", portd);
>  		return -1;
>  	}
>  
>  	if (stats2.ipackets != 1 || stats2.opackets != 1 ||
>  			stats2.ibytes != 0 || stats2.obytes != 0 ||
>  			stats2.ierrors != 0 || stats2.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", porte);
>  		return -1;
>  	}
>  
>  	/*
> -	 * send and receive 1 packet (RXTX_PORT3 -> RXTX_PORT3)
> +	 * send and receive 1 packet (porte -> porte)
>  	 * and check for stats update
>  	 */
> -	if (rte_eth_tx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
> -		printf("Error sending packet to RXTX port\n");
> +	printf("Testing send and receive 1 packet (porte -> porte)\n");
> +	if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) {
> +		printf("Error sending packet to port %d\n", porte);
>  		return -1;
>  	}
>  
> -	if (rte_eth_rx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
> -		printf("Error receiving packet from RXTX port\n");
> +	if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) {
> +		printf("Error receiving packet from port %d\n", porte);
>  		return -1;
>  	}
>  
> -	rte_eth_stats_get(RXTX_PORT2, &stats);
> -	rte_eth_stats_get(RXTX_PORT3, &stats2);
> +	rte_eth_stats_get(portd, &stats);
> +	rte_eth_stats_get(porte, &stats2);
>  	if (stats.ipackets != 2 || stats.opackets != 2 ||
>  			stats.ibytes != 0 || stats.obytes != 0 ||
>  			stats.ierrors != 0 || stats.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", portd);
>  		return -1;
>  	}
>  
>  	if (stats2.ipackets != 2 || stats2.opackets != 2 ||
>  			stats2.ibytes != 0 || stats2.obytes != 0 ||
>  			stats2.ierrors != 0 || stats2.oerrors != 0) {
> -		printf("Error: RXTX port stats are not as expected\n");
> +		printf("Error: port %d stats are not as expected\n", porte);
>  		return -1;
>  	}
>  
> -	rte_eth_dev_stop(RXTX_PORT2);
> -	rte_eth_dev_stop(RXTX_PORT3);
> +	rte_eth_dev_stop(portd);
> +	rte_eth_dev_stop(porte);
>  
>  	return 0;
>  }
> @@ -405,36 +424,95 @@ test_pmd_ring_pair_create_attach(void)
>  static int
>  test_pmd_ring(void)
>  {
> +	struct rte_ring *rxtx[NUM_RINGS];
> +	int cmdl_port0 = 0;
> +	uint8_t nb_ports;
> +
> +	nb_ports = rte_eth_dev_count();
> +	printf("nb_ports=%d\n", (int)nb_ports);
> +
> +	/*  create the rings and eth_rings in the test code.
> +	 *  This does not test the rte_pmd_ring_devinit function.
> +	 *
> +	 *  Test with the command line option --vdev=eth_ring0 to test rte_pmd_ring_devinit.
> +	 */
> +	rxtx[0] = rte_ring_create("R0", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
> +	if (rxtx[0] == NULL) {
> +		printf("rte_ring_create R0 failed");
> +		return -1;
> +	}
> +
> +	rxtx[1] = rte_ring_create("R1", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
> +	if (rxtx[1] == NULL) {
> +		printf("rte_ring_create R1 failed");
> +		return -1;
> +	}
> +
> +	tx_porta = rte_eth_from_rings("eth_ringa", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
> +	rx_portb = rte_eth_from_rings("eth_ringb", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
> +	rxtx_portc = rte_eth_from_rings("eth_ringc", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
> +	rxtx_portd = rte_eth_from_rings("eth_ringd", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
> +	rxtx_porte = rte_eth_from_rings("eth_ringe", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
> +
> +	printf("tx_porta=%d rx_portb=%d rxtx_portc=%d rxtx_portd=%d rxtx_porte=%d\n",
> +			tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte);
> +
> +	if ((tx_porta == -1) || (rx_portb == -1) || (rxtx_portc == -1)
> +		|| (rxtx_portd == -1) || (rxtx_porte == -1)) {
> +		printf("rte_eth_from rings failed\n");
> +		return -1;
> +	}
> +
>  	mp = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
>  		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
>  	if (mp == NULL)
>  		return -1;
>  
> -	if ((TX_PORT >= RTE_MAX_ETHPORTS) || (RX_PORT >= RTE_MAX_ETHPORTS)\
> -		|| (RXTX_PORT >= RTE_MAX_ETHPORTS)) {
> -		printf(" TX/RX port exceed max eth ports\n");
> +	if ((tx_porta >= RTE_MAX_ETHPORTS) || (rx_portb >= RTE_MAX_ETHPORTS)
> +		|| (rxtx_portc >= RTE_MAX_ETHPORTS)
> +		|| (rxtx_portd >= RTE_MAX_ETHPORTS)
> +		|| (rxtx_porte >= RTE_MAX_ETHPORTS)) {
> +		printf(" port exceed max eth ports\n");
>  		return -1;
>  	}
>  
> -	if (test_ethdev_configure() < 0)
> +	if (test_ethdev_configure_port(tx_porta) < 0)
> +		return -1;
> +
> +	if (test_ethdev_configure_port(rx_portb) < 0)
> +		return -1;
> +
> +	if (test_ethdev_configure_port(rxtx_portc) < 0)
>  		return -1;
>  
>  	if (test_send_basic_packets() < 0)
>  		return -1;
>  
> -	if (test_get_stats() < 0)
> +	if (test_get_stats(rxtx_portc) < 0)
>  		return -1;
>  
> -	if (test_stats_reset() < 0)
> +	if (test_stats_reset(rxtx_portc) < 0)
>  		return -1;
>  
> -	rte_eth_dev_stop(RX_PORT);
> -	rte_eth_dev_stop(TX_PORT);
> -	rte_eth_dev_stop(RXTX_PORT);
> +	rte_eth_dev_stop(tx_porta);
> +	rte_eth_dev_stop(rx_portb);
> +	rte_eth_dev_stop(rxtx_portc);
>  
> -	if (test_pmd_ring_pair_create_attach() < 0)
> +	if (test_pmd_ring_pair_create_attach(rxtx_portd, rxtx_porte) < 0)
>  		return -1;
>  
> +	if (nb_ports > 0) {
> +		/* test port 0 created with the --vdev=eth_ring0 command line option */
> +		if (test_ethdev_configure_port(cmdl_port0) < 0)
> +			return -1;
> +		if (test_send_basic_packets_port(cmdl_port0) < 0)
> +			return -1;
> +		if (test_stats_reset(cmdl_port0) < 0)
> +			return -1;
> +		if (test_get_stats(cmdl_port0) < 0)
> +			return -1;
> +		rte_eth_dev_stop(cmdl_port0);
> +	}
>  	return 0;
>  }
>  
> diff --git a/doc/guides/nics/pcap_ring.rst b/doc/guides/nics/pcap_ring.rst
> index 5d65dc6..46aa3ac 100644
> --- a/doc/guides/nics/pcap_ring.rst
> +++ b/doc/guides/nics/pcap_ring.rst
> @@ -1,5 +1,5 @@
>  ..  BSD LICENSE
> -    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> +    Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
>      All rights reserved.
>  
>      Redistribution and use in source and binary forms, with or without
> @@ -217,7 +217,7 @@ Using the Poll Mode Driver from an Application
>  Both drivers can provide similar APIs to allow the user to create a PMD, that is,
>  rte_ethdev structure, instances at run-time in the end-application,
>  for example, using rte_eth_from_rings() or rte_eth_from_pcaps() APIs.
> -For the rings- based PMD, this functionality could be used, for example,
> +For the rings-based PMD, this functionality could be used, for example,
>  to allow data exchange between cores using rings to be done in exactly the
>  same way as sending or receiving packets from an Ethernet device.
>  For the libpcap-based PMD, it allows an application to open one or more pcap files
> @@ -231,26 +231,30 @@ for reception on the same port (error handling omitted for clarity):
>  
>  .. code-block:: c
>  
> -    struct rte_ring *r1, *r2;
> -    int port1, port2;
> +    #define RING_SIZE 256
> +    #define NUM_RINGS 2
> +    #define SOCKET0 0
>  
> -    r1 = rte_ring_create("R1", 256, SOCKET0,RING_F_SP_ENQ|RING_F_SC_DEQ);
> -    r2 = rte_ring_create("R2", 256, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
> +    struct rte_ring *ring[NUM_RINGS];
> +    int port0, port1;
>  
> -    /* create an ethdev where RX and TX are done to/from r1, and * another from r2 */
> +    ring[0] = rte_ring_create("R0", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
> +    ring[1] = rte_ring_create("R1", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
>  
> -    port1 = rte_eth_from_rings(r1, 1, r1, 1, SOCKET0);
> -    port2 = rte_eth_from_rings(r2, 1, r2, 1, SOCKET0);
> +    /* create two ethdev's */
> +
> +    port0 = rte_eth_from_rings("eth_ring0", ring, NUM_RINGS, ring, NUM_RINGS, SOCKET0);
> +    port1 = rte_eth_from_rings("eth_ring1", ring, NUM_RINGS, ring, NUM_RINGS, SOCKET0);
>  
>  
>  To create two pseudo-Ethernet ports where the traffic is switched between them,
> -that is, traffic sent to port 1 is read back from port 2 and vice-versa,
> +that is, traffic sent to port 0 is read back from port 1 and vice-versa,
>  the final two lines could be changed as below:
>  
>  .. code-block:: c
>  
> -    port1 = rte_eth_from_rings(r1, 1, r2, 1, SOCKET0);
> -    port2 = rte_eth_from_rings(r2, 1, r1, 1, SOCKET0);
> +    port0 = rte_eth_from_rings("eth_ring0", &ring[0], 1, &ring[1], 1, SOCKET0);
> +    port1 = rte_eth_from_rings("eth_ring1", &ring[1], 1, &ring[0], 1, SOCKET0);
>  
>  This type of configuration could be useful in a pipeline model, for example,
>  where one may want to have inter-core communication using pseudo Ethernet devices rather than raw rings,
> -- 
> 1.9.1
>
  
Iremonger, Bernard Nov. 24, 2015, 4:29 p.m. UTC | #2
Hi Bruce,

> -----Original Message-----
> From: Richardson, Bruce
> Sent: Tuesday, November 24, 2015 4:14 PM
> To: Iremonger, Bernard <bernard.iremonger@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 1/1] app/test: create ring and ethdevs in
> pmd_ring_autotest
> 
> On Mon, Nov 23, 2015 at 03:20:46PM +0000, Bernard Iremonger wrote:
> > Use command line option --vdev=eth_ring0 to create port 0.
> > Create two rings and five ethdevs in test_pmd_ring for ports 1 to 5.
> > Improve test output by adding the port number to printf statements,
> > and adding a printf describing each test.
> >
> > revise ring-based PMD doc to match latest ring PMD code.
> >
> > Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> 
> The doc changes are not relevant to the unit test fixes, so should be in a
> separate patch. The test changes themselves are good though, and actually
> makes the test runable without having to find a very specific command-line
> incantation to make things work right.
> 
> Subject to this being split into two:
> Acked-by: Bruce Richardson <bruce.richardson@intel.com>

Will I keep your ack on both patches when I split them?

Regards,

Bernard.

<snip>
  
Bruce Richardson Nov. 24, 2015, 4:30 p.m. UTC | #3
> -----Original Message-----
> From: Iremonger, Bernard
> Sent: Tuesday, November 24, 2015 4:29 PM
> To: Richardson, Bruce <bruce.richardson@intel.com>
> Cc: dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH 1/1] app/test: create ring and ethdevs in
> pmd_ring_autotest
> 
> Hi Bruce,
> 
> > -----Original Message-----
> > From: Richardson, Bruce
> > Sent: Tuesday, November 24, 2015 4:14 PM
> > To: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 1/1] app/test: create ring and ethdevs
> > in pmd_ring_autotest
> >
> > On Mon, Nov 23, 2015 at 03:20:46PM +0000, Bernard Iremonger wrote:
> > > Use command line option --vdev=eth_ring0 to create port 0.
> > > Create two rings and five ethdevs in test_pmd_ring for ports 1 to 5.
> > > Improve test output by adding the port number to printf statements,
> > > and adding a printf describing each test.
> > >
> > > revise ring-based PMD doc to match latest ring PMD code.
> > >
> > > Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> >
> > The doc changes are not relevant to the unit test fixes, so should be
> > in a separate patch. The test changes themselves are good though, and
> > actually makes the test runable without having to find a very specific
> > command-line incantation to make things work right.
> >
> > Subject to this being split into two:
> > Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> 
> Will I keep your ack on both patches when I split them?
> 
> Regards,
> 
> Bernard.
> 
Sure, feel free to.

/Bruce
  

Patch

diff --git a/app/test/test_pmd_ring.c b/app/test/test_pmd_ring.c
index a555db8..5568759 100644
--- a/app/test/test_pmd_ring.c
+++ b/app/test/test_pmd_ring.c
@@ -1,7 +1,7 @@ 
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -38,108 +38,104 @@ 
 #include <rte_ethdev.h>
 
 static struct rte_mempool *mp;
+static int tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte;
 
-#define TX_PORT 0
-#define RX_PORT 1
-#define RXTX_PORT 2
-#define RXTX_PORT2 3
-#define RXTX_PORT3 4
 #define SOCKET0 0
-
 #define RING_SIZE 256
+#define NUM_RINGS 2
+#define NB_MBUF 512
 
-#define NB_MBUF   512
 
 static int
-test_ethdev_configure(void)
+test_ethdev_configure_port(int port)
 {
 	struct rte_eth_conf null_conf;
 	struct rte_eth_link link;
 
 	memset(&null_conf, 0, sizeof(struct rte_eth_conf));
 
-	if ((TX_PORT >= RTE_MAX_ETHPORTS) || (RX_PORT >= RTE_MAX_ETHPORTS)\
-		|| (RXTX_PORT >= RTE_MAX_ETHPORTS)) {
-		printf(" TX/RX port exceed max eth ports\n");
-		return -1;
-	}
-	if (rte_eth_dev_configure(TX_PORT, 1, 2, &null_conf) < 0) {
-		printf("Configure failed for TX port\n");
+	if (rte_eth_dev_configure(port, 1, 2, &null_conf) < 0) {
+		printf("Configure failed for port %d\n", port);
 		return -1;
 	}
 
 	/* Test queue release */
-	if (rte_eth_dev_configure(TX_PORT, 1, 1, &null_conf) < 0) {
-		printf("Configure failed for TX port\n");
-		return -1;
-	}
-	if (rte_eth_dev_configure(RX_PORT, 1, 1, &null_conf) < 0) {
-		printf("Configure failed for RX port\n");
-		return -1;
-	}
-	if (rte_eth_dev_configure(RXTX_PORT, 1, 1, &null_conf) < 0) {
-		printf("Configure failed for RXTX port\n");
+	if (rte_eth_dev_configure(port, 1, 1, &null_conf) < 0) {
+		printf("Configure failed for port %d\n", port);
 		return -1;
 	}
 
-	if (rte_eth_tx_queue_setup(TX_PORT, 0, RING_SIZE, SOCKET0, NULL) < 0) {
-		printf("TX queue setup failed\n");
-		return -1;
-	}
-	if (rte_eth_rx_queue_setup(RX_PORT, 0, RING_SIZE, SOCKET0,
-			NULL, mp) < 0) {
-		printf("RX queue setup failed\n");
-		return -1;
-	}
-	if (rte_eth_tx_queue_setup(RXTX_PORT, 0, RING_SIZE, SOCKET0, NULL) < 0) {
-		printf("TX queue setup failed\n");
+	if (rte_eth_tx_queue_setup(port, 0, RING_SIZE, SOCKET0, NULL) < 0) {
+		printf("TX queue setup failed port %d\n", port);
 		return -1;
 	}
-	if (rte_eth_rx_queue_setup(RXTX_PORT, 0, RING_SIZE, SOCKET0,
+
+	if (rte_eth_rx_queue_setup(port, 0, RING_SIZE, SOCKET0,
 			NULL, mp) < 0) {
-		printf("RX queue setup failed\n");
+		printf("RX queue setup failed port %d\n", port);
 		return -1;
 	}
 
-	if (rte_eth_dev_start(TX_PORT) < 0) {
-		printf("Error starting TX port\n");
+	if (rte_eth_dev_start(port) < 0) {
+		printf("Error starting port %d\n", port);
 		return -1;
 	}
-	if (rte_eth_dev_start(RX_PORT) < 0) {
-		printf("Error starting RX port\n");
+
+	rte_eth_link_get(port, &link);
+
+	return 0;
+}
+
+static int
+test_send_basic_packets(void)
+{
+	struct rte_mbuf  bufs[RING_SIZE];
+	struct rte_mbuf *pbufs[RING_SIZE];
+	int i;
+
+	printf("Testing send and receive RING_SIZE/2 packets (tx_porta -> rx_portb)\n");
+
+	for (i = 0; i < RING_SIZE/2; i++)
+		pbufs[i] = &bufs[i];
+
+	if (rte_eth_tx_burst(tx_porta, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
+		printf("Failed to transmit packet burst port %d\n", tx_porta);
 		return -1;
 	}
-	if (rte_eth_dev_start(RXTX_PORT) < 0) {
-		printf("Error starting RX port\n");
+
+	if (rte_eth_rx_burst(rx_portb, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
+		printf("Failed to receive packet burst on port %d\n", rx_portb);
 		return -1;
 	}
 
-	rte_eth_link_get(TX_PORT, &link);
-	rte_eth_link_get(RX_PORT, &link);
-	rte_eth_link_get(RXTX_PORT, &link);
+	for (i = 0; i < RING_SIZE/2; i++)
+		if (pbufs[i] != &bufs[i]) {
+			printf("Error: received data does not match that transmitted\n");
+			return -1;
+		}
 
 	return 0;
 }
 
 static int
-test_send_basic_packets(void)
+test_send_basic_packets_port(int port)
 {
 	struct rte_mbuf  bufs[RING_SIZE];
 	struct rte_mbuf *pbufs[RING_SIZE];
 	int i;
 
-	printf("Testing ring pmd RX/TX\n");
+	printf("Testing send and receive RING_SIZE/2 packets (cmdl_port0 -> cmdl_port0)\n");
 
 	for (i = 0; i < RING_SIZE/2; i++)
 		pbufs[i] = &bufs[i];
 
-	if (rte_eth_tx_burst(TX_PORT, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
-		printf("Failed to transmit packet burst\n");
+	if (rte_eth_tx_burst(port, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) {
+		printf("Failed to transmit packet burst port %d\n", port);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RX_PORT, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
-		printf("Failed to receive packet burst\n");
+	if (rte_eth_rx_burst(port, 0, pbufs, RING_SIZE) != RING_SIZE/2) {
+		printf("Failed to receive packet burst on port %d\n", port);
 		return -1;
 	}
 
@@ -152,89 +148,92 @@  test_send_basic_packets(void)
 	return 0;
 }
 
+
 static int
-test_get_stats(void)
+test_get_stats(int port)
 {
 	struct rte_eth_stats stats;
 	struct rte_mbuf buf, *pbuf = &buf;
 
-	printf("Testing ring PMD stats\n");
+	printf("Testing ring PMD stats_get port %d\n", port);
 
 	/* check stats of RXTX port, should all be zero */
-	rte_eth_stats_get(RXTX_PORT, &stats);
+
+	rte_eth_stats_get(port, &stats);
 	if (stats.ipackets != 0 || stats.opackets != 0 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not zero\n");
+		printf("Error: port %d stats are not zero\n", port);
 		return -1;
 	}
 
 	/* send and receive 1 packet and check for stats update */
-	if (rte_eth_tx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", port);
 		return -1;
 	}
-	if (rte_eth_rx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+
+	if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", port);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT, &stats);
+	rte_eth_stats_get(port, &stats);
 	if (stats.ipackets != 1 || stats.opackets != 1 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", port);
 		return -1;
 	}
 	return 0;
 }
 
 static int
-test_stats_reset(void)
+test_stats_reset(int port)
 {
 	struct rte_eth_stats stats;
 	struct rte_mbuf buf, *pbuf = &buf;
 
-	printf("Testing ring PMD stats reset\n");
+	printf("Testing ring PMD stats_reset port %d\n", port);
 
-	rte_eth_stats_reset(RXTX_PORT);
+	rte_eth_stats_reset(port);
 
 	/* check stats of RXTX port, should all be zero */
-	rte_eth_stats_get(RXTX_PORT, &stats);
+	rte_eth_stats_get(port, &stats);
 	if (stats.ipackets != 0 || stats.opackets != 0 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not zero\n");
+		printf("Error: port %d stats are not zero\n", port);
 		return -1;
 	}
 
 	/* send and receive 1 packet and check for stats update */
-	if (rte_eth_tx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", port);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RXTX_PORT, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+	if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", port);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT, &stats);
+	rte_eth_stats_get(port, &stats);
 	if (stats.ipackets != 1 || stats.opackets != 1 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", port);
 		return -1;
 	}
 
-	rte_eth_stats_reset(RXTX_PORT);
+	rte_eth_stats_reset(port);
 
 	/* check stats of RXTX port, should all be zero */
-	rte_eth_stats_get(RXTX_PORT, &stats);
+	rte_eth_stats_get(port, &stats);
 	if (stats.ipackets != 0 || stats.opackets != 0 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not zero\n");
+		printf("Error: port %d stats are not zero\n", port);
 		return -1;
 	}
 
@@ -242,162 +241,182 @@  test_stats_reset(void)
 }
 
 static int
-test_pmd_ring_pair_create_attach(void)
+test_pmd_ring_pair_create_attach(int portd, int porte)
 {
 	struct rte_eth_stats stats, stats2;
 	struct rte_mbuf buf, *pbuf = &buf;
 	struct rte_eth_conf null_conf;
 
-	if ((RXTX_PORT2 >= RTE_MAX_ETHPORTS) || (RXTX_PORT3 >= RTE_MAX_ETHPORTS)) {
-		printf(" TX/RX port exceed max eth ports\n");
-		return -1;
-	}
-	if ((rte_eth_dev_configure(RXTX_PORT2, 1, 1, &null_conf) < 0)
-		|| (rte_eth_dev_configure(RXTX_PORT3, 1, 1, &null_conf) < 0)) {
-		printf("Configure failed for RXTX port\n");
+	if ((rte_eth_dev_configure(portd, 1, 1, &null_conf) < 0)
+		|| (rte_eth_dev_configure(porte, 1, 1, &null_conf) < 0)) {
+		printf("Configure failed for port\n");
 		return -1;
 	}
 
-	if ((rte_eth_tx_queue_setup(RXTX_PORT2, 0, RING_SIZE, SOCKET0, NULL) < 0)
-		|| (rte_eth_tx_queue_setup(RXTX_PORT3, 0, RING_SIZE, SOCKET0, NULL) < 0)) {
+	if ((rte_eth_tx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL) < 0)
+		|| (rte_eth_tx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL) < 0)) {
 		printf("TX queue setup failed\n");
 		return -1;
 	}
 
-	if ((rte_eth_rx_queue_setup(RXTX_PORT2, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)
-		|| (rte_eth_rx_queue_setup(RXTX_PORT3, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)) {
+	if ((rte_eth_rx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)
+		|| (rte_eth_rx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)) {
 		printf("RX queue setup failed\n");
 		return -1;
 	}
 
-	if ((rte_eth_dev_start(RXTX_PORT2) < 0)
-		|| (rte_eth_dev_start(RXTX_PORT3) < 0)) {
-		printf("Error starting RXTX port\n");
+	if ((rte_eth_dev_start(portd) < 0)
+		|| (rte_eth_dev_start(porte) < 0)) {
+		printf("Error starting port\n");
+		return -1;
+	}
+
+	rte_eth_stats_reset(portd);
+	/* check stats of port, should all be zero */
+	rte_eth_stats_get(portd, &stats);
+	if (stats.ipackets != 0 || stats.opackets != 0 ||
+			stats.ibytes != 0 || stats.obytes != 0 ||
+			stats.ierrors != 0 || stats.oerrors != 0) {
+		printf("Error: port %d stats are not zero\n", portd);
+		return -1;
+	}
+
+	rte_eth_stats_reset(porte);
+	/* check stats of port, should all be zero */
+	rte_eth_stats_get(porte, &stats2);
+	if (stats2.ipackets != 0 || stats2.opackets != 0 ||
+			stats2.ibytes != 0 || stats2.obytes != 0 ||
+			stats2.ierrors != 0 || stats2.oerrors != 0) {
+		printf("Error: port %d stats are not zero\n", porte);
 		return -1;
 	}
 
 	/*
-	 * send and receive 1 packet (RXTX_PORT2 -> RXTX_PORT3)
+	 * send and receive 1 packet (portd -> porte)
 	 * and check for stats update
 	 */
-	if (rte_eth_tx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	printf("Testing send and receive 1 packet (portd -> porte)\n");
+	if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", portd);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+	if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", porte);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT2, &stats);
-	rte_eth_stats_get(RXTX_PORT3, &stats2);
+	rte_eth_stats_get(portd, &stats);
+	rte_eth_stats_get(porte, &stats2);
 	if (stats.ipackets != 0 || stats.opackets != 1 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", portd);
 		return -1;
 	}
 
 	if (stats2.ipackets != 1 || stats2.opackets != 0 ||
 			stats2.ibytes != 0 || stats2.obytes != 0 ||
 			stats2.ierrors != 0 || stats2.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", porte);
 		return -1;
 	}
 
 	/*
-	 * send and receive 1 packet (RXTX_PORT3 -> RXTX_PORT2)
+	 * send and receive 1 packet (porte -> portd)
 	 * and check for stats update
 	 */
-	if (rte_eth_tx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	printf("Testing send and receive 1 packet (porte -> portd)\n");
+	if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", porte);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+	if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", portd);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT2, &stats);
-	rte_eth_stats_get(RXTX_PORT3, &stats2);
+	rte_eth_stats_get(portd, &stats);
+	rte_eth_stats_get(porte, &stats2);
 	if (stats.ipackets != 1 || stats.opackets != 1 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", portd);
 		return -1;
 	}
 
 	if (stats2.ipackets != 1 || stats2.opackets != 1 ||
 			stats2.ibytes != 0 || stats2.obytes != 0 ||
 			stats2.ierrors != 0 || stats2.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", porte);
 		return -1;
 	}
 
 	/*
-	 * send and receive 1 packet (RXTX_PORT2 -> RXTX_PORT2)
+	 * send and receive 1 packet (portd -> portd)
 	 * and check for stats update
 	 */
-	if (rte_eth_tx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	printf("Testing send and receive 1 packet (portd -> portd)\n");
+	if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", portd);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RXTX_PORT2, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+	if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", porte);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT2, &stats);
-	rte_eth_stats_get(RXTX_PORT3, &stats2);
+	rte_eth_stats_get(portd, &stats);
+	rte_eth_stats_get(porte, &stats2);
 	if (stats.ipackets != 2 || stats.opackets != 2 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", portd);
 		return -1;
 	}
 
 	if (stats2.ipackets != 1 || stats2.opackets != 1 ||
 			stats2.ibytes != 0 || stats2.obytes != 0 ||
 			stats2.ierrors != 0 || stats2.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", porte);
 		return -1;
 	}
 
 	/*
-	 * send and receive 1 packet (RXTX_PORT3 -> RXTX_PORT3)
+	 * send and receive 1 packet (porte -> porte)
 	 * and check for stats update
 	 */
-	if (rte_eth_tx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
-		printf("Error sending packet to RXTX port\n");
+	printf("Testing send and receive 1 packet (porte -> porte)\n");
+	if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) {
+		printf("Error sending packet to port %d\n", porte);
 		return -1;
 	}
 
-	if (rte_eth_rx_burst(RXTX_PORT3, 0, &pbuf, 1) != 1) {
-		printf("Error receiving packet from RXTX port\n");
+	if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) {
+		printf("Error receiving packet from port %d\n", porte);
 		return -1;
 	}
 
-	rte_eth_stats_get(RXTX_PORT2, &stats);
-	rte_eth_stats_get(RXTX_PORT3, &stats2);
+	rte_eth_stats_get(portd, &stats);
+	rte_eth_stats_get(porte, &stats2);
 	if (stats.ipackets != 2 || stats.opackets != 2 ||
 			stats.ibytes != 0 || stats.obytes != 0 ||
 			stats.ierrors != 0 || stats.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", portd);
 		return -1;
 	}
 
 	if (stats2.ipackets != 2 || stats2.opackets != 2 ||
 			stats2.ibytes != 0 || stats2.obytes != 0 ||
 			stats2.ierrors != 0 || stats2.oerrors != 0) {
-		printf("Error: RXTX port stats are not as expected\n");
+		printf("Error: port %d stats are not as expected\n", porte);
 		return -1;
 	}
 
-	rte_eth_dev_stop(RXTX_PORT2);
-	rte_eth_dev_stop(RXTX_PORT3);
+	rte_eth_dev_stop(portd);
+	rte_eth_dev_stop(porte);
 
 	return 0;
 }
@@ -405,36 +424,95 @@  test_pmd_ring_pair_create_attach(void)
 static int
 test_pmd_ring(void)
 {
+	struct rte_ring *rxtx[NUM_RINGS];
+	int cmdl_port0 = 0;
+	uint8_t nb_ports;
+
+	nb_ports = rte_eth_dev_count();
+	printf("nb_ports=%d\n", (int)nb_ports);
+
+	/*  create the rings and eth_rings in the test code.
+	 *  This does not test the rte_pmd_ring_devinit function.
+	 *
+	 *  Test with the command line option --vdev=eth_ring0 to test rte_pmd_ring_devinit.
+	 */
+	rxtx[0] = rte_ring_create("R0", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
+	if (rxtx[0] == NULL) {
+		printf("rte_ring_create R0 failed");
+		return -1;
+	}
+
+	rxtx[1] = rte_ring_create("R1", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
+	if (rxtx[1] == NULL) {
+		printf("rte_ring_create R1 failed");
+		return -1;
+	}
+
+	tx_porta = rte_eth_from_rings("eth_ringa", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
+	rx_portb = rte_eth_from_rings("eth_ringb", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
+	rxtx_portc = rte_eth_from_rings("eth_ringc", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
+	rxtx_portd = rte_eth_from_rings("eth_ringd", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
+	rxtx_porte = rte_eth_from_rings("eth_ringe", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0);
+
+	printf("tx_porta=%d rx_portb=%d rxtx_portc=%d rxtx_portd=%d rxtx_porte=%d\n",
+			tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte);
+
+	if ((tx_porta == -1) || (rx_portb == -1) || (rxtx_portc == -1)
+		|| (rxtx_portd == -1) || (rxtx_porte == -1)) {
+		printf("rte_eth_from rings failed\n");
+		return -1;
+	}
+
 	mp = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
 		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
 	if (mp == NULL)
 		return -1;
 
-	if ((TX_PORT >= RTE_MAX_ETHPORTS) || (RX_PORT >= RTE_MAX_ETHPORTS)\
-		|| (RXTX_PORT >= RTE_MAX_ETHPORTS)) {
-		printf(" TX/RX port exceed max eth ports\n");
+	if ((tx_porta >= RTE_MAX_ETHPORTS) || (rx_portb >= RTE_MAX_ETHPORTS)
+		|| (rxtx_portc >= RTE_MAX_ETHPORTS)
+		|| (rxtx_portd >= RTE_MAX_ETHPORTS)
+		|| (rxtx_porte >= RTE_MAX_ETHPORTS)) {
+		printf(" port exceed max eth ports\n");
 		return -1;
 	}
 
-	if (test_ethdev_configure() < 0)
+	if (test_ethdev_configure_port(tx_porta) < 0)
+		return -1;
+
+	if (test_ethdev_configure_port(rx_portb) < 0)
+		return -1;
+
+	if (test_ethdev_configure_port(rxtx_portc) < 0)
 		return -1;
 
 	if (test_send_basic_packets() < 0)
 		return -1;
 
-	if (test_get_stats() < 0)
+	if (test_get_stats(rxtx_portc) < 0)
 		return -1;
 
-	if (test_stats_reset() < 0)
+	if (test_stats_reset(rxtx_portc) < 0)
 		return -1;
 
-	rte_eth_dev_stop(RX_PORT);
-	rte_eth_dev_stop(TX_PORT);
-	rte_eth_dev_stop(RXTX_PORT);
+	rte_eth_dev_stop(tx_porta);
+	rte_eth_dev_stop(rx_portb);
+	rte_eth_dev_stop(rxtx_portc);
 
-	if (test_pmd_ring_pair_create_attach() < 0)
+	if (test_pmd_ring_pair_create_attach(rxtx_portd, rxtx_porte) < 0)
 		return -1;
 
+	if (nb_ports > 0) {
+		/* test port 0 created with the --vdev=eth_ring0 command line option */
+		if (test_ethdev_configure_port(cmdl_port0) < 0)
+			return -1;
+		if (test_send_basic_packets_port(cmdl_port0) < 0)
+			return -1;
+		if (test_stats_reset(cmdl_port0) < 0)
+			return -1;
+		if (test_get_stats(cmdl_port0) < 0)
+			return -1;
+		rte_eth_dev_stop(cmdl_port0);
+	}
 	return 0;
 }
 
diff --git a/doc/guides/nics/pcap_ring.rst b/doc/guides/nics/pcap_ring.rst
index 5d65dc6..46aa3ac 100644
--- a/doc/guides/nics/pcap_ring.rst
+++ b/doc/guides/nics/pcap_ring.rst
@@ -1,5 +1,5 @@ 
 ..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+    Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -217,7 +217,7 @@  Using the Poll Mode Driver from an Application
 Both drivers can provide similar APIs to allow the user to create a PMD, that is,
 rte_ethdev structure, instances at run-time in the end-application,
 for example, using rte_eth_from_rings() or rte_eth_from_pcaps() APIs.
-For the rings- based PMD, this functionality could be used, for example,
+For the rings-based PMD, this functionality could be used, for example,
 to allow data exchange between cores using rings to be done in exactly the
 same way as sending or receiving packets from an Ethernet device.
 For the libpcap-based PMD, it allows an application to open one or more pcap files
@@ -231,26 +231,30 @@  for reception on the same port (error handling omitted for clarity):
 
 .. code-block:: c
 
-    struct rte_ring *r1, *r2;
-    int port1, port2;
+    #define RING_SIZE 256
+    #define NUM_RINGS 2
+    #define SOCKET0 0
 
-    r1 = rte_ring_create("R1", 256, SOCKET0,RING_F_SP_ENQ|RING_F_SC_DEQ);
-    r2 = rte_ring_create("R2", 256, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
+    struct rte_ring *ring[NUM_RINGS];
+    int port0, port1;
 
-    /* create an ethdev where RX and TX are done to/from r1, and * another from r2 */
+    ring[0] = rte_ring_create("R0", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
+    ring[1] = rte_ring_create("R1", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ);
 
-    port1 = rte_eth_from_rings(r1, 1, r1, 1, SOCKET0);
-    port2 = rte_eth_from_rings(r2, 1, r2, 1, SOCKET0);
+    /* create two ethdev's */
+
+    port0 = rte_eth_from_rings("eth_ring0", ring, NUM_RINGS, ring, NUM_RINGS, SOCKET0);
+    port1 = rte_eth_from_rings("eth_ring1", ring, NUM_RINGS, ring, NUM_RINGS, SOCKET0);
 
 
 To create two pseudo-Ethernet ports where the traffic is switched between them,
-that is, traffic sent to port 1 is read back from port 2 and vice-versa,
+that is, traffic sent to port 0 is read back from port 1 and vice-versa,
 the final two lines could be changed as below:
 
 .. code-block:: c
 
-    port1 = rte_eth_from_rings(r1, 1, r2, 1, SOCKET0);
-    port2 = rte_eth_from_rings(r2, 1, r1, 1, SOCKET0);
+    port0 = rte_eth_from_rings("eth_ring0", &ring[0], 1, &ring[1], 1, SOCKET0);
+    port1 = rte_eth_from_rings("eth_ring1", &ring[1], 1, &ring[0], 1, SOCKET0);
 
 This type of configuration could be useful in a pipeline model, for example,
 where one may want to have inter-core communication using pseudo Ethernet devices rather than raw rings,