Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.a...@intel.com> Signed-off-by: Remy Horton <remy.hor...@intel.com> Signed-off-by: Declan Doherty <declan.dohe...@intel.com> --- config/common_base | 5 + drivers/net/Makefile | 2 + drivers/net/representor/Makefile | 51 ++ drivers/net/representor/rte_eth_representor.c | 973 +++++++++++++++++++++ .../representor/rte_pmd_representor_version.map | 4 + lib/librte_ether/rte_ethdev_vdev.h | 37 +- mk/rte.app.mk | 1 + 7 files changed, 1070 insertions(+), 3 deletions(-) create mode 100644 drivers/net/representor/Makefile create mode 100644 drivers/net/representor/rte_eth_representor.c create mode 100644 drivers/net/representor/rte_pmd_representor_version.map
diff --git a/config/common_base b/config/common_base index 5e97a08..d7ba871 100644 --- a/config/common_base +++ b/config/common_base @@ -750,3 +750,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y # Compile the eventdev application # CONFIG_RTE_APP_EVENTDEV=y + +# +# Compile representor PMD +# +CONFIG_RTE_LIBRTE_PMD_REPRESENTOR=y diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d33c959..1b76a42 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -83,6 +83,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap DEPDIRS-pcap = $(core-libs) DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede DEPDIRS-qede = $(core-libs) +DIRS-$(CONFIG_RTE_LIBRTE_PMD_REPRESENTOR) += representor +DEPDIRS-representor = $(core-libs) DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring DEPDIRS-ring = $(core-libs) DIRS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD) += sfc diff --git a/drivers/net/representor/Makefile b/drivers/net/representor/Makefile new file mode 100644 index 0000000..18b23f4 --- /dev/null +++ b/drivers/net/representor/Makefile @@ -0,0 +1,51 @@ +# BSD LICENSE +# +# Copyright(c) 2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_representor.a + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +EXPORT_MAP := rte_pmd_representor_version.map + +LIBABIVER := 1 + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_REPRESENTOR) += rte_eth_representor.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/representor/rte_eth_representor.c b/drivers/net/representor/rte_eth_representor.c new file mode 100644 index 0000000..cec532d --- /dev/null +++ b/drivers/net/representor/rte_eth_representor.c @@ -0,0 +1,973 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_ethdev.h> +#include <rte_ethdev_vdev.h> +#include <rte_vdev.h> +#include <rte_kvargs.h> +#include <rte_port_representor.h> +#include <rte_flow_driver.h> + +#define PORT_REP_MAX_VFS 64 + +static struct ether_addr list_eth_addrs[PORT_REP_MAX_VFS]; + +struct port_rep_parameters { + uint32_t mask; + uint64_t vf_mask; + uint8_t parent; +}; + +struct port_rep_internals { + uint8_t port_id; + struct port_rep_parameters params; + struct rte_port_representor *port_rep; +}; + +static struct port_rep_parameters vdev_params; + +static inline void +apply_range_to_mask(int lower, int upper, uint64_t *mask) +{ + int idx_mask; + + for (idx_mask = lower; idx_mask <= upper; idx_mask++) + *mask = *mask | (0x01ULL << idx_mask); +} + +static int +range_to_mask(const char *range_str, uint64_t *mask) +{ + int value; + int state; + int lower_bound; + + state = 0; + while (1) { + switch (state) { + case 0: /* Initial */ + if (!isdigit(*range_str)) + return -EINVAL; + value = *range_str - '0'; + state = 1; + break; + + case 1: /* Parsing lower bound */ + if (isdigit(*range_str)) { + value *= 10; + value += *range_str - '0'; + } else if (*range_str == '-') { + state = '-'; + lower_bound = value; + value = 0; + } else if (*range_str == '\0') { + apply_range_to_mask(value, value, mask); + return 0; + } else if (*range_str == ':') { + apply_range_to_mask(value, value, mask); + value = 0; + state = 0; + } else { + return -EINVAL; + } + break; + + case '-': /* Parsing upper bound */ + if (isdigit(*range_str)) { + value *= 10; + value += *range_str - '0'; + } else if (*range_str == '\0') { + apply_range_to_mask(lower_bound, value, mask); + return 0; + } else if (*range_str == ':') { + apply_range_to_mask(lower_bound, value, mask); + value = 0; + state = 0; + } else { + return -EINVAL; + } + break; + } + range_str++; + } + + return -EINVAL; +} + +/**************************************************************************** + * PMD operation callbacks + ****************************************************************************/ + +static void +port_rep_info(struct rte_eth_dev *dev, + struct rte_eth_dev_info *dev_info) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev || !dev_info) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) { + RTE_LOG(ERR, PMD, "Representor PMD is NULL\n"); + return; + } + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) { + RTE_LOG(ERR, PMD, "Representor Broker is NULL\n"); + return; + } + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->dev_infos_get); + repr_broker->rep_ops->dev_infos_get(repr_broker, internals->port_rep, + dev_info); +} + +static int +port_rep_start(struct rte_eth_dev *dev) +{ + if (!dev) + return -EINVAL; + + dev->data->dev_link.link_status = ETH_LINK_UP; + return 0; +} + +static void +port_rep_stop(struct rte_eth_dev *dev) +{ + if (!dev) + return; + + dev->data->dev_link.link_status = ETH_LINK_DOWN; +} + +static int +port_rep_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, + uint16_t nb_rx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_rxconf *rx_conf __rte_unused, + struct rte_mempool *mb_pool) +{ + if (!dev || !mb_pool) + return -EINVAL; + + if (rx_queue_id >= dev->data->nb_rx_queues) + return -ENODEV; + + dev->data->rx_queues[rx_queue_id] = (void *)0xdeadbeef; + + return 0; +} + +static int +port_rep_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id, + uint16_t nb_tx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_txconf *tx_conf __rte_unused) +{ + if (!dev) + return -EINVAL; + + if (tx_queue_id >= dev->data->nb_tx_queues) + return -ENODEV; + + dev->data->tx_queues[tx_queue_id] = (void *)0xdeadbeef; + + return 0; +} + +static void +port_rep_queue_release(__rte_unused void *q) +{ +} + +static int +port_rep_link_update(struct rte_eth_dev *dev, int wait_to_complete) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->link_update, -ENOTSUP); + + return repr_broker->rep_ops->link_update(repr_broker, + internals->port_rep, wait_to_complete); +} + +static void +port_rep_promiscuous_enable(struct rte_eth_dev *dev) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->promiscuous_enable); + repr_broker->rep_ops->promiscuous_enable( + repr_broker, internals->port_rep); +} + +static void +port_rep_promiscuous_disable(struct rte_eth_dev *dev) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->promiscuous_disable); + repr_broker->rep_ops->promiscuous_disable( + repr_broker, internals->port_rep); +} + +static void +port_rep_allmulticast_enable(struct rte_eth_dev *dev) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->allmulticast_enable); + repr_broker->rep_ops->allmulticast_enable( + repr_broker, internals->port_rep); +} + +static void +port_rep_allmulticast_disable(struct rte_eth_dev *dev) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->allmulticast_disable); + repr_broker->rep_ops->allmulticast_disable( + repr_broker, internals->port_rep); +} + +static void +port_rep_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->mac_addr_remove); + repr_broker->rep_ops->mac_addr_remove( + repr_broker, internals->port_rep, index); +} + +static int +port_rep_mac_addr_add(__rte_unused struct rte_eth_dev *dev, + struct ether_addr *mac_addr, uint32_t index, uint32_t vmdq) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->mac_addr_add, -ENOTSUP); + + return repr_broker->rep_ops->mac_addr_add(repr_broker, + internals->port_rep, mac_addr, index, vmdq); +} + +static void +port_rep_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev || !mac_addr) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->mac_addr_set); + repr_broker->rep_ops->mac_addr_set(repr_broker, internals->port_rep, + mac_addr); +} + +static int +port_rep_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->vlan_filter_set, + -ENOTSUP); + return repr_broker->rep_ops->vlan_filter_set(repr_broker, + internals->port_rep, vlan_id, on); +} + +static int +port_rep_vlan_tpid_set(struct rte_eth_dev *dev, enum rte_vlan_type type, + uint16_t tpid) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->vlan_tpid_set, -ENOTSUP); + + return repr_broker->rep_ops->vlan_tpid_set(repr_broker, + internals->port_rep, type, tpid); +} + +static void +port_rep_vlan_strip_queue_set(struct rte_eth_dev *dev, + __rte_unused uint16_t rx_queue_id, int on) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->vlan_strip_queue_set); + repr_broker->rep_ops->vlan_strip_queue_set(repr_broker, + internals->port_rep, on); +} + +static void +port_rep_vlan_offload_set(struct rte_eth_dev *dev, int mask) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->vlan_offload_set); + repr_broker->rep_ops->vlan_offload_set(repr_broker, + internals->port_rep, mask); +} + +static int +port_rep_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t vlan_id, + __rte_unused int on) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->vlan_pvid_set, -ENOTSUP); + + return repr_broker->rep_ops->vlan_pvid_set(repr_broker, + internals->port_rep, vlan_id); +} + +static void +port_rep_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->stats_get); + repr_broker->rep_ops->stats_get(repr_broker, + internals->port_rep, stats); +} + +static void +port_rep_stats_reset(struct rte_eth_dev *dev) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return; + + RTE_FUNC_PTR_OR_RET(*repr_broker->rep_ops->stats_reset); + repr_broker->rep_ops->stats_reset(repr_broker, + internals->port_rep); +} + +static int +port_rep_flow_validate(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], struct rte_flow_error *error) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->flow_validate, -EINVAL); + return repr_broker->rep_ops->flow_validate(repr_broker, + internals->port_rep, attr, pattern, actions, error); +} + +static struct rte_flow * +port_rep_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, + const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], struct rte_flow_error *error) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return NULL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return NULL; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return NULL; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->flow_validate, NULL); + return repr_broker->rep_ops->flow_create(repr_broker, + internals->port_rep, attr, pattern, actions, error); +} + +static int +port_rep_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow, + struct rte_flow_error *error) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->flow_validate, -EINVAL); + return repr_broker->rep_ops->flow_destroy(repr_broker, + internals->port_rep, flow, error); +} + +static int +port_rep_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error) +{ + struct port_rep_internals *internals; + struct rte_port_representor_broker *repr_broker; + + if (!dev) + return -EINVAL; + + internals = dev->data->dev_private; + if (!internals->port_rep) + return -ENODEV; + repr_broker = internals->port_rep->pdev->rep_broker; + if (!repr_broker) + return -ENODEV; + + RTE_FUNC_PTR_OR_ERR_RET(*repr_broker->rep_ops->flow_validate, -EINVAL); + return repr_broker->rep_ops->flow_flush(repr_broker, + internals->port_rep, error); +} + +static const struct rte_flow_ops port_rep_flow_ops = { + .validate = port_rep_flow_validate, + .create = port_rep_flow_create, + .destroy = port_rep_flow_destroy, + .flush = port_rep_flow_flush, +}; + +static int +port_rep_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type, + enum rte_filter_op filter_op, void *arg) +{ + int ret = 0; + + if (!dev) + return -EINVAL; + + switch (filter_type) { + case RTE_ETH_FILTER_GENERIC: + if (filter_op != RTE_ETH_FILTER_GET) + return -EINVAL; + *(const void **)arg = &port_rep_flow_ops; + break; + default: + RTE_LOG(WARNING, PMD, "Filter type (%d) not supported", + filter_type); + ret = -EINVAL; + break; + } + + return ret; +} + +/* Stub function to make eth_dev happy */ +static int +port_rep_configure(__rte_unused struct rte_eth_dev *dev) +{ + return 0; +} + +/* Stub function to make eth_dev happy */ +static uint16_t +port_rep_rx(__rte_unused void *q, __rte_unused struct rte_mbuf **bufs, + __rte_unused uint16_t nb_bufs) +{ + return 0; +} + +/* Stub function to make eth_dev happy */ +static uint16_t +port_rep_tx(__rte_unused void *q, __rte_unused struct rte_mbuf **bufs, + __rte_unused uint16_t nb_bufs) +{ + return 0; +} + +static const struct eth_dev_ops port_rep_ops = { + .dev_start = port_rep_start, + .dev_stop = port_rep_stop, + .dev_configure = port_rep_configure, + .dev_infos_get = port_rep_info, + .rx_queue_setup = port_rep_rx_queue_setup, + .tx_queue_setup = port_rep_tx_queue_setup, + .rx_queue_release = port_rep_queue_release, + .tx_queue_release = port_rep_queue_release, + + .link_update = port_rep_link_update, + + .promiscuous_enable = port_rep_promiscuous_enable, + .promiscuous_disable = port_rep_promiscuous_disable, + .allmulticast_enable = port_rep_allmulticast_enable, + .allmulticast_disable = port_rep_allmulticast_disable, + + .mac_addr_remove = port_rep_mac_addr_remove, + .mac_addr_add = port_rep_mac_addr_add, + .mac_addr_set = port_rep_mac_addr_set, + + .vlan_filter_set = port_rep_vlan_filter_set, + .vlan_tpid_set = port_rep_vlan_tpid_set, + .vlan_strip_queue_set = port_rep_vlan_strip_queue_set, + .vlan_offload_set = port_rep_vlan_offload_set, + .vlan_pvid_set = port_rep_vlan_pvid_set, + + .stats_get = port_rep_stats_get, + .stats_reset = port_rep_stats_reset, + + .filter_ctrl = port_rep_filter_ctrl, +}; + +/**************************************************************************** + * Startup & parameter handling + ****************************************************************************/ + +static void port_rep_default_params(struct port_rep_parameters *params) +{ + params->parent = -1; + params->vf_mask = 0UL; +} + +static int +port_rep_kvargs_parent(__rte_unused const char *key, + const char *value, void *ptr) +{ + struct port_rep_parameters *params = ptr; + int ret = 0; + + /* only added this check to accept uint values as we do not have + * B:D:F to uint mapping function + */ + if (!strchr(value, ':')) { + params->parent = strtoul(value, NULL, 0); + } else { + ret = rte_eth_dev_get_port_by_pci_addr_str(value, + ¶ms->parent); + if (ret != 0) + RTE_LOG(ERR, PMD, + "'pfid=%s' does not give a valid device name\n", + value); + } + + return ret; +} + +static int +port_rep_kvargs_vf_index(__rte_unused const char *key, + const char *value, void *ptr) +{ + struct port_rep_parameters *params = ptr; + int ret; + + ret = range_to_mask(value, ¶ms->vf_mask); + if (ret != 0) + RTE_LOG(ERR, PMD, "'vf_index=%s' does not give a valid device " + "name\n", value); + return ret; +} + +typedef int (*port_rep_arg_func_t)(const char*, const char*, void*); + +static const char * const port_rep_kvargs_codes[] = { + "parent", "vf_index", NULL +}; + +static port_rep_arg_func_t port_rep_kvargs_callbacks[] = { + &port_rep_kvargs_parent, + &port_rep_kvargs_vf_index, + NULL +}; + +static int +port_rep_create(struct rte_vdev_device *dev, + struct port_rep_parameters *params) +{ + const unsigned nb_rx_queues = 1; + const unsigned nb_tx_queues = 1; + struct rte_eth_dev_data *data = NULL; + struct port_rep_internals *internals = NULL; + struct rte_eth_dev *eth_dev = NULL; + struct rte_port_representor *rep = NULL; + uint64_t vf_mask; + uint16_t idx_vf; + + char name_buffer[RTE_ETH_NAME_MAX_LEN]; + + if (dev->device.numa_node == SOCKET_ID_ANY) + dev->device.numa_node = rte_socket_id(); + + RTE_LOG(INFO, PMD, "Creating representor ethdev on numa socket %u\n", + dev->device.numa_node); + + memset(&list_eth_addrs, 0, sizeof(list_eth_addrs)); + + vf_mask = 1; + idx_vf = 0; + while (vf_mask <= params->vf_mask) { + if (params->vf_mask & vf_mask) { + /* now do all data allocation - for eth_dev structure, + * dummy pci driver and internal (private) data + */ + data = rte_zmalloc_socket(rte_vdev_device_name(dev), + sizeof(*data), 0, dev->device.numa_node); + if (!data) + return -ENOMEM; + + snprintf(name_buffer, RTE_ETH_NAME_MAX_LEN, + "%s.%i", rte_vdev_device_name(dev), idx_vf); + + eth_dev = rte_eth_vdev_allocate_2(dev, + sizeof(*internals), name_buffer); + if (!eth_dev) { + rte_free(data); + return -ENOMEM; + } + /* create hook for port representor in broker */ + rep = NULL; + if (rte_representor_enabled()) { + rep = rte_representor_initialize( + params->parent, idx_vf, eth_dev); + if (!rep) { + rte_free(data); + return -ENOMEM; + } + } + /* now put it all together + * - store queue data in internals, + * - store numa_node info in ethdev data + * - point eth_dev_data to internals + * - and point eth_dev structure to new eth_dev_data + * structure + */ + /* NOTE: we'll replace the data element, of originally + * allocated eth_dev so the nulls are local per-process + */ + + internals = eth_dev->data->dev_private; + + rte_memcpy(&internals->params, params, + sizeof(struct port_rep_parameters)); + internals->port_id = eth_dev->data->port_id; + internals->port_rep = rep; + + rte_memcpy(data, eth_dev->data, sizeof(*data)); + data->nb_rx_queues = (uint16_t)nb_rx_queues; + data->nb_tx_queues = (uint16_t)nb_tx_queues; + + /* Link state. */ + data->dev_link.link_speed = ETH_SPEED_NUM_10G; + data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; + data->dev_link.link_status = ETH_LINK_DOWN; + data->dev_link.link_autoneg = ETH_LINK_SPEED_AUTONEG; + + /* MAC address. Same caveats as link state. */ + data->mac_addrs = &list_eth_addrs[idx_vf]; + + eth_dev->data = data; + eth_dev->dev_ops = &port_rep_ops; + + data->dev_flags = RTE_ETH_DEV_DETACHABLE; + + /* finally assign rx and tx ops */ + eth_dev->rx_pkt_burst = port_rep_rx; + eth_dev->tx_pkt_burst = port_rep_tx; + } + /* Keep bitmask and bit index in sync */ + vf_mask = vf_mask << 1; + idx_vf++; + } + + return 0; +} + +static int +port_rep_probe(struct rte_vdev_device *dev) +{ + const char *name; + const char *args; + struct rte_kvargs *kvlist = NULL; + int ret; + int idx_table; + + if (!dev) + return -EINVAL; + + port_rep_default_params(&vdev_params); + + name = rte_vdev_device_name(dev); + args = rte_vdev_device_args(dev); + RTE_LOG(INFO, PMD, "Initializing port_representor pmd for %s\n", name); + if (args) { + kvlist = rte_kvargs_parse(args, port_rep_kvargs_codes); + if (!kvlist) + return -1; + + idx_table = 0; + while (port_rep_kvargs_codes[idx_table] != NULL) { + ret = rte_kvargs_process(kvlist, + port_rep_kvargs_codes[idx_table], + port_rep_kvargs_callbacks[idx_table], + &vdev_params); + if (ret != 0) { + RTE_LOG(ERR, PMD, "port_representor pmd " + "parameter error\n"); + rte_kvargs_free(kvlist); + return -1; + } + idx_table++; + } + } + RTE_LOG(INFO, PMD, "Configure port_representor pmd with args=\"%s\"\n", + args); + + ret = port_rep_create(dev, &vdev_params); + + if (kvlist) + rte_kvargs_free(kvlist); + + return ret; +} + +static int +port_rep_remove(struct rte_vdev_device *dev) +{ + struct rte_eth_dev *eth_dev = NULL; + uint64_t vf_mask; + uint16_t cnt_vf; + char name_buffer[RTE_ETH_NAME_MAX_LEN]; + + if (!dev) + return -EINVAL; + + RTE_LOG(INFO, PMD, "Closing representor port on numa socket %u\n", + rte_socket_id()); + + vf_mask = 1; + cnt_vf = 0; + while (vf_mask <= vdev_params.vf_mask) { + if (vdev_params.vf_mask & vf_mask) { + snprintf(name_buffer, RTE_ETH_NAME_MAX_LEN, "%s.%i", + rte_vdev_device_name(dev), cnt_vf); + + /* Find and deallocate the ethdev entry */ + eth_dev = rte_eth_dev_allocated( + rte_vdev_device_name(dev)); + if (!eth_dev) + return -1; + + rte_free(eth_dev->data->dev_private); + rte_free(eth_dev->data); + rte_eth_dev_release_port(eth_dev); + } + + cnt_vf++; + vf_mask = vf_mask << 1; + } + + return 0; +} + +static struct rte_vdev_driver port_rep_vdev_drv = { + .probe = port_rep_probe, + .remove = port_rep_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_representor, port_rep_vdev_drv); +RTE_PMD_REGISTER_ALIAS(net_representor, eth_representor); +RTE_PMD_REGISTER_PARAM_STRING(net_representor, + "parent=<pci addr>:vf_index=<uint range>"); diff --git a/drivers/net/representor/rte_pmd_representor_version.map b/drivers/net/representor/rte_pmd_representor_version.map new file mode 100644 index 0000000..ef35398 --- /dev/null +++ b/drivers/net/representor/rte_pmd_representor_version.map @@ -0,0 +1,4 @@ +DPDK_2.0 { + + local: *; +}; diff --git a/lib/librte_ether/rte_ethdev_vdev.h b/lib/librte_ether/rte_ethdev_vdev.h index 4d2c3e2..7aaaca3 100644 --- a/lib/librte_ether/rte_ethdev_vdev.h +++ b/lib/librte_ether/rte_ethdev_vdev.h @@ -49,18 +49,29 @@ * @param private_data_size * Size of private data structure * + * @param override_name + * Given name for the vdev instead of default one + * * @return * A pointer to a rte_eth_dev or NULL if allocation failed. */ static inline struct rte_eth_dev * -rte_eth_vdev_allocate(struct rte_vdev_device *dev, size_t private_data_size) +rte_eth_vdev_allocate_2(struct rte_vdev_device *dev, size_t private_data_size, + const char *override_name) { struct rte_eth_dev *eth_dev; - const char *name = rte_vdev_device_name(dev); + const char *name; + + if (override_name) + name = override_name; + else + name = rte_vdev_device_name(dev); eth_dev = rte_eth_dev_allocate(name); - if (!eth_dev) + if (!eth_dev) { + printf("FAILED!\n"); return NULL; + } if (private_data_size) { eth_dev->data->dev_private = rte_zmalloc_socket(name, @@ -80,4 +91,24 @@ rte_eth_vdev_allocate(struct rte_vdev_device *dev, size_t private_data_size) return eth_dev; } +/** + * @internal + * Allocates a new ethdev slot for an ethernet device and returns the pointer + * to that slot for the driver to use. + * + * @param dev + * Pointer to virtual device + * + * @param private_data_size + * Size of private data structure + * + * @return + * A pointer to a rte_eth_dev or NULL if allocation failed. + */ +static inline struct rte_eth_dev * +rte_eth_vdev_allocate(struct rte_vdev_device *dev, size_t private_data_size) +{ + return rte_eth_vdev_allocate_2(dev, private_data_size, NULL); +} + #endif /* _RTE_ETHDEV_VDEV_H_ */ diff --git a/mk/rte.app.mk b/mk/rte.app.mk index c25fdd9..3dbbe3a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -132,6 +132,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += -lrte_pmd_mlx4 -libverbs _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += -lrte_pmd_mlx5 -libverbs _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += -lrte_pmd_nfp _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += -lrte_pmd_null +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_REPRESENTOR) += -lrte_pmd_representor _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += -lrte_pmd_pcap -lpcap _LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += -lrte_pmd_qede _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING) += -lrte_pmd_ring -- 2.7.4