app/testpmd: add device related commands
authorNithin Dabilpuram <ndabilpuram@marvell.com>
Wed, 17 Jul 2019 12:30:55 +0000 (18:00 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 23 Jul 2019 12:31:35 +0000 (14:31 +0200)
With the latest published interface of
rte_eal_hotplug_[add,remove](), and rte_eth_dev_close(),
rte_eth_dev_close() would cleanup all the data structures of
port's eth dev leaving the device common resource intact
if RTE_ETH_DEV_CLOSE_REMOVE is set in dev flags.

So a new command "detach device" (~hotplug remove) to work,
with device identifier like "port attach" is added
to be able to detach closed devices.

Also to display currently probed devices, another command
"show device info <identifier>|all" is also added as a
part of this change.

Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
app/test-pmd/cmdline.c
app/test-pmd/config.c
app/test-pmd/testpmd.c
app/test-pmd/testpmd.h
doc/guides/testpmd_app_ug/testpmd_funcs.rst

index 1180176..a28362d 100644 (file)
@@ -101,6 +101,7 @@ static void cmd_help_brief_parsed(__attribute__((unused)) void *parsed_result,
                "    help registers                  : Reading and setting port registers.\n"
                "    help filters                    : Filters configuration help.\n"
                "    help traffic_management         : Traffic Management commmands.\n"
+               "    help devices                    : Device related cmds.\n"
                "    help all                        : All of the above sections.\n\n"
        );
 
@@ -236,6 +237,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "show port (port_id) tx_metadata\n"
                        "    Show Tx metadata value set"
                        " for a specific port\n\n"
+
+                       "show device info (<identifier>|all)"
+                       "       Show general information about devices probed.\n\n"
                );
        }
 
@@ -1247,6 +1251,17 @@ static void cmd_help_long_parsed(void *parsed_result,
                );
        }
 
+       if (show_all || !strcmp(res->section, "devices")) {
+               cmdline_printf(
+                       cl,
+                       "\n"
+                       "Device Operations:\n"
+                       "--------------\n"
+                       "device detach (identifier)\n"
+                       "       Detach device by identifier.\n\n"
+               );
+       }
+
 }
 
 cmdline_parse_token_string_t cmd_help_long_help =
@@ -1255,13 +1270,13 @@ cmdline_parse_token_string_t cmd_help_long_help =
 cmdline_parse_token_string_t cmd_help_long_section =
        TOKEN_STRING_INITIALIZER(struct cmd_help_long_result, section,
                        "all#control#display#config#"
-                       "ports#registers#filters#traffic_management");
+                       "ports#registers#filters#traffic_management#devices");
 
 cmdline_parse_inst_t cmd_help_long = {
        .f = cmd_help_long_parsed,
        .data = NULL,
        .help_str = "help all|control|display|config|ports|register|"
-               "filters|traffic_management: "
+               "filters|traffic_management|devices: "
                "Show help",
        .tokens = {
                (void *)&cmd_help_long_help,
@@ -1500,6 +1515,47 @@ cmdline_parse_inst_t cmd_operate_detach_port = {
        },
 };
 
+/* *** detach device by identifier *** */
+struct cmd_operate_detach_device_result {
+       cmdline_fixed_string_t device;
+       cmdline_fixed_string_t keyword;
+       cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_detach_device_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct cmd_operate_detach_device_result *res = parsed_result;
+
+       if (!strcmp(res->keyword, "detach"))
+               detach_device(res->identifier);
+       else
+               printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_device_device =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+                       device, "device");
+cmdline_parse_token_string_t cmd_operate_detach_device_keyword =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+                       keyword, "detach");
+cmdline_parse_token_string_t cmd_operate_detach_device_identifier =
+       TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+                       identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_detach_device = {
+       .f = cmd_operate_detach_device_parsed,
+       .data = NULL,
+       .help_str = "device detach <identifier>:"
+               "(identifier: pci address or virtual dev name)",
+       .tokens = {
+               (void *)&cmd_operate_detach_device_device,
+               (void *)&cmd_operate_detach_device_keyword,
+               (void *)&cmd_operate_detach_device_identifier,
+               NULL,
+       },
+};
 /* *** configure speed for all ports *** */
 struct cmd_config_speed_all {
        cmdline_fixed_string_t port;
@@ -7463,6 +7519,51 @@ cmdline_parse_inst_t cmd_showport = {
        },
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+       cmdline_fixed_string_t show;
+       cmdline_fixed_string_t device;
+       cmdline_fixed_string_t what;
+       cmdline_fixed_string_t identifier;
+};
+
+static void cmd_showdevice_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct cmd_showdevice_result *res = parsed_result;
+       if (!strcmp(res->what, "info")) {
+               if (!strcmp(res->identifier, "all"))
+                       device_infos_display(NULL);
+               else
+                       device_infos_display(res->identifier);
+       }
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+       TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, show,
+                                "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+       TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, device, "device");
+cmdline_parse_token_string_t cmd_showdevice_what =
+       TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, what,
+                                "info");
+cmdline_parse_token_string_t cmd_showdevice_identifier =
+       TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+                       identifier, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+       .f = cmd_showdevice_parsed,
+       .data = NULL,
+       .help_str = "show device info <identifier>|all",
+       .tokens = {
+               (void *)&cmd_showdevice_show,
+               (void *)&cmd_showdevice_device,
+               (void *)&cmd_showdevice_what,
+               (void *)&cmd_showdevice_identifier,
+               NULL,
+       },
+};
 /* *** SHOW QUEUE INFO *** */
 struct cmd_showqueue_result {
        cmdline_fixed_string_t show;
@@ -18730,6 +18831,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_showport,
        (cmdline_parse_inst_t *)&cmd_showqueue,
        (cmdline_parse_inst_t *)&cmd_showportall,
+       (cmdline_parse_inst_t *)&cmd_showdevice,
        (cmdline_parse_inst_t *)&cmd_showcfg,
        (cmdline_parse_inst_t *)&cmd_showfwdall,
        (cmdline_parse_inst_t *)&cmd_start,
@@ -18818,6 +18920,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (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_operate_detach_device,
        (cmdline_parse_inst_t *)&cmd_set_port_setup_on,
        (cmdline_parse_inst_t *)&cmd_config_speed_all,
        (cmdline_parse_inst_t *)&cmd_config_speed_specific,
index ba43be5..1a5a5c1 100644 (file)
@@ -386,6 +386,79 @@ tx_queue_infos_display(portid_t port_id, uint16_t queue_id)
        printf("\n");
 }
 
+static int bus_match_all(const struct rte_bus *bus, const void *data)
+{
+       RTE_SET_USED(bus);
+       RTE_SET_USED(data);
+       return 0;
+}
+
+void
+device_infos_display(const char *identifier)
+{
+       static const char *info_border = "*********************";
+       struct rte_bus *start = NULL, *next;
+       struct rte_dev_iterator dev_iter;
+       char name[RTE_ETH_NAME_MAX_LEN];
+       struct rte_ether_addr mac_addr;
+       struct rte_device *dev;
+       struct rte_devargs da;
+       portid_t port_id;
+       char devstr[128];
+
+       memset(&da, 0, sizeof(da));
+       if (!identifier)
+               goto skip_parse;
+
+       if (rte_devargs_parsef(&da, "%s", identifier)) {
+               printf("cannot parse identifier\n");
+               if (da.args)
+                       free(da.args);
+               return;
+       }
+
+skip_parse:
+       while ((next = rte_bus_find(start, bus_match_all, NULL)) != NULL) {
+
+               start = next;
+               if (identifier && da.bus != next)
+                       continue;
+
+               /* Skip buses that don't have iterate method */
+               if (!next->dev_iterate)
+                       continue;
+
+               snprintf(devstr, sizeof(devstr), "bus=%s", next->name);
+               RTE_DEV_FOREACH(dev, devstr, &dev_iter) {
+
+                       if (!dev->driver)
+                               continue;
+                       /* Check for matching device if identifier is present */
+                       if (identifier &&
+                           strncmp(da.name, dev->name, strlen(dev->name)))
+                               continue;
+                       printf("\n%s Infos for device %s %s\n",
+                              info_border, dev->name, info_border);
+                       printf("Bus name: %s", dev->bus->name);
+                       printf("\nDriver name: %s", dev->driver->name);
+                       printf("\nDevargs: %s",
+                              dev->devargs ? dev->devargs->args : "");
+                       printf("\nConnect to socket: %d", dev->numa_node);
+                       printf("\n");
+
+                       /* List ports with matching device name */
+                       RTE_ETH_FOREACH_DEV_OF(port_id, dev) {
+                               rte_eth_macaddr_get(port_id, &mac_addr);
+                               printf("\n\tPort id: %-2d", port_id);
+                               print_ethaddr("\n\tMAC address: ", &mac_addr);
+                               rte_eth_dev_get_name_by_port(port_id, name);
+                               printf("\n\tDevice name: %s", name);
+                               printf("\n");
+                       }
+               }
+       };
+}
+
 void
 port_infos_display(portid_t port_id)
 {
index 3ed3523..a3b1542 100644 (file)
@@ -2475,6 +2475,51 @@ detach_port_device(portid_t port_id)
        return;
 }
 
+void
+detach_device(char *identifier)
+{
+       struct rte_dev_iterator iterator;
+       struct rte_devargs da;
+       portid_t port_id;
+
+       printf("Removing a device...\n");
+
+       memset(&da, 0, sizeof(da));
+       if (rte_devargs_parsef(&da, "%s", identifier)) {
+               printf("cannot parse identifier\n");
+               if (da.args)
+                       free(da.args);
+               return;
+       }
+
+       RTE_ETH_FOREACH_MATCHING_DEV(port_id, identifier, &iterator) {
+               if (ports[port_id].port_status != RTE_PORT_CLOSED) {
+                       if (ports[port_id].port_status != RTE_PORT_STOPPED) {
+                               printf("Port %u not stopped\n", port_id);
+                               return;
+                       }
+
+                       /* sibling ports are forced to be closed */
+                       if (ports[port_id].flow_list)
+                               port_flow_flush(port_id);
+                       ports[port_id].port_status = RTE_PORT_CLOSED;
+                       printf("Port %u is now closed\n", port_id);
+               }
+       }
+
+       if (rte_eal_hotplug_remove(da.bus->name, da.name) != 0) {
+               TESTPMD_LOG(ERR, "Failed to detach device %s(%s)\n",
+                           da.name, da.bus->name);
+               return;
+       }
+
+       remove_invalid_ports();
+
+       printf("Device %s is detached\n", identifier);
+       printf("Now total ports is %d\n", nb_ports);
+       printf("Done\n");
+}
+
 void
 pmd_test_exit(void)
 {
index ba04c3b..7799454 100644 (file)
@@ -691,6 +691,7 @@ void nic_stats_clear(portid_t port_id);
 void nic_xstats_display(portid_t port_id);
 void nic_xstats_clear(portid_t port_id);
 void nic_stats_mapping_display(portid_t port_id);
+void device_infos_display(const char *identifier);
 void port_infos_display(portid_t port_id);
 void port_summary_display(portid_t port_id);
 void port_summary_header_display(void);
@@ -790,6 +791,7 @@ void stop_port(portid_t pid);
 void close_port(portid_t pid);
 void reset_port(portid_t pid);
 void attach_port(char *identifier);
+void detach_device(char *identifier);
 void detach_port_device(portid_t port_id);
 int all_ports_stopped(void);
 int port_is_stopped(portid_t port_id);
index e1fcef9..313e070 100644 (file)
@@ -467,6 +467,29 @@ Show Tx metadata value set for a specific port::
 
    testpmd> show port (port_id) tx_metadata
 
+show device info
+~~~~~~~~~~~~~~~~
+
+Show general information about devices probed::
+
+   testpmd> show device info (<identifier>|all)
+
+For example:
+
+.. code-block:: console
+
+    testpmd> show device info net_pcap0
+
+    ********************* Infos for device net_pcap0 *********************
+    Bus name: vdev
+    Driver name: net_pcap
+    Devargs: iface=enP2p6s0,phy_mac=1
+    Connect to socket: -1
+
+            Port id: 2
+            MAC address: 1E:37:93:28:04:B8
+            Device name: net_pcap0
+
 dump physmem
 ~~~~~~~~~~~~
 
@@ -2313,6 +2336,47 @@ hash of input [IP] packets received on port::
                      ipv6-udp-ex <string of hex digits \
                      (variable length, NIC dependent)>)
 
+Device Functions
+----------------
+
+The following sections show functions for device operations.
+
+device detach
+~~~~~~~~~~~~~
+
+Detach a device specified by pci address or virtual device args::
+
+   testpmd> device detach (identifier)
+
+Before detaching a device associated with ports, the ports should be stopped and closed.
+
+For example, to detach a pci device whose address is 0002:03:00.0.
+
+.. code-block:: console
+
+    testpmd> device detach 0002:03:00.0
+    Removing a device...
+    Port 1 is now closed
+    EAL: Releasing pci mapped resource for 0002:03:00.0
+    EAL: Calling pci_unmap_resource for 0002:03:00.0 at 0x218a050000
+    EAL: Calling pci_unmap_resource for 0002:03:00.0 at 0x218c050000
+    Device 0002:03:00.0 is detached
+    Now total ports is 1
+
+For example, to detach a port created by pcap PMD.
+
+.. code-block:: console
+
+    testpmd> device detach net_pcap0
+    Removing a device...
+    Port 0 is now closed
+    Device net_pcap0 is detached
+    Now total ports is 0
+    Done
+
+In this case, identifier is ``net_pcap0``.
+This identifier format is the same as ``--vdev`` format of DPDK applications.
+
 Link Bonding Functions
 ----------------------