get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2378/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2378,
    "url": "https://patches.dpdk.org/api/patches/2378/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1421664151-18091-1-git-send-email-mukawa@igel.co.jp/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1421664151-18091-1-git-send-email-mukawa@igel.co.jp>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1421664151-18091-1-git-send-email-mukawa@igel.co.jp",
    "date": "2015-01-19T10:42:31",
    "name": "[dpdk-dev,v4] testpmd: Add port hotplug support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "cefafb27faa45d02cb9f0850acb5f154d5eb10b8",
    "submitter": {
        "id": 64,
        "url": "https://patches.dpdk.org/api/people/64/?format=api",
        "name": "Tetsuya Mukawa",
        "email": "mukawa@igel.co.jp"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1421664151-18091-1-git-send-email-mukawa@igel.co.jp/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/2378/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/2378/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 13DAD5ACD;\n\tMon, 19 Jan 2015 11:42:41 +0100 (CET)",
            "from mail-pa0-f54.google.com (mail-pa0-f54.google.com\n\t[209.85.220.54]) by dpdk.org (Postfix) with ESMTP id 6F3AF5ACB\n\tfor <dev@dpdk.org>; Mon, 19 Jan 2015 11:42:38 +0100 (CET)",
            "by mail-pa0-f54.google.com with SMTP id eu11so3758427pac.13\n\tfor <dev@dpdk.org>; Mon, 19 Jan 2015 02:42:37 -0800 (PST)",
            "from localhost.localdomain (napt.igel.co.jp. [219.106.231.132])\n\tby mx.google.com with ESMTPSA id\n\tle6sm1347193pab.33.2015.01.19.02.42.36\n\t(version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tMon, 19 Jan 2015 02:42:37 -0800 (PST)"
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=kYJhHt2FUmLaOvLHZXhgOQzCIB8sxMpGbHpzG2LkmK0=;\n\tb=NL0zsKY/R00dchjNMVzqFYzn0H86AtnUyAiYb3VxH/7lxX7yr4yvfr/g2NQOcgAFMz\n\tgBit8jU32oQPIrKegpgccPtxTbmA8/ZkdJnYQBqWw316DtAwngPZ3Ze6Xouzn+l9iaXP\n\tX0zQq1DtZlgXwN2K4hAzGiv3X8VD+7c2FyookRW3jSYQHoSY6iIc53bPpupz/2GbSumK\n\tXo3pEKgmfFs+YP5R2kfixupETXdHgEX3aKv4Xu1qnNO7VhzJ4/8A9cDqygVKcyqwaFcA\n\tOykPy2/OTab0hGK8WWkh690HmGe70rSo2Xm9lGZcwz4QXgHO5h5clAPvi6KbHB6zQOPc\n\tp/Mw==",
        "X-Gm-Message-State": "ALoCoQk3XE2MDJcZblaNat3Bk0Wa7IlSM/eqvdBCZ6AIkkVcbPAxB5jNNL/Igz8X5Zn1MMYityVt",
        "X-Received": "by 10.66.149.98 with SMTP id tz2mr42911576pab.63.1421664157739; \n\tMon, 19 Jan 2015 02:42:37 -0800 (PST)",
        "From": "Tetsuya Mukawa <mukawa@igel.co.jp>",
        "To": "dev@dpdk.org",
        "Date": "Mon, 19 Jan 2015 19:42:31 +0900",
        "Message-Id": "<1421664151-18091-1-git-send-email-mukawa@igel.co.jp>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1418106629-22227-2-git-send-email-mukawa@igel.co.j>",
        "References": "<1418106629-22227-2-git-send-email-mukawa@igel.co.j>",
        "Subject": "[dpdk-dev] [PATCH v4] 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>,\n\t<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>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "The patch introduces following commands.\n- port attach [ident]\n- port detach [port_id]\n - attach: attaching a port\n - detach: detaching a port\n - ident: pci address of physical device.\n          Or device name and paramerters of virtual device.\n         (ex. 0000:02:00.0, eth_pcap0,iface=eth0)\n - port_id: port identifier\n\nv4:\n - Fix strings of command help.\n\nSigned-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>\n---\n app/test-pmd/cmdline.c    | 133 +++++++++++++++++++++++++------\n app/test-pmd/config.c     | 116 +++++++++++++++------------\n app/test-pmd/parameters.c |  22 +++--\n app/test-pmd/testpmd.c    | 199 +++++++++++++++++++++++++++++++++++-----------\n app/test-pmd/testpmd.h    |  18 ++++-\n 5 files changed, 358 insertions(+), 130 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex 4618b92..3557dff 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -572,6 +572,12 @@ static void cmd_help_long_parsed(void *parsed_result,\n \t\t\t\"port close (port_id|all)\\n\"\n \t\t\t\"    Close all ports or port_id.\\n\\n\"\n \n+\t\t\t\"port attach (ident)\\n\"\n+\t\t\t\"    Attach physical or virtual dev by pci address or virtual device name\\n\\n\"\n+\n+\t\t\t\"port detach (port_id)\\n\"\n+\t\t\t\"    Detach physical or virtual dev by port_id\\n\\n\"\n+\n \t\t\t\"port config (port_id|all)\"\n \t\t\t\" speed (10|100|1000|10000|40000|auto)\"\n \t\t\t\" duplex (half|full|auto)\\n\"\n@@ -853,6 +859,89 @@ cmdline_parse_inst_t cmd_operate_specific_port = {\n \t},\n };\n \n+/* *** attach a specificied port *** */\n+struct cmd_operate_attach_port_result {\n+\tcmdline_fixed_string_t port;\n+\tcmdline_fixed_string_t keyword;\n+\tcmdline_fixed_string_t identifier;\n+};\n+\n+static void cmd_operate_attach_port_parsed(void *parsed_result,\n+\t\t\t\t__attribute__((unused)) struct cmdline *cl,\n+\t\t\t\t__attribute__((unused)) void *data)\n+{\n+\tstruct cmd_operate_attach_port_result *res = parsed_result;\n+\n+\tif (!strcmp(res->keyword, \"attach\"))\n+\t\tattach_port(res->identifier);\n+\telse\n+\t\tprintf(\"Unknown parameter\\n\");\n+}\n+\n+cmdline_parse_token_string_t cmd_operate_attach_port_port =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,\n+\t\t\tport, \"port\");\n+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,\n+\t\t\tkeyword, \"attach\");\n+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,\n+\t\t\tidentifier, NULL);\n+\n+cmdline_parse_inst_t cmd_operate_attach_port = {\n+\t.f = cmd_operate_attach_port_parsed,\n+\t.data = NULL,\n+\t.help_str = \"port attach identifier, \"\n+\t\t\"identifier: pci address or virtual dev name\",\n+\t.tokens = {\n+\t\t(void *)&cmd_operate_attach_port_port,\n+\t\t(void *)&cmd_operate_attach_port_keyword,\n+\t\t(void *)&cmd_operate_attach_port_identifier,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** detach a specificied port *** */\n+struct cmd_operate_detach_port_result {\n+\tcmdline_fixed_string_t port;\n+\tcmdline_fixed_string_t keyword;\n+\tuint8_t port_id;\n+};\n+\n+static void cmd_operate_detach_port_parsed(void *parsed_result,\n+\t\t\t\t__attribute__((unused)) struct cmdline *cl,\n+\t\t\t\t__attribute__((unused)) void *data)\n+{\n+\tstruct cmd_operate_detach_port_result *res = parsed_result;\n+\n+\tif (!strcmp(res->keyword, \"detach\"))\n+\t\tdetach_port(res->port_id);\n+\telse\n+\t\tprintf(\"Unknown parameter\\n\");\n+}\n+\n+cmdline_parse_token_string_t cmd_operate_detach_port_port =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,\n+\t\t\tport, \"port\");\n+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,\n+\t\t\tkeyword, \"detach\");\n+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,\n+\t\t\tport_id, UINT8);\n+\n+cmdline_parse_inst_t cmd_operate_detach_port = {\n+\t.f = cmd_operate_detach_port_parsed,\n+\t.data = NULL,\n+\t.help_str = \"port detach port_id\",\n+\t.tokens = {\n+\t\t(void *)&cmd_operate_detach_port_port,\n+\t\t(void *)&cmd_operate_detach_port_keyword,\n+\t\t(void *)&cmd_operate_detach_port_port_id,\n+\t\tNULL,\n+\t},\n+};\n+\n /* *** configure speed for all ports *** */\n struct cmd_config_speed_all {\n \tcmdline_fixed_string_t port;\n@@ -907,7 +996,7 @@ cmd_config_speed_all_parsed(void *parsed_result,\n \t\treturn;\n \t}\n \n-\tfor (pid = 0; pid < nb_ports; pid++) {\n+\tFOREACH_PORT(pid, ports) {\n \t\tports[pid].dev_conf.link_speed = link_speed;\n \t\tports[pid].dev_conf.link_duplex = link_duplex;\n \t}\n@@ -975,10 +1064,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,\n \t\treturn;\n \t}\n \n-\tif (res->id >= nb_ports) {\n-\t\tprintf(\"Port id %d must be less than %d\\n\", res->id, nb_ports);\n+\tif (port_id_is_invalid(res->id, ENABLED_WARN))\n \t\treturn;\n-\t}\n \n \tif (!strcmp(res->value1, \"10\"))\n \t\tlink_speed = ETH_LINK_SPEED_10;\n@@ -1538,7 +1625,7 @@ cmd_config_rxtx_queue_parsed(void *parsed_result,\n \t\treturn;\n \t}\n \n-\tif (port_id_is_invalid(res->portid))\n+\tif (port_id_is_invalid(res->portid, ENABLED_WARN))\n \t\treturn;\n \n \tif (port_is_started(res->portid) != 1) {\n@@ -2881,7 +2968,7 @@ cmd_tx_cksum_parsed(void *parsed_result,\n \tuint16_t ol_flags, mask = 0;\n \tstruct rte_eth_dev_info dev_info;\n \n-\tif (port_id_is_invalid(res->port_id)) {\n+\tif (port_id_is_invalid(res->port_id, ENABLED_WARN)) {\n \t\tprintf(\"invalid port %d\\n\", res->port_id);\n \t\treturn;\n \t}\n@@ -3008,7 +3095,7 @@ cmd_tso_set_parsed(void *parsed_result,\n \tstruct cmd_tso_set_result *res = parsed_result;\n \tstruct rte_eth_dev_info dev_info;\n \n-\tif (port_id_is_invalid(res->port_id))\n+\tif (port_id_is_invalid(res->port_id, ENABLED_WARN))\n \t\treturn;\n \n \tif (!strcmp(res->mode, \"set\"))\n@@ -3984,10 +4071,8 @@ static void cmd_set_bond_mac_addr_parsed(void *parsed_result,\n \tstruct cmd_set_bond_mac_addr_result *res = parsed_result;\n \tint ret;\n \n-\tif (res->port_num >= nb_ports) {\n-\t\tprintf(\"Port id %d must be less than %d\\n\", res->port_num, nb_ports);\n+\tif (port_id_is_invalid(res->port_num, ENABLED_WARN))\n \t\treturn;\n-\t}\n \n \tret = rte_eth_bond_mac_address_set(res->port_num, &res->address);\n \n@@ -4224,7 +4309,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result,\n \n \t/* all ports */\n \tif (allports) {\n-\t\tfor (i = 0; i < nb_ports; i++) {\n+\t\tFOREACH_PORT(i, ports) {\n \t\t\tif (enable)\n \t\t\t\trte_eth_promiscuous_enable(i);\n \t\t\telse\n@@ -4304,7 +4389,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result,\n \n \t/* all ports */\n \tif (allports) {\n-\t\tfor (i = 0; i < nb_ports; i++) {\n+\t\tFOREACH_PORT(i, ports) {\n \t\t\tif (enable)\n \t\t\t\trte_eth_allmulticast_enable(i);\n \t\t\telse\n@@ -5489,25 +5574,25 @@ static void cmd_showportall_parsed(void *parsed_result,\n \tstruct cmd_showportall_result *res = parsed_result;\n \tif (!strcmp(res->show, \"clear\")) {\n \t\tif (!strcmp(res->what, \"stats\"))\n-\t\t\tfor (i = 0; i < nb_ports; i++)\n+\t\t\tFOREACH_PORT(i, ports)\n \t\t\t\tnic_stats_clear(i);\n \t\telse if (!strcmp(res->what, \"xstats\"))\n-\t\t\tfor (i = 0; i < nb_ports; i++)\n+\t\t\tFOREACH_PORT(i, ports)\n \t\t\t\tnic_xstats_clear(i);\n \t} else if (!strcmp(res->what, \"info\"))\n-\t\tfor (i = 0; i < nb_ports; i++)\n+\t\tFOREACH_PORT(i, ports)\n \t\t\tport_infos_display(i);\n \telse if (!strcmp(res->what, \"stats\"))\n-\t\tfor (i = 0; i < nb_ports; i++)\n+\t\tFOREACH_PORT(i, ports)\n \t\t\tnic_stats_display(i);\n \telse if (!strcmp(res->what, \"xstats\"))\n-\t\tfor (i = 0; i < nb_ports; i++)\n+\t\tFOREACH_PORT(i, ports)\n \t\t\tnic_xstats_display(i);\n \telse if (!strcmp(res->what, \"fdir\"))\n-\t\tfor (i = 0; i < nb_ports; i++)\n+\t\tFOREACH_PORT(i, ports)\n \t\t\tfdir_get_infos(i);\n \telse if (!strcmp(res->what, \"stat_qmap\"))\n-\t\tfor (i = 0; i < nb_ports; i++)\n+\t\tFOREACH_PORT(i, ports)\n \t\t\tnic_stats_mapping_display(i);\n }\n \n@@ -8783,6 +8868,8 @@ cmdline_parse_ctx_t main_ctx[] = {\n \t(cmdline_parse_inst_t *)&cmd_set_qmap,\n \t(cmdline_parse_inst_t *)&cmd_operate_port,\n \t(cmdline_parse_inst_t *)&cmd_operate_specific_port,\n+\t(cmdline_parse_inst_t *)&cmd_operate_attach_port,\n+\t(cmdline_parse_inst_t *)&cmd_operate_detach_port,\n \t(cmdline_parse_inst_t *)&cmd_config_speed_all,\n \t(cmdline_parse_inst_t *)&cmd_config_speed_specific,\n \t(cmdline_parse_inst_t *)&cmd_config_rx_tx,\n@@ -8859,7 +8946,7 @@ prompt(void)\n static void\n cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)\n {\n-\tif (id < nb_ports) {\n+\tif (!port_id_is_invalid(id, DISABLED_WARN)) {\n \t\t/* check if need_reconfig has been set to 1 */\n \t\tif (ports[id].need_reconfig == 0)\n \t\t\tports[id].need_reconfig = dev;\n@@ -8869,7 +8956,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)\n \t} else {\n \t\tportid_t pid;\n \n-\t\tfor (pid = 0; pid < nb_ports; pid++) {\n+\t\tFOREACH_PORT(pid, ports) {\n \t\t\t/* check if need_reconfig has been set to 1 */\n \t\t\tif (ports[pid].need_reconfig == 0)\n \t\t\t\tports[pid].need_reconfig = dev;\n@@ -8887,10 +8974,8 @@ bypass_is_supported(portid_t port_id)\n \tstruct rte_port   *port;\n \tstruct rte_pci_id *pci_id;\n \n-\tif (port_id >= nb_ports) {\n-\t\tprintf(\"\\tPort id must be less than %d.\\n\", nb_ports);\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn 0;\n-\t}\n \n \t/* Get the device id. */\n \tport    = &ports[port_id];\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 97b6525..2662d7c 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -124,11 +124,15 @@ nic_stats_display(portid_t port_id)\n \tstruct rte_eth_stats stats;\n \tstruct rte_port *port = &ports[port_id];\n \tuint8_t i;\n+\tportid_t pid;\n \n \tstatic const char *nic_stats_border = \"########################\";\n \n-\tif (port_id >= nb_ports) {\n-\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\tprintf(\"Valid port range is [0\");\n+\t\tFOREACH_PORT(pid, ports)\n+\t\t\tprintf(\", %d\", pid);\n+\t\tprintf(\"]\\n\");\n \t\treturn;\n \t}\n \trte_eth_stats_get(port_id, &stats);\n@@ -201,8 +205,13 @@ nic_stats_display(portid_t port_id)\n void\n nic_stats_clear(portid_t port_id)\n {\n-\tif (port_id >= nb_ports) {\n-\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\tportid_t pid;\n+\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\tprintf(\"Valid port range is [0\");\n+\t\tFOREACH_PORT(pid, ports)\n+\t\t\tprintf(\", %d\", pid);\n+\t\tprintf(\"]\\n\");\n \t\treturn;\n \t}\n \trte_eth_stats_reset(port_id);\n@@ -249,11 +258,15 @@ nic_stats_mapping_display(portid_t port_id)\n {\n \tstruct rte_port *port = &ports[port_id];\n \tuint16_t i;\n+\tportid_t pid;\n \n \tstatic const char *nic_stats_mapping_border = \"########################\";\n \n-\tif (port_id >= nb_ports) {\n-\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\tprintf(\"Valid port range is [0\");\n+\t\tFOREACH_PORT(pid, ports)\n+\t\t\tprintf(\", %d\", pid);\n+\t\tprintf(\"]\\n\");\n \t\treturn;\n \t}\n \n@@ -302,9 +315,13 @@ port_infos_display(portid_t port_id)\n \tint vlan_offload;\n \tstruct rte_mempool * mp;\n \tstatic const char *info_border = \"*********************\";\n+\tportid_t pid;\n \n-\tif (port_id >= nb_ports) {\n-\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\tprintf(\"Valid port range is [0\");\n+\t\tFOREACH_PORT(pid, ports)\n+\t\t\tprintf(\", %d\", pid);\n+\t\tprintf(\"]\\n\");\n \t\treturn;\n \t}\n \tport = &ports[port_id];\n@@ -362,11 +379,14 @@ port_infos_display(portid_t port_id)\n }\n \n int\n-port_id_is_invalid(portid_t port_id)\n+port_id_is_invalid(portid_t port_id, enum print_warning warning)\n {\n-\tif (port_id < nb_ports)\n+\tif (ports[port_id].enabled)\n \t\treturn 0;\n-\tprintf(\"Invalid port %d (must be < nb_ports=%d)\\n\", port_id, nb_ports);\n+\n+\tif (warning == ENABLED_WARN)\n+\t\tprintf(\"Invalid port %d\\n\", port_id);\n+\n \treturn 1;\n }\n \n@@ -425,7 +445,7 @@ port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_x)\n \tuint32_t reg_v;\n \n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -444,7 +464,7 @@ port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,\n \tuint8_t  l_bit;\n \tuint8_t  h_bit;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -471,7 +491,7 @@ port_reg_display(portid_t port_id, uint32_t reg_off)\n {\n \tuint32_t reg_v;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -485,7 +505,7 @@ port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,\n {\n \tuint32_t reg_v;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -513,7 +533,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,\n \tuint8_t  l_bit;\n \tuint8_t  h_bit;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -547,7 +567,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,\n void\n port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)\n {\n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (port_reg_off_is_invalid(port_id, reg_off))\n \t\treturn;\n@@ -560,7 +580,7 @@ port_mtu_set(portid_t port_id, uint16_t mtu)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tdiag = rte_eth_dev_set_mtu(port_id, mtu);\n \tif (diag == 0)\n@@ -723,7 +743,7 @@ rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id)\n {\n \tconst struct rte_memzone *rx_mz;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (rx_queue_id_is_invalid(rxq_id))\n \t\treturn;\n@@ -740,7 +760,7 @@ tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id)\n {\n \tconst struct rte_memzone *tx_mz;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (tx_queue_id_is_invalid(txq_id))\n \t\treturn;\n@@ -796,7 +816,7 @@ port_rss_reta_info(portid_t port_id,\n \tuint16_t i, idx, shift;\n \tint ret;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);\n@@ -828,7 +848,7 @@ port_rss_hash_conf_show(portid_t port_id, int show_rss_key)\n \tuint8_t i;\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \t/* Get RSS hash key if asked to display it */\n \trss_conf.rss_key = (show_rss_key) ? rss_key : NULL;\n@@ -1406,12 +1426,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)\n  again:\n \tfor (i = 0; i < nb_pt; i++) {\n \t\tport_id = (portid_t) portlist[i];\n-\t\tif (port_id >= nb_ports) {\n-\t\t\tprintf(\"Invalid port id %u >= %u\\n\",\n-\t\t\t       (unsigned int) port_id,\n-\t\t\t       (unsigned int) nb_ports);\n+\t\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\t\treturn;\n-\t\t}\n \t\tif (record_now)\n \t\t\tfwd_ports_ids[i] = port_id;\n \t}\n@@ -1569,7 +1585,7 @@ vlan_extend_set(portid_t port_id, int on)\n \tint diag;\n \tint vlan_offload;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tvlan_offload = rte_eth_dev_get_vlan_offload(port_id);\n@@ -1591,7 +1607,7 @@ rx_vlan_strip_set(portid_t port_id, int on)\n \tint diag;\n \tint vlan_offload;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tvlan_offload = rte_eth_dev_get_vlan_offload(port_id);\n@@ -1612,7 +1628,7 @@ rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);\n@@ -1627,7 +1643,7 @@ rx_vlan_filter_set(portid_t port_id, int on)\n \tint diag;\n \tint vlan_offload;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tvlan_offload = rte_eth_dev_get_vlan_offload(port_id);\n@@ -1648,7 +1664,7 @@ rx_vft_set(portid_t port_id, uint16_t vlan_id, int on)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (vlan_id_is_invalid(vlan_id))\n \t\treturn;\n@@ -1665,7 +1681,7 @@ rx_vlan_all_filter_set(portid_t port_id, int on)\n {\n \tuint16_t vlan_id;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tfor (vlan_id = 0; vlan_id < 4096; vlan_id++)\n \t\trx_vft_set(port_id, vlan_id, on);\n@@ -1675,7 +1691,7 @@ void\n vlan_tpid_set(portid_t port_id, uint16_t tp_id)\n {\n \tint diag;\n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_set_vlan_ether_type(port_id, tp_id);\n@@ -1690,7 +1706,7 @@ vlan_tpid_set(portid_t port_id, uint16_t tp_id)\n void\n tx_vlan_set(portid_t port_id, uint16_t vlan_id)\n {\n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (vlan_id_is_invalid(vlan_id))\n \t\treturn;\n@@ -1701,7 +1717,7 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)\n void\n tx_vlan_reset(portid_t port_id)\n {\n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;\n }\n@@ -1709,7 +1725,7 @@ tx_vlan_reset(portid_t port_id)\n void\n tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)\n {\n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \trte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);\n@@ -1721,7 +1737,7 @@ set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value)\n \tuint16_t i;\n \tuint8_t existing_mapping_found = 0;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tif (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id)))\n@@ -1773,7 +1789,7 @@ fdir_add_signature_filter(portid_t port_id, uint8_t queue_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_add_signature_filter(port_id, fdir_filter,\n@@ -1791,7 +1807,7 @@ fdir_update_signature_filter(portid_t port_id, uint8_t queue_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_update_signature_filter(port_id, fdir_filter,\n@@ -1809,7 +1825,7 @@ fdir_remove_signature_filter(portid_t port_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_remove_signature_filter(port_id, fdir_filter);\n@@ -1881,7 +1897,7 @@ fdir_get_infos(portid_t port_id)\n \n \tstatic const char *fdir_stats_border = \"########################\";\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);\n \tif (ret < 0) {\n@@ -1955,7 +1971,7 @@ fdir_add_perfect_filter(portid_t port_id, uint16_t soft_id, uint8_t queue_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_add_perfect_filter(port_id, fdir_filter,\n@@ -1973,7 +1989,7 @@ fdir_update_perfect_filter(portid_t port_id, uint16_t soft_id, uint8_t queue_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_update_perfect_filter(port_id, fdir_filter,\n@@ -1991,7 +2007,7 @@ fdir_remove_perfect_filter(portid_t port_id, uint16_t soft_id,\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_remove_perfect_filter(port_id, fdir_filter,\n@@ -2008,7 +2024,7 @@ fdir_set_masks(portid_t port_id, struct rte_fdir_masks *fdir_masks)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \n \tdiag = rte_eth_dev_fdir_set_masks(port_id, fdir_masks);\n@@ -2085,7 +2101,7 @@ set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (is_rx)\n \t\tdiag = rte_eth_dev_set_vf_rx(port_id,vf,on);\n@@ -2107,7 +2123,7 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on)\n {\n \tint diag;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn;\n \tif (vlan_id_is_invalid(vlan_id))\n \t\treturn;\n@@ -2124,7 +2140,7 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)\n \tint diag;\n \tstruct rte_eth_link link;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn 1;\n \trte_eth_link_get_nowait(port_id, &link);\n \tif (rate > link.link_speed) {\n@@ -2149,7 +2165,7 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)\n \tif (q_msk == 0)\n \t\treturn 0;\n \n-\tif (port_id_is_invalid(port_id))\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n \t\treturn 1;\n \trte_eth_link_get_nowait(port_id, &link);\n \tif (rate > link.link_speed) {\ndiff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c\nindex adf3203..6f2af18 100644\n--- a/app/test-pmd/parameters.c\n+++ b/app/test-pmd/parameters.c\n@@ -376,6 +376,7 @@ parse_portnuma_config(const char *q_arg)\n \t};\n \tunsigned long int_fld[_NUM_FLD];\n \tchar *str_fld[_NUM_FLD];\n+\tportid_t pid;\n \n \t/* reset from value set at definition */\n \twhile ((p = strchr(p0,'(')) != NULL) {\n@@ -397,8 +398,11 @@ parse_portnuma_config(const char *q_arg)\n \t\t\t\treturn -1;\n \t\t}\n \t\tport_id = (uint8_t)int_fld[FLD_PORT];\n-\t\tif (port_id >= nb_ports) {\n-\t\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\t\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\t\tprintf(\"Valid port range is [0\");\n+\t\t\tFOREACH_PORT(pid, ports)\n+\t\t\t\tprintf(\", %d\", pid);\n+\t\t\tprintf(\"]\\n\");\n \t\t\treturn -1;\n \t\t}\n \t\tsocket_id = (uint8_t)int_fld[FLD_SOCKET];\n@@ -429,6 +433,7 @@ parse_ringnuma_config(const char *q_arg)\n \t};\n \tunsigned long int_fld[_NUM_FLD];\n \tchar *str_fld[_NUM_FLD];\n+\tportid_t pid;\n \t#define RX_RING_ONLY 0x1\n \t#define TX_RING_ONLY 0x2\n \t#define RXTX_RING    0x3\n@@ -453,8 +458,11 @@ parse_ringnuma_config(const char *q_arg)\n \t\t\t\treturn -1;\n \t\t}\n \t\tport_id = (uint8_t)int_fld[FLD_PORT];\n-\t\tif (port_id >= nb_ports) {\n-\t\t\tprintf(\"Invalid port, range is [0, %d]\\n\", nb_ports - 1);\n+\t\tif (port_id_is_invalid(port_id, ENABLED_WARN)) {\n+\t\t\tprintf(\"Valid port range is [0\");\n+\t\t\tFOREACH_PORT(pid, ports)\n+\t\t\t\tprintf(\", %d\", pid);\n+\t\t\tprintf(\"]\\n\");\n \t\t\treturn -1;\n \t\t}\n \t\tsocket_id = (uint8_t)int_fld[FLD_SOCKET];\n@@ -626,12 +634,12 @@ launch_args_parse(int argc, char** argv)\n #endif\n \t\t\tif (!strcmp(lgopts[opt_idx].name, \"nb-ports\")) {\n \t\t\t\tn = atoi(optarg);\n-\t\t\t\tif (n > 0 && n <= nb_ports)\n+\t\t\t\tif (n > 0 &&\n+\t\t\t\t    !port_id_is_invalid(n, DISABLED_WARN))\n \t\t\t\t\tnb_fwd_ports = (uint8_t) n;\n \t\t\t\telse\n \t\t\t\t\trte_exit(EXIT_FAILURE,\n-\t\t\t\t\t\t \"nb-ports should be > 0 and <= %d\\n\",\n-\t\t\t\t\t\t nb_ports);\n+\t\t\t\t\t\t \"Invalid port %d\\n\", n);\n \t\t\t}\n \t\t\tif (!strcmp(lgopts[opt_idx].name, \"nb-cores\")) {\n \t\t\t\tn = atoi(optarg);\ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex 773b8af..c18c1a9 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -71,6 +71,7 @@\n #include <rte_pci.h>\n #include <rte_ether.h>\n #include <rte_ethdev.h>\n+#include <rte_dev.h>\n #include <rte_string_fns.h>\n #ifdef RTE_LIBRTE_PMD_XENVIRT\n #include <rte_eth_xenvirt.h>\n@@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings = 0;\n \n /* Forward function declarations */\n static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);\n-static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);\n+static void check_all_ports_link_status(uint32_t port_mask);\n \n /*\n  * Check if all the ports are started.\n@@ -324,6 +325,20 @@ static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);\n static int all_ports_started(void);\n \n /*\n+ * Find next enabled port\n+ */\n+portid_t\n+find_next_port(portid_t p, struct rte_port *ports, int size)\n+{\n+\tif (ports == NULL)\n+\t\trte_exit(-EINVAL, \"failed to find a next port id\\n\");\n+\n+\twhile ((ports[p].enabled == 0) && (p < size))\n+\t\tp++;\n+\treturn p;\n+}\n+\n+/*\n  * Setup default configuration.\n  */\n static void\n@@ -552,7 +567,8 @@ init_config(void)\n \t\t\t\t+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;\n \n \t\tif (!numa_support)\n-\t\t\tnb_mbuf_per_pool = (nb_mbuf_per_pool * nb_ports);\n+\t\t\tnb_mbuf_per_pool =\n+\t\t\t\t(nb_mbuf_per_pool * RTE_MAX_ETHPORTS);\n \t}\n \n \tif (!numa_support) {\n@@ -565,14 +581,19 @@ init_config(void)\n \n \t/* Configuration of Ethernet ports. */\n \tports = rte_zmalloc(\"testpmd: ports\",\n-\t\t\t    sizeof(struct rte_port) * nb_ports,\n+\t\t\t    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,\n \t\t\t    RTE_CACHE_LINE_SIZE);\n \tif (ports == NULL) {\n-\t\trte_exit(EXIT_FAILURE, \"rte_zmalloc(%d struct rte_port) \"\n-\t\t\t\t\t\t\t\"failed\\n\", nb_ports);\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"rte_zmalloc(%d struct rte_port) failed\\n\",\n+\t\t\t\tRTE_MAX_ETHPORTS);\n \t}\n \n-\tfor (pid = 0; pid < nb_ports; pid++) {\n+\t/* enabled allocated ports */\n+\tfor (pid = 0; pid < nb_ports; pid++)\n+\t\tports[pid].enabled = 1;\n+\n+\tFOREACH_PORT(pid, ports) {\n \t\tport = &ports[pid];\n \t\trte_eth_dev_info_get(pid, &port->dev_info);\n \n@@ -602,8 +623,7 @@ init_config(void)\n \t\t\tnb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports;\n \n \t\tfor (i = 0; i < MAX_SOCKET; i++) {\n-\t\t\tnb_mbuf = (nb_mbuf_per_pool *\n-\t\t\t\t\t\tport_per_socket[i]);\n+\t\t\tnb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);\n \t\t\tif (nb_mbuf)\n \t\t\t\tmbuf_pool_create(mbuf_data_size,\n \t\t\t\t\t\tnb_mbuf,i);\n@@ -635,14 +655,6 @@ reconfig(portid_t new_port_id, unsigned socket_id)\n \tstruct rte_port *port;\n \n \t/* Reconfiguration of Ethernet ports. */\n-\tports = rte_realloc(ports,\n-\t\t\t    sizeof(struct rte_port) * nb_ports,\n-\t\t\t    RTE_CACHE_LINE_SIZE);\n-\tif (ports == NULL) {\n-\t\trte_exit(EXIT_FAILURE, \"rte_realloc(%d struct rte_port) failed\\n\",\n-\t\t\t\tnb_ports);\n-\t}\n-\n \tport = &ports[new_port_id];\n \trte_eth_dev_info_get(new_port_id, &port->dev_info);\n \n@@ -663,7 +675,7 @@ init_fwd_streams(void)\n \tstreamid_t sm_id, nb_fwd_streams_new;\n \n \t/* set socket id according to numa or not */\n-\tfor (pid = 0; pid < nb_ports; pid++) {\n+\tFOREACH_PORT(pid, ports) {\n \t\tport = &ports[pid];\n \t\tif (nb_rxq > port->dev_info.max_rx_queues) {\n \t\t\tprintf(\"Fail: nb_rxq(%d) is greater than \"\n@@ -1264,7 +1276,7 @@ all_ports_started(void)\n \tportid_t pi;\n \tstruct rte_port *port;\n \n-\tfor (pi = 0; pi < nb_ports; pi++) {\n+\tFOREACH_PORT(pi, ports) {\n \t\tport = &ports[pi];\n \t\t/* Check if there is a port which is not started */\n \t\tif (port->port_status != RTE_PORT_STARTED)\n@@ -1276,6 +1288,45 @@ all_ports_started(void)\n }\n \n int\n+all_ports_stopped(void)\n+{\n+\tportid_t pi;\n+\tstruct rte_port *port;\n+\n+\tFOREACH_PORT(pi, ports) {\n+\t\tport = &ports[pi];\n+\t\tif (port->port_status != RTE_PORT_STOPPED)\n+\t\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+int\n+port_is_started(portid_t port_id)\n+{\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n+\t\treturn 0;\n+\n+\tif (ports[port_id].port_status != RTE_PORT_STARTED)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n+static int\n+port_is_closed(portid_t port_id)\n+{\n+\tif (port_id_is_invalid(port_id, ENABLED_WARN))\n+\t\treturn 0;\n+\n+\tif (ports[port_id].port_status != RTE_PORT_CLOSED)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n+int\n start_port(portid_t pid)\n {\n \tint diag, need_check_link_status = 0;\n@@ -1296,8 +1347,8 @@ start_port(portid_t pid)\n \n \tif(dcb_config)\n \t\tdcb_test = 1;\n-\tfor (pi = 0; pi < nb_ports; pi++) {\n-\t\tif (pid < nb_ports && pid != pi)\n+\tFOREACH_PORT(pi, ports) {\n+\t\tif (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)\n \t\t\tcontinue;\n \n \t\tport = &ports[pi];\n@@ -1421,7 +1472,7 @@ start_port(portid_t pid)\n \t}\n \n \tif (need_check_link_status && !no_link_check)\n-\t\tcheck_all_ports_link_status(nb_ports, RTE_PORT_ALL);\n+\t\tcheck_all_ports_link_status(RTE_PORT_ALL);\n \telse\n \t\tprintf(\"Please stop the ports first\\n\");\n \n@@ -1446,8 +1497,8 @@ stop_port(portid_t pid)\n \t}\n \tprintf(\"Stopping ports...\\n\");\n \n-\tfor (pi = 0; pi < nb_ports; pi++) {\n-\t\tif (pid < nb_ports && pid != pi)\n+\tFOREACH_PORT(pi, ports) {\n+\t\tif (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)\n \t\t\tcontinue;\n \n \t\tport = &ports[pi];\n@@ -1463,7 +1514,7 @@ stop_port(portid_t pid)\n \t\tneed_check_link_status = 1;\n \t}\n \tif (need_check_link_status && !no_link_check)\n-\t\tcheck_all_ports_link_status(nb_ports, RTE_PORT_ALL);\n+\t\tcheck_all_ports_link_status(RTE_PORT_ALL);\n \n \tprintf(\"Done\\n\");\n }\n@@ -1481,8 +1532,8 @@ close_port(portid_t pid)\n \n \tprintf(\"Closing ports...\\n\");\n \n-\tfor (pi = 0; pi < nb_ports; pi++) {\n-\t\tif (pid < nb_ports && pid != pi)\n+\tFOREACH_PORT(pi, ports) {\n+\t\tif (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)\n \t\t\tcontinue;\n \n \t\tport = &ports[pi];\n@@ -1502,31 +1553,83 @@ close_port(portid_t pid)\n \tprintf(\"Done\\n\");\n }\n \n-int\n-all_ports_stopped(void)\n+void\n+attach_port(char *identifier)\n {\n-\tportid_t pi;\n-\tstruct rte_port *port;\n+\tportid_t i, j, pi = 0;\n \n-\tfor (pi = 0; pi < nb_ports; pi++) {\n-\t\tport = &ports[pi];\n-\t\tif (port->port_status != RTE_PORT_STOPPED)\n-\t\t\treturn 0;\n+\tprintf(\"Attaching a new port...\\n\");\n+\n+\tif (identifier == NULL) {\n+\t\tprintf(\"Invalid parameters are speficied\\n\");\n+\t\treturn;\n \t}\n \n-\treturn 1;\n+\tif (test_done == 0) {\n+\t\tprintf(\"Please stop forwarding first\\n\");\n+\t\treturn;\n+\t}\n+\n+\tif (rte_eal_dev_attach(identifier, &pi))\n+\t\treturn;\n+\n+\tports[pi].enabled = 1;\n+\treconfig(pi, rte_eth_dev_socket_id(pi));\n+\trte_eth_promiscuous_enable(pi);\n+\n+\tnb_ports = rte_eth_dev_count();\n+\n+\t/* set_default_fwd_ports_config(); */\n+\tbzero(fwd_ports_ids, sizeof(fwd_ports_ids));\n+\ti = 0;\n+\tFOREACH_PORT(j, ports) {\n+\t\tfwd_ports_ids[i] = j;\n+\t\ti++;\n+\t}\n+\tnb_cfg_ports = nb_ports;\n+\tnb_fwd_ports++;\n+\n+\tports[pi].port_status = RTE_PORT_STOPPED;\n+\n+\tprintf(\"Port %d is attached. Now total ports is %d\\n\", pi, nb_ports);\n+\tprintf(\"Done\\n\");\n }\n \n-int\n-port_is_started(portid_t port_id)\n+void\n+detach_port(uint8_t port_id)\n {\n-\tif (port_id_is_invalid(port_id))\n-\t\treturn -1;\n+\tportid_t i, pi = 0;\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n \n-\tif (ports[port_id].port_status != RTE_PORT_STARTED)\n-\t\treturn 0;\n+\tprintf(\"Detaching a port...\\n\");\n \n-\treturn 1;\n+\tif (!port_is_closed(port_id)) {\n+\t\tprintf(\"Please close port first\\n\");\n+\t\treturn;\n+\t}\n+\n+\trte_eth_promiscuous_disable(port_id);\n+\n+\tif (rte_eal_dev_detach(port_id, name))\n+\t\treturn;\n+\n+\tports[port_id].enabled = 0;\n+\tnb_ports = rte_eth_dev_count();\n+\n+\t/* set_default_fwd_ports_config(); */\n+\tbzero(fwd_ports_ids, sizeof(fwd_ports_ids));\n+\ti = 0;\n+\tFOREACH_PORT(pi, ports) {\n+\t\tfwd_ports_ids[i] = pi;\n+\t\ti++;\n+\t}\n+\tnb_cfg_ports = nb_ports;\n+\tnb_fwd_ports--;\n+\n+\tprintf(\"Port '%s' is detached. Now total ports is %d\\n\",\n+\t\t\tname, nb_ports);\n+\tprintf(\"Done\\n\");\n+\treturn;\n }\n \n void\n@@ -1534,7 +1637,7 @@ pmd_test_exit(void)\n {\n \tportid_t pt_id;\n \n-\tfor (pt_id = 0; pt_id < nb_ports; pt_id++) {\n+\tFOREACH_PORT(pt_id, ports) {\n \t\tprintf(\"Stopping port %d...\", pt_id);\n \t\tfflush(stdout);\n \t\trte_eth_dev_close(pt_id);\n@@ -1553,7 +1656,7 @@ struct pmd_test_command {\n \n /* Check the link status of all ports in up to 9s, and print them finally */\n static void\n-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)\n+check_all_ports_link_status(uint32_t port_mask)\n {\n #define CHECK_INTERVAL 100 /* 100ms */\n #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */\n@@ -1564,7 +1667,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)\n \tfflush(stdout);\n \tfor (count = 0; count <= MAX_CHECK_TIME; count++) {\n \t\tall_ports_up = 1;\n-\t\tfor (portid = 0; portid < port_num; portid++) {\n+\t\tFOREACH_PORT(portid, ports) {\n \t\t\tif ((port_mask & (1 << portid)) == 0)\n \t\t\t\tcontinue;\n \t\t\tmemset(&link, 0, sizeof(link));\n@@ -1688,7 +1791,7 @@ init_port_config(void)\n \tportid_t pid;\n \tstruct rte_port *port;\n \n-\tfor (pid = 0; pid < nb_ports; pid++) {\n+\tFOREACH_PORT(pid, ports) {\n \t\tport = &ports[pid];\n \t\tport->dev_conf.rxmode = rx_mode;\n \t\tport->dev_conf.fdir_conf = fdir_conf;\n@@ -1877,7 +1980,7 @@ main(int argc, char** argv)\n \n \tnb_ports = (portid_t) rte_eth_dev_count();\n \tif (nb_ports == 0)\n-\t\trte_exit(EXIT_FAILURE, \"No probed ethernet device\\n\");\n+\t\tRTE_LOG(WARNING, EAL, \"No probed ethernet devices\\n\");\n \n \tset_def_fwd_config();\n \tif (nb_lcores == 0)\n@@ -1899,7 +2002,7 @@ main(int argc, char** argv)\n \t\trte_exit(EXIT_FAILURE, \"Start ports failed\\n\");\n \n \t/* set all ports to promiscuous mode by default */\n-\tfor (port_id = 0; port_id < nb_ports; port_id++)\n+\tFOREACH_PORT(port_id, ports)\n \t\trte_eth_promiscuous_enable(port_id);\n \n #ifdef RTE_LIBRTE_CMDLINE\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex 8f5e6c7..109c670 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -134,6 +134,7 @@ struct fwd_stream {\n  * The data structure associated with each port.\n  */\n struct rte_port {\n+\tuint8_t                 enabled;    /**< Port enabled or not */\n \tstruct rte_eth_dev_info dev_info;   /**< PCI info + driver name */\n \tstruct rte_eth_conf     dev_conf;   /**< Port configuration. */\n \tstruct ether_addr       eth_addr;   /**< Port ethernet address */\n@@ -159,6 +160,14 @@ struct rte_port {\n \tstruct rte_eth_txconf   tx_conf;    /**< tx configuration */\n };\n \n+extern portid_t __rte_unused\n+find_next_port(portid_t p, struct rte_port *ports, int size);\n+\n+#define FOREACH_PORT(p, ports) \\\n+\tfor (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \\\n+\t    p < RTE_MAX_ETHPORTS; \\\n+\t    p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))\n+\n /**\n  * The data structure associated with each forwarding logical core.\n  * The logical cores are internally numbered by a core index from 0 to\n@@ -515,6 +524,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_config *dcb_conf);\n int start_port(portid_t pid);\n void stop_port(portid_t pid);\n void close_port(portid_t pid);\n+void attach_port(char *identifier);\n+void detach_port(uint8_t port_id);\n int all_ports_stopped(void);\n int port_is_started(portid_t port_id);\n void pmd_test_exit(void);\n@@ -558,10 +569,15 @@ void get_ethertype_filter(uint8_t port_id, uint16_t index);\n void get_2tuple_filter(uint8_t port_id, uint16_t index);\n void get_5tuple_filter(uint8_t port_id, uint16_t index);\n void get_flex_filter(uint8_t port_id, uint16_t index);\n-int port_id_is_invalid(portid_t port_id);\n int rx_queue_id_is_invalid(queueid_t rxq_id);\n int tx_queue_id_is_invalid(queueid_t txq_id);\n \n+enum print_warning {\n+\tENABLED_WARN = 0,\n+\tDISABLED_WARN\n+};\n+int port_id_is_invalid(portid_t port_id, enum print_warning warning);\n+\n /*\n  * Work-around of a compilation error with ICC on invocations of the\n  * rte_be_to_cpu_16() function.\n",
    "prefixes": [
        "dpdk-dev",
        "v4"
    ]
}