From patchwork Thu Nov 20 09:22:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tetsuya Mukawa X-Patchwork-Id: 1390 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id AE21B7FD6; Thu, 20 Nov 2014 10:12:33 +0100 (CET) Received: from mail-pa0-f45.google.com (mail-pa0-f45.google.com [209.85.220.45]) by dpdk.org (Postfix) with ESMTP id 881357FD5 for ; Thu, 20 Nov 2014 10:12:30 +0100 (CET) Received: by mail-pa0-f45.google.com with SMTP id lj1so2205136pab.4 for ; Thu, 20 Nov 2014 01:22:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=QnKgukPx75Q8Y/ANJCHhXlckvug7ogNX8HSftGu71Ug=; b=SlOeOeZvhMz7RORxdouoltiTUR5B69hQv4EILJQdX21i8ixrWMWYmNTtJCaSDkVumz ojF5TuLBLaSKzqrEOKF6oHiiditXps/ej69ZdWvrj5ck1TBFTzOf+LYWcAlBfu4Sy24R lFwCJSGVTUvLPpbvz7VdN8N/3or/upbbXfwhZ0E0lVaIwbu9vrXMzO3MbEUCocF75OPD tJacySK6iGhgGFBF8fC8FwLvAfqIcG0I27Ci+lgrpUEBvQoM4UPNiFf6EGYs7ifaagGN uM4BncFxUqu3pzW4H3H/VtPs1qnOR03q1PAdSr6OeXcox7UnJ+XzkoOR8DOjvJbjUMDI lRyg== X-Gm-Message-State: ALoCoQn4cXjg6rhewXShNY2RU8HJDnComUrcMvZNEM6nDNy75c0a+rSkcU4ZIM8LnjWjRG5DGvPk X-Received: by 10.70.92.201 with SMTP id co9mr28620061pdb.134.1416475379288; Thu, 20 Nov 2014 01:22:59 -0800 (PST) Received: from localhost.localdomain (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id yw1sm1483550pbb.52.2014.11.20.01.22.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 20 Nov 2014 01:22:58 -0800 (PST) From: Tetsuya Mukawa To: dev@dpdk.org Date: Thu, 20 Nov 2014 18:22:44 +0900 Message-Id: <1416475364-17887-1-git-send-email-mukawa@igel.co.jp> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1414572576-21371-1-git-send-email-mukawa@igel.co.jp> References: <1414572576-21371-1-git-send-email-mukawa@igel.co.jp> Cc: nakajima.yoshihiro@lab.ntt.co.jp, menrigh@brocade.com, masutani.hitoshi@lab.ntt.co.jp Subject: [dpdk-dev] [PATCH] 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The patch introduces following commands. - port [attach|detach] [p|v] [ident] - attach: attaching a port - detach: detaching a port - p: physical port - v: virtual port - ident: pci address of physical device. Or device name and paramerters of virtual device. (ex. 0000:02:00.0, eth_pcap0,iface=eth0) Signed-off-by: Tetsuya Mukawa --- app/test-pmd/cmdline.c | 139 +++++++++++++++++++++++----- app/test-pmd/config.c | 54 +++++++---- app/test-pmd/parameters.c | 21 +++-- app/test-pmd/testpmd.c | 226 ++++++++++++++++++++++++++++++++++++---------- app/test-pmd/testpmd.h | 17 ++++ 5 files changed, 366 insertions(+), 91 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 4c3fc76..980bd34 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -550,6 +550,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 add (p|a) (ident)\n" + " Add physical or virtual dev by pci address or virtual device name\n\n" + + "port del (p|a) (port_id)\n" + " Del 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" @@ -796,6 +802,101 @@ cmdline_parse_inst_t cmd_operate_specific_port = { }, }; +/* *** attach a specificied port *** */ +struct cmd_operate_attach_port_result { + cmdline_fixed_string_t port; + cmdline_fixed_string_t keyword; + cmdline_fixed_string_t type; + 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->type, 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_type = + TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result, + type, "p#v"); + +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 p|v ident p: physical, v: virtual, " + "ident: pci address or virtual dev name", + .tokens = { + (void *)&cmd_operate_attach_port_port, + (void *)&cmd_operate_attach_port_keyword, + (void *)&cmd_operate_attach_port_type, + (void *)&cmd_operate_attach_port_identifier, + NULL, + }, +}; + +/* *** detach a specificied port *** */ +struct cmd_operate_detach_port_result { + cmdline_fixed_string_t port; + cmdline_fixed_string_t keyword; + cmdline_fixed_string_t type; + 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->type, 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_string_t cmd_operate_detach_port_type = + TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result, + type, "p#v"); + +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 p|v port_id p: physical, v: virtual", + .tokens = { + (void *)&cmd_operate_detach_port_port, + (void *)&cmd_operate_detach_port_keyword, + (void *)&cmd_operate_detach_port_type, + (void *)&cmd_operate_detach_port_port_id, + NULL, + }, +}; + /* *** configure speed for all ports *** */ struct cmd_config_speed_all { cmdline_fixed_string_t port; @@ -850,7 +951,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; } @@ -918,10 +1019,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)) return; - } if (!strcmp(res->value1, "10")) link_speed = ETH_LINK_SPEED_10; @@ -3694,10 +3793,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)) return; - } ret = rte_eth_bond_mac_address_set(res->port_num, &res->address); @@ -3875,7 +3972,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 @@ -3955,7 +4052,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 @@ -5140,25 +5237,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); } @@ -7827,6 +7924,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, @@ -7897,7 +7996,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)) { /* check if need_reconfig has been set to 1 */ if (ports[id].need_reconfig == 0) ports[id].need_reconfig = dev; @@ -7907,7 +8006,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; @@ -7925,10 +8024,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)) return 0; - } /* Get the device id. */ port = &ports[port_id]; diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index b102b72..8f83916 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -110,11 +110,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)) { + printf("Valid port range is [0"); + FOREACH_PORT(pid, ports) + printf(", %d", pid); + printf("]\n"); return; } rte_eth_stats_get(port_id, &stats); @@ -187,8 +191,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)) { + printf("Valid port range is [0"); + FOREACH_PORT(pid, ports) + printf(", %d", pid); + printf("]\n"); return; } rte_eth_stats_reset(port_id); @@ -235,11 +244,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)) { + printf("Valid port range is [0"); + FOREACH_PORT(pid, ports) + printf(", %d", pid); + printf("]\n"); return; } @@ -287,9 +300,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)) { + printf("Valid port range is [0"); + FOREACH_PORT(pid, ports) + printf(", %d", pid); + printf("]\n"); return; } port = &ports[port_id]; @@ -342,14 +359,23 @@ port_infos_display(portid_t port_id) } int -port_id_is_invalid(portid_t port_id) +_port_id_is_invalid(portid_t port_id) { - 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); return 1; } +int +port_id_is_invalid(portid_t port_id) +{ + if (_port_id_is_invalid(port_id)) { + printf("Invalid port %d\n", port_id); + return 1; + } + return 0; +} + static int vlan_id_is_invalid(uint16_t vlan_id) { @@ -1382,12 +1408,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)) return; - } if (record_now) fwd_ports_ids[i] = port_id; } diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 9573a43..06d0eeb 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -375,6 +375,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) { @@ -396,8 +397,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)) { + 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]; @@ -428,6 +432,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 @@ -452,8 +457,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)) { + 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]; @@ -670,12 +678,11 @@ 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)) 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); diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 12adafa..b245936 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #ifdef RTE_LIBRTE_PMD_XENVIRT #include @@ -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. @@ -552,7 +553,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 +567,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, 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 +609,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 +641,6 @@ reconfig(portid_t new_port_id) struct rte_port *port; /* Reconfiguration of Ethernet ports. */ - ports = rte_realloc(ports, - sizeof(struct rte_port) * nb_ports, - 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); @@ -662,7 +660,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 " @@ -1263,7 +1261,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 +1273,45 @@ all_ports_started(void) } 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)) + 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)) + return 0; + + if (ports[port_id].port_status != RTE_PORT_CLOSED) + return 0; + + return 1; +} + +int start_port(portid_t pid) { int diag, need_check_link_status = 0; @@ -1295,8 +1332,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 (!_port_id_is_invalid(pid) && pid != pi) continue; port = &ports[pi]; @@ -1420,7 +1457,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"); @@ -1445,8 +1482,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) && pid != pi) continue; port = &ports[pi]; @@ -1462,7 +1499,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"); } @@ -1480,8 +1517,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) && pid != pi) continue; port = &ports[pi]; @@ -1501,31 +1538,126 @@ close_port(portid_t pid) printf("Done\n"); } -int -all_ports_stopped(void) + +static inline int +attach_physical_device_port(char *identifier, uint8_t *pi) { - portid_t pi; - struct rte_port *port; + struct rte_pci_addr addr; - for (pi = 0; pi < nb_ports; pi++) { - port = &ports[pi]; - if (port->port_status != RTE_PORT_STOPPED) - return 0; + if (eal_parse_pci_DomBDF(identifier, &addr) != 0) { + printf("invalid PCI identifier <%s>\n", identifier); + return -1; } + return rte_eal_dev_attach_pdev(&addr, pi); +} - return 1; +static inline int +attach_virtual_device_port(char *identifier, uint8_t *pi) +{ + return rte_eal_dev_attach_vdev(identifier, pi); } -int -port_is_started(portid_t port_id) +static inline int +detach_physical_device_port(uint8_t pi, char *identifier) { - if (port_id_is_invalid(port_id)) + struct rte_pci_addr addr; + + if (rte_eal_dev_detach_pdev(pi, &addr)) return -1; - if (ports[port_id].port_status != RTE_PORT_STARTED) - return 0; + snprintf(identifier, RTE_ETH_NAME_MAX_LEN, "%04x.%02x.%02x.%d", + addr.domain, addr.bus, addr.devid, addr.function); + return 0; +} - return 1; +static inline int +detach_virtual_device_port(uint8_t pi, char *identifier) +{ + return rte_eal_dev_detach_vdev(pi, identifier); +} + +void +attach_port(char *type, char *identifier) +{ + portid_t i, j, pi = 0; + + printf("Attaching a new port...\n"); + + if (test_done == 0) { + printf("Please stop forwarding first\n"); + return; + } + + if (strncmp(type, "p", 1) == 0) { + if (attach_physical_device_port(identifier, &pi)) + return; + } else if (strncmp(type, "v", 1) == 0) { + if (attach_virtual_device_port(identifier, &pi)) + return; + } + + ports[pi].enabled = 1; + reconfig(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"); +} + +void +detach_port(char *type, uint8_t port_id) +{ + portid_t i, pi = 0; + char name[RTE_ETH_NAME_MAX_LEN]; + + printf("Detaching a port...\n"); + + if (!port_is_closed(port_id)) { + printf("Please close port first\n"); + return; + } + + rte_eth_promiscuous_disable(port_id); + + if (strncmp(type, "p", 1) == 0) { + if (detach_physical_device_port(port_id, name)) + return; + } else if (strncmp(type, "v", 1) == 0) { + if (detach_virtual_device_port(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 @@ -1533,7 +1665,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); @@ -1552,7 +1684,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 */ @@ -1563,7 +1695,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)); @@ -1687,7 +1819,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; @@ -1870,7 +2002,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) @@ -1892,7 +2024,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 diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 9cbfeac..b79bd1f 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -133,6 +133,7 @@ struct fwd_stream { * Bit 11: Insert VLAN Label */ 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 */ @@ -157,6 +158,19 @@ struct rte_port { struct rte_eth_txconf tx_conf; /**< tx configuration */ }; +static portid_t __rte_unused +find_next_port(portid_t p, struct rte_port *ports, int size) +{ + while ((ports[p].enabled == 0) && (p < size)) + p++; + return p; +} + +#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 @@ -512,6 +526,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 *type, char *identifier); +void detach_port(char *type, uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); void pmd_test_exit(void); @@ -550,6 +566,7 @@ 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); void get_flex_filter(uint8_t port_id, uint16_t index); +int _port_id_is_invalid(portid_t port_id); 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);