patch the changes from 16.07 32/5232/1
authorHanoh Haim <[email protected]>
Sun, 8 Jan 2017 09:59:16 +0000 (11:59 +0200)
committerHanoh Haim <[email protected]>
Sun, 8 Jan 2017 09:59:16 +0000 (11:59 +0200)
Signed-off-by: Hanoh Haim <[email protected]>
src/dpdk/drivers/net/mlx5/mlx5.c
src/dpdk/drivers/net/mlx5/mlx5.h
src/dpdk/drivers/net/mlx5/mlx5_fdir.c
src/dpdk/drivers/net/mlx5/mlx5_rxq.c
src/dpdk/drivers/net/mlx5/mlx5_rxtx.h
src/dpdk/drivers/net/mlx5/mlx5_stats.c

index 7fc6ccf..7c07239 100644 (file)
@@ -181,6 +181,9 @@ mlx5_dev_close(struct rte_eth_dev *dev)
        }
        if (priv->reta_idx != NULL)
                rte_free(priv->reta_idx);
+
+    mlx5_stats_free(dev);
+
        priv_unlock(priv);
        memset(priv, 0, sizeof(*priv));
 }
@@ -1289,7 +1292,6 @@ rte_mlx5_pmd_init(void)
         * using this PMD, which is not supported in forked processes.
         */
        setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
-       ibv_fork_init();
        rte_eal_pci_register(&mlx5_driver.pci_drv);
 }
 
index 79b7a60..83b29e1 100644 (file)
@@ -84,6 +84,34 @@ enum {
        PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF = 0x1016,
 };
 
+struct mlx5_stats_priv {
+
+    struct rte_eth_stats m_shadow;
+    uint32_t      n_stats; /* number of counters */
+
+    void    *  et_stats  ;/* point to ethtool counter struct ethtool_stats*/
+
+    /* index into ethtool */
+    uint16_t inx_rx_vport_unicast_bytes;
+    uint16_t inx_rx_vport_multicast_bytes;
+    uint16_t inx_rx_vport_broadcast_bytes;
+    uint16_t inx_rx_vport_unicast_packets;
+    uint16_t inx_rx_vport_multicast_packets;
+    uint16_t inx_rx_vport_broadcast_packets;
+    uint16_t inx_tx_vport_unicast_bytes;
+    uint16_t inx_tx_vport_multicast_bytes;
+    uint16_t inx_tx_vport_broadcast_bytes;
+    uint16_t inx_tx_vport_unicast_packets;
+    uint16_t inx_tx_vport_multicast_packets;
+    uint16_t inx_tx_vport_broadcast_packets;
+    uint16_t inx_rx_wqe_err;
+    uint16_t inx_rx_crc_errors_phy;
+    uint16_t inx_rx_in_range_len_errors_phy;
+    uint16_t inx_rx_symbol_err_phy;
+    uint16_t inx_tx_errors_phy;
+};
+
+
 struct priv {
        struct rte_eth_dev *dev; /* Ethernet device. */
        struct ibv_context *ctx; /* Verbs context. */
@@ -137,6 +165,7 @@ struct priv {
        struct fdir_queue *fdir_drop_queue; /* Flow director drop queue. */
        uint32_t link_speed_capa; /* Link speed capabilities. */
        rte_spinlock_t lock; /* Lock for control functions. */
+    struct mlx5_stats_priv m_stats;
 };
 
 /* Local storage for secondary process data. */
@@ -246,6 +275,7 @@ void mlx5_allmulticast_disable(struct rte_eth_dev *);
 
 void mlx5_stats_get(struct rte_eth_dev *, struct rte_eth_stats *);
 void mlx5_stats_reset(struct rte_eth_dev *);
+void mlx5_stats_free(struct rte_eth_dev *dev);
 
 /* mlx5_vlan.c */
 
index 1acf682..f03e95e 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#define TREX_PATCH
+
 /* Verbs header. */
 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
 #ifdef PEDANTIC
 #pragma GCC diagnostic ignored "-Wpedantic"
 #endif
-#include <infiniband/verbs.h>
+#include <infiniband/verbs_exp.h>
 #ifdef PEDANTIC
 #pragma GCC diagnostic error "-Wpedantic"
 #endif
@@ -67,6 +69,9 @@ struct fdir_flow_desc {
        uint16_t src_port;
        uint32_t src_ip[4];
        uint32_t dst_ip[4];
+    uint8_t  tos;
+    uint8_t  ip_id;
+    uint8_t  proto;
        uint8_t mac[6];
        uint16_t vlan_tag;
        enum hash_rxq_type type;
@@ -102,6 +107,7 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
        /* Set VLAN ID. */
        desc->vlan_tag = fdir_filter->input.flow_ext.vlan_tci;
 
+#ifndef TREX_PATCH
        /* Set MAC address. */
        if (mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
                rte_memcpy(desc->mac,
@@ -111,6 +117,14 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
                desc->type = HASH_RXQ_ETH;
                return;
        }
+#else
+    if (fdir_filter->input.flow.ip4_flow.ip_id == 2) {
+        desc->type = HASH_RXQ_ETH;
+        desc->ip_id = fdir_filter->input.flow.ip4_flow.ip_id;
+        return;
+    }
+#endif
+
 
        /* Set mode */
        switch (fdir_filter->input.flow_type) {
@@ -145,6 +159,9 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
        case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
                desc->src_ip[0] = fdir_filter->input.flow.ip4_flow.src_ip;
                desc->dst_ip[0] = fdir_filter->input.flow.ip4_flow.dst_ip;
+        desc->tos       = fdir_filter->input.flow.ip4_flow.ttl; /* TTL is mapped to TOS TREX_PATCH */
+        desc->ip_id     = fdir_filter->input.flow.ip4_flow.ip_id;
+        desc->proto     = fdir_filter->input.flow.ip4_flow.proto;
                break;
        case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
        case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
@@ -158,6 +175,9 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
                rte_memcpy(desc->dst_ip,
                           fdir_filter->input.flow.ipv6_flow.dst_ip,
                           sizeof(desc->dst_ip));
+        desc->tos       = (uint8_t)fdir_filter->input.flow.ipv6_flow.hop_limits;  /* TTL is mapped to TOS - TREX_PATCH */
+        desc->ip_id     = (uint8_t)fdir_filter->input.flow.ipv6_flow.flow_label;
+        desc->proto     = fdir_filter->input.flow.ipv6_flow.proto;
                break;
        default:
                break;
@@ -198,6 +218,11 @@ priv_fdir_overlap(const struct priv *priv,
            ((desc1->dst_port & mask->dst_port_mask) !=
             (desc2->dst_port & mask->dst_port_mask)))
                return 0;
+    if  ( (desc1->tos    != desc2->tos)  ||
+          (desc1->ip_id  != desc2->ip_id) ||
+          (desc1->proto  != desc2->proto) ) 
+        return 0;
+
        switch (desc1->type) {
        case HASH_RXQ_IPV4:
        case HASH_RXQ_UDPV4:
@@ -252,8 +277,8 @@ priv_fdir_flow_add(struct priv *priv,
        struct ibv_exp_flow_attr *attr = &data->attr;
        uintptr_t spec_offset = (uintptr_t)&data->spec;
        struct ibv_exp_flow_spec_eth *spec_eth;
-       struct ibv_exp_flow_spec_ipv4 *spec_ipv4;
-       struct ibv_exp_flow_spec_ipv6 *spec_ipv6;
+       struct ibv_exp_flow_spec_ipv4_ext *spec_ipv4;
+       struct ibv_exp_flow_spec_ipv6_ext *spec_ipv6;
        struct ibv_exp_flow_spec_tcp_udp *spec_tcp_udp;
        struct mlx5_fdir_filter *iter_fdir_filter;
        unsigned int i;
@@ -265,8 +290,10 @@ priv_fdir_flow_add(struct priv *priv,
                    (iter_fdir_filter->flow != NULL) &&
                    (priv_fdir_overlap(priv,
                                       &mlx5_fdir_filter->desc,
-                                      &iter_fdir_filter->desc)))
-                       return EEXIST;
+                                      &iter_fdir_filter->desc))){
+            ERROR("overlap rules, please check your rules");
+            return EEXIST;
+        }
 
        /*
         * No padding must be inserted by the compiler between attr and spec.
@@ -289,6 +316,7 @@ priv_fdir_flow_add(struct priv *priv,
        /* Update priority */
        attr->priority = 2;
 
+#ifndef TREX_PATCH
        if (fdir_mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
                /* MAC Address */
                for (i = 0; i != RTE_DIM(spec_eth->mask.dst_mac); ++i) {
@@ -298,6 +326,14 @@ priv_fdir_flow_add(struct priv *priv,
                }
                goto create_flow;
        }
+#else
+    // empty mask means "match everything". This rule will match all packets, no matter what is the ether type
+    if (desc->ip_id == 2) {
+        spec_eth->val.ether_type = 0x0806;
+        spec_eth->mask.ether_type = 0x0000;
+        goto create_flow;
+    }
+#endif    
 
        switch (desc->type) {
        case HASH_RXQ_IPV4:
@@ -306,10 +342,10 @@ priv_fdir_flow_add(struct priv *priv,
                spec_offset += spec_eth->size;
 
                /* Set IP spec */
-               spec_ipv4 = (struct ibv_exp_flow_spec_ipv4 *)spec_offset;
+               spec_ipv4 = (struct ibv_exp_flow_spec_ipv4_ext *)spec_offset;
 
                /* The second specification must be IP. */
-               assert(spec_ipv4->type == IBV_EXP_FLOW_SPEC_IPV4);
+               assert(spec_ipv4->type == IBV_EXP_FLOW_SPEC_IPV4_EXT);
                assert(spec_ipv4->size == sizeof(*spec_ipv4));
 
                spec_ipv4->val.src_ip =
@@ -319,6 +355,21 @@ priv_fdir_flow_add(struct priv *priv,
                spec_ipv4->mask.src_ip = mask->ipv4_mask.src_ip;
                spec_ipv4->mask.dst_ip = mask->ipv4_mask.dst_ip;
 
+        /* PROTO */
+        spec_ipv4->val.proto  = desc->proto & mask->ipv4_mask.proto;
+        spec_ipv4->mask.proto = mask->ipv4_mask.proto;
+
+#ifdef TREX_PATCH
+        /* TOS */
+        if (desc->ip_id == 1) {
+            spec_ipv4->mask.tos = 0x1;
+            spec_ipv4->val.tos = 0x1;
+        } else {
+            spec_ipv4->mask.tos = 0x0;
+            spec_ipv4->val.tos = 0x0;
+        }
+#endif
+
                /* Update priority */
                attr->priority = 1;
 
@@ -333,10 +384,10 @@ priv_fdir_flow_add(struct priv *priv,
                spec_offset += spec_eth->size;
 
                /* Set IP spec */
-               spec_ipv6 = (struct ibv_exp_flow_spec_ipv6 *)spec_offset;
+               spec_ipv6 = (struct ibv_exp_flow_spec_ipv6_ext *)spec_offset;
 
                /* The second specification must be IP. */
-               assert(spec_ipv6->type == IBV_EXP_FLOW_SPEC_IPV6);
+               assert(spec_ipv6->type == IBV_EXP_FLOW_SPEC_IPV6_EXT);
                assert(spec_ipv6->size == sizeof(*spec_ipv6));
 
                for (i = 0; i != RTE_DIM(desc->src_ip); ++i) {
@@ -352,6 +403,20 @@ priv_fdir_flow_add(struct priv *priv,
                           mask->ipv6_mask.dst_ip,
                           sizeof(spec_ipv6->mask.dst_ip));
 
+        spec_ipv6->val.next_hdr  = desc->proto & mask->ipv6_mask.proto;
+        spec_ipv6->mask.next_hdr = mask->ipv6_mask.proto;
+
+#ifdef TREX_PATCH
+        /* TOS */
+        if (desc->ip_id == 1) {
+            spec_ipv6->mask.traffic_class = 0x1;
+            spec_ipv6->val.traffic_class = 0x1;
+        } else {
+            spec_ipv6->mask.traffic_class = 0;
+            spec_ipv6->val.traffic_class = 0;
+        }
+#endif
+
                /* Update priority */
                attr->priority = 1;
 
@@ -829,8 +894,10 @@ priv_fdir_filter_add(struct priv *priv,
        /* Duplicate filters are currently unsupported. */
        mlx5_fdir_filter = priv_find_filter_in_list(priv, fdir_filter);
        if (mlx5_fdir_filter != NULL) {
+#ifndef TREX_PATCH
                ERROR("filter already exists");
-               return EINVAL;
+#endif
+        return EEXIST;
        }
 
        /* Create new flow director filter. */
@@ -955,9 +1022,11 @@ priv_fdir_filter_delete(struct priv *priv,
                return 0;
        }
 
+#ifndef TREX_PATCH
        ERROR("%p: flow director delete failed, cannot find filter",
              (void *)priv);
-       return EINVAL;
+#endif
+        return ENOENT;
 }
 
 /**
index 28e93d3..c5746fa 100644 (file)
@@ -102,7 +102,7 @@ const struct hash_rxq_init hash_rxq_init[] = {
                                ETH_RSS_FRAG_IPV4),
                .flow_priority = 1,
                .flow_spec.ipv4 = {
-                       .type = IBV_EXP_FLOW_SPEC_IPV4,
+                       .type = IBV_EXP_FLOW_SPEC_IPV4_EXT,
                        .size = sizeof(hash_rxq_init[0].flow_spec.ipv4),
                },
                .underlayer = &hash_rxq_init[HASH_RXQ_ETH],
@@ -140,7 +140,7 @@ const struct hash_rxq_init hash_rxq_init[] = {
                                ETH_RSS_FRAG_IPV6),
                .flow_priority = 1,
                .flow_spec.ipv6 = {
-                       .type = IBV_EXP_FLOW_SPEC_IPV6,
+                       .type = IBV_EXP_FLOW_SPEC_IPV6_EXT,
                        .size = sizeof(hash_rxq_init[0].flow_spec.ipv6),
                },
                .underlayer = &hash_rxq_init[HASH_RXQ_ETH],
index 5579f89..f45e3f5 100644 (file)
@@ -178,8 +178,8 @@ struct hash_rxq_init {
                        uint16_t size;
                } hdr;
                struct ibv_exp_flow_spec_tcp_udp tcp_udp;
-               struct ibv_exp_flow_spec_ipv4 ipv4;
-               struct ibv_exp_flow_spec_ipv6 ipv6;
+               struct ibv_exp_flow_spec_ipv4_ext ipv4;
+               struct ibv_exp_flow_spec_ipv6_ext ipv6;
                struct ibv_exp_flow_spec_eth eth;
        } flow_spec; /* Flow specification template. */
        const struct hash_rxq_init *underlayer; /* Pointer to underlayer. */
index f2b5781..c6087d4 100644 (file)
 #include "mlx5_rxtx.h"
 #include "mlx5_defs.h"
 
-/**
- * DPDK callback to get device statistics.
- *
- * @param dev
- *   Pointer to Ethernet device structure.
- * @param[out] stats
- *   Stats structure output buffer.
- */
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+
+static void
+mlx5_stats_read_hw(struct rte_eth_dev *dev,
+                struct rte_eth_stats *stats){
+    struct priv *priv = mlx5_get_priv(dev);
+    struct mlx5_stats_priv * lps = &priv->m_stats;
+    unsigned int i;
+
+    struct rte_eth_stats tmp = {0};
+    struct ethtool_stats    *et_stats   = (struct ethtool_stats    *)lps->et_stats;
+    struct ifreq ifr;
+
+    et_stats->cmd = ETHTOOL_GSTATS;
+    et_stats->n_stats = lps->n_stats;
+
+    ifr.ifr_data = (caddr_t) et_stats;
+
+    if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) { 
+        WARN("unable to get statistic values for mlnx5 "); 
+    }
+
+    tmp.ibytes += et_stats->data[lps->inx_rx_vport_unicast_bytes] +
+                  et_stats->data[lps->inx_rx_vport_multicast_bytes] +
+                  et_stats->data[lps->inx_rx_vport_broadcast_bytes];
+
+    tmp.ipackets += et_stats->data[lps->inx_rx_vport_unicast_packets] +
+                et_stats->data[lps->inx_rx_vport_multicast_packets] +
+                et_stats->data[lps->inx_rx_vport_broadcast_packets];
+
+    tmp.ierrors +=     (et_stats->data[lps->inx_rx_wqe_err] +
+                    et_stats->data[lps->inx_rx_crc_errors_phy] +
+                    et_stats->data[lps->inx_rx_in_range_len_errors_phy] +
+                    et_stats->data[lps->inx_rx_symbol_err_phy]);
+
+    tmp.obytes += et_stats->data[lps->inx_tx_vport_unicast_bytes] +
+                  et_stats->data[lps->inx_tx_vport_multicast_bytes] +
+                  et_stats->data[lps->inx_tx_vport_broadcast_bytes];
+
+    tmp.opackets += (et_stats->data[lps->inx_tx_vport_unicast_packets] +
+                     et_stats->data[lps->inx_tx_vport_multicast_packets] +
+                     et_stats->data[lps->inx_tx_vport_broadcast_packets]);
+
+    tmp.oerrors += et_stats->data[lps->inx_tx_errors_phy];
+
+    /* SW Rx */
+    for (i = 0; (i != priv->rxqs_n); ++i) {
+        struct rxq *rxq = (*priv->rxqs)[i];
+        if (rxq) {
+            tmp.imissed += rxq->stats.idropped;
+            tmp.rx_nombuf += rxq->stats.rx_nombuf;
+        }
+    }
+
+    /*SW Tx */
+    for (i = 0; (i != priv->txqs_n); ++i) {
+        struct txq *txq = (*priv->txqs)[i];
+        if (txq) {
+            tmp.oerrors += txq->stats.odropped;
+        }
+    }
+
+    *stats =tmp;
+}
+
+void
+mlx5_stats_free(struct rte_eth_dev *dev)
+{
+    struct priv *priv = mlx5_get_priv(dev);
+    struct mlx5_stats_priv * lps = &priv->m_stats;
+
+    if ( lps->et_stats ){
+        free(lps->et_stats);
+        lps->et_stats=0;
+    }
+}
+
+
+static void
+mlx5_stats_init(struct rte_eth_dev *dev)
+{
+    struct priv *priv = mlx5_get_priv(dev);
+    struct mlx5_stats_priv * lps = &priv->m_stats;
+    struct rte_eth_stats tmp = {0};
+
+    unsigned int i;
+    unsigned int idx;
+    char ifname[IF_NAMESIZE];
+    struct ifreq ifr;
+
+    struct ethtool_stats    *et_stats   = NULL;
+    struct ethtool_drvinfo drvinfo;
+    struct ethtool_gstrings *strings = NULL;
+    unsigned int n_stats, sz_str, sz_stats;
+
+    if (priv_get_ifname(priv, &ifname)) {
+            WARN("unable to get interface name");
+            return;
+    }
+    /* How many statistics are available ? */
+    drvinfo.cmd = ETHTOOL_GDRVINFO;
+    ifr.ifr_data = (caddr_t) &drvinfo;
+    if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) {
+            WARN("unable to get driver info for %s", ifname);
+            return;
+    }
+
+    n_stats = drvinfo.n_stats;
+    if (n_stats < 1) {
+            WARN("no statistics available for %s", ifname);
+            return;
+    }
+    lps->n_stats = n_stats;
+
+    /* Allocate memory to grab stat names and values */ 
+    sz_str = n_stats * ETH_GSTRING_LEN; 
+    sz_stats = n_stats * sizeof(uint64_t); 
+    strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings)); 
+    if (!strings) { 
+        WARN("unable to allocate memory for strings"); 
+        return;
+    } 
+
+    et_stats = calloc(1, sz_stats + sizeof(struct ethtool_stats)); 
+    if (!et_stats) { 
+        free(strings);
+        WARN("unable to allocate memory for stats"); 
+    } 
+
+    strings->cmd = ETHTOOL_GSTRINGS; 
+    strings->string_set = ETH_SS_STATS; 
+    strings->len = n_stats; 
+    ifr.ifr_data = (caddr_t) strings; 
+    if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) { 
+        WARN("unable to get statistic names for %s", ifname); 
+        free(strings);
+        free(et_stats);
+        return;
+    } 
+
+    for (i = 0; (i != n_stats); ++i) {
+
+            const char * curr_string = (const char*) &(strings->data[i * ETH_GSTRING_LEN]);
+
+            if (!strcmp("rx_vport_unicast_bytes", curr_string)) lps->inx_rx_vport_unicast_bytes = i;
+            if (!strcmp("rx_vport_multicast_bytes", curr_string)) lps->inx_rx_vport_multicast_bytes = i;
+            if (!strcmp("rx_vport_broadcast_bytes", curr_string)) lps->inx_rx_vport_broadcast_bytes = i;
+
+            if (!strcmp("rx_vport_unicast_packets", curr_string)) lps->inx_rx_vport_unicast_packets = i;
+            if (!strcmp("rx_vport_multicast_packets", curr_string)) lps->inx_rx_vport_multicast_packets = i;
+            if (!strcmp("rx_vport_broadcast_packets", curr_string)) lps->inx_rx_vport_broadcast_packets = i;
+
+            if (!strcmp("tx_vport_unicast_bytes", curr_string)) lps->inx_tx_vport_unicast_bytes = i;
+            if (!strcmp("tx_vport_multicast_bytes", curr_string)) lps->inx_tx_vport_multicast_bytes = i;
+            if (!strcmp("tx_vport_broadcast_bytes", curr_string)) lps->inx_tx_vport_broadcast_bytes = i;
+
+            if (!strcmp("tx_vport_unicast_packets", curr_string)) lps->inx_tx_vport_unicast_packets = i;
+            if (!strcmp("tx_vport_multicast_packets", curr_string)) lps->inx_tx_vport_multicast_packets = i;
+            if (!strcmp("tx_vport_broadcast_packets", curr_string)) lps->inx_tx_vport_broadcast_packets = i;
+
+            if (!strcmp("rx_wqe_err", curr_string)) lps->inx_rx_wqe_err = i;
+            if (!strcmp("rx_crc_errors_phy", curr_string)) lps->inx_rx_crc_errors_phy = i;
+            if (!strcmp("rx_in_range_len_errors_phy", curr_string)) lps->inx_rx_in_range_len_errors_phy = i;
+            if (!strcmp("rx_symbol_err_phy", curr_string)) lps->inx_rx_symbol_err_phy = i;
+
+            if (!strcmp("tx_errors_phy", curr_string)) lps->inx_tx_errors_phy = i;
+    }
+
+    lps->et_stats =(void *)et_stats;
+
+    if (!lps->inx_rx_vport_unicast_bytes ||
+    !lps->inx_rx_vport_multicast_bytes ||
+    !lps->inx_rx_vport_broadcast_bytes || 
+    !lps->inx_rx_vport_unicast_packets ||
+    !lps->inx_rx_vport_multicast_packets ||
+    !lps->inx_rx_vport_broadcast_packets ||
+    !lps->inx_tx_vport_unicast_bytes || 
+    !lps->inx_tx_vport_multicast_bytes ||
+    !lps->inx_tx_vport_broadcast_bytes ||
+    !lps->inx_tx_vport_unicast_packets ||
+    !lps->inx_tx_vport_multicast_packets ||
+    !lps->inx_tx_vport_broadcast_packets ||
+    !lps->inx_rx_wqe_err ||
+    !lps->inx_rx_crc_errors_phy ||
+    !lps->inx_rx_in_range_len_errors_phy) {
+        WARN("Counters are not recognized %s", ifname);
+        return;
+    }
+
+    mlx5_stats_read_hw(dev,&tmp);
+
+    /* copy yo shadow at first time */
+    lps->m_shadow = tmp;
+
+    free(strings);
+}
+
+
+static void
+mlx5_stats_diff(struct rte_eth_stats *a,
+                struct rte_eth_stats *b,
+                struct rte_eth_stats *c){
+    #define MLX5_DIFF(cnt) { a->cnt = (b->cnt - c->cnt);  }
+
+    MLX5_DIFF(ipackets);
+    MLX5_DIFF(opackets); 
+    MLX5_DIFF(ibytes); 
+    MLX5_DIFF(obytes);
+    MLX5_DIFF(imissed);
+
+    MLX5_DIFF(ierrors); 
+    MLX5_DIFF(oerrors); 
+    MLX5_DIFF(rx_nombuf);
+}
+
+
+
 void
 mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
        struct priv *priv = mlx5_get_priv(dev);
-       struct rte_eth_stats tmp = {0};
-       unsigned int i;
-       unsigned int idx;
-
-       priv_lock(priv);
-       /* Add software counters. */
-       for (i = 0; (i != priv->rxqs_n); ++i) {
-               struct rxq *rxq = (*priv->rxqs)[i];
-
-               if (rxq == NULL)
-                       continue;
-               idx = rxq->stats.idx;
-               if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
-#ifdef MLX5_PMD_SOFT_COUNTERS
-                       tmp.q_ipackets[idx] += rxq->stats.ipackets;
-                       tmp.q_ibytes[idx] += rxq->stats.ibytes;
-#endif
-                       tmp.q_errors[idx] += (rxq->stats.idropped +
-                                             rxq->stats.rx_nombuf);
-               }
-#ifdef MLX5_PMD_SOFT_COUNTERS
-               tmp.ipackets += rxq->stats.ipackets;
-               tmp.ibytes += rxq->stats.ibytes;
-#endif
-               tmp.ierrors += rxq->stats.idropped;
-               tmp.rx_nombuf += rxq->stats.rx_nombuf;
-       }
-       for (i = 0; (i != priv->txqs_n); ++i) {
-               struct txq *txq = (*priv->txqs)[i];
-
-               if (txq == NULL)
-                       continue;
-               idx = txq->stats.idx;
-               if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
-#ifdef MLX5_PMD_SOFT_COUNTERS
-                       tmp.q_opackets[idx] += txq->stats.opackets;
-                       tmp.q_obytes[idx] += txq->stats.obytes;
-#endif
-                       tmp.q_errors[idx] += txq->stats.odropped;
-               }
-#ifdef MLX5_PMD_SOFT_COUNTERS
-               tmp.opackets += txq->stats.opackets;
-               tmp.obytes += txq->stats.obytes;
-#endif
-               tmp.oerrors += txq->stats.odropped;
-       }
-#ifndef MLX5_PMD_SOFT_COUNTERS
-       /* FIXME: retrieve and add hardware counters. */
-#endif
-       *stats = tmp;
+
+    struct mlx5_stats_priv * lps = &priv->m_stats;
+    priv_lock(priv);
+
+    if (lps->et_stats == NULL) {
+        mlx5_stats_init(dev);
+    }
+    struct rte_eth_stats tmp = {0};
+
+    mlx5_stats_read_hw(dev,&tmp);
+
+    mlx5_stats_diff(stats,
+                    &tmp,
+                    &lps->m_shadow);
+
        priv_unlock(priv);
 }
 
@@ -119,26 +294,20 @@ void
 mlx5_stats_reset(struct rte_eth_dev *dev)
 {
        struct priv *priv = dev->data->dev_private;
-       unsigned int i;
-       unsigned int idx;
-
-       priv_lock(priv);
-       for (i = 0; (i != priv->rxqs_n); ++i) {
-               if ((*priv->rxqs)[i] == NULL)
-                       continue;
-               idx = (*priv->rxqs)[i]->stats.idx;
-               (*priv->rxqs)[i]->stats =
-                       (struct mlx5_rxq_stats){ .idx = idx };
-       }
-       for (i = 0; (i != priv->txqs_n); ++i) {
-               if ((*priv->txqs)[i] == NULL)
-                       continue;
-               idx = (*priv->txqs)[i]->stats.idx;
-               (*priv->txqs)[i]->stats =
-                       (struct mlx5_txq_stats){ .idx = idx };
-       }
-#ifndef MLX5_PMD_SOFT_COUNTERS
-       /* FIXME: reset hardware counters. */
-#endif
+    struct mlx5_stats_priv * lps = &priv->m_stats;
+
+    priv_lock(priv);
+
+    if (lps->et_stats == NULL) {
+        mlx5_stats_init(dev);
+    }
+    struct rte_eth_stats tmp = {0};
+
+
+    mlx5_stats_read_hw(dev,&tmp);
+
+    /* copy to shadow */
+    lps->m_shadow = tmp;
+
        priv_unlock(priv);
 }