app/testpmd: support RSS config in flow query
[dpdk.git] / app / test-pmd / config.c
index 035d336..53a9b97 100644 (file)
 
 #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 {
@@ -77,7 +85,8 @@ static const struct {
 const struct rss_type_info rss_type_table[] = {
        { "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_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 },
@@ -118,6 +127,8 @@ const struct rss_type_info rss_type_table[] = {
        { "ah", ETH_RSS_AH },
        { "l2tpv3", ETH_RSS_L2TPV3 },
        { "pfcp", ETH_RSS_PFCP },
+       { "pppoe", ETH_RSS_PPPOE },
+       { "gtpu", ETH_RSS_GTPU },
        { NULL, 0 },
 };
 
@@ -136,9 +147,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];
@@ -195,10 +207,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;
@@ -206,10 +225,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;
@@ -217,10 +236,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"
@@ -234,11 +253,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);
 }
 
@@ -314,10 +350,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;
        }
 }
 
@@ -1253,8 +1300,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
@@ -1269,10 +1317,7 @@ 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. */
@@ -1350,6 +1395,56 @@ 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\n");
+       for (i = 0; i < rss_conf->queue_num; i++)
+               printf("%d\n", rss_conf->queue[i]);
+
+       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);
+       }
+}
+
 /** Validate flow rule. */
 int
 port_flow_validate(portid_t port_id,
@@ -1536,6 +1631,7 @@ 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;
        } query;
        int ret;
 
@@ -1557,6 +1653,7 @@ 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:
                break;
        default:
                printf("Cannot query action type %d (%s)\n",
@@ -1581,6 +1678,9 @@ 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;
        default:
                printf("Cannot display result for action type %d (%s)\n",
                       action->type, name);
@@ -3701,30 +3801,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: ");