app/testpmd: support port hotplug
authorTetsuya Mukawa <mukawa@igel.co.jp>
Wed, 25 Feb 2015 19:32:29 +0000 (04:32 +0900)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Wed, 25 Feb 2015 23:20:43 +0000 (00:20 +0100)
The patch introduces following commands.
- port attach [ident]
- port detach [port_id]
 - attach: attaching a port
 - detach: detaching a port
 - ident: pci address of physical device.
          Or device name and parameters of virtual device.
         (ex. 0000:02:00.0, eth_pcap0,iface=eth0)
 - port_id: port identifier

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>
app/test-pmd/cmdline.c
app/test-pmd/config.c
app/test-pmd/parameters.c
app/test-pmd/testpmd.c
app/test-pmd/testpmd.h
doc/guides/testpmd_app_ug/testpmd_funcs.rst

index 4c9f423..c8312be 100644 (file)
@@ -513,6 +513,12 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "port close (port_id|all)\n"
                        "    Close all ports or port_id.\n\n"
 
+                       "port attach (ident)\n"
+                       "    Attach physical or virtual dev by pci address or virtual device name\n\n"
+
+                       "port detach (port_id)\n"
+                       "    Detach physical or virtual dev by port_id\n\n"
+
                        "port config (port_id|all)"
                        " speed (10|100|1000|10000|40000|auto)"
                        " duplex (half|full|auto)\n"
@@ -793,6 +799,89 @@ cmdline_parse_inst_t cmd_operate_specific_port = {
        },
 };
 
+/* *** attach a specified port *** */
+struct cmd_operate_attach_port_result {
+       cmdline_fixed_string_t port;
+       cmdline_fixed_string_t keyword;
+       cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_attach_port_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct cmd_operate_attach_port_result *res = parsed_result;
+
+       if (!strcmp(res->keyword, "attach"))
+               attach_port(res->identifier);
+       else
+               printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_attach_port_port =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+                       port, "port");
+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+                       keyword, "attach");
+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+                       identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_attach_port = {
+       .f = cmd_operate_attach_port_parsed,
+       .data = NULL,
+       .help_str = "port attach identifier, "
+               "identifier: pci address or virtual dev name",
+       .tokens = {
+               (void *)&cmd_operate_attach_port_port,
+               (void *)&cmd_operate_attach_port_keyword,
+               (void *)&cmd_operate_attach_port_identifier,
+               NULL,
+       },
+};
+
+/* *** detach a specified port *** */
+struct cmd_operate_detach_port_result {
+       cmdline_fixed_string_t port;
+       cmdline_fixed_string_t keyword;
+       uint8_t port_id;
+};
+
+static void cmd_operate_detach_port_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct cmd_operate_detach_port_result *res = parsed_result;
+
+       if (!strcmp(res->keyword, "detach"))
+               detach_port(res->port_id);
+       else
+               printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_port_port =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+                       port, "port");
+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+                       keyword, "detach");
+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,
+                       port_id, UINT8);
+
+cmdline_parse_inst_t cmd_operate_detach_port = {
+       .f = cmd_operate_detach_port_parsed,
+       .data = NULL,
+       .help_str = "port detach port_id",
+       .tokens = {
+               (void *)&cmd_operate_detach_port_port,
+               (void *)&cmd_operate_detach_port_keyword,
+               (void *)&cmd_operate_detach_port_port_id,
+               NULL,
+       },
+};
+
 /* *** configure speed for all ports *** */
 struct cmd_config_speed_all {
        cmdline_fixed_string_t port;
@@ -847,7 +936,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
                return;
        }
 
-       for (pid = 0; pid < nb_ports; pid++) {
+       FOREACH_PORT(pid, ports) {
                ports[pid].dev_conf.link_speed = link_speed;
                ports[pid].dev_conf.link_duplex = link_duplex;
        }
@@ -915,10 +1004,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,
                return;
        }
 
-       if (res->id >= nb_ports) {
-               printf("Port id %d must be less than %d\n", res->id, nb_ports);
+       if (port_id_is_invalid(res->id, ENABLED_WARN))
                return;
-       }
 
        if (!strcmp(res->value1, "10"))
                link_speed = ETH_LINK_SPEED_10;
@@ -1489,7 +1576,7 @@ cmd_config_rxtx_queue_parsed(void *parsed_result,
                return;
        }
 
-       if (port_id_is_invalid(res->portid))
+       if (port_id_is_invalid(res->portid, ENABLED_WARN))
                return;
 
        if (port_is_started(res->portid) != 1) {
@@ -2889,7 +2976,7 @@ cmd_csum_parsed(void *parsed_result,
        int hw = 0;
        uint16_t mask = 0;
 
-       if (port_id_is_invalid(res->port_id)) {
+       if (port_id_is_invalid(res->port_id, ENABLED_WARN)) {
                printf("invalid port %d\n", res->port_id);
                return;
        }
@@ -2981,10 +3068,8 @@ cmd_csum_tunnel_parsed(void *parsed_result,
 {
        struct cmd_csum_tunnel_result *res = parsed_result;
 
-       if (port_id_is_invalid(res->port_id)) {
-               printf("invalid port %d\n", res->port_id);
+       if (port_id_is_invalid(res->port_id, ENABLED_WARN))
                return;
-       }
 
        if (!strcmp(res->onoff, "on"))
                ports[res->port_id].tx_ol_flags |=
@@ -3039,7 +3124,7 @@ cmd_tso_set_parsed(void *parsed_result,
        struct cmd_tso_set_result *res = parsed_result;
        struct rte_eth_dev_info dev_info;
 
-       if (port_id_is_invalid(res->port_id))
+       if (port_id_is_invalid(res->port_id, ENABLED_WARN))
                return;
 
        if (!strcmp(res->mode, "set"))
@@ -4015,10 +4100,8 @@ static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
        struct cmd_set_bond_mac_addr_result *res = parsed_result;
        int ret;
 
-       if (res->port_num >= nb_ports) {
-               printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
+       if (port_id_is_invalid(res->port_num, ENABLED_WARN))
                return;
-       }
 
        ret = rte_eth_bond_mac_address_set(res->port_num, &res->address);
 
@@ -4255,7 +4338,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result,
 
        /* all ports */
        if (allports) {
-               for (i = 0; i < nb_ports; i++) {
+               FOREACH_PORT(i, ports) {
                        if (enable)
                                rte_eth_promiscuous_enable(i);
                        else
@@ -4335,7 +4418,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result,
 
        /* all ports */
        if (allports) {
-               for (i = 0; i < nb_ports; i++) {
+               FOREACH_PORT(i, ports) {
                        if (enable)
                                rte_eth_allmulticast_enable(i);
                        else
@@ -5023,25 +5106,25 @@ static void cmd_showportall_parsed(void *parsed_result,
        struct cmd_showportall_result *res = parsed_result;
        if (!strcmp(res->show, "clear")) {
                if (!strcmp(res->what, "stats"))
-                       for (i = 0; i < nb_ports; i++)
+                       FOREACH_PORT(i, ports)
                                nic_stats_clear(i);
                else if (!strcmp(res->what, "xstats"))
-                       for (i = 0; i < nb_ports; i++)
+                       FOREACH_PORT(i, ports)
                                nic_xstats_clear(i);
        } else if (!strcmp(res->what, "info"))
-               for (i = 0; i < nb_ports; i++)
+               FOREACH_PORT(i, ports)
                        port_infos_display(i);
        else if (!strcmp(res->what, "stats"))
-               for (i = 0; i < nb_ports; i++)
+               FOREACH_PORT(i, ports)
                        nic_stats_display(i);
        else if (!strcmp(res->what, "xstats"))
-               for (i = 0; i < nb_ports; i++)
+               FOREACH_PORT(i, ports)
                        nic_xstats_display(i);
        else if (!strcmp(res->what, "fdir"))
-               for (i = 0; i < nb_ports; i++)
+               FOREACH_PORT(i, ports)
                        fdir_get_infos(i);
        else if (!strcmp(res->what, "stat_qmap"))
-               for (i = 0; i < nb_ports; i++)
+               FOREACH_PORT(i, ports)
                        nic_stats_mapping_display(i);
 }
 
@@ -8687,6 +8770,8 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_set_qmap,
        (cmdline_parse_inst_t *)&cmd_operate_port,
        (cmdline_parse_inst_t *)&cmd_operate_specific_port,
+       (cmdline_parse_inst_t *)&cmd_operate_attach_port,
+       (cmdline_parse_inst_t *)&cmd_operate_detach_port,
        (cmdline_parse_inst_t *)&cmd_config_speed_all,
        (cmdline_parse_inst_t *)&cmd_config_speed_specific,
        (cmdline_parse_inst_t *)&cmd_config_rx_tx,
@@ -8758,7 +8843,7 @@ prompt(void)
 static void
 cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 {
-       if (id < nb_ports) {
+       if (!port_id_is_invalid(id, DISABLED_WARN)) {
                /* check if need_reconfig has been set to 1 */
                if (ports[id].need_reconfig == 0)
                        ports[id].need_reconfig = dev;
@@ -8768,7 +8853,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
        } else {
                portid_t pid;
 
-               for (pid = 0; pid < nb_ports; pid++) {
+               FOREACH_PORT(pid, ports) {
                        /* check if need_reconfig has been set to 1 */
                        if (ports[pid].need_reconfig == 0)
                                ports[pid].need_reconfig = dev;
@@ -8786,10 +8871,8 @@ bypass_is_supported(portid_t port_id)
        struct rte_port   *port;
        struct rte_pci_id *pci_id;
 
-       if (port_id >= nb_ports) {
-               printf("\tPort id must be less than %d.\n", nb_ports);
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return 0;
-       }
 
        /* Get the device id. */
        port    = &ports[port_id];
index d436ce8..49be819 100644 (file)
@@ -112,11 +112,15 @@ nic_stats_display(portid_t port_id)
        struct rte_eth_stats stats;
        struct rte_port *port = &ports[port_id];
        uint8_t i;
+       portid_t pid;
 
        static const char *nic_stats_border = "########################";
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        rte_eth_stats_get(port_id, &stats);
@@ -189,8 +193,13 @@ nic_stats_display(portid_t port_id)
 void
 nic_stats_clear(portid_t port_id)
 {
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       portid_t pid;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        rte_eth_stats_reset(port_id);
@@ -237,11 +246,15 @@ nic_stats_mapping_display(portid_t port_id)
 {
        struct rte_port *port = &ports[port_id];
        uint16_t i;
+       portid_t pid;
 
        static const char *nic_stats_mapping_border = "########################";
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
 
@@ -290,9 +303,13 @@ port_infos_display(portid_t port_id)
        int vlan_offload;
        struct rte_mempool * mp;
        static const char *info_border = "*********************";
+       portid_t pid;
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        port = &ports[port_id];
@@ -365,11 +382,14 @@ port_infos_display(portid_t port_id)
 }
 
 int
-port_id_is_invalid(portid_t port_id)
+port_id_is_invalid(portid_t port_id, enum print_warning warning)
 {
-       if (port_id < nb_ports)
+       if (ports[port_id].enabled)
                return 0;
-       printf("Invalid port %d (must be < nb_ports=%d)\n", port_id, nb_ports);
+
+       if (warning == ENABLED_WARN)
+               printf("Invalid port %d\n", port_id);
+
        return 1;
 }
 
@@ -428,7 +448,7 @@ port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_x)
        uint32_t reg_v;
 
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -447,7 +467,7 @@ port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,
        uint8_t  l_bit;
        uint8_t  h_bit;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -474,7 +494,7 @@ port_reg_display(portid_t port_id, uint32_t reg_off)
 {
        uint32_t reg_v;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -488,7 +508,7 @@ port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,
 {
        uint32_t reg_v;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -516,7 +536,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
        uint8_t  l_bit;
        uint8_t  h_bit;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -550,7 +570,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
 void
 port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -563,7 +583,7 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        diag = rte_eth_dev_set_mtu(port_id, mtu);
        if (diag == 0)
@@ -726,7 +746,7 @@ rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id)
 {
        const struct rte_memzone *rx_mz;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (rx_queue_id_is_invalid(rxq_id))
                return;
@@ -743,7 +763,7 @@ tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id)
 {
        const struct rte_memzone *tx_mz;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (tx_queue_id_is_invalid(txq_id))
                return;
@@ -804,7 +824,7 @@ port_rss_reta_info(portid_t port_id,
        uint16_t i, idx, shift;
        int ret;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);
@@ -859,7 +879,7 @@ port_rss_hash_conf_show(portid_t port_id, int show_rss_key)
        uint8_t i;
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        /* Get RSS hash key if asked to display it */
        rss_conf.rss_key = (show_rss_key) ? rss_key : NULL;
@@ -1423,12 +1443,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
  again:
        for (i = 0; i < nb_pt; i++) {
                port_id = (portid_t) portlist[i];
-               if (port_id >= nb_ports) {
-                       printf("Invalid port id %u >= %u\n",
-                              (unsigned int) port_id,
-                              (unsigned int) nb_ports);
+               if (port_id_is_invalid(port_id, ENABLED_WARN))
                        return;
-               }
                if (record_now)
                        fwd_ports_ids[i] = port_id;
        }
@@ -1586,7 +1602,7 @@ vlan_extend_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1608,7 +1624,7 @@ rx_vlan_strip_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1629,7 +1645,7 @@ rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        diag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);
@@ -1644,7 +1660,7 @@ rx_vlan_filter_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1665,7 +1681,7 @@ rx_vft_set(portid_t port_id, uint16_t vlan_id, int on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
@@ -1682,7 +1698,7 @@ rx_vlan_all_filter_set(portid_t port_id, int on)
 {
        uint16_t vlan_id;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        for (vlan_id = 0; vlan_id < 4096; vlan_id++)
                rx_vft_set(port_id, vlan_id, on);
@@ -1692,7 +1708,7 @@ void
 vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 {
        int diag;
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        diag = rte_eth_dev_set_vlan_ether_type(port_id, tp_id);
@@ -1707,7 +1723,7 @@ vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 void
 tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
@@ -1718,7 +1734,7 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 void
 tx_vlan_reset(portid_t port_id)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        ports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;
 }
@@ -1726,7 +1742,7 @@ tx_vlan_reset(portid_t port_id)
 void
 tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);
@@ -1738,7 +1754,7 @@ set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value)
        uint16_t i;
        uint8_t existing_mapping_found = 0;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id)))
@@ -1904,7 +1920,7 @@ fdir_get_infos(portid_t port_id)
 
        static const char *fdir_stats_border = "########################";
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
        if (ret < 0) {
@@ -2030,7 +2046,7 @@ set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (is_rx)
                diag = rte_eth_dev_set_vf_rx(port_id,vf,on);
@@ -2052,7 +2068,7 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
@@ -2069,7 +2085,7 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)
        int diag;
        struct rte_eth_link link;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return 1;
        rte_eth_link_get_nowait(port_id, &link);
        if (rate > link.link_speed) {
@@ -2094,7 +2110,7 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
        if (q_msk == 0)
                return 0;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return 1;
        rte_eth_link_get_nowait(port_id, &link);
        if (rate > link.link_speed) {
index 473f824..fa5f2a8 100644 (file)
@@ -366,6 +366,7 @@ parse_portnuma_config(const char *q_arg)
        };
        unsigned long int_fld[_NUM_FLD];
        char *str_fld[_NUM_FLD];
+       portid_t pid;
 
        /* reset from value set at definition */
        while ((p = strchr(p0,'(')) != NULL) {
@@ -387,8 +388,11 @@ parse_portnuma_config(const char *q_arg)
                                return -1;
                }
                port_id = (uint8_t)int_fld[FLD_PORT];
-               if (port_id >= nb_ports) {
-                       printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+               if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+                       printf("Valid port range is [0");
+                       FOREACH_PORT(pid, ports)
+                               printf(", %d", pid);
+                       printf("]\n");
                        return -1;
                }
                socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -419,6 +423,7 @@ parse_ringnuma_config(const char *q_arg)
        };
        unsigned long int_fld[_NUM_FLD];
        char *str_fld[_NUM_FLD];
+       portid_t pid;
        #define RX_RING_ONLY 0x1
        #define TX_RING_ONLY 0x2
        #define RXTX_RING    0x3
@@ -443,8 +448,11 @@ parse_ringnuma_config(const char *q_arg)
                                return -1;
                }
                port_id = (uint8_t)int_fld[FLD_PORT];
-               if (port_id >= nb_ports) {
-                       printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+               if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+                       printf("Valid port range is [0");
+                       FOREACH_PORT(pid, ports)
+                               printf(", %d", pid);
+                       printf("]\n");
                        return -1;
                }
                socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -615,12 +623,12 @@ launch_args_parse(int argc, char** argv)
 #endif
                        if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {
                                n = atoi(optarg);
-                               if (n > 0 && n <= nb_ports)
+                               if (n > 0 &&
+                                   !port_id_is_invalid(n, DISABLED_WARN))
                                        nb_fwd_ports = (uint8_t) n;
                                else
                                        rte_exit(EXIT_FAILURE,
-                                                "nb-ports should be > 0 and <= %d\n",
-                                                nb_ports);
+                                                "Invalid port %d\n", n);
                        }
                        if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {
                                n = atoi(optarg);
index 605163b..43329ed 100644 (file)
@@ -71,6 +71,7 @@
 #include <rte_pci.h>
 #include <rte_ether.h>
 #include <rte_ethdev.h>
+#include <rte_dev.h>
 #include <rte_string_fns.h>
 #ifdef RTE_LIBRTE_PMD_XENVIRT
 #include <rte_eth_xenvirt.h>
@@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings = 0;
 
 /* Forward function declarations */
 static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);
-static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
+static void check_all_ports_link_status(uint32_t port_mask);
 
 /*
  * Check if all the ports are started.
@@ -323,6 +324,20 @@ static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
  */
 static int all_ports_started(void);
 
+/*
+ * Find next enabled port
+ */
+portid_t
+find_next_port(portid_t p, struct rte_port *ports, int size)
+{
+       if (ports == NULL)
+               rte_exit(-EINVAL, "failed to find a next port id\n");
+
+       while ((ports[p].enabled == 0) && (p < size))
+               p++;
+       return p;
+}
+
 /*
  * Setup default configuration.
  */
@@ -552,7 +567,8 @@ init_config(void)
                                + RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
 
                if (!numa_support)
-                       nb_mbuf_per_pool = (nb_mbuf_per_pool * nb_ports);
+                       nb_mbuf_per_pool =
+                               (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
        }
 
        if (!numa_support) {
@@ -565,14 +581,19 @@ init_config(void)
 
        /* Configuration of Ethernet ports. */
        ports = rte_zmalloc("testpmd: ports",
-                           sizeof(struct rte_port) * nb_ports,
+                           sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
                            RTE_CACHE_LINE_SIZE);
        if (ports == NULL) {
-               rte_exit(EXIT_FAILURE, "rte_zmalloc(%d struct rte_port) "
-                                                       "failed\n", nb_ports);
+               rte_exit(EXIT_FAILURE,
+                               "rte_zmalloc(%d struct rte_port) failed\n",
+                               RTE_MAX_ETHPORTS);
        }
 
-       for (pid = 0; pid < nb_ports; pid++) {
+       /* enabled allocated ports */
+       for (pid = 0; pid < nb_ports; pid++)
+               ports[pid].enabled = 1;
+
+       FOREACH_PORT(pid, ports) {
                port = &ports[pid];
                rte_eth_dev_info_get(pid, &port->dev_info);
 
@@ -602,8 +623,7 @@ init_config(void)
                        nb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports;
 
                for (i = 0; i < MAX_SOCKET; i++) {
-                       nb_mbuf = (nb_mbuf_per_pool *
-                                               port_per_socket[i]);
+                       nb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
                        if (nb_mbuf)
                                mbuf_pool_create(mbuf_data_size,
                                                nb_mbuf,i);
@@ -635,14 +655,6 @@ reconfig(portid_t new_port_id, unsigned socket_id)
        struct rte_port *port;
 
        /* Reconfiguration of Ethernet ports. */
-       ports = rte_realloc(ports,
-                           sizeof(struct rte_port) * nb_ports,
-                           RTE_CACHE_LINE_SIZE);
-       if (ports == NULL) {
-               rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",
-                               nb_ports);
-       }
-
        port = &ports[new_port_id];
        rte_eth_dev_info_get(new_port_id, &port->dev_info);
 
@@ -663,7 +675,7 @@ init_fwd_streams(void)
        streamid_t sm_id, nb_fwd_streams_new;
 
        /* set socket id according to numa or not */
-       for (pid = 0; pid < nb_ports; pid++) {
+       FOREACH_PORT(pid, ports) {
                port = &ports[pid];
                if (nb_rxq > port->dev_info.max_rx_queues) {
                        printf("Fail: nb_rxq(%d) is greater than "
@@ -1264,7 +1276,7 @@ all_ports_started(void)
        portid_t pi;
        struct rte_port *port;
 
-       for (pi = 0; pi < nb_ports; pi++) {
+       FOREACH_PORT(pi, ports) {
                port = &ports[pi];
                /* Check if there is a port which is not started */
                if (port->port_status != RTE_PORT_STARTED)
@@ -1275,6 +1287,45 @@ all_ports_started(void)
        return 1;
 }
 
+int
+all_ports_stopped(void)
+{
+       portid_t pi;
+       struct rte_port *port;
+
+       FOREACH_PORT(pi, ports) {
+               port = &ports[pi];
+               if (port->port_status != RTE_PORT_STOPPED)
+                       return 0;
+       }
+
+       return 1;
+}
+
+int
+port_is_started(portid_t port_id)
+{
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return 0;
+
+       if (ports[port_id].port_status != RTE_PORT_STARTED)
+               return 0;
+
+       return 1;
+}
+
+static int
+port_is_closed(portid_t port_id)
+{
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return 0;
+
+       if (ports[port_id].port_status != RTE_PORT_CLOSED)
+               return 0;
+
+       return 1;
+}
+
 int
 start_port(portid_t pid)
 {
@@ -1296,8 +1347,8 @@ start_port(portid_t pid)
 
        if(dcb_config)
                dcb_test = 1;
-       for (pi = 0; pi < nb_ports; pi++) {
-               if (pid < nb_ports && pid != pi)
+       FOREACH_PORT(pi, ports) {
+               if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
                        continue;
 
                port = &ports[pi];
@@ -1421,7 +1472,7 @@ start_port(portid_t pid)
        }
 
        if (need_check_link_status && !no_link_check)
-               check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+               check_all_ports_link_status(RTE_PORT_ALL);
        else
                printf("Please stop the ports first\n");
 
@@ -1446,8 +1497,8 @@ stop_port(portid_t pid)
        }
        printf("Stopping ports...\n");
 
-       for (pi = 0; pi < nb_ports; pi++) {
-               if (pid < nb_ports && pid != pi)
+       FOREACH_PORT(pi, ports) {
+               if (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)
                        continue;
 
                port = &ports[pi];
@@ -1463,7 +1514,7 @@ stop_port(portid_t pid)
                need_check_link_status = 1;
        }
        if (need_check_link_status && !no_link_check)
-               check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+               check_all_ports_link_status(RTE_PORT_ALL);
 
        printf("Done\n");
 }
@@ -1481,8 +1532,8 @@ close_port(portid_t pid)
 
        printf("Closing ports...\n");
 
-       for (pi = 0; pi < nb_ports; pi++) {
-               if (pid < nb_ports && pid != pi)
+       FOREACH_PORT(pi, ports) {
+               if (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)
                        continue;
 
                port = &ports[pi];
@@ -1502,31 +1553,83 @@ close_port(portid_t pid)
        printf("Done\n");
 }
 
-int
-all_ports_stopped(void)
+void
+attach_port(char *identifier)
 {
-       portid_t pi;
-       struct rte_port *port;
+       portid_t i, j, pi = 0;
 
-       for (pi = 0; pi < nb_ports; pi++) {
-               port = &ports[pi];
-               if (port->port_status != RTE_PORT_STOPPED)
-                       return 0;
+       printf("Attaching a new port...\n");
+
+       if (identifier == NULL) {
+               printf("Invalid parameters are specified\n");
+               return;
        }
 
-       return 1;
+       if (test_done == 0) {
+               printf("Please stop forwarding first\n");
+               return;
+       }
+
+       if (rte_eth_dev_attach(identifier, &pi))
+               return;
+
+       ports[pi].enabled = 1;
+       reconfig(pi, rte_eth_dev_socket_id(pi));
+       rte_eth_promiscuous_enable(pi);
+
+       nb_ports = rte_eth_dev_count();
+
+       /* set_default_fwd_ports_config(); */
+       bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+       i = 0;
+       FOREACH_PORT(j, ports) {
+               fwd_ports_ids[i] = j;
+               i++;
+       }
+       nb_cfg_ports = nb_ports;
+       nb_fwd_ports++;
+
+       ports[pi].port_status = RTE_PORT_STOPPED;
+
+       printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
+       printf("Done\n");
 }
 
-int
-port_is_started(portid_t port_id)
+void
+detach_port(uint8_t port_id)
 {
-       if (port_id_is_invalid(port_id))
-               return -1;
+       portid_t i, pi = 0;
+       char name[RTE_ETH_NAME_MAX_LEN];
 
-       if (ports[port_id].port_status != RTE_PORT_STARTED)
-               return 0;
+       printf("Detaching a port...\n");
 
-       return 1;
+       if (!port_is_closed(port_id)) {
+               printf("Please close port first\n");
+               return;
+       }
+
+       rte_eth_promiscuous_disable(port_id);
+
+       if (rte_eth_dev_detach(port_id, name))
+               return;
+
+       ports[port_id].enabled = 0;
+       nb_ports = rte_eth_dev_count();
+
+       /* set_default_fwd_ports_config(); */
+       bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+       i = 0;
+       FOREACH_PORT(pi, ports) {
+               fwd_ports_ids[i] = pi;
+               i++;
+       }
+       nb_cfg_ports = nb_ports;
+       nb_fwd_ports--;
+
+       printf("Port '%s' is detached. Now total ports is %d\n",
+                       name, nb_ports);
+       printf("Done\n");
+       return;
 }
 
 void
@@ -1534,7 +1637,7 @@ pmd_test_exit(void)
 {
        portid_t pt_id;
 
-       for (pt_id = 0; pt_id < nb_ports; pt_id++) {
+       FOREACH_PORT(pt_id, ports) {
                printf("Stopping port %d...", pt_id);
                fflush(stdout);
                rte_eth_dev_close(pt_id);
@@ -1553,7 +1656,7 @@ struct pmd_test_command {
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1564,7 +1667,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
        fflush(stdout);
        for (count = 0; count <= MAX_CHECK_TIME; count++) {
                all_ports_up = 1;
-               for (portid = 0; portid < port_num; portid++) {
+               FOREACH_PORT(portid, ports) {
                        if ((port_mask & (1 << portid)) == 0)
                                continue;
                        memset(&link, 0, sizeof(link));
@@ -1729,7 +1832,7 @@ init_port_config(void)
        portid_t pid;
        struct rte_port *port;
 
-       for (pid = 0; pid < nb_ports; pid++) {
+       FOREACH_PORT(pid, ports) {
                port = &ports[pid];
                port->dev_conf.rxmode = rx_mode;
                port->dev_conf.fdir_conf = fdir_conf;
@@ -1908,7 +2011,7 @@ main(int argc, char** argv)
 
        nb_ports = (portid_t) rte_eth_dev_count();
        if (nb_ports == 0)
-               rte_exit(EXIT_FAILURE, "No probed ethernet device\n");
+               RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
 
        set_def_fwd_config();
        if (nb_lcores == 0)
@@ -1930,7 +2033,7 @@ main(int argc, char** argv)
                rte_exit(EXIT_FAILURE, "Start ports failed\n");
 
        /* set all ports to promiscuous mode by default */
-       for (port_id = 0; port_id < nb_ports; port_id++)
+       FOREACH_PORT(port_id, ports)
                rte_eth_promiscuous_enable(port_id);
 
 #ifdef RTE_LIBRTE_CMDLINE
index 126bef7..0d5a526 100644 (file)
@@ -137,6 +137,7 @@ struct fwd_stream {
  * The data structure associated with each port.
  */
 struct rte_port {
+       uint8_t                 enabled;    /**< Port enabled or not */
        struct rte_eth_dev_info dev_info;   /**< PCI info + driver name */
        struct rte_eth_conf     dev_conf;   /**< Port configuration. */
        struct ether_addr       eth_addr;   /**< Port ethernet address */
@@ -162,6 +163,14 @@ struct rte_port {
        struct rte_eth_txconf   tx_conf;    /**< tx configuration */
 };
 
+extern portid_t __rte_unused
+find_next_port(portid_t p, struct rte_port *ports, int size);
+
+#define FOREACH_PORT(p, ports) \
+       for (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \
+           p < RTE_MAX_ETHPORTS; \
+           p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))
+
 /**
  * The data structure associated with each forwarding logical core.
  * The logical cores are internally numbered by a core index from 0 to
@@ -522,6 +531,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_config *dcb_conf);
 int start_port(portid_t pid);
 void stop_port(portid_t pid);
 void close_port(portid_t pid);
+void attach_port(char *identifier);
+void detach_port(uint8_t port_id);
 int all_ports_stopped(void);
 int port_is_started(portid_t port_id);
 void pmd_test_exit(void);
@@ -548,10 +559,15 @@ void get_syn_filter(uint8_t port_id);
 void get_ethertype_filter(uint8_t port_id, uint16_t index);
 void get_2tuple_filter(uint8_t port_id, uint16_t index);
 void get_5tuple_filter(uint8_t port_id, uint16_t index);
-int port_id_is_invalid(portid_t port_id);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
 
+enum print_warning {
+       ENABLED_WARN = 0,
+       DISABLED_WARN
+};
+int port_id_is_invalid(portid_t port_id, enum print_warning warning);
+
 /*
  * Work-around of a compilation error with ICC on invocations of the
  * rte_be_to_cpu_16() function.
index afe1970..a99e14d 100644 (file)
@@ -807,6 +807,63 @@ The following sections show functions for configuring ports.
 
     Port configuration changes only become active when forwarding is started/restarted.
 
+port attach
+~~~~~~~~~~~
+
+Attach a port specified by pci address or virtual device args.
+
+To attach a new pci device, the device should be recognized by kernel first.
+Then it should be moved under DPDK management.
+Finally the port can be attached to testpmd.
+On the other hand, to attach a port created by virtual device, above steps are not needed.
+
+port attach (identifier)
+
+For example, to attach a port whose pci address is 0000:02:00.0.
+
+.. code-block:: console
+
+    testpmd> port attach 0000:02:00.0
+    Attaching a new port...
+    ... snip ...
+    Port 0 is attached. Now total ports is 1
+    Done
+
+For example, to attach a port created by pcap PMD.
+
+.. code-block:: console
+
+    testpmd> port attach eth_pcap0,iface=eth0
+    Attaching a new port...
+    ... snip ...
+    Port 0 is attached. Now total ports is 1
+    Done
+
+In this case, identifier is "eth_pcap0,iface=eth0".
+This identifier format is the same as "--vdev" format of DPDK applications.
+
+port detach
+~~~~~~~~~~~
+
+Detach a specific port.
+
+Before detaching a port, the port should be closed.
+Also to remove a pci device completely from the system, first detach the port from testpmd.
+Then the device should be moved under kernel management.
+Finally the device can be removed using kernel pci hotplug functionality.
+On the other hand, to remove a port created by a virtual device, above steps are not needed.
+
+port detach (port_id)
+
+For example, to detach a port 0.
+
+.. code-block:: console
+
+    testpmd> port detach 0
+    Detaching a port...
+    ... snip ...
+    Done
+
 port start
 ~~~~~~~~~~