From 3318aef7e7dfde119eb3da129684c9bcf76d79e4 Mon Sep 17 00:00:00 2001 From: Adrien Mazarguil Date: Fri, 30 Oct 2015 19:52:32 +0100 Subject: [PATCH] mlx5: add MAC handling This commit adds support for MAC flow steering rules mandatory for the RX path as well as the related callbacks to add/remove MAC addresses. Signed-off-by: Adrien Mazarguil Signed-off-by: Nelio Laranjeiro Signed-off-by: Didier Pallard --- drivers/net/mlx5/mlx5.c | 4 +- drivers/net/mlx5/mlx5.h | 5 + drivers/net/mlx5/mlx5_mac.c | 282 +++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rxq.c | 10 ++ drivers/net/mlx5/mlx5_rxtx.h | 2 + 5 files changed, 302 insertions(+), 1 deletion(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 54bd6b9456..a241c28b57 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -134,6 +134,8 @@ static const struct eth_dev_ops mlx5_dev_ops = { .tx_queue_setup = mlx5_tx_queue_setup, .rx_queue_release = mlx5_rx_queue_release, .tx_queue_release = mlx5_tx_queue_release, + .mac_addr_remove = mlx5_mac_addr_remove, + .mac_addr_add = mlx5_mac_addr_add, }; static struct { @@ -390,7 +392,7 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) claim_zero(priv_mac_addr_add(priv, 0, (const uint8_t (*)[ETHER_ADDR_LEN]) mac.addr_bytes)); - claim_zero(priv_mac_addr_add(priv, 1, + claim_zero(priv_mac_addr_add(priv, (RTE_DIM(priv->mac) - 1), &(const uint8_t [ETHER_ADDR_LEN]) { "\xff\xff\xff\xff\xff\xff" })); #ifndef NDEBUG diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 49978f5efa..6ab31ad4d9 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -166,7 +166,12 @@ int mlx5_ibv_device_to_pci_addr(const struct ibv_device *, /* mlx5_mac.c */ int priv_get_mac(struct priv *, uint8_t (*)[ETHER_ADDR_LEN]); +void rxq_mac_addrs_del(struct rxq *); +void mlx5_mac_addr_remove(struct rte_eth_dev *, uint32_t); +int rxq_mac_addrs_add(struct rxq *); int priv_mac_addr_add(struct priv *, unsigned int, const uint8_t (*)[ETHER_ADDR_LEN]); +void mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t, + uint32_t); #endif /* RTE_PMD_MLX5_H_ */ diff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c index f7e1cf6888..262d7c6984 100644 --- a/drivers/net/mlx5/mlx5_mac.c +++ b/drivers/net/mlx5/mlx5_mac.c @@ -65,6 +65,8 @@ #include "mlx5.h" #include "mlx5_utils.h" +#include "mlx5_rxtx.h" +#include "mlx5_defs.h" /** * Get MAC address by querying netdevice. @@ -88,9 +90,70 @@ priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN]) return 0; } +/** + * Delete MAC flow steering rule. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index. + */ +static void +rxq_del_mac_flow(struct rxq *rxq, unsigned int mac_index) +{ +#ifndef NDEBUG + const uint8_t (*mac)[ETHER_ADDR_LEN] = + (const uint8_t (*)[ETHER_ADDR_LEN]) + rxq->priv->mac[mac_index].addr_bytes; +#endif + + assert(mac_index < RTE_DIM(rxq->mac_flow)); + if (rxq->mac_flow[mac_index] == NULL) + return; + DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u", + (void *)rxq, + (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], + mac_index); + claim_zero(ibv_destroy_flow(rxq->mac_flow[mac_index])); + rxq->mac_flow[mac_index] = NULL; +} + +/** + * Unregister a MAC address from a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index. + */ +static void +rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index) +{ + assert(mac_index < RTE_DIM(rxq->mac_flow)); + rxq_del_mac_flow(rxq, mac_index); +} + +/** + * Unregister all MAC addresses from a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + */ +void +rxq_mac_addrs_del(struct rxq *rxq) +{ + unsigned int i; + + for (i = 0; (i != RTE_DIM(rxq->mac_flow)); ++i) + rxq_mac_addr_del(rxq, i); +} + /** * Unregister a MAC address. * + * In RSS mode, the MAC address is unregistered from the parent queue, + * otherwise it is unregistered from each queue directly. + * * @param priv * Pointer to private structure. * @param mac_index @@ -99,15 +162,179 @@ priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN]) static void priv_mac_addr_del(struct priv *priv, unsigned int mac_index) { + unsigned int i; + assert(mac_index < RTE_DIM(priv->mac)); if (!BITFIELD_ISSET(priv->mac_configured, mac_index)) return; + if (priv->rss) { + rxq_mac_addr_del(&priv->rxq_parent, mac_index); + goto end; + } + for (i = 0; (i != priv->dev->data->nb_rx_queues); ++i) + rxq_mac_addr_del((*priv->rxqs)[i], mac_index); +end: BITFIELD_RESET(priv->mac_configured, mac_index); } +/** + * DPDK callback to remove a MAC address. + * + * @param dev + * Pointer to Ethernet device structure. + * @param index + * MAC address index. + */ +void +mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) +{ + struct priv *priv = dev->data->dev_private; + + priv_lock(priv); + DEBUG("%p: removing MAC address from index %" PRIu32, + (void *)dev, index); + /* Last array entry is reserved for broadcast. */ + if (index >= (RTE_DIM(priv->mac) - 1)) + goto end; + priv_mac_addr_del(priv, index); +end: + priv_unlock(priv); +} + +/** + * Add MAC flow steering rule. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index to register. + * + * @return + * 0 on success, errno value on failure. + */ +static int +rxq_add_mac_flow(struct rxq *rxq, unsigned int mac_index) +{ + struct ibv_flow *flow; + struct priv *priv = rxq->priv; + const uint8_t (*mac)[ETHER_ADDR_LEN] = + (const uint8_t (*)[ETHER_ADDR_LEN]) + priv->mac[mac_index].addr_bytes; + struct __attribute__((packed)) { + struct ibv_flow_attr attr; + struct ibv_flow_spec_eth spec; + } data; + struct ibv_flow_attr *attr = &data.attr; + struct ibv_flow_spec_eth *spec = &data.spec; + + assert(mac_index < RTE_DIM(rxq->mac_flow)); + if (rxq->mac_flow[mac_index] != NULL) + return 0; + /* + * No padding must be inserted by the compiler between attr and spec. + * This layout is expected by libibverbs. + */ + assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec); + *attr = (struct ibv_flow_attr){ + .type = IBV_FLOW_ATTR_NORMAL, + .num_of_specs = 1, + .port = priv->port, + .flags = 0 + }; + *spec = (struct ibv_flow_spec_eth){ + .type = IBV_FLOW_SPEC_ETH, + .size = sizeof(*spec), + .val = { + .dst_mac = { + (*mac)[0], (*mac)[1], (*mac)[2], + (*mac)[3], (*mac)[4], (*mac)[5] + }, + }, + .mask = { + .dst_mac = "\xff\xff\xff\xff\xff\xff", + }, + }; + DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u", + (void *)rxq, + (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], + mac_index); + /* Create related flow. */ + errno = 0; + flow = ibv_create_flow(rxq->qp, attr); + if (flow == NULL) { + /* It's not clear whether errno is always set in this case. */ + ERROR("%p: flow configuration failed, errno=%d: %s", + (void *)rxq, errno, + (errno ? strerror(errno) : "Unknown error")); + if (errno) + return errno; + return EINVAL; + } + rxq->mac_flow[mac_index] = flow; + return 0; +} + +/** + * Register a MAC address in a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index to register. + * + * @return + * 0 on success, errno value on failure. + */ +static int +rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) +{ + int ret; + + assert(mac_index < RTE_DIM(rxq->mac_flow)); + ret = rxq_add_mac_flow(rxq, mac_index); + if (ret) + return ret; + return 0; +} + +/** + * Register all MAC addresses in a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + * + * @return + * 0 on success, errno value on failure. + */ +int +rxq_mac_addrs_add(struct rxq *rxq) +{ + struct priv *priv = rxq->priv; + unsigned int i; + int ret; + + assert(RTE_DIM(priv->mac) == RTE_DIM(rxq->mac_flow)); + for (i = 0; (i != RTE_DIM(priv->mac)); ++i) { + if (!BITFIELD_ISSET(priv->mac_configured, i)) + continue; + ret = rxq_mac_addr_add(rxq, i); + if (!ret) + continue; + /* Failure, rollback. */ + while (i != 0) + rxq_mac_addr_del(rxq, --i); + assert(ret > 0); + return ret; + } + return 0; +} + /** * Register a MAC address. * + * In RSS mode, the MAC address is registered in the parent queue, + * otherwise it is registered in each queue directly. + * * @param priv * Pointer to private structure. * @param mac_index @@ -123,6 +350,7 @@ priv_mac_addr_add(struct priv *priv, unsigned int mac_index, const uint8_t (*mac)[ETHER_ADDR_LEN]) { unsigned int i; + int ret; assert(mac_index < RTE_DIM(priv->mac)); /* First, make sure this address isn't already configured. */ @@ -145,6 +373,60 @@ priv_mac_addr_add(struct priv *priv, unsigned int mac_index, (*mac)[3], (*mac)[4], (*mac)[5] } }; + /* If device isn't started, this is all we need to do. */ + if (!priv->started) + goto end; + if (priv->rss) { + ret = rxq_mac_addr_add(&priv->rxq_parent, mac_index); + if (ret) + return ret; + goto end; + } + for (i = 0; (i != priv->rxqs_n); ++i) { + if ((*priv->rxqs)[i] == NULL) + continue; + ret = rxq_mac_addr_add((*priv->rxqs)[i], mac_index); + if (!ret) + continue; + /* Failure, rollback. */ + while (i != 0) + if ((*priv->rxqs)[--i] != NULL) + rxq_mac_addr_del((*priv->rxqs)[i], mac_index); + return ret; + } +end: BITFIELD_SET(priv->mac_configured, mac_index); return 0; } + +/** + * DPDK callback to add a MAC address. + * + * @param dev + * Pointer to Ethernet device structure. + * @param mac_addr + * MAC address to register. + * @param index + * MAC address index. + * @param vmdq + * VMDq pool index to associate address with (ignored). + */ +void +mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr, + uint32_t index, uint32_t vmdq) +{ + struct priv *priv = dev->data->dev_private; + + (void)vmdq; + priv_lock(priv); + DEBUG("%p: adding MAC address at index %" PRIu32, + (void *)dev, index); + /* Last array entry is reserved for broadcast. */ + if (index >= (RTE_DIM(priv->mac) - 1)) + goto end; + priv_mac_addr_add(priv, index, + (const uint8_t (*)[ETHER_ADDR_LEN]) + mac_addr->addr_bytes); +end: + priv_unlock(priv); +} diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c index 01cc649993..8450fe3825 100644 --- a/drivers/net/mlx5/mlx5_rxq.c +++ b/drivers/net/mlx5/mlx5_rxq.c @@ -248,6 +248,7 @@ rxq_cleanup(struct rxq *rxq) ¶ms)); } if (rxq->qp != NULL) { + rxq_mac_addrs_del(rxq); claim_zero(ibv_destroy_qp(rxq->qp)); } if (rxq->cq != NULL) @@ -515,6 +516,15 @@ skip_mr: (void *)dev, strerror(ret)); goto error; } + if ((parent) || (!priv->rss)) { + /* Configure MAC and broadcast addresses. */ + ret = rxq_mac_addrs_add(&tmpl); + if (ret) { + ERROR("%p: QP flow attachment failed: %s", + (void *)dev, strerror(ret)); + goto error; + } + } /* Allocate descriptors for RX queues, except for the RSS parent. */ if (parent) goto skip_alloc; diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h index 1459317e4b..3733d3ec77 100644 --- a/drivers/net/mlx5/mlx5_rxtx.h +++ b/drivers/net/mlx5/mlx5_rxtx.h @@ -78,6 +78,8 @@ struct rxq { struct ibv_qp *qp; /* Queue Pair. */ struct ibv_exp_qp_burst_family *if_qp; /* QP burst interface. */ struct ibv_exp_cq_family *if_cq; /* CQ interface. */ + /* MAC flow steering rules. */ + struct ibv_flow *mac_flow[MLX5_MAX_MAC_ADDRESSES]; unsigned int port_id; /* Port ID for incoming packets. */ unsigned int elts_n; /* (*elts)[] length. */ unsigned int elts_head; /* Current index in (*elts)[]. */ -- 2.20.1