From: Yaacov Hazan <yaac...@mellanox.com>

Allows HW to strip the 802.1Q header from incoming frames and report it
through the mbuf structure.

This feature requires MLNX_OFED >= 3.2.

Signed-off-by: Yaacov Hazan <yaacovh at mellanox.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil at 6wind.com>
---
 doc/guides/nics/mlx5.rst               |   2 +
 doc/guides/rel_notes/release_16_04.rst |   6 ++
 drivers/net/mlx5/mlx5.c                |  16 ++++-
 drivers/net/mlx5/mlx5.h                |   3 +
 drivers/net/mlx5/mlx5_rxq.c            |  17 +++++-
 drivers/net/mlx5/mlx5_rxtx.c           |  27 +++++++++
 drivers/net/mlx5/mlx5_rxtx.h           |   5 ++
 drivers/net/mlx5/mlx5_vlan.c           | 104 +++++++++++++++++++++++++++++++++
 8 files changed, 178 insertions(+), 2 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 6bd452e..edfbf1f 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -83,6 +83,7 @@ Features
 - Configurable RETA table.
 - Support for multiple MAC addresses.
 - VLAN filtering.
+- RX VLAN stripping.
 - Promiscuous mode.
 - Multicast promiscuous mode.
 - Hardware checksum offloads.
@@ -229,6 +230,7 @@ Currently supported by DPDK:
     above only:

     - Flow director.
+    - RX VLAN stripping.

 - Minimum firmware version:

diff --git a/doc/guides/rel_notes/release_16_04.rst 
b/doc/guides/rel_notes/release_16_04.rst
index c6c76d6..c69e55e 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -81,6 +81,12 @@ This section should contain new features added in this 
release. Sample format:

   Only available with Mellanox OFED >= 3.2.

+* **mlx5: RX VLAN stripping support.**
+
+  Added support for RX VLAN stripping.
+
+  Only available with Mellanox OFED >= 3.2.
+

 Resolved Issues
 ---------------
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 43e24ff..575420e 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -171,6 +171,10 @@ static const struct eth_dev_ops mlx5_dev_ops = {
        .mac_addr_add = mlx5_mac_addr_add,
        .mac_addr_set = mlx5_mac_addr_set,
        .mtu_set = mlx5_dev_set_mtu,
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+       .vlan_strip_queue_set = mlx5_vlan_strip_queue_set,
+       .vlan_offload_set = mlx5_vlan_offload_set,
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
        .reta_update = mlx5_dev_rss_reta_update,
        .reta_query = mlx5_dev_rss_reta_query,
        .rss_hash_update = mlx5_rss_hash_update,
@@ -325,7 +329,11 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct 
rte_pci_device *pci_dev)
 #ifdef HAVE_EXP_QUERY_DEVICE
                exp_device_attr.comp_mask =
                        IBV_EXP_DEVICE_ATTR_EXP_CAP_FLAGS |
-                       IBV_EXP_DEVICE_ATTR_RX_HASH;
+                       IBV_EXP_DEVICE_ATTR_RX_HASH |
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+                       IBV_EXP_DEVICE_ATTR_VLAN_OFFLOADS |
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
+                       0;
 #endif /* HAVE_EXP_QUERY_DEVICE */

                DEBUG("using port %u (%08" PRIx32 ")", port, test);
@@ -396,6 +404,12 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct 
rte_pci_device *pci_dev)
                        priv->ind_table_max_size = RSS_INDIRECTION_TABLE_SIZE;
                DEBUG("maximum RX indirection table size is %u",
                      priv->ind_table_max_size);
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               priv->hw_vlan_strip = !!(exp_device_attr.wq_vlan_offloads_cap &
+                                        IBV_EXP_RECEIVE_WQ_CVLAN_STRIP);
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
+               DEBUG("VLAN stripping is %ssupported",
+                     (priv->hw_vlan_strip ? "" : "not "));

 #else /* HAVE_EXP_QUERY_DEVICE */
                priv->ind_table_max_size = RSS_INDIRECTION_TABLE_SIZE;
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 8019ee3..8442016 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -101,6 +101,7 @@ struct priv {
        unsigned int allmulti_req:1; /* All multicast mode requested. */
        unsigned int hw_csum:1; /* Checksum offload is supported. */
        unsigned int hw_csum_l2tun:1; /* Same for L2 tunnels. */
+       unsigned int hw_vlan_strip:1; /* VLAN stripping is supported. */
        unsigned int vf:1; /* This is a VF device. */
        unsigned int pending_alarm:1; /* An alarm is pending. */
        /* RX/TX queues. */
@@ -211,6 +212,8 @@ void mlx5_stats_reset(struct rte_eth_dev *);
 /* mlx5_vlan.c */

 int mlx5_vlan_filter_set(struct rte_eth_dev *, uint16_t, int);
+void mlx5_vlan_offload_set(struct rte_eth_dev *, int);
+void mlx5_vlan_strip_queue_set(struct rte_eth_dev *, uint16_t, int);

 /* mlx5_trigger.c */

diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index 093f4e5..573ad8f 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -1224,6 +1224,8 @@ rxq_setup(struct rte_eth_dev *dev, struct rxq *rxq, 
uint16_t desc,
              priv->device_attr.max_qp_wr);
        DEBUG("priv->device_attr.max_sge is %d",
              priv->device_attr.max_sge);
+       /* Configure VLAN stripping. */
+       tmpl.vlan_strip = dev->data->dev_conf.rxmode.hw_vlan_strip;
        attr.wq = (struct ibv_exp_wq_init_attr){
                .wq_context = NULL, /* Could be useful in the future. */
                .wq_type = IBV_EXP_WQT_RQ,
@@ -1238,8 +1240,18 @@ rxq_setup(struct rte_eth_dev *dev, struct rxq *rxq, 
uint16_t desc,
                                 MLX5_PMD_SGE_WR_N),
                .pd = priv->pd,
                .cq = tmpl.cq,
-               .comp_mask = IBV_EXP_CREATE_WQ_RES_DOMAIN,
+               .comp_mask =
+                       IBV_EXP_CREATE_WQ_RES_DOMAIN |
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+                       IBV_EXP_CREATE_WQ_VLAN_OFFLOADS |
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
+                       0,
                .res_domain = tmpl.rd,
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               .vlan_offloads = (tmpl.vlan_strip ?
+                                 IBV_EXP_RECEIVE_WQ_CVLAN_STRIP :
+                                 0),
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
        };
        tmpl.wq = ibv_exp_create_wq(priv->ctx, &attr.wq);
        if (tmpl.wq == NULL) {
@@ -1262,6 +1274,9 @@ rxq_setup(struct rte_eth_dev *dev, struct rxq *rxq, 
uint16_t desc,
        DEBUG("%p: RTE port ID: %u", (void *)rxq, tmpl.port_id);
        attr.params = (struct ibv_exp_query_intf_params){
                .intf_scope = IBV_EXP_INTF_GLOBAL,
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               .intf_version = 1,
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
                .intf = IBV_EXP_INTF_CQ,
                .obj = tmpl.cq,
        };
diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c
index fa5e648..7585570 100644
--- a/drivers/net/mlx5/mlx5_rxtx.c
+++ b/drivers/net/mlx5/mlx5_rxtx.c
@@ -62,6 +62,7 @@
 #include "mlx5.h"
 #include "mlx5_utils.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_autoconf.h"
 #include "mlx5_defs.h"

 /**
@@ -713,12 +714,19 @@ mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                unsigned int seg_headroom = RTE_PKTMBUF_HEADROOM;
                unsigned int j = 0;
                uint32_t flags;
+               uint16_t vlan_tci;

                /* Sanity checks. */
                assert(elts_head < rxq->elts_n);
                assert(rxq->elts_head < rxq->elts_n);
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               ret = rxq->if_cq->poll_length_flags_cvlan(rxq->cq, NULL, NULL,
+                                                         &flags, &vlan_tci);
+#else /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
                ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL,
                                                    &flags);
+               (void)vlan_tci;
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
                if (unlikely(ret < 0)) {
                        struct ibv_wc wc;
                        int wcs_n;
@@ -840,6 +848,12 @@ mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                PKT_LEN(pkt_buf) = pkt_buf_len;
                pkt_buf->packet_type = rxq_cq_to_pkt_type(flags);
                pkt_buf->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
+                       pkt_buf->ol_flags |= PKT_RX_VLAN_PKT;
+                       pkt_buf->vlan_tci = vlan_tci;
+               }
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */

                /* Return packet. */
                *(pkts++) = pkt_buf;
@@ -910,6 +924,7 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                struct rte_mbuf *seg = elt->buf;
                struct rte_mbuf *rep;
                uint32_t flags;
+               uint16_t vlan_tci;

                /* Sanity checks. */
                assert(seg != NULL);
@@ -921,8 +936,14 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                 */
                rte_prefetch0(seg);
                rte_prefetch0(&seg->cacheline1);
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               ret = rxq->if_cq->poll_length_flags_cvlan(rxq->cq, NULL, NULL,
+                                                         &flags, &vlan_tci);
+#else /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
                ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL,
                                                    &flags);
+               (void)vlan_tci;
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
                if (unlikely(ret < 0)) {
                        struct ibv_wc wc;
                        int wcs_n;
@@ -989,6 +1010,12 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                DATA_LEN(seg) = len;
                seg->packet_type = rxq_cq_to_pkt_type(flags);
                seg->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+               if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
+                       seg->ol_flags |= PKT_RX_VLAN_PKT;
+                       seg->vlan_tci = vlan_tci;
+               }
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */

                /* Return packet. */
                *(pkts++) = seg;
diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h
index b2f72f8..fde0ca2 100644
--- a/drivers/net/mlx5/mlx5_rxtx.h
+++ b/drivers/net/mlx5/mlx5_rxtx.h
@@ -109,7 +109,11 @@ struct rxq {
        struct ibv_cq *cq; /* Completion Queue. */
        struct ibv_exp_wq *wq; /* Work Queue. */
        struct ibv_exp_wq_family *if_wq; /* WQ burst interface. */
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+       struct ibv_exp_cq_family_v1 *if_cq; /* CQ interface. */
+#else /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
        struct ibv_exp_cq_family *if_cq; /* CQ interface. */
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
        unsigned int port_id; /* Port ID for incoming packets. */
        unsigned int elts_n; /* (*elts)[] length. */
        unsigned int elts_head; /* Current index in (*elts)[]. */
@@ -120,6 +124,7 @@ struct rxq {
        unsigned int sp:1; /* Use scattered RX elements. */
        unsigned int csum:1; /* Enable checksum offloading. */
        unsigned int csum_l2tun:1; /* Same for L2 tunnels. */
+       unsigned int vlan_strip:1; /* Enable VLAN stripping. */
        uint32_t mb_len; /* Length of a mp-issued mbuf. */
        struct mlx5_rxq_stats stats; /* RX queue counters. */
        unsigned int socket; /* CPU socket ID for allocations. */
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index 3a07ad1..fa9e3b8 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -48,6 +48,7 @@

 #include "mlx5_utils.h"
 #include "mlx5.h"
+#include "mlx5_autoconf.h"

 /**
  * Configure a VLAN filter.
@@ -127,3 +128,106 @@ mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t 
vlan_id, int on)
        assert(ret >= 0);
        return -ret;
 }
+
+/**
+ * Set/reset VLAN stripping for a specific queue.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param idx
+ *   RX queue index.
+ * @param on
+ *   Enable/disable VLAN stripping.
+ */
+static void
+priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)
+{
+       struct rxq *rxq = (*priv->rxqs)[idx];
+#ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
+       struct ibv_exp_wq_attr mod;
+       uint16_t vlan_offloads =
+               (on ? IBV_EXP_RECEIVE_WQ_CVLAN_STRIP : 0) |
+               0;
+       int err;
+
+       DEBUG("set VLAN offloads 0x%x for port %d queue %d",
+             vlan_offloads, rxq->port_id, idx);
+       mod = (struct ibv_exp_wq_attr){
+               .attr_mask = IBV_EXP_WQ_ATTR_VLAN_OFFLOADS,
+               .vlan_offloads = vlan_offloads,
+       };
+
+       err = ibv_exp_modify_wq(rxq->wq, &mod);
+       if (err) {
+               ERROR("%p: failed to modified stripping mode: %s",
+                     (void *)priv, strerror(err));
+               return;
+       }
+
+#endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
+
+       /* Update related bits in RX queue. */
+       rxq->vlan_strip = !!on;
+}
+
+/**
+ * Callback to set/reset VLAN stripping for a specific queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param queue
+ *   RX queue index.
+ * @param on
+ *   Enable/disable VLAN stripping.
+ */
+void
+mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on)
+{
+       struct priv *priv = dev->data->dev_private;
+
+       /* Validate hw support */
+       if (!priv->hw_vlan_strip) {
+               ERROR("VLAN stripping is not supported");
+               return;
+       }
+
+       /* Validate queue number */
+       if (queue >= priv->rxqs_n) {
+               ERROR("VLAN stripping, invalid queue number %d", queue);
+               return;
+       }
+
+       priv_lock(priv);
+       priv_vlan_strip_queue_set(priv, queue, on);
+       priv_unlock(priv);
+}
+
+/**
+ * Callback to set/reset VLAN offloads for a port.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mask
+ *   VLAN offload bit mask.
+ */
+void
+mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int i;
+
+       if (mask & ETH_VLAN_STRIP_MASK) {
+               int hw_vlan_strip = dev->data->dev_conf.rxmode.hw_vlan_strip;
+
+               if (!priv->hw_vlan_strip) {
+                       ERROR("VLAN stripping is not supported");
+                       return;
+               }
+
+               /* Run on every RX queue and set/reset VLAN stripping. */
+               priv_lock(priv);
+               for (i = 0; (i != priv->rxqs_n); i++)
+                       priv_vlan_strip_queue_set(priv, i, hw_vlan_strip);
+               priv_unlock(priv);
+       }
+}
-- 
2.1.4

Reply via email to