diff options
Diffstat (limited to 'platform/linux-generic/pktio/dpdk.c')
-rw-r--r-- | platform/linux-generic/pktio/dpdk.c | 269 |
1 files changed, 211 insertions, 58 deletions
diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 5d5fead16..4841402aa 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -138,7 +138,8 @@ typedef struct ODP_ALIGNED_CACHE { struct rte_mempool *pkt_pool; /**< DPDK packet pool */ uint32_t data_room; /**< maximum packet length */ unsigned int min_rx_burst; /**< minimum RX burst size */ - odp_pktin_hash_proto_t hash; /**< Packet input hash protocol */ + /** RSS configuration */ + struct rte_eth_rss_conf rss_conf; /* Supported RTE_PTYPE_XXX flags in a mask */ uint32_t supported_ptypes; uint16_t mtu; /**< maximum transmission unit */ @@ -1131,7 +1132,7 @@ static int dpdk_vdev_promisc_mode_set(uint16_t port_id, int enable) return mode; } -static void rss_conf_to_hash_proto(struct rte_eth_rss_conf *rss_conf, +static void hash_proto_to_rss_conf(struct rte_eth_rss_conf *rss_conf, const odp_pktin_hash_proto_t *hash_proto) { if (hash_proto->proto.ipv4_udp) @@ -1154,34 +1155,19 @@ static void rss_conf_to_hash_proto(struct rte_eth_rss_conf *rss_conf, rss_conf->rss_key = NULL; } -static int dpdk_setup_eth_dev(pktio_entry_t *pktio_entry, - const struct rte_eth_dev_info *dev_info) +static int dpdk_setup_eth_dev(pktio_entry_t *pktio_entry) { int ret; pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); - struct rte_eth_rss_conf rss_conf; struct rte_eth_conf eth_conf; - uint64_t rss_hf_capa = dev_info->flow_type_rss_offloads; uint64_t rx_offloads = 0; uint64_t tx_offloads = 0; - memset(&rss_conf, 0, sizeof(struct rte_eth_rss_conf)); - - /* Always set some hash functions to enable DPDK RSS hash calculation. - * Hash capability has been checked in pktin config. */ - if (pkt_dpdk->hash.all_bits == 0) - rss_conf.rss_hf = ETH_RSS_IP | ETH_RSS_TCP | ETH_RSS_UDP; - else - rss_conf_to_hash_proto(&rss_conf, &pkt_dpdk->hash); - - /* Filter out unsupported flags */ - rss_conf.rss_hf &= rss_hf_capa; - memset(ð_conf, 0, sizeof(eth_conf)); eth_conf.rxmode.mq_mode = ETH_MQ_RX_RSS; eth_conf.txmode.mq_mode = ETH_MQ_TX_NONE; - eth_conf.rx_adv_conf.rss_conf = rss_conf; + eth_conf.rx_adv_conf.rss_conf = pkt_dpdk->rss_conf; /* Setup RX checksum offloads */ if (pktio_entry->s.config.pktin.bit.ipv4_chksum) @@ -1423,59 +1409,57 @@ static int dpdk_pktio_term(void) return 0; } -static int check_hash_proto(pktio_entry_t *pktio_entry, - const odp_pktin_queue_param_t *p) +static void prepare_rss_conf(pktio_entry_t *pktio_entry, + const odp_pktin_queue_param_t *p) { struct rte_eth_dev_info dev_info; uint64_t rss_hf_capa; pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); uint16_t port_id = pkt_dpdk->port_id; + memset(&pkt_dpdk->rss_conf, 0, sizeof(struct rte_eth_rss_conf)); + + if (!p->hash_enable) + return; + rte_eth_dev_info_get(port_id, &dev_info); rss_hf_capa = dev_info.flow_type_rss_offloads; + /* Print debug info about unsupported hash protocols */ if (p->hash_proto.proto.ipv4 && - ((rss_hf_capa & ETH_RSS_IPV4) == 0)) { - ODP_ERR("hash_proto.ipv4 not supported\n"); - return -1; - } + ((rss_hf_capa & ETH_RSS_IPV4) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4 not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv4_udp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_UDP) == 0)) { - ODP_ERR("hash_proto.ipv4_udp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_UDP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4_udp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv4_tcp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_TCP) == 0)) { - ODP_ERR("hash_proto.ipv4_tcp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_TCP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4_tcp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6 && - ((rss_hf_capa & ETH_RSS_IPV6) == 0)) { - ODP_ERR("hash_proto.ipv6 not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_IPV6) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6 not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6_udp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_UDP) == 0)) { - ODP_ERR("hash_proto.ipv6_udp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_UDP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6_udp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6_tcp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_TCP) == 0)) { - ODP_ERR("hash_proto.ipv6_tcp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_TCP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6_tcp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); - return 0; + hash_proto_to_rss_conf(&pkt_dpdk->rss_conf, &p->hash_proto); + + /* Filter out unsupported hash functions */ + pkt_dpdk->rss_conf.rss_hf &= rss_hf_capa; } static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, @@ -1484,8 +1468,7 @@ static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, odp_pktin_mode_t mode = pktio_entry->s.param.in_mode; uint8_t lockless; - if (p->hash_enable && check_hash_proto(pktio_entry, p)) - return -1; + prepare_rss_conf(pktio_entry, p); /** * Scheduler synchronizes input queue polls. Only single thread @@ -1496,9 +1479,6 @@ static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, else lockless = 0; - if (p->hash_enable && p->num_queues > 1) - pkt_priv(pktio_entry)->hash = p->hash_proto; - pkt_priv(pktio_entry)->lockless_rx = lockless; return 0; @@ -1633,6 +1613,21 @@ static int dpdk_init_capability(pktio_entry_t *pktio_entry, capa->config.pktout.bit.tcp_chksum; capa->config.pktout.bit.ts_ena = 1; + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.in_discards = 1; + capa->stats.pktio.counter.in_errors = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + capa->stats.pktio.counter.out_errors = 1; + + capa->stats.pktin_queue.counter.octets = 1; + capa->stats.pktin_queue.counter.packets = 1; + capa->stats.pktin_queue.counter.errors = 1; + + capa->stats.pktout_queue.counter.octets = 1; + capa->stats.pktout_queue.counter.packets = 1; + return 0; } @@ -1811,6 +1806,17 @@ static int dpdk_setup_eth_tx(pktio_entry_t *pktio_entry, } } + /* Set per queue statistics mappings. Not supported by all PMDs, so + * ignore the return value. */ + for (i = 0; i < pktio_entry->s.num_out_queue && i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { + ret = rte_eth_dev_set_tx_queue_stats_mapping(port_id, i, i); + if (ret) { + ODP_DBG("Mapping per TX queue statistics not supported: %d\n", ret); + break; + } + } + ODP_DBG("Mapped %" PRIu32 "/%d TX counters\n", i, RTE_ETHDEV_QUEUE_STAT_CNTRS); + return 0; } @@ -1839,6 +1845,17 @@ static int dpdk_setup_eth_rx(const pktio_entry_t *pktio_entry, } } + /* Set per queue statistics mappings. Not supported by all PMDs, so + * ignore the return value. */ + for (i = 0; i < pktio_entry->s.num_in_queue && i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { + ret = rte_eth_dev_set_rx_queue_stats_mapping(port_id, i, i); + if (ret) { + ODP_DBG("Mapping per RX queue statistics not supported: %d\n", ret); + break; + } + } + ODP_DBG("Mapped %" PRIu32 "/%d RX counters\n", i, RTE_ETHDEV_QUEUE_STAT_CNTRS); + return 0; } @@ -1901,7 +1918,7 @@ static int dpdk_start(pktio_entry_t *pktio_entry) rte_eth_dev_info_get(port_id, &dev_info); /* Setup device */ - if (dpdk_setup_eth_dev(pktio_entry, &dev_info)) { + if (dpdk_setup_eth_dev(pktio_entry)) { ODP_ERR("Failed to configure device\n"); return -1; } @@ -2225,7 +2242,138 @@ static int dpdk_stats(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats) static int dpdk_stats_reset(pktio_entry_t *pktio_entry) { - rte_eth_stats_reset(pkt_priv(pktio_entry)->port_id); + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + + (void)rte_eth_stats_reset(port_id); + (void)rte_eth_xstats_reset(port_id); + return 0; +} + +static int dpdk_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int num_stats, ret, i; + + num_stats = rte_eth_xstats_get_names(port_id, NULL, 0); + if (num_stats < 0) { + ODP_ERR("rte_eth_xstats_get_names() failed: %d\n", num_stats); + return num_stats; + } else if (info == NULL || num == 0 || num_stats == 0) { + return num_stats; + } + + struct rte_eth_xstat_name xstats_names[num_stats]; + + ret = rte_eth_xstats_get_names(port_id, xstats_names, num_stats); + if (ret < 0 || ret > num_stats) { + ODP_ERR("rte_eth_xstats_get_names() failed: %d\n", ret); + return -1; + } + num_stats = ret; + + for (i = 0; i < num && i < num_stats; i++) + strncpy(info[i].name, xstats_names[i].name, + ODP_PKTIO_STATS_EXTRA_NAME_LEN - 1); + + return num_stats; +} + +static int dpdk_extra_stats(pktio_entry_t *pktio_entry, + uint64_t stats[], int num) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int num_stats, ret, i; + + num_stats = rte_eth_xstats_get(port_id, NULL, 0); + if (num_stats < 0) { + ODP_ERR("rte_eth_xstats_get() failed: %d\n", num_stats); + return num_stats; + } else if (stats == NULL || num == 0 || num_stats == 0) { + return num_stats; + } + + struct rte_eth_xstat xstats[num_stats]; + + ret = rte_eth_xstats_get(port_id, xstats, num_stats); + if (ret < 0 || ret > num_stats) { + ODP_ERR("rte_eth_xstats_get() failed: %d\n", ret); + return -1; + } + num_stats = ret; + + for (i = 0; i < num && i < num_stats; i++) + stats[i] = xstats[i].value; + + return num_stats; +} + +static int dpdk_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + uint64_t xstat_id = id; + int ret; + + ret = rte_eth_xstats_get_by_id(port_id, &xstat_id, stat, 1); + if (ret != 1) { + ODP_ERR("rte_eth_xstats_get_by_id() failed: %d\n", ret); + return -1; + } + + return 0; +} + +static int dpdk_pktin_stats(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktin_queue_stats_t *pktin_stats) +{ + struct rte_eth_stats rte_stats; + int ret; + + if (odp_unlikely(index > RTE_ETHDEV_QUEUE_STAT_CNTRS - 1)) { + ODP_ERR("DPDK supports max %d per queue counters\n", + RTE_ETHDEV_QUEUE_STAT_CNTRS); + return -1; + } + + ret = rte_eth_stats_get(pkt_priv(pktio_entry)->port_id, &rte_stats); + if (odp_unlikely(ret)) { + ODP_ERR("Failed to read DPDK pktio stats: %d\n", ret); + return -1; + } + + memset(pktin_stats, 0, sizeof(odp_pktin_queue_stats_t)); + + pktin_stats->packets = rte_stats.q_ipackets[index]; + pktin_stats->octets = rte_stats.q_ibytes[index]; + pktin_stats->errors = rte_stats.q_errors[index]; + + return 0; +} + +static int dpdk_pktout_stats(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktout_queue_stats_t *pktout_stats) +{ + struct rte_eth_stats rte_stats; + int ret; + + if (odp_unlikely(index > RTE_ETHDEV_QUEUE_STAT_CNTRS - 1)) { + ODP_ERR("DPDK supports max %d per queue counters\n", + RTE_ETHDEV_QUEUE_STAT_CNTRS); + return -1; + } + + ret = rte_eth_stats_get(pkt_priv(pktio_entry)->port_id, &rte_stats); + if (odp_unlikely(ret)) { + ODP_ERR("Failed to read DPDK pktio stats: %d\n", ret); + return -1; + } + + memset(pktout_stats, 0, sizeof(odp_pktout_queue_stats_t)); + + pktout_stats->packets = rte_stats.q_opackets[index]; + pktout_stats->octets = rte_stats.q_obytes[index]; + return 0; } @@ -2240,6 +2388,11 @@ const pktio_if_ops_t _odp_dpdk_pktio_ops = { .stop = dpdk_stop, .stats = dpdk_stats, .stats_reset = dpdk_stats_reset, + .pktin_queue_stats = dpdk_pktin_stats, + .pktout_queue_stats = dpdk_pktout_stats, + .extra_stat_info = dpdk_extra_stat_info, + .extra_stats = dpdk_extra_stats, + .extra_stat_counter = dpdk_extra_stat_counter, .recv = dpdk_recv, .send = dpdk_send, .link_status = dpdk_link_status, |