From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <michael.qiu@intel.com>
Received: from mga09.intel.com (mga09.intel.com [134.134.136.24])
 by dpdk.org (Postfix) with ESMTP id DC7119AA4
 for <dev@dpdk.org>; Tue,  3 Feb 2015 08:02:23 +0100 (CET)
Received: from fmsmga002.fm.intel.com ([10.253.24.26])
 by orsmga102.jf.intel.com with ESMTP; 02 Feb 2015 22:58:52 -0800
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.09,511,1418112000"; d="scan'208";a="671884790"
Received: from pgsmsx102.gar.corp.intel.com ([10.221.44.80])
 by fmsmga002.fm.intel.com with ESMTP; 02 Feb 2015 23:02:16 -0800
Received: from shsmsx102.ccr.corp.intel.com (10.239.4.154) by
 PGSMSX102.gar.corp.intel.com (10.221.44.80) with Microsoft SMTP Server (TLS)
 id 14.3.195.1; Tue, 3 Feb 2015 14:59:30 +0800
Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.253]) by
 shsmsx102.ccr.corp.intel.com ([169.254.2.124]) with mapi id 14.03.0195.001;
 Tue, 3 Feb 2015 14:59:28 +0800
From: "Qiu, Michael" <michael.qiu@intel.com>
To: Tetsuya Mukawa <mukawa@igel.co.jp>, "dev@dpdk.org" <dev@dpdk.org>
Thread-Topic: [PATCH v6] testpmd: Add port hotplug support
Thread-Index: AQHQPdP23bysSjCN/EiSLvqSV3tO8A==
Date: Tue, 3 Feb 2015 06:59:28 +0000
Message-ID: <533710CFB86FA344BFBF2D6802E60286CD3EA9@SHSMSX101.ccr.corp.intel.com>
References: <1421664027-17971-9-git-send-email-mukawa@igel.co.jp>
 <1422763322-13742-1-git-send-email-mukawa@igel.co.jp>
 <1422763322-13742-16-git-send-email-mukawa@igel.co.jp>
Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
x-originating-ip: [10.239.127.40]
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
Subject: Re: [dpdk-dev] [PATCH v6] testpmd: Add port hotplug support
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: patches and discussions about DPDK <dev.dpdk.org>
List-Unsubscribe: <http://dpdk.org/ml/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://dpdk.org/ml/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <http://dpdk.org/ml/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
X-List-Received-Date: Tue, 03 Feb 2015 07:02:25 -0000

On 2/1/2015 12:02 PM, Tetsuya Mukawa wrote:=0A=
> The patch introduces following commands.=0A=
> - port attach [ident]=0A=
> - port detach [port_id]=0A=
>  - attach: attaching a port=0A=
>  - detach: detaching a port=0A=
>  - ident: pci address of physical device.=0A=
>           Or device name and paramerters of virtual device.=0A=
>          (ex. 0000:02:00.0, eth_pcap0,iface=3Deth0)=0A=
>  - port_id: port identifier=0A=
>=0A=
> v5:=0A=
> - Add testpmd documentation.=0A=
>   (Thanks to Iremonger, Bernard)=0A=
> v4:=0A=
>  - Fix strings of command help.=0A=
>=0A=
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>=0A=
> ---=0A=
>  app/test-pmd/cmdline.c                      | 133 +++++++++++++++----=0A=
>  app/test-pmd/config.c                       | 116 +++++++++-------=0A=
>  app/test-pmd/parameters.c                   |  22 ++-=0A=
>  app/test-pmd/testpmd.c                      | 199 +++++++++++++++++++++-=
------=0A=
>  app/test-pmd/testpmd.h                      |  18 ++-=0A=
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst |  57 ++++++++=0A=
>  6 files changed, 415 insertions(+), 130 deletions(-)=0A=
>=0A=
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c=0A=
> index 4beb404..2f813d8 100644=0A=
> --- a/app/test-pmd/cmdline.c=0A=
> +++ b/app/test-pmd/cmdline.c=0A=
> @@ -572,6 +572,12 @@ static void cmd_help_long_parsed(void *parsed_result=
,=0A=
>  			"port close (port_id|all)\n"=0A=
>  			"    Close all ports or port_id.\n\n"=0A=
>  =0A=
> +			"port attach (ident)\n"=0A=
> +			"    Attach physical or virtual dev by pci address or virtual device =
name\n\n"=0A=
> +=0A=
> +			"port detach (port_id)\n"=0A=
> +			"    Detach physical or virtual dev by port_id\n\n"=0A=
> +=0A=
>  			"port config (port_id|all)"=0A=
>  			" speed (10|100|1000|10000|40000|auto)"=0A=
>  			" duplex (half|full|auto)\n"=0A=
> @@ -848,6 +854,89 @@ cmdline_parse_inst_t cmd_operate_specific_port =3D {=
=0A=
>  	},=0A=
>  };=0A=
>  =0A=
> +/* *** attach a specificied port *** */=0A=
> +struct cmd_operate_attach_port_result {=0A=
> +	cmdline_fixed_string_t port;=0A=
> +	cmdline_fixed_string_t keyword;=0A=
> +	cmdline_fixed_string_t identifier;=0A=
> +};=0A=
> +=0A=
> +static void cmd_operate_attach_port_parsed(void *parsed_result,=0A=
> +				__attribute__((unused)) struct cmdline *cl,=0A=
> +				__attribute__((unused)) void *data)=0A=
> +{=0A=
> +	struct cmd_operate_attach_port_result *res =3D parsed_result;=0A=
> +=0A=
> +	if (!strcmp(res->keyword, "attach"))=0A=
> +		attach_port(res->identifier);=0A=
> +	else=0A=
> +		printf("Unknown parameter\n");=0A=
> +}=0A=
> +=0A=
> +cmdline_parse_token_string_t cmd_operate_attach_port_port =3D=0A=
> +	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,=0A=
> +			port, "port");=0A=
> +cmdline_parse_token_string_t cmd_operate_attach_port_keyword =3D=0A=
> +	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,=0A=
> +			keyword, "attach");=0A=
> +cmdline_parse_token_string_t cmd_operate_attach_port_identifier =3D=0A=
> +	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,=0A=
> +			identifier, NULL);=0A=
> +=0A=
> +cmdline_parse_inst_t cmd_operate_attach_port =3D {=0A=
> +	.f =3D cmd_operate_attach_port_parsed,=0A=
> +	.data =3D NULL,=0A=
> +	.help_str =3D "port attach identifier, "=0A=
> +		"identifier: pci address or virtual dev name",=0A=
> +	.tokens =3D {=0A=
> +		(void *)&cmd_operate_attach_port_port,=0A=
> +		(void *)&cmd_operate_attach_port_keyword,=0A=
> +		(void *)&cmd_operate_attach_port_identifier,=0A=
> +		NULL,=0A=
> +	},=0A=
> +};=0A=
> +=0A=
> +/* *** detach a specificied port *** */=0A=
> +struct cmd_operate_detach_port_result {=0A=
> +	cmdline_fixed_string_t port;=0A=
> +	cmdline_fixed_string_t keyword;=0A=
> +	uint8_t port_id;=0A=
> +};=0A=
> +=0A=
> +static void cmd_operate_detach_port_parsed(void *parsed_result,=0A=
> +				__attribute__((unused)) struct cmdline *cl,=0A=
> +				__attribute__((unused)) void *data)=0A=
> +{=0A=
> +	struct cmd_operate_detach_port_result *res =3D parsed_result;=0A=
> +=0A=
> +	if (!strcmp(res->keyword, "detach"))=0A=
> +		detach_port(res->port_id);=0A=
> +	else=0A=
> +		printf("Unknown parameter\n");=0A=
> +}=0A=
> +=0A=
> +cmdline_parse_token_string_t cmd_operate_detach_port_port =3D=0A=
> +	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,=0A=
> +			port, "port");=0A=
> +cmdline_parse_token_string_t cmd_operate_detach_port_keyword =3D=0A=
> +	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,=0A=
> +			keyword, "detach");=0A=
> +cmdline_parse_token_num_t cmd_operate_detach_port_port_id =3D=0A=
> +	TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,=0A=
> +			port_id, UINT8);=0A=
> +=0A=
> +cmdline_parse_inst_t cmd_operate_detach_port =3D {=0A=
> +	.f =3D cmd_operate_detach_port_parsed,=0A=
> +	.data =3D NULL,=0A=
> +	.help_str =3D "port detach port_id",=0A=
> +	.tokens =3D {=0A=
> +		(void *)&cmd_operate_detach_port_port,=0A=
> +		(void *)&cmd_operate_detach_port_keyword,=0A=
> +		(void *)&cmd_operate_detach_port_port_id,=0A=
> +		NULL,=0A=
> +	},=0A=
> +};=0A=
> +=0A=
>  /* *** configure speed for all ports *** */=0A=
>  struct cmd_config_speed_all {=0A=
>  	cmdline_fixed_string_t port;=0A=
> @@ -902,7 +991,7 @@ cmd_config_speed_all_parsed(void *parsed_result,=0A=
>  		return;=0A=
>  	}=0A=
>  =0A=
> -	for (pid =3D 0; pid < nb_ports; pid++) {=0A=
> +	FOREACH_PORT(pid, ports) {=0A=
>  		ports[pid].dev_conf.link_speed =3D link_speed;=0A=
>  		ports[pid].dev_conf.link_duplex =3D link_duplex;=0A=
>  	}=0A=
> @@ -970,10 +1059,8 @@ cmd_config_speed_specific_parsed(void *parsed_resul=
t,=0A=
>  		return;=0A=
>  	}=0A=
>  =0A=
> -	if (res->id >=3D nb_ports) {=0A=
> -		printf("Port id %d must be less than %d\n", res->id, nb_ports);=0A=
> +	if (port_id_is_invalid(res->id, ENABLED_WARN))=0A=
>  		return;=0A=
> -	}=0A=
>  =0A=
>  	if (!strcmp(res->value1, "10"))=0A=
>  		link_speed =3D ETH_LINK_SPEED_10;=0A=
> @@ -1533,7 +1620,7 @@ cmd_config_rxtx_queue_parsed(void *parsed_result,=
=0A=
>  		return;=0A=
>  	}=0A=
>  =0A=
> -	if (port_id_is_invalid(res->portid))=0A=
> +	if (port_id_is_invalid(res->portid, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	if (port_is_started(res->portid) !=3D 1) {=0A=
> @@ -2876,7 +2963,7 @@ cmd_tx_cksum_parsed(void *parsed_result,=0A=
>  	uint16_t ol_flags, mask =3D 0;=0A=
>  	struct rte_eth_dev_info dev_info;=0A=
>  =0A=
> -	if (port_id_is_invalid(res->port_id)) {=0A=
> +	if (port_id_is_invalid(res->port_id, ENABLED_WARN)) {=0A=
>  		printf("invalid port %d\n", res->port_id);=0A=
>  		return;=0A=
>  	}=0A=
> @@ -3003,7 +3090,7 @@ cmd_tso_set_parsed(void *parsed_result,=0A=
>  	struct cmd_tso_set_result *res =3D parsed_result;=0A=
>  	struct rte_eth_dev_info dev_info;=0A=
>  =0A=
> -	if (port_id_is_invalid(res->port_id))=0A=
> +	if (port_id_is_invalid(res->port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	if (!strcmp(res->mode, "set"))=0A=
> @@ -3979,10 +4066,8 @@ static void cmd_set_bond_mac_addr_parsed(void *par=
sed_result,=0A=
>  	struct cmd_set_bond_mac_addr_result *res =3D parsed_result;=0A=
>  	int ret;=0A=
>  =0A=
> -	if (res->port_num >=3D nb_ports) {=0A=
> -		printf("Port id %d must be less than %d\n", res->port_num, nb_ports);=
=0A=
> +	if (port_id_is_invalid(res->port_num, ENABLED_WARN))=0A=
>  		return;=0A=
> -	}=0A=
>  =0A=
>  	ret =3D rte_eth_bond_mac_address_set(res->port_num, &res->address);=0A=
>  =0A=
> @@ -4219,7 +4304,7 @@ static void cmd_set_promisc_mode_parsed(void *parse=
d_result,=0A=
>  =0A=
>  	/* all ports */=0A=
>  	if (allports) {=0A=
> -		for (i =3D 0; i < nb_ports; i++) {=0A=
> +		FOREACH_PORT(i, ports) {=0A=
>  			if (enable)=0A=
>  				rte_eth_promiscuous_enable(i);=0A=
>  			else=0A=
> @@ -4299,7 +4384,7 @@ static void cmd_set_allmulti_mode_parsed(void *pars=
ed_result,=0A=
>  =0A=
>  	/* all ports */=0A=
>  	if (allports) {=0A=
> -		for (i =3D 0; i < nb_ports; i++) {=0A=
> +		FOREACH_PORT(i, ports) {=0A=
>  			if (enable)=0A=
>  				rte_eth_allmulticast_enable(i);=0A=
>  			else=0A=
> @@ -5484,25 +5569,25 @@ static void cmd_showportall_parsed(void *parsed_r=
esult,=0A=
>  	struct cmd_showportall_result *res =3D parsed_result;=0A=
>  	if (!strcmp(res->show, "clear")) {=0A=
>  		if (!strcmp(res->what, "stats"))=0A=
> -			for (i =3D 0; i < nb_ports; i++)=0A=
> +			FOREACH_PORT(i, ports)=0A=
>  				nic_stats_clear(i);=0A=
>  		else if (!strcmp(res->what, "xstats"))=0A=
> -			for (i =3D 0; i < nb_ports; i++)=0A=
> +			FOREACH_PORT(i, ports)=0A=
>  				nic_xstats_clear(i);=0A=
>  	} else if (!strcmp(res->what, "info"))=0A=
> -		for (i =3D 0; i < nb_ports; i++)=0A=
> +		FOREACH_PORT(i, ports)=0A=
>  			port_infos_display(i);=0A=
>  	else if (!strcmp(res->what, "stats"))=0A=
> -		for (i =3D 0; i < nb_ports; i++)=0A=
> +		FOREACH_PORT(i, ports)=0A=
>  			nic_stats_display(i);=0A=
>  	else if (!strcmp(res->what, "xstats"))=0A=
> -		for (i =3D 0; i < nb_ports; i++)=0A=
> +		FOREACH_PORT(i, ports)=0A=
>  			nic_xstats_display(i);=0A=
>  	else if (!strcmp(res->what, "fdir"))=0A=
> -		for (i =3D 0; i < nb_ports; i++)=0A=
> +		FOREACH_PORT(i, ports)=0A=
>  			fdir_get_infos(i);=0A=
>  	else if (!strcmp(res->what, "stat_qmap"))=0A=
> -		for (i =3D 0; i < nb_ports; i++)=0A=
> +		FOREACH_PORT(i, ports)=0A=
>  			nic_stats_mapping_display(i);=0A=
>  }=0A=
>  =0A=
> @@ -8756,6 +8841,8 @@ cmdline_parse_ctx_t main_ctx[] =3D {=0A=
>  	(cmdline_parse_inst_t *)&cmd_set_qmap,=0A=
>  	(cmdline_parse_inst_t *)&cmd_operate_port,=0A=
>  	(cmdline_parse_inst_t *)&cmd_operate_specific_port,=0A=
> +	(cmdline_parse_inst_t *)&cmd_operate_attach_port,=0A=
> +	(cmdline_parse_inst_t *)&cmd_operate_detach_port,=0A=
>  	(cmdline_parse_inst_t *)&cmd_config_speed_all,=0A=
>  	(cmdline_parse_inst_t *)&cmd_config_speed_specific,=0A=
>  	(cmdline_parse_inst_t *)&cmd_config_rx_tx,=0A=
> @@ -8830,7 +8917,7 @@ prompt(void)=0A=
>  static void=0A=
>  cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)=0A=
>  {=0A=
> -	if (id < nb_ports) {=0A=
> +	if (!port_id_is_invalid(id, DISABLED_WARN)) {=0A=
>  		/* check if need_reconfig has been set to 1 */=0A=
>  		if (ports[id].need_reconfig =3D=3D 0)=0A=
>  			ports[id].need_reconfig =3D dev;=0A=
> @@ -8840,7 +8927,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev,=
 uint8_t queue)=0A=
>  	} else {=0A=
>  		portid_t pid;=0A=
>  =0A=
> -		for (pid =3D 0; pid < nb_ports; pid++) {=0A=
> +		FOREACH_PORT(pid, ports) {=0A=
>  			/* check if need_reconfig has been set to 1 */=0A=
>  			if (ports[pid].need_reconfig =3D=3D 0)=0A=
>  				ports[pid].need_reconfig =3D dev;=0A=
> @@ -8858,10 +8945,8 @@ bypass_is_supported(portid_t port_id)=0A=
>  	struct rte_port   *port;=0A=
>  	struct rte_pci_id *pci_id;=0A=
>  =0A=
> -	if (port_id >=3D nb_ports) {=0A=
> -		printf("\tPort id must be less than %d.\n", nb_ports);=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return 0;=0A=
> -	}=0A=
>  =0A=
>  	/* Get the device id. */=0A=
>  	port    =3D &ports[port_id];=0A=
> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c=0A=
> index c40f819..32d8f9a 100644=0A=
> --- a/app/test-pmd/config.c=0A=
> +++ b/app/test-pmd/config.c=0A=
> @@ -124,11 +124,15 @@ nic_stats_display(portid_t port_id)=0A=
>  	struct rte_eth_stats stats;=0A=
>  	struct rte_port *port =3D &ports[port_id];=0A=
>  	uint8_t i;=0A=
> +	portid_t pid;=0A=
>  =0A=
>  	static const char *nic_stats_border =3D "########################";=0A=
>  =0A=
> -	if (port_id >=3D nb_ports) {=0A=
> -		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +		printf("Valid port range is [0");=0A=
> +		FOREACH_PORT(pid, ports)=0A=
> +			printf(", %d", pid);=0A=
> +		printf("]\n");=0A=
>  		return;=0A=
>  	}=0A=
>  	rte_eth_stats_get(port_id, &stats);=0A=
> @@ -201,8 +205,13 @@ nic_stats_display(portid_t port_id)=0A=
>  void=0A=
>  nic_stats_clear(portid_t port_id)=0A=
>  {=0A=
> -	if (port_id >=3D nb_ports) {=0A=
> -		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +	portid_t pid;=0A=
> +=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +		printf("Valid port range is [0");=0A=
> +		FOREACH_PORT(pid, ports)=0A=
> +			printf(", %d", pid);=0A=
> +		printf("]\n");=0A=
>  		return;=0A=
>  	}=0A=
>  	rte_eth_stats_reset(port_id);=0A=
> @@ -249,11 +258,15 @@ nic_stats_mapping_display(portid_t port_id)=0A=
>  {=0A=
>  	struct rte_port *port =3D &ports[port_id];=0A=
>  	uint16_t i;=0A=
> +	portid_t pid;=0A=
>  =0A=
>  	static const char *nic_stats_mapping_border =3D "######################=
##";=0A=
>  =0A=
> -	if (port_id >=3D nb_ports) {=0A=
> -		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +		printf("Valid port range is [0");=0A=
> +		FOREACH_PORT(pid, ports)=0A=
> +			printf(", %d", pid);=0A=
> +		printf("]\n");=0A=
>  		return;=0A=
>  	}=0A=
>  =0A=
> @@ -302,9 +315,13 @@ port_infos_display(portid_t port_id)=0A=
>  	int vlan_offload;=0A=
>  	struct rte_mempool * mp;=0A=
>  	static const char *info_border =3D "*********************";=0A=
> +	portid_t pid;=0A=
>  =0A=
> -	if (port_id >=3D nb_ports) {=0A=
> -		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +		printf("Valid port range is [0");=0A=
> +		FOREACH_PORT(pid, ports)=0A=
> +			printf(", %d", pid);=0A=
> +		printf("]\n");=0A=
>  		return;=0A=
>  	}=0A=
>  	port =3D &ports[port_id];=0A=
> @@ -362,11 +379,14 @@ port_infos_display(portid_t port_id)=0A=
>  }=0A=
>  =0A=
>  int=0A=
> -port_id_is_invalid(portid_t port_id)=0A=
> +port_id_is_invalid(portid_t port_id, enum print_warning warning)=0A=
>  {=0A=
> -	if (port_id < nb_ports)=0A=
> +	if (ports[port_id].enabled)=0A=
=0A=
Here maybe care about overflow,  it could be passed a value of=0A=
RTE_PORT_ALL, which is 255.=0A=
=0A=
Thanks,=0A=
Michael=0A=
>  		return 0;=0A=
> -	printf("Invalid port %d (must be < nb_ports=3D%d)\n", port_id, nb_ports=
);=0A=
> +=0A=
> +	if (warning =3D=3D ENABLED_WARN)=0A=
> +		printf("Invalid port %d\n", port_id);=0A=
> +=0A=
>  	return 1;=0A=
>  }=0A=
>  =0A=
> @@ -425,7 +445,7 @@ port_reg_bit_display(portid_t port_id, uint32_t reg_o=
ff, uint8_t bit_x)=0A=
>  	uint32_t reg_v;=0A=
>  =0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -444,7 +464,7 @@ port_reg_bit_field_display(portid_t port_id, uint32_t=
 reg_off,=0A=
>  	uint8_t  l_bit;=0A=
>  	uint8_t  h_bit;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -471,7 +491,7 @@ port_reg_display(portid_t port_id, uint32_t reg_off)=
=0A=
>  {=0A=
>  	uint32_t reg_v;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -485,7 +505,7 @@ port_reg_bit_set(portid_t port_id, uint32_t reg_off, =
uint8_t bit_pos,=0A=
>  {=0A=
>  	uint32_t reg_v;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -513,7 +533,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg=
_off,=0A=
>  	uint8_t  l_bit;=0A=
>  	uint8_t  h_bit;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -547,7 +567,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg=
_off,=0A=
>  void=0A=
>  port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)=0A=
>  {=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (port_reg_off_is_invalid(port_id, reg_off))=0A=
>  		return;=0A=
> @@ -560,7 +580,7 @@ port_mtu_set(portid_t port_id, uint16_t mtu)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	diag =3D rte_eth_dev_set_mtu(port_id, mtu);=0A=
>  	if (diag =3D=3D 0)=0A=
> @@ -723,7 +743,7 @@ rx_ring_desc_display(portid_t port_id, queueid_t rxq_=
id, uint16_t rxd_id)=0A=
>  {=0A=
>  	const struct rte_memzone *rx_mz;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (rx_queue_id_is_invalid(rxq_id))=0A=
>  		return;=0A=
> @@ -740,7 +760,7 @@ tx_ring_desc_display(portid_t port_id, queueid_t txq_=
id, uint16_t txd_id)=0A=
>  {=0A=
>  	const struct rte_memzone *tx_mz;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (tx_queue_id_is_invalid(txq_id))=0A=
>  		return;=0A=
> @@ -796,7 +816,7 @@ port_rss_reta_info(portid_t port_id,=0A=
>  	uint16_t i, idx, shift;=0A=
>  	int ret;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	ret =3D rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);=0A=
> @@ -828,7 +848,7 @@ port_rss_hash_conf_show(portid_t port_id, int show_rs=
s_key)=0A=
>  	uint8_t i;=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	/* Get RSS hash key if asked to display it */=0A=
>  	rss_conf.rss_key =3D (show_rss_key) ? rss_key : NULL;=0A=
> @@ -1406,12 +1426,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigne=
d int nb_pt)=0A=
>   again:=0A=
>  	for (i =3D 0; i < nb_pt; i++) {=0A=
>  		port_id =3D (portid_t) portlist[i];=0A=
> -		if (port_id >=3D nb_ports) {=0A=
> -			printf("Invalid port id %u >=3D %u\n",=0A=
> -			       (unsigned int) port_id,=0A=
> -			       (unsigned int) nb_ports);=0A=
> +		if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  			return;=0A=
> -		}=0A=
>  		if (record_now)=0A=
>  			fwd_ports_ids[i] =3D port_id;=0A=
>  	}=0A=
> @@ -1569,7 +1585,7 @@ vlan_extend_set(portid_t port_id, int on)=0A=
>  	int diag;=0A=
>  	int vlan_offload;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	vlan_offload =3D rte_eth_dev_get_vlan_offload(port_id);=0A=
> @@ -1591,7 +1607,7 @@ rx_vlan_strip_set(portid_t port_id, int on)=0A=
>  	int diag;=0A=
>  	int vlan_offload;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	vlan_offload =3D rte_eth_dev_get_vlan_offload(port_id);=0A=
> @@ -1612,7 +1628,7 @@ rx_vlan_strip_set_on_queue(portid_t port_id, uint16=
_t queue_id, int on)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);=0A=
> @@ -1627,7 +1643,7 @@ rx_vlan_filter_set(portid_t port_id, int on)=0A=
>  	int diag;=0A=
>  	int vlan_offload;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	vlan_offload =3D rte_eth_dev_get_vlan_offload(port_id);=0A=
> @@ -1648,7 +1664,7 @@ rx_vft_set(portid_t port_id, uint16_t vlan_id, int =
on)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (vlan_id_is_invalid(vlan_id))=0A=
>  		return;=0A=
> @@ -1665,7 +1681,7 @@ rx_vlan_all_filter_set(portid_t port_id, int on)=0A=
>  {=0A=
>  	uint16_t vlan_id;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	for (vlan_id =3D 0; vlan_id < 4096; vlan_id++)=0A=
>  		rx_vft_set(port_id, vlan_id, on);=0A=
> @@ -1675,7 +1691,7 @@ void=0A=
>  vlan_tpid_set(portid_t port_id, uint16_t tp_id)=0A=
>  {=0A=
>  	int diag;=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_set_vlan_ether_type(port_id, tp_id);=0A=
> @@ -1690,7 +1706,7 @@ vlan_tpid_set(portid_t port_id, uint16_t tp_id)=0A=
>  void=0A=
>  tx_vlan_set(portid_t port_id, uint16_t vlan_id)=0A=
>  {=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (vlan_id_is_invalid(vlan_id))=0A=
>  		return;=0A=
> @@ -1701,7 +1717,7 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)=0A=
>  void=0A=
>  tx_vlan_reset(portid_t port_id)=0A=
>  {=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	ports[port_id].tx_ol_flags &=3D ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;=0A=
>  }=0A=
> @@ -1709,7 +1725,7 @@ tx_vlan_reset(portid_t port_id)=0A=
>  void=0A=
>  tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)=0A=
>  {=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);=0A=
> @@ -1721,7 +1737,7 @@ set_qmap(portid_t port_id, uint8_t is_rx, uint16_t =
queue_id, uint8_t map_value)=0A=
>  	uint16_t i;=0A=
>  	uint8_t existing_mapping_found =3D 0;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invali=
d(queue_id)))=0A=
> @@ -1773,7 +1789,7 @@ fdir_add_signature_filter(portid_t port_id, uint8_t=
 queue_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_add_signature_filter(port_id, fdir_filter,=0A=
> @@ -1791,7 +1807,7 @@ fdir_update_signature_filter(portid_t port_id, uint=
8_t queue_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_update_signature_filter(port_id, fdir_filter,=
=0A=
> @@ -1809,7 +1825,7 @@ fdir_remove_signature_filter(portid_t port_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_remove_signature_filter(port_id, fdir_filter)=
;=0A=
> @@ -1881,7 +1897,7 @@ fdir_get_infos(portid_t port_id)=0A=
>  =0A=
>  	static const char *fdir_stats_border =3D "########################";=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	ret =3D rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);=0A=
>  	if (ret < 0) {=0A=
> @@ -1955,7 +1971,7 @@ fdir_add_perfect_filter(portid_t port_id, uint16_t =
soft_id, uint8_t queue_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_add_perfect_filter(port_id, fdir_filter,=0A=
> @@ -1973,7 +1989,7 @@ fdir_update_perfect_filter(portid_t port_id, uint16=
_t soft_id, uint8_t queue_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_update_perfect_filter(port_id, fdir_filter,=
=0A=
> @@ -1991,7 +2007,7 @@ fdir_remove_perfect_filter(portid_t port_id, uint16=
_t soft_id,=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_remove_perfect_filter(port_id, fdir_filter,=
=0A=
> @@ -2008,7 +2024,7 @@ fdir_set_masks(portid_t port_id, struct rte_fdir_ma=
sks *fdir_masks)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  =0A=
>  	diag =3D rte_eth_dev_fdir_set_masks(port_id, fdir_masks);=0A=
> @@ -2085,7 +2101,7 @@ set_vf_traffic(portid_t port_id, uint8_t is_rx, uin=
t16_t vf, uint8_t on)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (is_rx)=0A=
>  		diag =3D rte_eth_dev_set_vf_rx(port_id,vf,on);=0A=
> @@ -2107,7 +2123,7 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, =
uint64_t vf_mask, uint8_t on)=0A=
>  {=0A=
>  	int diag;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return;=0A=
>  	if (vlan_id_is_invalid(vlan_id))=0A=
>  		return;=0A=
> @@ -2124,7 +2140,7 @@ set_queue_rate_limit(portid_t port_id, uint16_t que=
ue_idx, uint16_t rate)=0A=
>  	int diag;=0A=
>  	struct rte_eth_link link;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return 1;=0A=
>  	rte_eth_link_get_nowait(port_id, &link);=0A=
>  	if (rate > link.link_speed) {=0A=
> @@ -2149,7 +2165,7 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, ui=
nt16_t rate, uint64_t q_msk)=0A=
>  	if (q_msk =3D=3D 0)=0A=
>  		return 0;=0A=
>  =0A=
> -	if (port_id_is_invalid(port_id))=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
>  		return 1;=0A=
>  	rte_eth_link_get_nowait(port_id, &link);=0A=
>  	if (rate > link.link_speed) {=0A=
> diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c=0A=
> index adf3203..6f2af18 100644=0A=
> --- a/app/test-pmd/parameters.c=0A=
> +++ b/app/test-pmd/parameters.c=0A=
> @@ -376,6 +376,7 @@ parse_portnuma_config(const char *q_arg)=0A=
>  	};=0A=
>  	unsigned long int_fld[_NUM_FLD];=0A=
>  	char *str_fld[_NUM_FLD];=0A=
> +	portid_t pid;=0A=
>  =0A=
>  	/* reset from value set at definition */=0A=
>  	while ((p =3D strchr(p0,'(')) !=3D NULL) {=0A=
> @@ -397,8 +398,11 @@ parse_portnuma_config(const char *q_arg)=0A=
>  				return -1;=0A=
>  		}=0A=
>  		port_id =3D (uint8_t)int_fld[FLD_PORT];=0A=
> -		if (port_id >=3D nb_ports) {=0A=
> -			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +		if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +			printf("Valid port range is [0");=0A=
> +			FOREACH_PORT(pid, ports)=0A=
> +				printf(", %d", pid);=0A=
> +			printf("]\n");=0A=
>  			return -1;=0A=
>  		}=0A=
>  		socket_id =3D (uint8_t)int_fld[FLD_SOCKET];=0A=
> @@ -429,6 +433,7 @@ parse_ringnuma_config(const char *q_arg)=0A=
>  	};=0A=
>  	unsigned long int_fld[_NUM_FLD];=0A=
>  	char *str_fld[_NUM_FLD];=0A=
> +	portid_t pid;=0A=
>  	#define RX_RING_ONLY 0x1=0A=
>  	#define TX_RING_ONLY 0x2=0A=
>  	#define RXTX_RING    0x3=0A=
> @@ -453,8 +458,11 @@ parse_ringnuma_config(const char *q_arg)=0A=
>  				return -1;=0A=
>  		}=0A=
>  		port_id =3D (uint8_t)int_fld[FLD_PORT];=0A=
> -		if (port_id >=3D nb_ports) {=0A=
> -			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);=0A=
> +		if (port_id_is_invalid(port_id, ENABLED_WARN)) {=0A=
> +			printf("Valid port range is [0");=0A=
> +			FOREACH_PORT(pid, ports)=0A=
> +				printf(", %d", pid);=0A=
> +			printf("]\n");=0A=
>  			return -1;=0A=
>  		}=0A=
>  		socket_id =3D (uint8_t)int_fld[FLD_SOCKET];=0A=
> @@ -626,12 +634,12 @@ launch_args_parse(int argc, char** argv)=0A=
>  #endif=0A=
>  			if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {=0A=
>  				n =3D atoi(optarg);=0A=
> -				if (n > 0 && n <=3D nb_ports)=0A=
> +				if (n > 0 &&=0A=
> +				    !port_id_is_invalid(n, DISABLED_WARN))=0A=
>  					nb_fwd_ports =3D (uint8_t) n;=0A=
>  				else=0A=
>  					rte_exit(EXIT_FAILURE,=0A=
> -						 "nb-ports should be > 0 and <=3D %d\n",=0A=
> -						 nb_ports);=0A=
> +						 "Invalid port %d\n", n);=0A=
>  			}=0A=
>  			if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {=0A=
>  				n =3D atoi(optarg);=0A=
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c=0A=
> index 773b8af..c18c1a9 100644=0A=
> --- a/app/test-pmd/testpmd.c=0A=
> +++ b/app/test-pmd/testpmd.c=0A=
> @@ -71,6 +71,7 @@=0A=
>  #include <rte_pci.h>=0A=
>  #include <rte_ether.h>=0A=
>  #include <rte_ethdev.h>=0A=
> +#include <rte_dev.h>=0A=
>  #include <rte_string_fns.h>=0A=
>  #ifdef RTE_LIBRTE_PMD_XENVIRT=0A=
>  #include <rte_eth_xenvirt.h>=0A=
> @@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings =3D 0;=0A=
>  =0A=
>  /* Forward function declarations */=0A=
>  static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rt=
e_port *port);=0A=
> -static void check_all_ports_link_status(uint8_t port_num, uint32_t port_=
mask);=0A=
> +static void check_all_ports_link_status(uint32_t port_mask);=0A=
>  =0A=
>  /*=0A=
>   * Check if all the ports are started.=0A=
> @@ -324,6 +325,20 @@ static void check_all_ports_link_status(uint8_t port=
_num, uint32_t port_mask);=0A=
>  static int all_ports_started(void);=0A=
>  =0A=
>  /*=0A=
> + * Find next enabled port=0A=
> + */=0A=
> +portid_t=0A=
> +find_next_port(portid_t p, struct rte_port *ports, int size)=0A=
> +{=0A=
> +	if (ports =3D=3D NULL)=0A=
> +		rte_exit(-EINVAL, "failed to find a next port id\n");=0A=
> +=0A=
> +	while ((ports[p].enabled =3D=3D 0) && (p < size))=0A=
> +		p++;=0A=
> +	return p;=0A=
> +}=0A=
> +=0A=
> +/*=0A=
>   * Setup default configuration.=0A=
>   */=0A=
>  static void=0A=
> @@ -552,7 +567,8 @@ init_config(void)=0A=
>  				+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;=0A=
>  =0A=
>  		if (!numa_support)=0A=
> -			nb_mbuf_per_pool =3D (nb_mbuf_per_pool * nb_ports);=0A=
> +			nb_mbuf_per_pool =3D=0A=
> +				(nb_mbuf_per_pool * RTE_MAX_ETHPORTS);=0A=
>  	}=0A=
>  =0A=
>  	if (!numa_support) {=0A=
> @@ -565,14 +581,19 @@ init_config(void)=0A=
>  =0A=
>  	/* Configuration of Ethernet ports. */=0A=
>  	ports =3D rte_zmalloc("testpmd: ports",=0A=
> -			    sizeof(struct rte_port) * nb_ports,=0A=
> +			    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,=0A=
>  			    RTE_CACHE_LINE_SIZE);=0A=
>  	if (ports =3D=3D NULL) {=0A=
> -		rte_exit(EXIT_FAILURE, "rte_zmalloc(%d struct rte_port) "=0A=
> -							"failed\n", nb_ports);=0A=
> +		rte_exit(EXIT_FAILURE,=0A=
> +				"rte_zmalloc(%d struct rte_port) failed\n",=0A=
> +				RTE_MAX_ETHPORTS);=0A=
>  	}=0A=
>  =0A=
> -	for (pid =3D 0; pid < nb_ports; pid++) {=0A=
> +	/* enabled allocated ports */=0A=
> +	for (pid =3D 0; pid < nb_ports; pid++)=0A=
> +		ports[pid].enabled =3D 1;=0A=
> +=0A=
> +	FOREACH_PORT(pid, ports) {=0A=
>  		port =3D &ports[pid];=0A=
>  		rte_eth_dev_info_get(pid, &port->dev_info);=0A=
>  =0A=
> @@ -602,8 +623,7 @@ init_config(void)=0A=
>  			nb_mbuf_per_pool =3D nb_mbuf_per_pool/nb_ports;=0A=
>  =0A=
>  		for (i =3D 0; i < MAX_SOCKET; i++) {=0A=
> -			nb_mbuf =3D (nb_mbuf_per_pool *=0A=
> -						port_per_socket[i]);=0A=
> +			nb_mbuf =3D (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);=0A=
>  			if (nb_mbuf)=0A=
>  				mbuf_pool_create(mbuf_data_size,=0A=
>  						nb_mbuf,i);=0A=
> @@ -635,14 +655,6 @@ reconfig(portid_t new_port_id, unsigned socket_id)=
=0A=
>  	struct rte_port *port;=0A=
>  =0A=
>  	/* Reconfiguration of Ethernet ports. */=0A=
> -	ports =3D rte_realloc(ports,=0A=
> -			    sizeof(struct rte_port) * nb_ports,=0A=
> -			    RTE_CACHE_LINE_SIZE);=0A=
> -	if (ports =3D=3D NULL) {=0A=
> -		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",=0A=
> -				nb_ports);=0A=
> -	}=0A=
> -=0A=
>  	port =3D &ports[new_port_id];=0A=
>  	rte_eth_dev_info_get(new_port_id, &port->dev_info);=0A=
>  =0A=
> @@ -663,7 +675,7 @@ init_fwd_streams(void)=0A=
>  	streamid_t sm_id, nb_fwd_streams_new;=0A=
>  =0A=
>  	/* set socket id according to numa or not */=0A=
> -	for (pid =3D 0; pid < nb_ports; pid++) {=0A=
> +	FOREACH_PORT(pid, ports) {=0A=
>  		port =3D &ports[pid];=0A=
>  		if (nb_rxq > port->dev_info.max_rx_queues) {=0A=
>  			printf("Fail: nb_rxq(%d) is greater than "=0A=
> @@ -1264,7 +1276,7 @@ all_ports_started(void)=0A=
>  	portid_t pi;=0A=
>  	struct rte_port *port;=0A=
>  =0A=
> -	for (pi =3D 0; pi < nb_ports; pi++) {=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
>  		port =3D &ports[pi];=0A=
>  		/* Check if there is a port which is not started */=0A=
>  		if (port->port_status !=3D RTE_PORT_STARTED)=0A=
> @@ -1276,6 +1288,45 @@ all_ports_started(void)=0A=
>  }=0A=
>  =0A=
>  int=0A=
> +all_ports_stopped(void)=0A=
> +{=0A=
> +	portid_t pi;=0A=
> +	struct rte_port *port;=0A=
> +=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
> +		port =3D &ports[pi];=0A=
> +		if (port->port_status !=3D RTE_PORT_STOPPED)=0A=
> +			return 0;=0A=
> +	}=0A=
> +=0A=
> +	return 1;=0A=
> +}=0A=
> +=0A=
> +int=0A=
> +port_is_started(portid_t port_id)=0A=
> +{=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
> +		return 0;=0A=
> +=0A=
> +	if (ports[port_id].port_status !=3D RTE_PORT_STARTED)=0A=
> +		return 0;=0A=
> +=0A=
> +	return 1;=0A=
> +}=0A=
> +=0A=
> +static int=0A=
> +port_is_closed(portid_t port_id)=0A=
> +{=0A=
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))=0A=
> +		return 0;=0A=
> +=0A=
> +	if (ports[port_id].port_status !=3D RTE_PORT_CLOSED)=0A=
> +		return 0;=0A=
> +=0A=
> +	return 1;=0A=
> +}=0A=
> +=0A=
> +int=0A=
>  start_port(portid_t pid)=0A=
>  {=0A=
>  	int diag, need_check_link_status =3D 0;=0A=
> @@ -1296,8 +1347,8 @@ start_port(portid_t pid)=0A=
>  =0A=
>  	if(dcb_config)=0A=
>  		dcb_test =3D 1;=0A=
> -	for (pi =3D 0; pi < nb_ports; pi++) {=0A=
> -		if (pid < nb_ports && pid !=3D pi)=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
> +		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid !=3D pi)=0A=
>  			continue;=0A=
>  =0A=
>  		port =3D &ports[pi];=0A=
> @@ -1421,7 +1472,7 @@ start_port(portid_t pid)=0A=
>  	}=0A=
>  =0A=
>  	if (need_check_link_status && !no_link_check)=0A=
> -		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);=0A=
> +		check_all_ports_link_status(RTE_PORT_ALL);=0A=
>  	else=0A=
>  		printf("Please stop the ports first\n");=0A=
>  =0A=
> @@ -1446,8 +1497,8 @@ stop_port(portid_t pid)=0A=
>  	}=0A=
>  	printf("Stopping ports...\n");=0A=
>  =0A=
> -	for (pi =3D 0; pi < nb_ports; pi++) {=0A=
> -		if (pid < nb_ports && pid !=3D pi)=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
> +		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid !=3D pi)=0A=
>  			continue;=0A=
>  =0A=
>  		port =3D &ports[pi];=0A=
> @@ -1463,7 +1514,7 @@ stop_port(portid_t pid)=0A=
>  		need_check_link_status =3D 1;=0A=
>  	}=0A=
>  	if (need_check_link_status && !no_link_check)=0A=
> -		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);=0A=
> +		check_all_ports_link_status(RTE_PORT_ALL);=0A=
>  =0A=
>  	printf("Done\n");=0A=
>  }=0A=
> @@ -1481,8 +1532,8 @@ close_port(portid_t pid)=0A=
>  =0A=
>  	printf("Closing ports...\n");=0A=
>  =0A=
> -	for (pi =3D 0; pi < nb_ports; pi++) {=0A=
> -		if (pid < nb_ports && pid !=3D pi)=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
> +		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid !=3D pi)=0A=
>  			continue;=0A=
>  =0A=
>  		port =3D &ports[pi];=0A=
> @@ -1502,31 +1553,83 @@ close_port(portid_t pid)=0A=
>  	printf("Done\n");=0A=
>  }=0A=
>  =0A=
> -int=0A=
> -all_ports_stopped(void)=0A=
> +void=0A=
> +attach_port(char *identifier)=0A=
>  {=0A=
> -	portid_t pi;=0A=
> -	struct rte_port *port;=0A=
> +	portid_t i, j, pi =3D 0;=0A=
>  =0A=
> -	for (pi =3D 0; pi < nb_ports; pi++) {=0A=
> -		port =3D &ports[pi];=0A=
> -		if (port->port_status !=3D RTE_PORT_STOPPED)=0A=
> -			return 0;=0A=
> +	printf("Attaching a new port...\n");=0A=
> +=0A=
> +	if (identifier =3D=3D NULL) {=0A=
> +		printf("Invalid parameters are speficied\n");=0A=
> +		return;=0A=
>  	}=0A=
>  =0A=
> -	return 1;=0A=
> +	if (test_done =3D=3D 0) {=0A=
> +		printf("Please stop forwarding first\n");=0A=
> +		return;=0A=
> +	}=0A=
> +=0A=
> +	if (rte_eal_dev_attach(identifier, &pi))=0A=
> +		return;=0A=
> +=0A=
> +	ports[pi].enabled =3D 1;=0A=
> +	reconfig(pi, rte_eth_dev_socket_id(pi));=0A=
> +	rte_eth_promiscuous_enable(pi);=0A=
> +=0A=
> +	nb_ports =3D rte_eth_dev_count();=0A=
> +=0A=
> +	/* set_default_fwd_ports_config(); */=0A=
> +	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));=0A=
> +	i =3D 0;=0A=
> +	FOREACH_PORT(j, ports) {=0A=
> +		fwd_ports_ids[i] =3D j;=0A=
> +		i++;=0A=
> +	}=0A=
> +	nb_cfg_ports =3D nb_ports;=0A=
> +	nb_fwd_ports++;=0A=
> +=0A=
> +	ports[pi].port_status =3D RTE_PORT_STOPPED;=0A=
> +=0A=
> +	printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);=
=0A=
> +	printf("Done\n");=0A=
>  }=0A=
>  =0A=
> -int=0A=
> -port_is_started(portid_t port_id)=0A=
> +void=0A=
> +detach_port(uint8_t port_id)=0A=
>  {=0A=
> -	if (port_id_is_invalid(port_id))=0A=
> -		return -1;=0A=
> +	portid_t i, pi =3D 0;=0A=
> +	char name[RTE_ETH_NAME_MAX_LEN];=0A=
>  =0A=
> -	if (ports[port_id].port_status !=3D RTE_PORT_STARTED)=0A=
> -		return 0;=0A=
> +	printf("Detaching a port...\n");=0A=
>  =0A=
> -	return 1;=0A=
> +	if (!port_is_closed(port_id)) {=0A=
> +		printf("Please close port first\n");=0A=
> +		return;=0A=
> +	}=0A=
> +=0A=
> +	rte_eth_promiscuous_disable(port_id);=0A=
> +=0A=
> +	if (rte_eal_dev_detach(port_id, name))=0A=
> +		return;=0A=
> +=0A=
> +	ports[port_id].enabled =3D 0;=0A=
> +	nb_ports =3D rte_eth_dev_count();=0A=
> +=0A=
> +	/* set_default_fwd_ports_config(); */=0A=
> +	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));=0A=
> +	i =3D 0;=0A=
> +	FOREACH_PORT(pi, ports) {=0A=
> +		fwd_ports_ids[i] =3D pi;=0A=
> +		i++;=0A=
> +	}=0A=
> +	nb_cfg_ports =3D nb_ports;=0A=
> +	nb_fwd_ports--;=0A=
> +=0A=
> +	printf("Port '%s' is detached. Now total ports is %d\n",=0A=
> +			name, nb_ports);=0A=
> +	printf("Done\n");=0A=
> +	return;=0A=
>  }=0A=
>  =0A=
>  void=0A=
> @@ -1534,7 +1637,7 @@ pmd_test_exit(void)=0A=
>  {=0A=
>  	portid_t pt_id;=0A=
>  =0A=
> -	for (pt_id =3D 0; pt_id < nb_ports; pt_id++) {=0A=
> +	FOREACH_PORT(pt_id, ports) {=0A=
>  		printf("Stopping port %d...", pt_id);=0A=
>  		fflush(stdout);=0A=
>  		rte_eth_dev_close(pt_id);=0A=
> @@ -1553,7 +1656,7 @@ struct pmd_test_command {=0A=
>  =0A=
>  /* Check the link status of all ports in up to 9s, and print them finall=
y */=0A=
>  static void=0A=
> -check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)=0A=
> +check_all_ports_link_status(uint32_t port_mask)=0A=
>  {=0A=
>  #define CHECK_INTERVAL 100 /* 100ms */=0A=
>  #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */=0A=
> @@ -1564,7 +1667,7 @@ check_all_ports_link_status(uint8_t port_num, uint3=
2_t port_mask)=0A=
>  	fflush(stdout);=0A=
>  	for (count =3D 0; count <=3D MAX_CHECK_TIME; count++) {=0A=
>  		all_ports_up =3D 1;=0A=
> -		for (portid =3D 0; portid < port_num; portid++) {=0A=
> +		FOREACH_PORT(portid, ports) {=0A=
>  			if ((port_mask & (1 << portid)) =3D=3D 0)=0A=
>  				continue;=0A=
>  			memset(&link, 0, sizeof(link));=0A=
> @@ -1688,7 +1791,7 @@ init_port_config(void)=0A=
>  	portid_t pid;=0A=
>  	struct rte_port *port;=0A=
>  =0A=
> -	for (pid =3D 0; pid < nb_ports; pid++) {=0A=
> +	FOREACH_PORT(pid, ports) {=0A=
>  		port =3D &ports[pid];=0A=
>  		port->dev_conf.rxmode =3D rx_mode;=0A=
>  		port->dev_conf.fdir_conf =3D fdir_conf;=0A=
> @@ -1877,7 +1980,7 @@ main(int argc, char** argv)=0A=
>  =0A=
>  	nb_ports =3D (portid_t) rte_eth_dev_count();=0A=
>  	if (nb_ports =3D=3D 0)=0A=
> -		rte_exit(EXIT_FAILURE, "No probed ethernet device\n");=0A=
> +		RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");=0A=
>  =0A=
>  	set_def_fwd_config();=0A=
>  	if (nb_lcores =3D=3D 0)=0A=
> @@ -1899,7 +2002,7 @@ main(int argc, char** argv)=0A=
>  		rte_exit(EXIT_FAILURE, "Start ports failed\n");=0A=
>  =0A=
>  	/* set all ports to promiscuous mode by default */=0A=
> -	for (port_id =3D 0; port_id < nb_ports; port_id++)=0A=
> +	FOREACH_PORT(port_id, ports)=0A=
>  		rte_eth_promiscuous_enable(port_id);=0A=
>  =0A=
>  #ifdef RTE_LIBRTE_CMDLINE=0A=
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h=0A=
> index 8f5e6c7..109c670 100644=0A=
> --- a/app/test-pmd/testpmd.h=0A=
> +++ b/app/test-pmd/testpmd.h=0A=
> @@ -134,6 +134,7 @@ struct fwd_stream {=0A=
>   * The data structure associated with each port.=0A=
>   */=0A=
>  struct rte_port {=0A=
> +	uint8_t                 enabled;    /**< Port enabled or not */=0A=
>  	struct rte_eth_dev_info dev_info;   /**< PCI info + driver name */=0A=
>  	struct rte_eth_conf     dev_conf;   /**< Port configuration. */=0A=
>  	struct ether_addr       eth_addr;   /**< Port ethernet address */=0A=
> @@ -159,6 +160,14 @@ struct rte_port {=0A=
>  	struct rte_eth_txconf   tx_conf;    /**< tx configuration */=0A=
>  };=0A=
>  =0A=
> +extern portid_t __rte_unused=0A=
> +find_next_port(portid_t p, struct rte_port *ports, int size);=0A=
> +=0A=
> +#define FOREACH_PORT(p, ports) \=0A=
> +	for (p =3D find_next_port(0, ports, RTE_MAX_ETHPORTS); \=0A=
> +	    p < RTE_MAX_ETHPORTS; \=0A=
> +	    p =3D find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))=0A=
> +=0A=
>  /**=0A=
>   * The data structure associated with each forwarding logical core.=0A=
>   * The logical cores are internally numbered by a core index from 0 to=
=0A=
> @@ -515,6 +524,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_conf=
ig *dcb_conf);=0A=
>  int start_port(portid_t pid);=0A=
>  void stop_port(portid_t pid);=0A=
>  void close_port(portid_t pid);=0A=
> +void attach_port(char *identifier);=0A=
> +void detach_port(uint8_t port_id);=0A=
>  int all_ports_stopped(void);=0A=
>  int port_is_started(portid_t port_id);=0A=
>  void pmd_test_exit(void);=0A=
> @@ -558,10 +569,15 @@ void get_ethertype_filter(uint8_t port_id, uint16_t=
 index);=0A=
>  void get_2tuple_filter(uint8_t port_id, uint16_t index);=0A=
>  void get_5tuple_filter(uint8_t port_id, uint16_t index);=0A=
>  void get_flex_filter(uint8_t port_id, uint16_t index);=0A=
> -int port_id_is_invalid(portid_t port_id);=0A=
>  int rx_queue_id_is_invalid(queueid_t rxq_id);=0A=
>  int tx_queue_id_is_invalid(queueid_t txq_id);=0A=
>  =0A=
> +enum print_warning {=0A=
> +	ENABLED_WARN =3D 0,=0A=
> +	DISABLED_WARN=0A=
> +};=0A=
> +int port_id_is_invalid(portid_t port_id, enum print_warning warning);=0A=
> +=0A=
>  /*=0A=
>   * Work-around of a compilation error with ICC on invocations of the=0A=
>   * rte_be_to_cpu_16() function.=0A=
> diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/tes=
tpmd_app_ug/testpmd_funcs.rst=0A=
> index 218835a..1cacbcf 100644=0A=
> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst=0A=
> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst=0A=
> @@ -808,6 +808,63 @@ The following sections show functions for configurin=
g ports.=0A=
>  =0A=
>      Port configuration changes only become active when forwarding is sta=
rted/restarted.=0A=
>  =0A=
> +port attach=0A=
> +~~~~~~~~~~~=0A=
> +=0A=
> +Attach a port specified by pci address or virtual device args.=0A=
> +=0A=
> +To attach a new pci device, the device should be recognized by kernel fi=
rst.=0A=
> +Then it should be moved under DPDK management.=0A=
> +Finally the port can be attached to testpmd.=0A=
> +On the other hand, to attach a port created by virtual device, above ste=
ps are not needed.=0A=
> +=0A=
> +port attach (identifier)=0A=
> +=0A=
> +For example, to attach a port that pci address is 0000:02:00.0.=0A=
> +=0A=
> +.. code-block:: console=0A=
> +=0A=
> +    testpmd> port attach 0000:02:00.0=0A=
> +    Attaching a new port...=0A=
> +    ... snip ...=0A=
> +    Port 0 is attached. Now total ports is 1=0A=
> +    Done=0A=
> +=0A=
> +For example, to attach a port created by pcap PMD.=0A=
> +=0A=
> +.. code-block:: console=0A=
> +=0A=
> +    testpmd> port attach eth_pcap0,iface=3Deth0=0A=
> +    Attaching a new port...=0A=
> +    ... snip ...=0A=
> +    Port 0 is attached. Now total ports is 1=0A=
> +    Done=0A=
> +=0A=
> +In this case, identifier is "eth_pcap0,iface=3Deth0".=0A=
> +This identifier format is the same as "--vdev" format of DPDK applicatio=
ns.=0A=
> +=0A=
> +port detach=0A=
> +~~~~~~~~~~~=0A=
> +=0A=
> +Detach a specific port.=0A=
> +=0A=
> +Before detaching a port, the port should be closed.=0A=
> +Also to remove a pci device completely from the system, first detach the=
 port from testpmd.=0A=
> +Then the device should be moved under kernel management.=0A=
> +Finally the device can be remove using kernel pci hotplug functionality.=
=0A=
> +On the other hand, to remove a port created by virtual device, above ste=
ps are not needed.=0A=
> +=0A=
> +port detach (port_id)=0A=
> +=0A=
> +For example, to detach a port 0.=0A=
> +=0A=
> +.. code-block:: console=0A=
> +=0A=
> +    testpmd> port detach 0=0A=
> +    Detaching a port...=0A=
> +    ... snip ...=0A=
> +    Done=0A=
> +=0A=
>  port start=0A=
>  ~~~~~~~~~~=0A=
>  =0A=
=0A=