X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest-pmd%2Fconfig.c;h=2dfef810d7cebb9ae6cd2aab5dbf19085357e015;hb=1b9f274623b8;hp=d93941f0319ae6a04a244811f3e63c908b346996;hpb=5e4154cec49cb30c82c19c13fb62827e13563019;p=dpdk.git diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index d93941f031..2dfef810d7 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -49,9 +49,20 @@ #include #endif #include +#include #include "testpmd.h" +#define ETHDEV_FWVERS_LEN 32 + +#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */ +#define CLOCK_TYPE_ID CLOCK_MONOTONIC_RAW +#else +#define CLOCK_TYPE_ID CLOCK_MONOTONIC +#endif + +#define NS_PER_SEC 1E9 + static char *flowtype_to_str(uint16_t flow_type); static const struct { @@ -73,10 +84,17 @@ static const struct { }; const struct rss_type_info rss_type_table[] = { - { "all", ETH_RSS_IP | ETH_RSS_TCP | - ETH_RSS_UDP | ETH_RSS_SCTP | - ETH_RSS_L2_PAYLOAD }, + { "all", ETH_RSS_ETH | ETH_RSS_VLAN | ETH_RSS_IP | ETH_RSS_TCP | + ETH_RSS_UDP | ETH_RSS_SCTP | ETH_RSS_L2_PAYLOAD | + ETH_RSS_L2TPV3 | ETH_RSS_ESP | ETH_RSS_AH | ETH_RSS_PFCP | + ETH_RSS_GTPU}, { "none", 0 }, + { "eth", ETH_RSS_ETH }, + { "l2-src-only", ETH_RSS_L2_SRC_ONLY }, + { "l2-dst-only", ETH_RSS_L2_DST_ONLY }, + { "vlan", ETH_RSS_VLAN }, + { "s-vlan", ETH_RSS_S_VLAN }, + { "c-vlan", ETH_RSS_C_VLAN }, { "ipv4", ETH_RSS_IPV4 }, { "ipv4-frag", ETH_RSS_FRAG_IPV4 }, { "ipv4-tcp", ETH_RSS_NONFRAG_IPV4_TCP }, @@ -102,13 +120,47 @@ const struct rss_type_info rss_type_table[] = { { "tcp", ETH_RSS_TCP }, { "sctp", ETH_RSS_SCTP }, { "tunnel", ETH_RSS_TUNNEL }, + { "l3-pre32", RTE_ETH_RSS_L3_PRE32 }, + { "l3-pre40", RTE_ETH_RSS_L3_PRE40 }, + { "l3-pre48", RTE_ETH_RSS_L3_PRE48 }, + { "l3-pre56", RTE_ETH_RSS_L3_PRE56 }, + { "l3-pre64", RTE_ETH_RSS_L3_PRE64 }, + { "l3-pre96", RTE_ETH_RSS_L3_PRE96 }, { "l3-src-only", ETH_RSS_L3_SRC_ONLY }, { "l3-dst-only", ETH_RSS_L3_DST_ONLY }, { "l4-src-only", ETH_RSS_L4_SRC_ONLY }, { "l4-dst-only", ETH_RSS_L4_DST_ONLY }, + { "esp", ETH_RSS_ESP }, + { "ah", ETH_RSS_AH }, + { "l2tpv3", ETH_RSS_L2TPV3 }, + { "pfcp", ETH_RSS_PFCP }, + { "pppoe", ETH_RSS_PPPOE }, + { "gtpu", ETH_RSS_GTPU }, { NULL, 0 }, }; +static const struct { + enum rte_eth_fec_mode mode; + const char *name; +} fec_mode_name[] = { + { + .mode = RTE_ETH_FEC_NOFEC, + .name = "off", + }, + { + .mode = RTE_ETH_FEC_AUTO, + .name = "auto", + }, + { + .mode = RTE_ETH_FEC_BASER, + .name = "baser", + }, + { + .mode = RTE_ETH_FEC_RS, + .name = "rs", + }, +}; + static void print_ethaddr(const char *name, struct rte_ether_addr *eth_addr) { @@ -124,9 +176,10 @@ nic_stats_display(portid_t port_id) static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS]; static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS]; static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS]; - static uint64_t prev_cycles[RTE_MAX_ETHPORTS]; + static uint64_t prev_ns[RTE_MAX_ETHPORTS]; + struct timespec cur_time; uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx, - diff_cycles; + diff_ns; uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx; struct rte_eth_stats stats; struct rte_port *port = &ports[port_id]; @@ -183,10 +236,17 @@ nic_stats_display(portid_t port_id) } } - diff_cycles = prev_cycles[port_id]; - prev_cycles[port_id] = rte_rdtsc(); - if (diff_cycles > 0) - diff_cycles = prev_cycles[port_id] - diff_cycles; + diff_ns = 0; + if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) { + uint64_t ns; + + ns = cur_time.tv_sec * NS_PER_SEC; + ns += cur_time.tv_nsec; + + if (prev_ns[port_id] != 0) + diff_ns = ns - prev_ns[port_id]; + prev_ns[port_id] = ns; + } diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ? (stats.ipackets - prev_pkts_rx[port_id]) : 0; @@ -194,10 +254,10 @@ nic_stats_display(portid_t port_id) (stats.opackets - prev_pkts_tx[port_id]) : 0; prev_pkts_rx[port_id] = stats.ipackets; prev_pkts_tx[port_id] = stats.opackets; - mpps_rx = diff_cycles > 0 ? - diff_pkts_rx * rte_get_tsc_hz() / diff_cycles : 0; - mpps_tx = diff_cycles > 0 ? - diff_pkts_tx * rte_get_tsc_hz() / diff_cycles : 0; + mpps_rx = diff_ns > 0 ? + (double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0; + mpps_tx = diff_ns > 0 ? + (double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0; diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ? (stats.ibytes - prev_bytes_rx[port_id]) : 0; @@ -205,10 +265,10 @@ nic_stats_display(portid_t port_id) (stats.obytes - prev_bytes_tx[port_id]) : 0; prev_bytes_rx[port_id] = stats.ibytes; prev_bytes_tx[port_id] = stats.obytes; - mbps_rx = diff_cycles > 0 ? - diff_bytes_rx * rte_get_tsc_hz() / diff_cycles : 0; - mbps_tx = diff_cycles > 0 ? - diff_bytes_tx * rte_get_tsc_hz() / diff_cycles : 0; + mbps_rx = diff_ns > 0 ? + (double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0; + mbps_tx = diff_ns > 0 ? + (double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0; printf("\n Throughput (since last show)\n"); printf(" Rx-pps: %12"PRIu64" Rx-bps: %12"PRIu64"\n Tx-pps: %12" @@ -222,11 +282,28 @@ nic_stats_display(portid_t port_id) void nic_stats_clear(portid_t port_id) { + int ret; + if (port_id_is_invalid(port_id, ENABLED_WARN)) { print_valid_ports(); return; } - rte_eth_stats_reset(port_id); + + ret = rte_eth_stats_reset(port_id); + if (ret != 0) { + printf("%s: Error: failed to reset stats (port %u): %s", + __func__, port_id, strerror(-ret)); + return; + } + + ret = rte_eth_stats_get(port_id, &ports[port_id].stats); + if (ret != 0) { + if (ret < 0) + ret = -ret; + printf("%s: Error: failed to get stats (port %u): %s", + __func__, port_id, strerror(ret)); + return; + } printf("\n NIC statistics for port %d cleared\n", port_id); } @@ -302,10 +379,21 @@ nic_xstats_clear(portid_t port_id) print_valid_ports(); return; } + ret = rte_eth_xstats_reset(port_id); if (ret != 0) { printf("%s: Error: failed to reset xstats (port %u): %s", + __func__, port_id, strerror(-ret)); + return; + } + + ret = rte_eth_stats_get(port_id, &ports[port_id].stats); + if (ret != 0) { + if (ret < 0) + ret = -ret; + printf("%s: Error: failed to get stats (port %u): %s", __func__, port_id, strerror(ret)); + return; } } @@ -387,6 +475,8 @@ rx_queue_infos_display(portid_t port_id, uint16_t queue_id) (qinfo.conf.rx_deferred_start != 0) ? "on" : "off"); printf("\nRX scattered packets: %s", (qinfo.scattered_rx != 0) ? "on" : "off"); + if (qinfo.rx_buf_size != 0) + printf("\nRX buffer size: %hu", qinfo.rx_buf_size); printf("\nNumber of RXDs: %hu", qinfo.nb_desc); if (rte_eth_rx_burst_mode_get(port_id, queue_id, &mode) == 0) @@ -442,6 +532,46 @@ static int bus_match_all(const struct rte_bus *bus, const void *data) return 0; } +static void +device_infos_display_speeds(uint32_t speed_capa) +{ + printf("\n\tDevice speed capability:"); + if (speed_capa == ETH_LINK_SPEED_AUTONEG) + printf(" Autonegotiate (all speeds)"); + if (speed_capa & ETH_LINK_SPEED_FIXED) + printf(" Disable autonegotiate (fixed speed) "); + if (speed_capa & ETH_LINK_SPEED_10M_HD) + printf(" 10 Mbps half-duplex "); + if (speed_capa & ETH_LINK_SPEED_10M) + printf(" 10 Mbps full-duplex "); + if (speed_capa & ETH_LINK_SPEED_100M_HD) + printf(" 100 Mbps half-duplex "); + if (speed_capa & ETH_LINK_SPEED_100M) + printf(" 100 Mbps full-duplex "); + if (speed_capa & ETH_LINK_SPEED_1G) + printf(" 1 Gbps "); + if (speed_capa & ETH_LINK_SPEED_2_5G) + printf(" 2.5 Gbps "); + if (speed_capa & ETH_LINK_SPEED_5G) + printf(" 5 Gbps "); + if (speed_capa & ETH_LINK_SPEED_10G) + printf(" 10 Gbps "); + if (speed_capa & ETH_LINK_SPEED_20G) + printf(" 20 Gbps "); + if (speed_capa & ETH_LINK_SPEED_25G) + printf(" 25 Gbps "); + if (speed_capa & ETH_LINK_SPEED_40G) + printf(" 40 Gbps "); + if (speed_capa & ETH_LINK_SPEED_50G) + printf(" 50 Gbps "); + if (speed_capa & ETH_LINK_SPEED_56G) + printf(" 56 Gbps "); + if (speed_capa & ETH_LINK_SPEED_100G) + printf(" 100 Gbps "); + if (speed_capa & ETH_LINK_SPEED_200G) + printf(" 200 Gbps "); +} + void device_infos_display(const char *identifier) { @@ -453,6 +583,7 @@ device_infos_display(const char *identifier) struct rte_device *dev; struct rte_devargs da; portid_t port_id; + struct rte_eth_dev_info dev_info; char devstr[128]; memset(&da, 0, sizeof(da)); @@ -504,6 +635,8 @@ skip_parse: &mac_addr); rte_eth_dev_get_name_by_port(port_id, name); printf("\n\tDevice name: %s", name); + if (rte_eth_dev_info_get(port_id, &dev_info) == 0) + device_infos_display_speeds(dev_info.speed_capa); printf("\n"); } } @@ -523,6 +656,7 @@ port_infos_display(portid_t port_id) uint16_t mtu; char name[RTE_ETH_NAME_MAX_LEN]; int ret; + char fw_version[ETHDEV_FWVERS_LEN]; if (port_id_is_invalid(port_id, ENABLED_WARN)) { print_valid_ports(); @@ -544,6 +678,13 @@ port_infos_display(portid_t port_id) rte_eth_dev_get_name_by_port(port_id, name); printf("\nDevice name: %s", name); printf("\nDriver name: %s", dev_info.driver_name); + + if (rte_eth_dev_fw_version_get(port_id, fw_version, + ETHDEV_FWVERS_LEN) == 0) + printf("\nFirmware-version: %s", fw_version); + else + printf("\nFirmware-version: %s", "not available"); + if (dev_info.device->devargs && dev_info.device->devargs->args) printf("\nDevargs: %s", dev_info.device->devargs->args); printf("\nConnect to socket: %u", port->socket_id); @@ -557,7 +698,7 @@ port_infos_display(portid_t port_id) printf("\nmemory allocation on the socket: %u",port->socket_id); printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down")); - printf("Link speed: %u Mbps\n", (unsigned) link.link_speed); + printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed)); printf("Link duplex: %s\n", (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? ("full-duplex") : ("half-duplex")); @@ -702,12 +843,128 @@ port_summary_display(portid_t port_id) if (ret != 0) return; - printf("%-4d %02X:%02X:%02X:%02X:%02X:%02X %-12s %-14s %-8s %uMbps\n", + printf("%-4d %02X:%02X:%02X:%02X:%02X:%02X %-12s %-14s %-8s %s\n", port_id, mac_addr.addr_bytes[0], mac_addr.addr_bytes[1], mac_addr.addr_bytes[2], mac_addr.addr_bytes[3], mac_addr.addr_bytes[4], mac_addr.addr_bytes[5], name, dev_info.driver_name, (link.link_status) ? ("up") : ("down"), - (unsigned int) link.link_speed); + rte_eth_link_speed_to_str(link.link_speed)); +} + +void +port_eeprom_display(portid_t port_id) +{ + struct rte_dev_eeprom_info einfo; + int ret; + if (port_id_is_invalid(port_id, ENABLED_WARN)) { + print_valid_ports(); + return; + } + + int len_eeprom = rte_eth_dev_get_eeprom_length(port_id); + if (len_eeprom < 0) { + switch (len_eeprom) { + case -ENODEV: + printf("port index %d invalid\n", port_id); + break; + case -ENOTSUP: + printf("operation not supported by device\n"); + break; + case -EIO: + printf("device is removed\n"); + break; + default: + printf("Unable to get EEPROM: %d\n", len_eeprom); + break; + } + return; + } + + char buf[len_eeprom]; + einfo.offset = 0; + einfo.length = len_eeprom; + einfo.data = buf; + + ret = rte_eth_dev_get_eeprom(port_id, &einfo); + if (ret != 0) { + switch (ret) { + case -ENODEV: + printf("port index %d invalid\n", port_id); + break; + case -ENOTSUP: + printf("operation not supported by device\n"); + break; + case -EIO: + printf("device is removed\n"); + break; + default: + printf("Unable to get EEPROM: %d\n", ret); + break; + } + return; + } + rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); + printf("Finish -- Port: %d EEPROM length: %d bytes\n", port_id, len_eeprom); +} + +void +port_module_eeprom_display(portid_t port_id) +{ + struct rte_eth_dev_module_info minfo; + struct rte_dev_eeprom_info einfo; + int ret; + + if (port_id_is_invalid(port_id, ENABLED_WARN)) { + print_valid_ports(); + return; + } + + + ret = rte_eth_dev_get_module_info(port_id, &minfo); + if (ret != 0) { + switch (ret) { + case -ENODEV: + printf("port index %d invalid\n", port_id); + break; + case -ENOTSUP: + printf("operation not supported by device\n"); + break; + case -EIO: + printf("device is removed\n"); + break; + default: + printf("Unable to get module EEPROM: %d\n", ret); + break; + } + return; + } + + char buf[minfo.eeprom_len]; + einfo.offset = 0; + einfo.length = minfo.eeprom_len; + einfo.data = buf; + + ret = rte_eth_dev_get_module_eeprom(port_id, &einfo); + if (ret != 0) { + switch (ret) { + case -ENODEV: + printf("port index %d invalid\n", port_id); + break; + case -ENOTSUP: + printf("operation not supported by device\n"); + break; + case -EIO: + printf("device is removed\n"); + break; + default: + printf("Unable to get module EEPROM: %d\n", ret); + break; + } + return; + } + + rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); + printf("Finish -- Port: %d MODULE EEPROM length: %d bytes\n", port_id, einfo.length); } void @@ -979,6 +1236,15 @@ port_offload_cap_display(portid_t port_id) printf("off\n"); } + if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SEND_ON_TIMESTAMP) { + printf("Tx scheduling on timestamp: "); + if (ports[port_id].dev_conf.txmode.offloads & + DEV_TX_OFFLOAD_SEND_ON_TIMESTAMP) + printf("on\n"); + else + printf("off\n"); + } + } int @@ -1233,8 +1499,9 @@ port_mtu_set(portid_t port_id, uint16_t mtu) return; } diag = rte_eth_dev_set_mtu(port_id, mtu); - if (diag == 0 && - dev_info.rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME) { + if (diag) + printf("Set MTU failed. diag=%d\n", diag); + else if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME) { /* * Ether overhead in driver is equal to the difference of * max_rx_pktlen and max_mtu in rte_eth_dev_info when the @@ -1249,14 +1516,120 @@ port_mtu_set(portid_t port_id, uint16_t mtu) } else rte_port->dev_conf.rxmode.offloads &= ~DEV_RX_OFFLOAD_JUMBO_FRAME; - - return; } - printf("Set MTU failed. diag=%d\n", diag); } /* Generic flow management functions. */ +static struct port_flow_tunnel * +port_flow_locate_tunnel_id(struct rte_port *port, uint32_t port_tunnel_id) +{ + struct port_flow_tunnel *flow_tunnel; + + LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { + if (flow_tunnel->id == port_tunnel_id) + goto out; + } + flow_tunnel = NULL; + +out: + return flow_tunnel; +} + +const char * +port_flow_tunnel_type(struct rte_flow_tunnel *tunnel) +{ + const char *type; + switch (tunnel->type) { + default: + type = "unknown"; + break; + case RTE_FLOW_ITEM_TYPE_VXLAN: + type = "vxlan"; + break; + } + + return type; +} + +struct port_flow_tunnel * +port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun) +{ + struct rte_port *port = &ports[port_id]; + struct port_flow_tunnel *flow_tunnel; + + LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { + if (!memcmp(&flow_tunnel->tunnel, tun, sizeof(*tun))) + goto out; + } + flow_tunnel = NULL; + +out: + return flow_tunnel; +} + +void port_flow_tunnel_list(portid_t port_id) +{ + struct rte_port *port = &ports[port_id]; + struct port_flow_tunnel *flt; + + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + printf("port %u tunnel #%u type=%s", + port_id, flt->id, port_flow_tunnel_type(&flt->tunnel)); + if (flt->tunnel.tun_id) + printf(" id=%" PRIu64, flt->tunnel.tun_id); + printf("\n"); + } +} + +void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id) +{ + struct rte_port *port = &ports[port_id]; + struct port_flow_tunnel *flt; + + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + if (flt->id == tunnel_id) + break; + } + if (flt) { + LIST_REMOVE(flt, chain); + free(flt); + printf("port %u: flow tunnel #%u destroyed\n", + port_id, tunnel_id); + } +} + +void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops) +{ + struct rte_port *port = &ports[port_id]; + enum rte_flow_item_type type; + struct port_flow_tunnel *flt; + + if (!strcmp(ops->type, "vxlan")) + type = RTE_FLOW_ITEM_TYPE_VXLAN; + else { + printf("cannot offload \"%s\" tunnel type\n", ops->type); + return; + } + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + if (flt->tunnel.type == type) + break; + } + if (!flt) { + flt = calloc(1, sizeof(*flt)); + if (!flt) { + printf("failed to allocate port flt object\n"); + return; + } + flt->tunnel.type = type; + flt->id = LIST_EMPTY(&port->flow_tunnel_list) ? 1 : + LIST_FIRST(&port->flow_tunnel_list)->id + 1; + LIST_INSERT_HEAD(&port->flow_tunnel_list, flt, chain); + } + printf("port %d: flow tunnel #%u type %s\n", + port_id, flt->id, ops->type); +} + /** Generate a port_flow entry from attributes/pattern/actions. */ static struct port_flow * port_flow_new(const struct rte_flow_attr *attr, @@ -1330,61 +1703,478 @@ port_flow_complain(struct rte_flow_error *error) return -err; } +static void +rss_config_display(struct rte_flow_action_rss *rss_conf) +{ + uint8_t i; + + if (rss_conf == NULL) { + printf("Invalid rule\n"); + return; + } + + printf("RSS:\n" + " queues:"); + if (rss_conf->queue_num == 0) + printf(" none"); + for (i = 0; i < rss_conf->queue_num; i++) + printf(" %d", rss_conf->queue[i]); + printf("\n"); + + printf(" function: "); + switch (rss_conf->func) { + case RTE_ETH_HASH_FUNCTION_DEFAULT: + printf("default\n"); + break; + case RTE_ETH_HASH_FUNCTION_TOEPLITZ: + printf("toeplitz\n"); + break; + case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR: + printf("simple_xor\n"); + break; + case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ: + printf("symmetric_toeplitz\n"); + break; + default: + printf("Unknown function\n"); + return; + } + + printf(" types:\n"); + if (rss_conf->types == 0) { + printf(" none\n"); + return; + } + for (i = 0; rss_type_table[i].str; i++) { + if ((rss_conf->types & + rss_type_table[i].rss_type) == + rss_type_table[i].rss_type && + rss_type_table[i].rss_type != 0) + printf(" %s\n", rss_type_table[i].str); + } +} + +static struct port_shared_action * +action_get_by_id(portid_t port_id, uint32_t id) +{ + struct rte_port *port; + struct port_shared_action **ppsa; + struct port_shared_action *psa = NULL; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return NULL; + port = &ports[port_id]; + ppsa = &port->actions_list; + while (*ppsa) { + if ((*ppsa)->id == id) { + psa = *ppsa; + break; + } + ppsa = &(*ppsa)->next; + } + if (!psa) + printf("Failed to find shared action #%u on port %u\n", + id, port_id); + return psa; +} + +static int +action_alloc(portid_t port_id, uint32_t id, + struct port_shared_action **action) +{ + struct rte_port *port; + struct port_shared_action **ppsa; + struct port_shared_action *psa = NULL; + + *action = NULL; + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + if (id == UINT32_MAX) { + /* taking first available ID */ + if (port->actions_list) { + if (port->actions_list->id == UINT32_MAX - 1) { + printf("Highest shared action ID is already" + " assigned, delete it first\n"); + return -ENOMEM; + } + id = port->actions_list->id + 1; + } else { + id = 0; + } + } + psa = calloc(1, sizeof(*psa)); + if (!psa) { + printf("Allocation of port %u shared action failed\n", + port_id); + return -ENOMEM; + } + ppsa = &port->actions_list; + while (*ppsa && (*ppsa)->id > id) + ppsa = &(*ppsa)->next; + if (*ppsa && (*ppsa)->id == id) { + printf("Shared action #%u is already assigned," + " delete it first\n", id); + free(psa); + return -EINVAL; + } + psa->next = *ppsa; + psa->id = id; + *ppsa = psa; + *action = psa; + return 0; +} + +/** Create shared action */ +int +port_shared_action_create(portid_t port_id, uint32_t id, + const struct rte_flow_shared_action_conf *conf, + const struct rte_flow_action *action) +{ + struct port_shared_action *psa; + int ret; + struct rte_flow_error error; + + ret = action_alloc(port_id, id, &psa); + if (ret) + return ret; + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x22, sizeof(error)); + psa->action = rte_flow_shared_action_create(port_id, conf, action, + &error); + if (!psa->action) { + uint32_t destroy_id = psa->id; + port_shared_action_destroy(port_id, 1, &destroy_id); + return port_flow_complain(&error); + } + psa->type = action->type; + printf("Shared action #%u created\n", psa->id); + return 0; +} + +/** Destroy shared action */ +int +port_shared_action_destroy(portid_t port_id, + uint32_t n, + const uint32_t *actions) +{ + struct rte_port *port; + struct port_shared_action **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + tmp = &port->actions_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_shared_action *psa = *tmp; + + if (actions[i] != psa->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x33, sizeof(error)); + + if (psa->action && rte_flow_shared_action_destroy( + port_id, psa->action, &error)) { + ret = port_flow_complain(&error); + continue; + } + *tmp = psa->next; + free(psa); + printf("Shared action #%u destroyed\n", psa->id); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + + +/** Get shared action by port + id */ +struct rte_flow_shared_action * +port_shared_action_get_by_id(portid_t port_id, uint32_t id) +{ + + struct port_shared_action *psa = action_get_by_id(port_id, id); + + return (psa) ? psa->action : NULL; +} + +/** Update shared action */ +int +port_shared_action_update(portid_t port_id, uint32_t id, + const struct rte_flow_action *action) +{ + struct rte_flow_error error; + struct rte_flow_shared_action *shared_action; + + shared_action = port_shared_action_get_by_id(port_id, id); + if (!shared_action) + return -EINVAL; + if (rte_flow_shared_action_update(port_id, shared_action, action, + &error)) { + return port_flow_complain(&error); + } + printf("Shared action #%u updated\n", id); + return 0; +} + +int +port_shared_action_query(portid_t port_id, uint32_t id) +{ + struct rte_flow_error error; + struct port_shared_action *psa; + uint64_t default_data; + void *data = NULL; + int ret = 0; + + psa = action_get_by_id(port_id, id); + if (!psa) + return -EINVAL; + switch (psa->type) { + case RTE_FLOW_ACTION_TYPE_RSS: + data = &default_data; + break; + default: + printf("Shared action %u (type: %d) on port %u doesn't support" + " query\n", id, psa->type, port_id); + return -1; + } + if (rte_flow_shared_action_query(port_id, psa->action, data, &error)) + ret = port_flow_complain(&error); + switch (psa->type) { + case RTE_FLOW_ACTION_TYPE_RSS: + if (!ret) + printf("Shared RSS action:\n\trefs:%u\n", + *((uint32_t *)data)); + data = NULL; + break; + default: + printf("Shared action %u (type: %d) on port %u doesn't support" + " query\n", id, psa->type, port_id); + ret = -1; + } + return ret; +} +static struct port_flow_tunnel * +port_flow_tunnel_offload_cmd_prep(portid_t port_id, + const struct rte_flow_item *pattern, + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) +{ + int ret; + struct rte_port *port; + struct port_flow_tunnel *pft; + struct rte_flow_error error; + + port = &ports[port_id]; + pft = port_flow_locate_tunnel_id(port, tunnel_ops->id); + if (!pft) { + printf("failed to locate port flow tunnel #%u\n", + tunnel_ops->id); + return NULL; + } + if (tunnel_ops->actions) { + uint32_t num_actions; + const struct rte_flow_action *aptr; + + ret = rte_flow_tunnel_decap_set(port_id, &pft->tunnel, + &pft->pmd_actions, + &pft->num_pmd_actions, + &error); + if (ret) { + port_flow_complain(&error); + return NULL; + } + for (aptr = actions, num_actions = 1; + aptr->type != RTE_FLOW_ACTION_TYPE_END; + aptr++, num_actions++); + pft->actions = malloc( + (num_actions + pft->num_pmd_actions) * + sizeof(actions[0])); + if (!pft->actions) { + rte_flow_tunnel_action_decap_release( + port_id, pft->actions, + pft->num_pmd_actions, &error); + return NULL; + } + rte_memcpy(pft->actions, pft->pmd_actions, + pft->num_pmd_actions * sizeof(actions[0])); + rte_memcpy(pft->actions + pft->num_pmd_actions, actions, + num_actions * sizeof(actions[0])); + } + if (tunnel_ops->items) { + uint32_t num_items; + const struct rte_flow_item *iptr; + + ret = rte_flow_tunnel_match(port_id, &pft->tunnel, + &pft->pmd_items, + &pft->num_pmd_items, + &error); + if (ret) { + port_flow_complain(&error); + return NULL; + } + for (iptr = pattern, num_items = 1; + iptr->type != RTE_FLOW_ITEM_TYPE_END; + iptr++, num_items++); + pft->items = malloc((num_items + pft->num_pmd_items) * + sizeof(pattern[0])); + if (!pft->items) { + rte_flow_tunnel_item_release( + port_id, pft->pmd_items, + pft->num_pmd_items, &error); + return NULL; + } + rte_memcpy(pft->items, pft->pmd_items, + pft->num_pmd_items * sizeof(pattern[0])); + rte_memcpy(pft->items + pft->num_pmd_items, pattern, + num_items * sizeof(pattern[0])); + } + + return pft; +} + +static void +port_flow_tunnel_offload_cmd_release(portid_t port_id, + const struct tunnel_ops *tunnel_ops, + struct port_flow_tunnel *pft) +{ + struct rte_flow_error error; + + if (tunnel_ops->actions) { + free(pft->actions); + rte_flow_tunnel_action_decap_release( + port_id, pft->pmd_actions, + pft->num_pmd_actions, &error); + pft->actions = NULL; + pft->pmd_actions = NULL; + } + if (tunnel_ops->items) { + free(pft->items); + rte_flow_tunnel_item_release(port_id, pft->pmd_items, + pft->num_pmd_items, + &error); + pft->items = NULL; + pft->pmd_items = NULL; + } +} + /** Validate flow rule. */ int port_flow_validate(portid_t port_id, const struct rte_flow_attr *attr, const struct rte_flow_item *pattern, - const struct rte_flow_action *actions) + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) { struct rte_flow_error error; + struct port_flow_tunnel *pft = NULL; /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x11, sizeof(error)); + if (tunnel_ops->enabled) { + pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, + actions, tunnel_ops); + if (!pft) + return -ENOENT; + if (pft->items) + pattern = pft->items; + if (pft->actions) + actions = pft->actions; + } if (rte_flow_validate(port_id, attr, pattern, actions, &error)) return port_flow_complain(&error); + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); printf("Flow rule validated\n"); return 0; } +/** Update age action context by port_flow pointer. */ +void +update_age_action_context(const struct rte_flow_action *actions, + struct port_flow *pf) +{ + struct rte_flow_action_age *age = NULL; + + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_AGE: + age = (struct rte_flow_action_age *) + (uintptr_t)actions->conf; + age->context = pf; + return; + default: + break; + } + } +} + /** Create flow rule. */ int port_flow_create(portid_t port_id, const struct rte_flow_attr *attr, const struct rte_flow_item *pattern, - const struct rte_flow_action *actions) + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) { struct rte_flow *flow; struct rte_port *port; struct port_flow *pf; - uint32_t id; + uint32_t id = 0; struct rte_flow_error error; + struct port_flow_tunnel *pft = NULL; - /* Poisoning to make sure PMDs update it in case of error. */ - memset(&error, 0x22, sizeof(error)); - flow = rte_flow_create(port_id, attr, pattern, actions, &error); - if (!flow) - return port_flow_complain(&error); port = &ports[port_id]; if (port->flow_list) { if (port->flow_list->id == UINT32_MAX) { printf("Highest rule ID is already assigned, delete" " it first"); - rte_flow_destroy(port_id, flow, NULL); return -ENOMEM; } id = port->flow_list->id + 1; - } else - id = 0; + } + if (tunnel_ops->enabled) { + pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, + actions, tunnel_ops); + if (!pft) + return -ENOENT; + if (pft->items) + pattern = pft->items; + if (pft->actions) + actions = pft->actions; + } pf = port_flow_new(attr, pattern, actions, &error); - if (!pf) { - rte_flow_destroy(port_id, flow, NULL); + if (!pf) + return port_flow_complain(&error); + update_age_action_context(actions, pf); + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x22, sizeof(error)); + flow = rte_flow_create(port_id, attr, pattern, actions, &error); + if (!flow) { + free(pf); return port_flow_complain(&error); } pf->next = port->flow_list; pf->id = id; pf->flow = flow; port->flow_list = pf; + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); printf("Flow rule #%u created\n", pf->id); return 0; } @@ -1441,15 +2231,21 @@ port_flow_flush(portid_t port_id) struct rte_port *port; int ret = 0; + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + + port = &ports[port_id]; + + if (port->flow_list == NULL) + return ret; + /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x44, sizeof(error)); if (rte_flow_flush(port_id, &error)) { - ret = port_flow_complain(&error); - if (port_id_is_invalid(port_id, DISABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return ret; + port_flow_complain(&error); } - port = &ports[port_id]; + while (port->flow_list) { struct port_flow *pf = port->flow_list->next; @@ -1497,6 +2293,8 @@ port_flow_query(portid_t port_id, uint32_t rule, const char *name; union { struct rte_flow_query_count count; + struct rte_flow_action_rss rss_conf; + struct rte_flow_query_age age; } query; int ret; @@ -1518,6 +2316,8 @@ port_flow_query(portid_t port_id, uint32_t rule, return port_flow_complain(&error); switch (action->type) { case RTE_FLOW_ACTION_TYPE_COUNT: + case RTE_FLOW_ACTION_TYPE_RSS: + case RTE_FLOW_ACTION_TYPE_AGE: break; default: printf("Cannot query action type %d (%s)\n", @@ -1542,6 +2342,19 @@ port_flow_query(portid_t port_id, uint32_t rule, query.count.hits, query.count.bytes); break; + case RTE_FLOW_ACTION_TYPE_RSS: + rss_config_display(&query.rss_conf); + break; + case RTE_FLOW_ACTION_TYPE_AGE: + printf("%s:\n" + " aged: %u\n" + " sec_since_last_hit_valid: %u\n" + " sec_since_last_hit: %" PRIu32 "\n", + name, + query.age.aged, + query.age.sec_since_last_hit_valid, + query.age.sec_since_last_hit); + break; default: printf("Cannot display result for action type %d (%s)\n", action->type, name); @@ -1550,9 +2363,76 @@ port_flow_query(portid_t port_id, uint32_t rule, return 0; } +/** List simply and destroy all aged flows. */ +void +port_flow_aged(portid_t port_id, uint8_t destroy) +{ + void **contexts; + int nb_context, total = 0, idx; + struct rte_flow_error error; + struct port_flow *pf; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return; + total = rte_flow_get_aged_flows(port_id, NULL, 0, &error); + printf("Port %u total aged flows: %d\n", port_id, total); + if (total < 0) { + port_flow_complain(&error); + return; + } + if (total == 0) + return; + contexts = malloc(sizeof(void *) * total); + if (contexts == NULL) { + printf("Cannot allocate contexts for aged flow\n"); + return; + } + printf("ID\tGroup\tPrio\tAttr\n"); + nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error); + if (nb_context != total) { + printf("Port:%d get aged flows count(%d) != total(%d)\n", + port_id, nb_context, total); + free(contexts); + return; + } + for (idx = 0; idx < nb_context; idx++) { + pf = (struct port_flow *)contexts[idx]; + if (!pf) { + printf("Error: get Null context in port %u\n", port_id); + continue; + } + printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t\n", + pf->id, + pf->rule.attr->group, + pf->rule.attr->priority, + pf->rule.attr->ingress ? 'i' : '-', + pf->rule.attr->egress ? 'e' : '-', + pf->rule.attr->transfer ? 't' : '-'); + } + if (destroy) { + int ret; + uint32_t flow_id; + + total = 0; + printf("\n"); + for (idx = 0; idx < nb_context; idx++) { + pf = (struct port_flow *)contexts[idx]; + if (!pf) + continue; + flow_id = pf->id; + ret = port_flow_destroy(port_id, 1, &flow_id); + if (!ret) + total++; + } + printf("%d flows be destroyed\n", total); + } + free(contexts); +} + /** List flow rules. */ void -port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n]) +port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group) { struct rte_port *port; struct port_flow *pf; @@ -1607,7 +2487,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n]) pf->rule.attr->egress ? 'e' : '-', pf->rule.attr->transfer ? 't' : '-'); while (item->type != RTE_FLOW_ITEM_TYPE_END) { - if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR, + if ((uint32_t)item->type > INT_MAX) + name = "PMD_INTERNAL"; + else if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR, &name, sizeof(name), (void *)(uintptr_t)item->type, NULL) <= 0) @@ -1618,7 +2500,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n]) } printf("=>"); while (action->type != RTE_FLOW_ACTION_TYPE_END) { - if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, + if ((uint32_t)action->type > INT_MAX) + name = "PMD_INTERNAL"; + else if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, &name, sizeof(name), (void *)(uintptr_t)action->type, NULL) <= 0) @@ -1669,22 +2553,102 @@ tx_queue_id_is_invalid(queueid_t txq_id) } static int -rx_desc_id_is_invalid(uint16_t rxdesc_id) +get_rx_ring_size(portid_t port_id, queueid_t rxq_id, uint16_t *ring_size) { - if (rxdesc_id < nb_rxd) + struct rte_port *port = &ports[port_id]; + struct rte_eth_rxq_info rx_qinfo; + int ret; + + ret = rte_eth_rx_queue_info_get(port_id, rxq_id, &rx_qinfo); + if (ret == 0) { + *ring_size = rx_qinfo.nb_desc; + return ret; + } + + if (ret != -ENOTSUP) + return ret; + /* + * If the rte_eth_rx_queue_info_get is not support for this PMD, + * ring_size stored in testpmd will be used for validity verification. + * When configure the rxq by rte_eth_rx_queue_setup with nb_rx_desc + * being 0, it will use a default value provided by PMDs to setup this + * rxq. If the default value is 0, it will use the + * RTE_ETH_DEV_FALLBACK_RX_RINGSIZE to setup this rxq. + */ + if (port->nb_rx_desc[rxq_id]) + *ring_size = port->nb_rx_desc[rxq_id]; + else if (port->dev_info.default_rxportconf.ring_size) + *ring_size = port->dev_info.default_rxportconf.ring_size; + else + *ring_size = RTE_ETH_DEV_FALLBACK_RX_RINGSIZE; + return 0; +} + +static int +get_tx_ring_size(portid_t port_id, queueid_t txq_id, uint16_t *ring_size) +{ + struct rte_port *port = &ports[port_id]; + struct rte_eth_txq_info tx_qinfo; + int ret; + + ret = rte_eth_tx_queue_info_get(port_id, txq_id, &tx_qinfo); + if (ret == 0) { + *ring_size = tx_qinfo.nb_desc; + return ret; + } + + if (ret != -ENOTSUP) + return ret; + /* + * If the rte_eth_tx_queue_info_get is not support for this PMD, + * ring_size stored in testpmd will be used for validity verification. + * When configure the txq by rte_eth_tx_queue_setup with nb_tx_desc + * being 0, it will use a default value provided by PMDs to setup this + * txq. If the default value is 0, it will use the + * RTE_ETH_DEV_FALLBACK_TX_RINGSIZE to setup this txq. + */ + if (port->nb_tx_desc[txq_id]) + *ring_size = port->nb_tx_desc[txq_id]; + else if (port->dev_info.default_txportconf.ring_size) + *ring_size = port->dev_info.default_txportconf.ring_size; + else + *ring_size = RTE_ETH_DEV_FALLBACK_TX_RINGSIZE; + return 0; +} + +static int +rx_desc_id_is_invalid(portid_t port_id, queueid_t rxq_id, uint16_t rxdesc_id) +{ + uint16_t ring_size; + int ret; + + ret = get_rx_ring_size(port_id, rxq_id, &ring_size); + if (ret) + return 1; + + if (rxdesc_id < ring_size) return 0; - printf("Invalid RX descriptor %d (must be < nb_rxd=%d)\n", - rxdesc_id, nb_rxd); + + printf("Invalid RX descriptor %u (must be < ring_size=%u)\n", + rxdesc_id, ring_size); return 1; } static int -tx_desc_id_is_invalid(uint16_t txdesc_id) +tx_desc_id_is_invalid(portid_t port_id, queueid_t txq_id, uint16_t txdesc_id) { - if (txdesc_id < nb_txd) + uint16_t ring_size; + int ret; + + ret = get_tx_ring_size(port_id, txq_id, &ring_size); + if (ret) + return 1; + + if (txdesc_id < ring_size) return 0; - printf("Invalid TX descriptor %d (must be < nb_txd=%d)\n", - txdesc_id, nb_txd); + + printf("Invalid TX descriptor %u (must be < ring_size=%u)\n", + txdesc_id, ring_size); return 1; } @@ -1805,11 +2769,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, ENABLED_WARN)) - return; - if (rx_queue_id_is_invalid(rxq_id)) - return; - if (rx_desc_id_is_invalid(rxd_id)) + if (rx_desc_id_is_invalid(port_id, rxq_id, rxd_id)) return; rx_mz = ring_dma_zone_lookup("rx_ring", port_id, rxq_id); if (rx_mz == NULL) @@ -1822,11 +2782,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, ENABLED_WARN)) - return; - if (tx_queue_id_is_invalid(txq_id)) - return; - if (tx_desc_id_is_invalid(txd_id)) + if (tx_desc_id_is_invalid(port_id, txq_id, txd_id)) return; tx_mz = ring_dma_zone_lookup("tx_ring", port_id, txq_id); if (tx_mz == NULL) @@ -1867,10 +2823,17 @@ rxtx_config_display(void) struct rte_eth_txconf *tx_conf = &ports[pid].tx_conf[0]; uint16_t *nb_rx_desc = &ports[pid].nb_rx_desc[0]; uint16_t *nb_tx_desc = &ports[pid].nb_tx_desc[0]; - uint16_t nb_rx_desc_tmp; - uint16_t nb_tx_desc_tmp; struct rte_eth_rxq_info rx_qinfo; struct rte_eth_txq_info tx_qinfo; + uint16_t rx_free_thresh_tmp; + uint16_t tx_free_thresh_tmp; + uint16_t tx_rs_thresh_tmp; + uint16_t nb_rx_desc_tmp; + uint16_t nb_tx_desc_tmp; + uint64_t offloads_tmp; + uint8_t pthresh_tmp; + uint8_t hthresh_tmp; + uint8_t wthresh_tmp; int32_t rc; /* per port config */ @@ -1884,41 +2847,64 @@ rxtx_config_display(void) /* per rx queue config only for first queue to be less verbose */ for (qid = 0; qid < 1; qid++) { rc = rte_eth_rx_queue_info_get(pid, qid, &rx_qinfo); - if (rc) + if (rc) { nb_rx_desc_tmp = nb_rx_desc[qid]; - else + rx_free_thresh_tmp = + rx_conf[qid].rx_free_thresh; + pthresh_tmp = rx_conf[qid].rx_thresh.pthresh; + hthresh_tmp = rx_conf[qid].rx_thresh.hthresh; + wthresh_tmp = rx_conf[qid].rx_thresh.wthresh; + offloads_tmp = rx_conf[qid].offloads; + } else { nb_rx_desc_tmp = rx_qinfo.nb_desc; + rx_free_thresh_tmp = + rx_qinfo.conf.rx_free_thresh; + pthresh_tmp = rx_qinfo.conf.rx_thresh.pthresh; + hthresh_tmp = rx_qinfo.conf.rx_thresh.hthresh; + wthresh_tmp = rx_qinfo.conf.rx_thresh.wthresh; + offloads_tmp = rx_qinfo.conf.offloads; + } printf(" RX queue: %d\n", qid); printf(" RX desc=%d - RX free threshold=%d\n", - nb_rx_desc_tmp, rx_conf[qid].rx_free_thresh); + nb_rx_desc_tmp, rx_free_thresh_tmp); printf(" RX threshold registers: pthresh=%d hthresh=%d " " wthresh=%d\n", - rx_conf[qid].rx_thresh.pthresh, - rx_conf[qid].rx_thresh.hthresh, - rx_conf[qid].rx_thresh.wthresh); - printf(" RX Offloads=0x%"PRIx64"\n", - rx_conf[qid].offloads); + pthresh_tmp, hthresh_tmp, wthresh_tmp); + printf(" RX Offloads=0x%"PRIx64"\n", offloads_tmp); } /* per tx queue config only for first queue to be less verbose */ for (qid = 0; qid < 1; qid++) { rc = rte_eth_tx_queue_info_get(pid, qid, &tx_qinfo); - if (rc) + if (rc) { nb_tx_desc_tmp = nb_tx_desc[qid]; - else + tx_free_thresh_tmp = + tx_conf[qid].tx_free_thresh; + pthresh_tmp = tx_conf[qid].tx_thresh.pthresh; + hthresh_tmp = tx_conf[qid].tx_thresh.hthresh; + wthresh_tmp = tx_conf[qid].tx_thresh.wthresh; + offloads_tmp = tx_conf[qid].offloads; + tx_rs_thresh_tmp = tx_conf[qid].tx_rs_thresh; + } else { nb_tx_desc_tmp = tx_qinfo.nb_desc; + tx_free_thresh_tmp = + tx_qinfo.conf.tx_free_thresh; + pthresh_tmp = tx_qinfo.conf.tx_thresh.pthresh; + hthresh_tmp = tx_qinfo.conf.tx_thresh.hthresh; + wthresh_tmp = tx_qinfo.conf.tx_thresh.wthresh; + offloads_tmp = tx_qinfo.conf.offloads; + tx_rs_thresh_tmp = tx_qinfo.conf.tx_rs_thresh; + } printf(" TX queue: %d\n", qid); printf(" TX desc=%d - TX free threshold=%d\n", - nb_tx_desc_tmp, tx_conf[qid].tx_free_thresh); + nb_tx_desc_tmp, tx_free_thresh_tmp); printf(" TX threshold registers: pthresh=%d hthresh=%d " " wthresh=%d\n", - tx_conf[qid].tx_thresh.pthresh, - tx_conf[qid].tx_thresh.hthresh, - tx_conf[qid].tx_thresh.wthresh); + pthresh_tmp, hthresh_tmp, wthresh_tmp); printf(" TX offloads=0x%"PRIx64" - TX RS bit threshold=%d\n", - tx_conf[qid].offloads, tx_conf->tx_rs_thresh); + offloads_tmp, tx_rs_thresh_tmp); } } } @@ -2353,55 +3339,6 @@ icmp_echo_config_setup(void) } } -#if defined RTE_LIBRTE_PMD_SOFTNIC -static void -softnic_fwd_config_setup(void) -{ - struct rte_port *port; - portid_t pid, softnic_portid; - queueid_t i; - uint8_t softnic_enable = 0; - - RTE_ETH_FOREACH_DEV(pid) { - port = &ports[pid]; - const char *driver = port->dev_info.driver_name; - - if (strcmp(driver, "net_softnic") == 0) { - softnic_portid = pid; - softnic_enable = 1; - break; - } - } - - if (softnic_enable == 0) { - printf("Softnic mode not configured(%s)!\n", __func__); - return; - } - - cur_fwd_config.nb_fwd_ports = 1; - cur_fwd_config.nb_fwd_streams = (streamid_t) nb_rxq; - - /* Re-initialize forwarding streams */ - init_fwd_streams(); - - /* - * In the softnic forwarding test, the number of forwarding cores - * is set to one and remaining are used for softnic packet processing. - */ - cur_fwd_config.nb_fwd_lcores = 1; - setup_fwd_config_of_each_lcore(&cur_fwd_config); - - for (i = 0; i < cur_fwd_config.nb_fwd_streams; i++) { - fwd_streams[i]->rx_port = softnic_portid; - fwd_streams[i]->rx_queue = i; - fwd_streams[i]->tx_port = softnic_portid; - fwd_streams[i]->tx_queue = i; - fwd_streams[i]->peer_addr = fwd_streams[i]->tx_port; - fwd_streams[i]->retry_enabled = retry_enabled; - } -} -#endif - void fwd_config_setup(void) { @@ -2411,13 +3348,6 @@ fwd_config_setup(void) return; } -#if defined RTE_LIBRTE_PMD_SOFTNIC - if (strcmp(cur_fwd_eng->fwd_mode_name, "softnic") == 0) { - softnic_fwd_config_setup(); - return; - } -#endif - if ((nb_rxq > 1) && (nb_txq > 1)){ if (dcb_config) dcb_fwd_config_setup(); @@ -2616,9 +3546,6 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt) * If the user wants to use only the ports 1,2 then the input * is 1,2. * valid characters are '-' and ',' - * invalid chars like '.' or '#' will result in - * EAL: Error - exiting with code: 1 - * Cause: Invalid fwd port list * @param[out] values * This array will be filled with a list of port IDs * based on the user input @@ -2630,7 +3557,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt) * 1) Number of elements in the values array * 2) Maximum value of each element in the values array * @return - * -returns total count of parsed port IDs + * On success, returns total count of parsed port IDs + * On failure, returns 0 */ static unsigned int parse_port_list(const char *list, unsigned int *values, unsigned int maxsize) @@ -2642,7 +3570,7 @@ parse_port_list(const char *list, unsigned int *values, unsigned int maxsize) unsigned int marked[maxsize]; if (list == NULL || values == NULL) - return -1; + return 0; for (i = 0; i < (int)maxsize; i++) marked[i] = 0; @@ -2803,6 +3731,40 @@ set_tx_pkt_split(const char *name) printf("unknown value: \"%s\"\n", name); } +int +parse_fec_mode(const char *name, uint32_t *mode) +{ + uint8_t i; + + for (i = 0; i < RTE_DIM(fec_mode_name); i++) { + if (strcmp(fec_mode_name[i].name, name) == 0) { + *mode = RTE_ETH_FEC_MODE_TO_CAPA(fec_mode_name[i].mode); + return 0; + } + } + return -1; +} + +void +show_fec_capability(unsigned int num, struct rte_eth_fec_capa *speed_fec_capa) +{ + unsigned int i, j; + + printf("FEC capabilities:\n"); + + for (i = 0; i < num; i++) { + printf("%s : ", + rte_eth_link_speed_to_str(speed_fec_capa[i].speed)); + + for (j = RTE_ETH_FEC_AUTO; j < RTE_DIM(fec_mode_name); j++) { + if (RTE_ETH_FEC_MODE_TO_CAPA(j) & + speed_fec_capa[i].capa) + printf("%s ", fec_mode_name[j].name); + } + printf("\n"); + } +} + void show_tx_pkt_segments(void) { @@ -2820,17 +3782,41 @@ show_tx_pkt_segments(void) printf("Split packet: %s\n", split); } +static bool +nb_segs_is_invalid(unsigned int nb_segs) +{ + uint16_t ring_size; + uint16_t queue_id; + uint16_t port_id; + int ret; + + RTE_ETH_FOREACH_DEV(port_id) { + for (queue_id = 0; queue_id < nb_txq; queue_id++) { + ret = get_tx_ring_size(port_id, queue_id, &ring_size); + + if (ret) + return true; + + if (ring_size < nb_segs) { + printf("nb segments per TX packets=%u >= " + "TX queue(%u) ring_size=%u - ignored\n", + nb_segs, queue_id, ring_size); + return true; + } + } + } + + return false; +} + void set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs) { uint16_t tx_pkt_len; unsigned i; - if (nb_segs >= (unsigned) nb_txd) { - printf("nb segments per TX packets=%u >= nb_txd=%u - ignored\n", - nb_segs, (unsigned int) nb_txd); + if (nb_segs_is_invalid(nb_segs)) return; - } /* * Check that each segment length is greater or equal than @@ -2862,6 +3848,58 @@ set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs) tx_pkt_nb_segs = (uint8_t) nb_segs; } +void +show_tx_pkt_times(void) +{ + printf("Interburst gap: %u\n", tx_pkt_times_inter); + printf("Intraburst gap: %u\n", tx_pkt_times_intra); +} + +void +set_tx_pkt_times(unsigned int *tx_times) +{ + uint16_t port_id; + int offload_found = 0; + int offset; + int flag; + + static const struct rte_mbuf_dynfield desc_offs = { + .name = RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, + .size = sizeof(uint64_t), + .align = __alignof__(uint64_t), + }; + static const struct rte_mbuf_dynflag desc_flag = { + .name = RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, + }; + + RTE_ETH_FOREACH_DEV(port_id) { + struct rte_eth_dev_info dev_info = { 0 }; + int ret; + + ret = rte_eth_dev_info_get(port_id, &dev_info); + if (ret == 0 && dev_info.tx_offload_capa & + DEV_TX_OFFLOAD_SEND_ON_TIMESTAMP) { + offload_found = 1; + break; + } + } + if (!offload_found) { + printf("No device supporting Tx timestamp scheduling found, " + "dynamic flag and field not registered\n"); + return; + } + offset = rte_mbuf_dynfield_register(&desc_offs); + if (offset < 0 && rte_errno != EEXIST) + printf("Dynamic timestamp field registration error: %d", + rte_errno); + flag = rte_mbuf_dynflag_register(&desc_flag); + if (flag < 0 && rte_errno != EEXIST) + printf("Dynamic timestamp flag registration error: %d", + rte_errno); + tx_pkt_times_inter = tx_times[0]; + tx_pkt_times_intra = tx_times[1]; +} + void setup_gro(const char *onoff, portid_t port_id) { @@ -3174,9 +4212,11 @@ vlan_extend_set(portid_t port_id, int on) } diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); - if (diag < 0) + if (diag < 0) { printf("rx_vlan_extend_set(port_pi=%d, on=%d) failed " "diag=%d\n", port_id, on, diag); + return; + } ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; } @@ -3201,9 +4241,11 @@ rx_vlan_strip_set(portid_t port_id, int on) } diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); - if (diag < 0) + if (diag < 0) { printf("rx_vlan_strip_set(port_pi=%d, on=%d) failed " "diag=%d\n", port_id, on, diag); + return; + } ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; } @@ -3242,9 +4284,11 @@ rx_vlan_filter_set(portid_t port_id, int on) } diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); - if (diag < 0) + if (diag < 0) { printf("rx_vlan_filter_set(port_pi=%d, on=%d) failed " "diag=%d\n", port_id, on, diag); + return; + } ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; } @@ -3269,9 +4313,11 @@ rx_vlan_qinq_strip_set(portid_t port_id, int on) } diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); - if (diag < 0) + if (diag < 0) { printf("%s(port_pi=%d, on=%d) failed " "diag=%d\n", __func__, port_id, on, diag); + return; + } ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; } @@ -3329,8 +4375,6 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id) struct rte_eth_dev_info dev_info; int ret; - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return; if (vlan_id_is_invalid(vlan_id)) return; @@ -3361,8 +4405,6 @@ tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer) struct rte_eth_dev_info dev_info; int ret; - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return; if (vlan_id_is_invalid(vlan_id)) return; if (vlan_id_is_invalid(vlan_id_outer)) @@ -3388,8 +4430,6 @@ tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer) void tx_vlan_reset(portid_t port_id) { - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return; ports[port_id].dev_conf.txmode.offloads &= ~(DEV_TX_OFFLOAD_VLAN_INSERT | DEV_TX_OFFLOAD_QINQ_INSERT); @@ -3464,6 +4504,18 @@ set_xstats_hide_zero(uint8_t on_off) xstats_hide_zero = on_off; } +void +set_record_core_cycles(uint8_t on_off) +{ + record_core_cycles = on_off; +} + +void +set_record_burst_stats(uint8_t on_off) +{ + record_burst_stats = on_off; +} + static inline void print_fdir_mask(struct rte_eth_fdir_masks *mask) { @@ -3597,30 +4649,65 @@ print_fdir_flow_type(uint32_t flow_types_mask) printf("\n"); } +static int +get_fdir_info(portid_t port_id, struct rte_eth_fdir_info *fdir_info, + struct rte_eth_fdir_stats *fdir_stat) +{ + int ret; + + ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR); + if (!ret) { + rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, + RTE_ETH_FILTER_INFO, fdir_info); + rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, + RTE_ETH_FILTER_STATS, fdir_stat); + return 0; + } + +#ifdef RTE_LIBRTE_I40E_PMD + if (ret == -ENOTSUP) { + ret = rte_pmd_i40e_get_fdir_info(port_id, fdir_info); + if (!ret) + ret = rte_pmd_i40e_get_fdir_stats(port_id, fdir_stat); + } +#endif +#ifdef RTE_LIBRTE_IXGBE_PMD + if (ret == -ENOTSUP) { + ret = rte_pmd_ixgbe_get_fdir_info(port_id, fdir_info); + if (!ret) + ret = rte_pmd_ixgbe_get_fdir_stats(port_id, fdir_stat); + } +#endif + switch (ret) { + case 0: + break; + case -ENOTSUP: + printf("\n FDIR is not supported on port %-2d\n", + port_id); + break; + default: + printf("programming error: (%s)\n", strerror(-ret)); + break; + } + return ret; +} + void fdir_get_infos(portid_t port_id) { struct rte_eth_fdir_stats fdir_stat; struct rte_eth_fdir_info fdir_info; - int ret; static const char *fdir_stats_border = "########################"; 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) { - printf("\n FDIR is not supported on port %-2d\n", - port_id); - return; - } memset(&fdir_info, 0, sizeof(fdir_info)); - rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, - RTE_ETH_FILTER_INFO, &fdir_info); memset(&fdir_stat, 0, sizeof(fdir_stat)); - rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, - RTE_ETH_FILTER_STATS, &fdir_stat); + if (get_fdir_info(port_id, &fdir_info, &fdir_stat)) + return; + printf("\n %s FDIR infos for port %-2d %s\n", fdir_stats_border, port_id, fdir_stats_border); printf(" MODE: "); @@ -3769,7 +4856,8 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate) ret = eth_link_get_nowait_print_err(port_id, &link); if (ret < 0) return 1; - if (rate > link.link_speed) { + if (link.link_speed != ETH_SPEED_NUM_UNKNOWN && + rate > link.link_speed) { printf("Invalid rate value:%u bigger than link speed: %u\n", rate, link.link_speed); return 1;