mlx5: add VLAN insertion offload

VLAN insertion can be done in hardware when supported in Verbs. A software
fallback is provided otherwise. The software implementation is also used
when multi-packet send is enabled on a queue, as both features are mutually
exclusive.

Signed-off-by: Yaacov Hazan <yaacovh@mellanox.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
This commit is contained in:
Yaacov Hazan 2016-03-17 16:38:58 +01:00 committed by Thomas Monjalon
parent 4d803a7246
commit e192ef8034
9 changed files with 151 additions and 28 deletions

View File

@ -79,6 +79,7 @@ Features
- Support for multiple MAC addresses. - Support for multiple MAC addresses.
- VLAN filtering. - VLAN filtering.
- RX VLAN stripping. - RX VLAN stripping.
- TX VLAN insertion.
- RX CRC stripping configuration. - RX CRC stripping configuration.
- Promiscuous mode. - Promiscuous mode.
- Multicast promiscuous mode. - Multicast promiscuous mode.
@ -242,6 +243,7 @@ Currently supported by DPDK:
- Flow director. - Flow director.
- RX VLAN stripping. - RX VLAN stripping.
- TX VLAN insertion.
- RX CRC stripping configuration. - RX CRC stripping configuration.
- Minimum firmware version: - Minimum firmware version:

View File

@ -230,6 +230,12 @@ This section should contain new features added in this release. Sample format:
Only available with Mellanox OFED >= 3.2. Only available with Mellanox OFED >= 3.2.
* **Added mlx5 TX VLAN insertion support.**
Added support for TX VLAN insertion.
Only available with Mellanox OFED >= 3.2.
* **Changed szedata2 type of driver from vdev to pdev.** * **Changed szedata2 type of driver from vdev to pdev.**
Previously szedata2 device had to be added by ``--vdev`` option. Previously szedata2 device had to be added by ``--vdev`` option.

View File

@ -141,6 +141,11 @@ mlx5_autoconf.h: $(RTE_SDK)/scripts/auto-config-h.sh
infiniband/verbs.h \ infiniband/verbs.h \
enum IBV_EXP_CREATE_WQ_FLAG_RX_END_PADDING \ enum IBV_EXP_CREATE_WQ_FLAG_RX_END_PADDING \
$(AUTOCONF_OUTPUT) $(AUTOCONF_OUTPUT)
$Q sh -- '$<' '$@' \
HAVE_VERBS_VLAN_INSERTION \
infiniband/verbs.h \
enum IBV_EXP_RECEIVE_WQ_CVLAN_INSERTION \
$(AUTOCONF_OUTPUT)
$(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h $(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h

View File

@ -261,6 +261,7 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
struct ibv_context *attr_ctx = NULL; struct ibv_context *attr_ctx = NULL;
struct ibv_device_attr device_attr; struct ibv_device_attr device_attr;
unsigned int vf; unsigned int vf;
unsigned int mps;
int idx; int idx;
int i; int i;
@ -306,8 +307,14 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
PCI_DEVICE_ID_MELLANOX_CONNECTX4VF) || PCI_DEVICE_ID_MELLANOX_CONNECTX4VF) ||
(pci_dev->id.device_id == (pci_dev->id.device_id ==
PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF)); PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF));
INFO("PCI information matches, using device \"%s\" (VF: %s)", /* Multi-packet send is only supported by ConnectX-4 Lx PF. */
list[i]->name, (vf ? "true" : "false")); mps = (pci_dev->id.device_id ==
PCI_DEVICE_ID_MELLANOX_CONNECTX4LX);
INFO("PCI information matches, using device \"%s\" (VF: %s,"
" MPS: %s)",
list[i]->name,
vf ? "true" : "false",
mps ? "true" : "false");
attr_ctx = ibv_open_device(list[i]); attr_ctx = ibv_open_device(list[i]);
err = errno; err = errno;
break; break;
@ -458,6 +465,7 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
#endif /* HAVE_EXP_QUERY_DEVICE */ #endif /* HAVE_EXP_QUERY_DEVICE */
priv->vf = vf; priv->vf = vf;
priv->mps = mps;
/* Allocate and register default RSS hash keys. */ /* Allocate and register default RSS hash keys. */
priv->rss_conf = rte_calloc(__func__, hash_rxq_init_n, priv->rss_conf = rte_calloc(__func__, hash_rxq_init_n,
sizeof((*priv->rss_conf)[0]), 0); sizeof((*priv->rss_conf)[0]), 0);

View File

@ -106,6 +106,7 @@ struct priv {
unsigned int hw_fcs_strip:1; /* FCS stripping is supported. */ unsigned int hw_fcs_strip:1; /* FCS stripping is supported. */
unsigned int hw_padding:1; /* End alignment padding is supported. */ unsigned int hw_padding:1; /* End alignment padding is supported. */
unsigned int vf:1; /* This is a VF device. */ unsigned int vf:1; /* This is a VF device. */
unsigned int mps:1; /* Whether multi-packet send is supported. */
unsigned int pending_alarm:1; /* An alarm is pending. */ unsigned int pending_alarm:1; /* An alarm is pending. */
/* RX/TX queues. */ /* RX/TX queues. */
unsigned int rxqs_n; /* RX queues array size. */ unsigned int rxqs_n; /* RX queues array size. */

View File

@ -544,12 +544,12 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
DEV_RX_OFFLOAD_UDP_CKSUM | DEV_RX_OFFLOAD_UDP_CKSUM |
DEV_RX_OFFLOAD_TCP_CKSUM) : DEV_RX_OFFLOAD_TCP_CKSUM) :
0); 0);
info->tx_offload_capa = info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT;
(priv->hw_csum ? if (priv->hw_csum)
(DEV_TX_OFFLOAD_IPV4_CKSUM | info->tx_offload_capa |=
DEV_TX_OFFLOAD_UDP_CKSUM | (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM) : DEV_TX_OFFLOAD_UDP_CKSUM |
0); DEV_TX_OFFLOAD_TCP_CKSUM);
if (priv_get_ifname(priv, &ifname) == 0) if (priv_get_ifname(priv, &ifname) == 0)
info->if_index = if_nametoindex(ifname); info->if_index = if_nametoindex(ifname);
/* FIXME: RETA update/query API expects the callee to know the size of /* FIXME: RETA update/query API expects the callee to know the size of

View File

@ -333,6 +333,36 @@ txq_mp2mr_iter(const struct rte_mempool *mp, void *arg)
txq_mp2mr(txq, mp); txq_mp2mr(txq, mp);
} }
/**
* Insert VLAN using mbuf headroom space.
*
* @param buf
* Buffer for VLAN insertion.
*
* @return
* 0 on success, errno value on failure.
*/
static inline int
insert_vlan_sw(struct rte_mbuf *buf)
{
uintptr_t addr;
uint32_t vlan;
uint16_t head_room_len = rte_pktmbuf_headroom(buf);
if (head_room_len < 4)
return EINVAL;
addr = rte_pktmbuf_mtod(buf, uintptr_t);
vlan = htonl(0x81000000 | buf->vlan_tci);
memmove((void *)(addr - 4), (void *)addr, 12);
memcpy((void *)(addr + 8), &vlan, sizeof(vlan));
SET_DATA_OFF(buf, head_room_len - 4);
DATA_LEN(buf) += 4;
return 0;
}
#if MLX5_PMD_SGE_WR_N > 1 #if MLX5_PMD_SGE_WR_N > 1
/** /**
@ -534,6 +564,9 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
unsigned int sent_size = 0; unsigned int sent_size = 0;
#endif #endif
uint32_t send_flags = 0; uint32_t send_flags = 0;
#ifdef HAVE_VERBS_VLAN_INSERTION
int insert_vlan = 0;
#endif /* HAVE_VERBS_VLAN_INSERTION */
if (i + 1 < max) if (i + 1 < max)
rte_prefetch0(buf_next); rte_prefetch0(buf_next);
@ -554,6 +587,18 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type)) if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type))
send_flags |= IBV_EXP_QP_BURST_TUNNEL; send_flags |= IBV_EXP_QP_BURST_TUNNEL;
} }
if (buf->ol_flags & PKT_TX_VLAN_PKT) {
#ifdef HAVE_VERBS_VLAN_INSERTION
if (!txq->priv->mps)
insert_vlan = 1;
else
#endif /* HAVE_VERBS_VLAN_INSERTION */
{
err = insert_vlan_sw(buf);
if (unlikely(err))
goto stop;
}
}
if (likely(segs == 1)) { if (likely(segs == 1)) {
uintptr_t addr; uintptr_t addr;
uint32_t length; uint32_t length;
@ -577,13 +622,23 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
} }
/* Put packet into send queue. */ /* Put packet into send queue. */
#if MLX5_PMD_MAX_INLINE > 0 #if MLX5_PMD_MAX_INLINE > 0
if (length <= txq->max_inline) if (length <= txq->max_inline) {
err = txq->send_pending_inline #ifdef HAVE_VERBS_VLAN_INSERTION
(txq->qp, if (insert_vlan)
(void *)addr, err = txq->send_pending_inline_vlan
length, (txq->qp,
send_flags); (void *)addr,
else length,
send_flags,
&buf->vlan_tci);
else
#endif /* HAVE_VERBS_VLAN_INSERTION */
err = txq->send_pending_inline
(txq->qp,
(void *)addr,
length,
send_flags);
} else
#endif #endif
{ {
/* Retrieve Memory Region key for this /* Retrieve Memory Region key for this
@ -597,12 +652,23 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
elt->buf = NULL; elt->buf = NULL;
goto stop; goto stop;
} }
err = txq->send_pending #ifdef HAVE_VERBS_VLAN_INSERTION
(txq->qp, if (insert_vlan)
addr, err = txq->send_pending_vlan
length, (txq->qp,
lkey, addr,
send_flags); length,
lkey,
send_flags,
&buf->vlan_tci);
else
#endif /* HAVE_VERBS_VLAN_INSERTION */
err = txq->send_pending
(txq->qp,
addr,
length,
lkey,
send_flags);
} }
if (unlikely(err)) if (unlikely(err))
goto stop; goto stop;
@ -619,11 +685,21 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
if (ret.length == (unsigned int)-1) if (ret.length == (unsigned int)-1)
goto stop; goto stop;
/* Put SG list into send queue. */ /* Put SG list into send queue. */
err = txq->send_pending_sg_list #ifdef HAVE_VERBS_VLAN_INSERTION
(txq->qp, if (insert_vlan)
sges, err = txq->send_pending_sg_list_vlan
ret.num, (txq->qp,
send_flags); sges,
ret.num,
send_flags,
&buf->vlan_tci);
else
#endif /* HAVE_VERBS_VLAN_INSERTION */
err = txq->send_pending_sg_list
(txq->qp,
sges,
ret.num,
send_flags);
if (unlikely(err)) if (unlikely(err))
goto stop; goto stop;
#ifdef MLX5_PMD_SOFT_COUNTERS #ifdef MLX5_PMD_SOFT_COUNTERS

View File

@ -255,11 +255,20 @@ struct txq {
struct priv *priv; /* Back pointer to private data. */ struct priv *priv; /* Back pointer to private data. */
int32_t (*poll_cnt)(struct ibv_cq *cq, uint32_t max); int32_t (*poll_cnt)(struct ibv_cq *cq, uint32_t max);
int (*send_pending)(); int (*send_pending)();
#ifdef HAVE_VERBS_VLAN_INSERTION
int (*send_pending_vlan)();
#endif
#if MLX5_PMD_MAX_INLINE > 0 #if MLX5_PMD_MAX_INLINE > 0
int (*send_pending_inline)(); int (*send_pending_inline)();
#ifdef HAVE_VERBS_VLAN_INSERTION
int (*send_pending_inline_vlan)();
#endif
#endif #endif
#if MLX5_PMD_SGE_WR_N > 1 #if MLX5_PMD_SGE_WR_N > 1
int (*send_pending_sg_list)(); int (*send_pending_sg_list)();
#ifdef HAVE_VERBS_VLAN_INSERTION
int (*send_pending_sg_list_vlan)();
#endif
#endif #endif
int (*send_flush)(struct ibv_qp *qp); int (*send_flush)(struct ibv_qp *qp);
struct ibv_cq *cq; /* Completion Queue. */ struct ibv_cq *cq; /* Completion Queue. */
@ -283,7 +292,11 @@ struct txq {
/* Elements used only for init part are here. */ /* Elements used only for init part are here. */
linear_t (*elts_linear)[]; /* Linearized buffers. */ linear_t (*elts_linear)[]; /* Linearized buffers. */
struct ibv_mr *mr_linear; /* Memory Region for linearized buffers. */ struct ibv_mr *mr_linear; /* Memory Region for linearized buffers. */
#ifdef HAVE_VERBS_VLAN_INSERTION
struct ibv_exp_qp_burst_family_v1 *if_qp; /* QP burst interface. */
#else
struct ibv_exp_qp_burst_family *if_qp; /* QP burst interface. */ struct ibv_exp_qp_burst_family *if_qp; /* QP burst interface. */
#endif
struct ibv_exp_cq_family *if_cq; /* CQ interface. */ struct ibv_exp_cq_family *if_cq; /* CQ interface. */
struct ibv_exp_res_domain *rd; /* Resource Domain. */ struct ibv_exp_res_domain *rd; /* Resource Domain. */
unsigned int socket; /* CPU socket ID for allocations. */ unsigned int socket; /* CPU socket ID for allocations. */

View File

@ -400,10 +400,13 @@ txq_setup(struct rte_eth_dev *dev, struct txq *txq, uint16_t desc,
.intf_scope = IBV_EXP_INTF_GLOBAL, .intf_scope = IBV_EXP_INTF_GLOBAL,
.intf = IBV_EXP_INTF_QP_BURST, .intf = IBV_EXP_INTF_QP_BURST,
.obj = tmpl.qp, .obj = tmpl.qp,
#ifdef HAVE_VERBS_VLAN_INSERTION
.intf_version = 1,
#endif
#ifdef HAVE_EXP_QP_BURST_CREATE_ENABLE_MULTI_PACKET_SEND_WR #ifdef HAVE_EXP_QP_BURST_CREATE_ENABLE_MULTI_PACKET_SEND_WR
/* Multi packet send WR can only be used outside of VF. */ /* Enable multi-packet send if supported. */
.family_flags = .family_flags =
(!priv->vf ? (priv->mps ?
IBV_EXP_QP_BURST_CREATE_ENABLE_MULTI_PACKET_SEND_WR : IBV_EXP_QP_BURST_CREATE_ENABLE_MULTI_PACKET_SEND_WR :
0), 0),
#endif #endif
@ -422,11 +425,20 @@ txq_setup(struct rte_eth_dev *dev, struct txq *txq, uint16_t desc,
txq->poll_cnt = txq->if_cq->poll_cnt; txq->poll_cnt = txq->if_cq->poll_cnt;
#if MLX5_PMD_MAX_INLINE > 0 #if MLX5_PMD_MAX_INLINE > 0
txq->send_pending_inline = txq->if_qp->send_pending_inline; txq->send_pending_inline = txq->if_qp->send_pending_inline;
#ifdef HAVE_VERBS_VLAN_INSERTION
txq->send_pending_inline_vlan = txq->if_qp->send_pending_inline_vlan;
#endif
#endif #endif
#if MLX5_PMD_SGE_WR_N > 1 #if MLX5_PMD_SGE_WR_N > 1
txq->send_pending_sg_list = txq->if_qp->send_pending_sg_list; txq->send_pending_sg_list = txq->if_qp->send_pending_sg_list;
#ifdef HAVE_VERBS_VLAN_INSERTION
txq->send_pending_sg_list_vlan = txq->if_qp->send_pending_sg_list_vlan;
#endif
#endif #endif
txq->send_pending = txq->if_qp->send_pending; txq->send_pending = txq->if_qp->send_pending;
#ifdef HAVE_VERBS_VLAN_INSERTION
txq->send_pending_vlan = txq->if_qp->send_pending_vlan;
#endif
txq->send_flush = txq->if_qp->send_flush; txq->send_flush = txq->if_qp->send_flush;
DEBUG("%p: txq updated with %p", (void *)txq, (void *)&tmpl); DEBUG("%p: txq updated with %p", (void *)txq, (void *)&tmpl);
/* Pre-register known mempools. */ /* Pre-register known mempools. */