Skip to contentSkip to conversation

introduce fail-safe PMD

PATCH Superseded Gaetan Rivet 6 participants 195 messages May 24, 2017 – Aug 3, 2017 Network drivers Page 2 of 2

lore
Share & tools
lore
#108 lore raw

Re: [PATCH v7 03/11] net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet
Quoted 680 lines · Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                                       |   5 +
 config/common_base                                |   6 +
 doc/guides/nics/fail_safe.rst                     | 133 +++++
 doc/guides/nics/features/failsafe.ini             |  24 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  76 +++
 drivers/net/failsafe/failsafe.c                   | 231 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 331 +++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 154 +++++
 drivers/net/failsafe/failsafe_ops.c               | 663 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 227 ++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 107 ++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 mk/rte.app.mk                                     |   1 +
 15 files changed, 1965 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
MAINTAINERS +5 -0
index 8fb2132..b4a446f 100644
@@ -336,6 +336,11 @@ F: drivers/net/enic/
 F: doc/guides/nics/enic.rst
 F: doc/guides/nics/features/enic.ini
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +6 -0
index bb1ba8b..cf5e7f5 100644
@@ -420,6 +420,12 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG=n
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +133 -0
new file mode 100644
index 0000000..056f85f
@@ -0,0 +1,133 @@
+..  BSD LICENSE
+    Copyright 2017 6WIND S.A.
+
+    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 6WIND S.A. 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.
+
+Fail-safe poll mode driver library
+==================================
+
+The Fail-safe poll mode driver library (**librte_pmd_failsafe**) is a virtual
+device that allows using any device supporting hotplug (sudden device removal
+and plugging on its bus), without modifying other components relying on such
+device (application, other PMDs).
+
+Additionally to the Seamless Hotplug feature, the Fail-safe PMD offers the
+ability to redirect operations to secondary devices when the primary has been
+removed from the system.
+
+.. note::
+
+   The library is enabled by default. You can enable it or disable it manually
+   by setting the ``CONFIG_RTE_LIBRTE_PMD_FAILSAFE`` configuration option.
+
+Features
+--------
+
+The Fail-safe PMD only supports a limited set of features. If you plan to use a
+device underneath the Fail-safe PMD with a specific feature, this feature must
+be supported by the Fail-safe PMD to avoid throwing any error.
+
+Check the feature matrix for the complete set of supported features.
+
+Compilation options
+-------------------
+
+These options can be modified in the ``$RTE_TARGET/build/.config`` file.
+
+- ``CONFIG_RTE_LIBRTE_PMD_FAILSAFE`` (default **y**)
+
+  Toggle compiling librte_pmd_failsafe itself.
+
+- ``CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG`` (default **n**)
+
+  Toggle debugging code.
+
+Using the Fail-safe PMD from the EAL command line
+-------------------------------------------------
+
+The Fail-safe PMD can be used like most other DPDK virtual devices, by passing a
+``--vdev`` parameter to the EAL when starting the application. The device name
+must start with the *net_failsafe* prefix, followed by numbers or letters. This
+name must be unique for each device. Each fail-safe instance must have at least one
+sub-device, up to ``RTE_MAX_ETHPORTS-1``.
+
+A sub-device can be any legal DPDK device, including possibly another fail-safe
+instance.
+
+Fail-safe command line parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- **dev(<iface>)** parameter
+
+  This parameter allows the user to define a sub-device. The ``<iface>`` part of
+  this parameter must be a valid device definition. It could be the argument
+  provided to a ``-w`` PCI device specification or the argument that would be
+  given to a ``--vdev`` parameter (including a fail-safe).
+  Enclosing the device definition within parenthesis here allows using
+  additional sub-device parameters if need be. They will be passed on to the
+  sub-device.
+
+- **mac** parameter [MAC address]
+
+  This parameter allows the user to set a default MAC address to the fail-safe
+  and all of its sub-devices.
+  If no default mac address is provided, the fail-safe PMD will read the MAC
+  address of the first of its sub-device to be successfully probed and use it as
+  its default MAC address, trying to set it to all of its other sub-devices.
+  If no sub-device was successfully probed at initialization, then a random MAC
+  address is generated, that will be subsequently applied to all sub-device once
+  they are probed.
+
+Usage example
+~~~~~~~~~~~~~
+
+This section shows some example of using **testpmd** with a fail-safe PMD.
+
+#. Request huge pages:
+
+   .. code-block:: console
+
+      echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
+
+#. Start testpmd
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0,nodeaction=r1:0:CREATE)' -- \
+         -i
+
+Using the Fail-safe PMD from an application
+-------------------------------------------
+
+This driver strives to be as seamless as possible to existing applications, in
+order to propose the hotplug functionality in the easiest way possible.
+
+Care must be taken, however, to respect the **ether** API concerning device
+access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
+over ethernet devices, instead of directly accessing them or by writing one's
+own device iterator.
doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..3c52823
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+Queue start/stop     = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 240d082..17eaaf4 100644
@@ -64,6 +64,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +2 -0
index 35ed813..d33c959 100644
@@ -59,6 +59,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DEPDIRS-ena = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DEPDIRS-enic = $(core-libs) librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
+DEPDIRS-failsafe = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DEPDIRS-fm10k = $(core-libs) librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
drivers/net/failsafe/Makefile new file +76 -0
new file mode 100644
index 0000000..c759035
@@ -0,0 +1,76 @@
+#   BSD LICENSE
+#
+#   Copyright 2017 6WIND S.A.
+#   Copyright 2017 Mellanox.
+#
+#   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 6WIND S.A. 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_failsafe.a
+
+EXPORT_MAP := rte_pmd_failsafe_version.map
+
+LIBABIVER := 1
+
+# Sources are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+
+# No exported include files
+
+# This lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_kvargs
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_mbuf
+
+ifneq ($(DEBUG),)
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG := y
+endif
+
+# Basic CFLAGS:
+CFLAGS += -std=gnu99 -Wall -Wextra
+CFLAGS += -I.
+CFLAGS += -D_DEFAULT_SOURCE
+CFLAGS += -D_XOPEN_SOURCE=700
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -Wno-strict-prototypes
+CFLAGS += -pedantic -DPEDANTIC
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG),y)
+CFLAGS += -g -UNDEBUG
+else
+CFLAGS += -O3
+CFLAGS += -DNDEBUG
+endif
+
+include $(RTE_SDK)/mk/rte.lib.mk
drivers/net/failsafe/failsafe.c new file +231 -0
new file mode 100644
index 0000000..7cf33e8
@@ -0,0 +1,231 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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_alarm.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_vdev.h>
+#include <rte_devargs.h>
+#include <rte_kvargs.h>
+#include <rte_vdev.h>
+
+#include "failsafe_private.h"
+
+const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
+static const struct rte_eth_link eth_link = {
+       .link_speed = ETH_SPEED_NUM_10G,
+       .link_duplex = ETH_LINK_FULL_DUPLEX,
+       .link_status = ETH_LINK_UP,
+       .link_autoneg = ETH_LINK_SPEED_AUTONEG,
+};
+
+static int
+fs_sub_device_create(struct rte_eth_dev *dev,
+               const char *params)
+{
+       uint8_t nb_subs;
+       int ret;
+
+       ret = failsafe_args_count_subdevice(dev, params);
+       if (ret)
+               return ret;
+       if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
+               ERROR("Cannot allocate more than %d ports",
+                       FAILSAFE_MAX_ETHPORTS);
+               return -ENOSPC;
+       }
+       nb_subs = PRIV(dev)->subs_tail;
+       PRIV(dev)->subs = rte_zmalloc(NULL,
+                       sizeof(struct sub_device) * nb_subs,
+                       RTE_CACHE_LINE_SIZE);
+       if (PRIV(dev)->subs == NULL) {
+               ERROR("Could not allocate sub_devices");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void
+fs_sub_device_free(struct rte_eth_dev *dev)
+{
+       rte_free(PRIV(dev)->subs);
+}
+
+static int
+fs_eth_dev_create(struct rte_vdev_device *vdev)
+{
+       struct rte_eth_dev *dev;
+       struct ether_addr *mac;
+       struct fs_priv *priv;
+       struct sub_device *sdev;
+       const char *params;
+       unsigned int socket_id;
+       uint8_t i;
+       int ret;
+
+       dev = NULL;
+       priv = NULL;
+       params = rte_vdev_device_args(vdev);
+       socket_id = rte_socket_id();
+       INFO("Creating fail-safe device on NUMA socket %u",
+            socket_id);
+       dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
+       if (dev == NULL) {
+               ERROR("Unable to allocate rte_eth_dev");
+               return -1;
+       }
+       priv = dev->data->dev_private;
+       PRIV(dev)->dev = dev;
+       dev->dev_ops = &failsafe_ops;
+       TAILQ_INIT(&dev->link_intr_cbs);
+       dev->data->dev_flags = 0x0;
+       dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
+       dev->data->dev_link = eth_link;
+       PRIV(dev)->nb_mac_addr = 1;
+       dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
+       dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
+       if (params == NULL) {
+               ERROR("This PMD requires sub-devices, none provided");
+               goto free_dev;
+       }
+       ret = fs_sub_device_create(dev, params);
+       if (ret) {
+               ERROR("Could not allocate sub_devices");
+               goto free_dev;
+       }
+       ret = failsafe_args_parse(dev, params);
+       if (ret)
+               goto free_subs;
+       ret = failsafe_eal_init(dev);
+       if (ret)
+               goto free_args;
+       mac = &dev->data->mac_addrs[0];
+       if (mac_from_arg) {
+               /*
+                * If MAC address was provided as a parameter,
+                * apply to all probed slaves.
+                */
+               FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
+                       ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
+                                                              mac);
+                       if (ret) {
+                               ERROR("Failed to set default MAC address");
+                               goto free_args;
+                       }
+               }
+       } else {
+               /*
+                * Use the ether_addr from first probed
+                * device, either preferred or fallback.
+                */
+               FOREACH_SUBDEV(sdev, i, dev)
+                       if (sdev->state >= DEV_PROBED) {
+                               ether_addr_copy(&ETH(sdev)->data->mac_addrs[0],
+                                               mac);
+                               break;
+                       }
+               /*
+                * If no device has been probed and no ether_addr
+                * has been provided on the command line, use a random
+                * valid one.
+                * It will be applied during future slave state syncs to
+                * probed slaves.
+                */
+               if (i == priv->subs_tail)
+                       eth_random_addr(&mac->addr_bytes[0]);
+       }
+       INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
+               mac->addr_bytes[0], mac->addr_bytes[1],
+               mac->addr_bytes[2], mac->addr_bytes[3],
+               mac->addr_bytes[4], mac->addr_bytes[5]);
+       return 0;
+free_args:
+       failsafe_args_free(dev);
+free_subs:
+       fs_sub_device_free(dev);
+free_dev:
+       rte_eth_dev_release_port(dev);
+       return -1;
+}
+
+static int
+fs_rte_eth_free(const char *name)
+{
+       struct rte_eth_dev *dev;
+       int ret;
+
+       dev = rte_eth_dev_allocated(name);
+       if (dev == NULL)
+               return -ENODEV;
+       ret = failsafe_eal_uninit(dev);
+       if (ret)
+               ERROR("Error while uninitializing sub-EAL");
+       failsafe_args_free(dev);
+       fs_sub_device_free(dev);
+       rte_free(PRIV(dev));
+       rte_eth_dev_release_port(dev);
+       return ret;
+}
+
+static int
+rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
+{
+       const char *name;
+
+       name = rte_vdev_device_name(vdev);
+       if (vdev == NULL)
+               return -EINVAL;
+       INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
+                       name);
+       return fs_eth_dev_create(vdev);
+}
+
+static int
+rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
+{
+       const char *name;
+
+       name = rte_vdev_device_name(vdev);
+       if (name == NULL)
+               return -EINVAL;
+       INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
+       return fs_rte_eth_free(name);
+}
+
+static struct rte_vdev_driver failsafe_drv = {
+       .probe = rte_pmd_failsafe_probe,
+       .remove = rte_pmd_failsafe_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
+RTE_PMD_REGISTER_ALIAS(net_failsafe, eth_failsafe);
+RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
drivers/net/failsafe/failsafe_args.c new file +83 -0
new file mode 100644
index 0000000..f07d26e
@@ -0,0 +1,331 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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 <string.h>
+#include <errno.h>
+
+#include <rte_devargs.h>
+#include <rte_malloc.h>
+#include <rte_kvargs.h>
+
+#include "failsafe_private.h"
+
+#define DEVARGS_MAXLEN 4096
+
+/* Callback used when a new device is found in devargs */
+typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
+               uint8_t head);
+
+int mac_from_arg;
+
+const char *pmd_failsafe_init_parameters[] = {
+       PMD_FAILSAFE_MAC_KVARG,
+       NULL,
+};
+
+/*
+ * input: text.
+ * output: 0: if text[0] != '(',
+ *         0: if there are no corresponding ')'
+ *         n: distance to corresponding ')' otherwise
+ */
+static size_t
+closing_paren(const char *text)
+{
+       int nb_open = 0;
+       size_t i = 0;
+
+       while (text[i] != '\0') {
+               if (text[i] == '(')
+                       nb_open++;
+               if (text[i] == ')')
+                       nb_open--;
+               if (nb_open == 0)
+                       return i;
+               i++;
+       }
+       return 0;
+}
+
+static int
+fs_parse_device(struct sub_device *sdev, char *args)
+{
+       struct rte_devargs *d;
+       int ret;

drivers/net/failsafe/failsafe_args.c line 93

Quoted 10 lines
drivers/net/failsafe/failsafe_args.c new file +10 -0
+
+       d = &sdev->devargs;
+       DEBUG("%s", args);
+       ret = rte_eal_devargs_parse(args, d);
+       if (ret) {
+               DEBUG("devargs parsing failed with code %d", ret);
+               return ret;
+       }
+       sdev->bus = d->bus;
+       sdev->state = DEV_PARSED;

You seem to be mostly interested in the bus name for the device. Why don't you track this via your sub_device structure instead of using rte_devargs?

Quoted 284 lines
drivers/net/failsafe/failsafe_args.c new file +238 -0
+       return 0;
+}
+
+static int
+fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
+               uint8_t head)
+{
+       struct fs_priv *priv;
+       struct sub_device *sdev;
+       char *args = NULL;
+       size_t a, b;
+       int ret;
+
+       priv = PRIV(dev);
+       a = 0;
+       b = 0;
+       ret = 0;
+       while  (param[b] != '(' &&
+               param[b] != '\0')
+               b++;
+       a = b;
+       b += closing_paren(&param[b]);
+       if (a == b) {
+               ERROR("Dangling parenthesis");
+               return -EINVAL;
+       }
+       a += 1;
+       args = strndup(&param[a], b - a);
+       if (args == NULL) {
+               ERROR("Not enough memory for parameter parsing");
+               return -ENOMEM;
+       }
+       sdev = &priv->subs[head];
+       if (strncmp(param, "dev", 3) == 0) {
+               ret = fs_parse_device(sdev, args);
+               if (ret)
+                       goto free_args;
+       } else {
+               ERROR("Unrecognized device type: %.*s", (int)b, param);
+               return -EINVAL;
+       }
+free_args:
+       free(args);
+       return ret;
+}
+
+static int
+fs_parse_sub_devices(parse_cb *cb,
+               struct rte_eth_dev *dev, const char *params)
+{
+       size_t a, b;
+       uint8_t head;
+       int ret;
+
+       a = 0;
+       head = 0;
+       ret = 0;
+       while (params[a] != '\0') {
+               b = a;
+               while (params[b] != '(' &&
+                      params[b] != ',' &&
+                      params[b] != '\0')
+                       b++;
+               if (b == a) {
+                       ERROR("Invalid parameter");
+                       return -EINVAL;
+               }
+               if (params[b] == ',') {
+                       a = b + 1;
+                       continue;
+               }
+               if (params[b] == '(') {
+                       size_t start = b;
+
+                       b += closing_paren(&params[b]);
+                       if (b == start) {
+                               ERROR("Dangling parenthesis");
+                               return -EINVAL;
+                       }
+                       ret = (*cb)(dev, &params[a], head);
+                       if (ret)
+                               return ret;
+                       head += 1;
+                       b += 1;
+                       if (params[b] == '\0')
+                               return 0;
+               }
+               a = b + 1;
+       }
+       return 0;
+}
+
+static int
+fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
+{
+       char buffer[DEVARGS_MAXLEN] = {0};
+       size_t a, b;
+       int i;
+
+       a = 0;
+       i = 0;
+       while (params[a] != '\0') {
+               b = a;
+               while (params[b] != '(' &&
+                      params[b] != ',' &&
+                      params[b] != '\0')
+                       b++;
+               if (b == a) {
+                       ERROR("Invalid parameter");
+                       return -EINVAL;
+               }
+               if (params[b] == ',' || params[b] == '\0')
+                       i += snprintf(&buffer[i], b - a + 1, "%s", &params[a]);
+               if (params[b] == '(') {
+                       size_t start = b;
+                       b += closing_paren(&params[b]);
+                       if (b == start)
+                               return -EINVAL;
+                       b += 1;
+                       if (params[b] == '\0')
+                               goto out;
+               }
+               a = b + 1;
+       }
+out:
+       snprintf(params, DEVARGS_MAXLEN, "%s", buffer);
+       return 0;
+}
+
+static int
+fs_get_mac_addr_arg(const char *key __rte_unused,
+               const char *value, void *out)
+{
+       struct ether_addr *ea = out;
+       int ret;
+
+       if ((value == NULL) || (out == NULL))
+               return -EINVAL;
+       ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+               &ea->addr_bytes[0], &ea->addr_bytes[1],
+               &ea->addr_bytes[2], &ea->addr_bytes[3],
+               &ea->addr_bytes[4], &ea->addr_bytes[5]);
+       return ret != ETHER_ADDR_LEN;
+}
+
+int
+failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
+{
+       struct fs_priv *priv;
+       char mut_params[DEVARGS_MAXLEN] = "";
+       struct rte_kvargs *kvlist = NULL;
+       unsigned int arg_count;
+       size_t n;
+       int ret;
+
+       if (dev == NULL || params == NULL)
+               return -EINVAL;
+       priv = PRIV(dev);
+       ret = 0;
+       priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
+       /* default parameters */
+       mac_from_arg = 0;
+       n = snprintf(mut_params, sizeof(mut_params), "%s", params);
+       if (n >= sizeof(mut_params)) {
+               ERROR("Parameter string too long (>=%zu)",
+                               sizeof(mut_params));
+               return -ENOMEM;
+       }
+       ret = fs_parse_sub_devices(fs_parse_device_param,
+                                  dev, params);
+       if (ret < 0)
+               return ret;
+       ret = fs_remove_sub_devices_definition(mut_params);
+       if (ret < 0)
+               return ret;
+       if (strnlen(mut_params, sizeof(mut_params)) > 0) {
+               kvlist = rte_kvargs_parse(mut_params,
+                               pmd_failsafe_init_parameters);
+               if (kvlist == NULL) {
+                       ERROR("Error parsing parameters, usage:\n"
+                               PMD_FAILSAFE_PARAM_STRING);
+                       return -1;
+               }
+               /* MAC addr */
+               arg_count = rte_kvargs_count(kvlist,
+                               PMD_FAILSAFE_MAC_KVARG);
+               if (arg_count == 1) {
+                       ret = rte_kvargs_process(kvlist,
+                                       PMD_FAILSAFE_MAC_KVARG,
+                                       &fs_get_mac_addr_arg,
+                                       &dev->data->mac_addrs[0]);
+                       if (ret < 0)
+                               goto free_kvlist;
+                       mac_from_arg = 1;
+               }
+       }
+free_kvlist:
+       rte_kvargs_free(kvlist);
+       return ret;
+}
+
+void
+failsafe_args_free(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV(sdev, i, dev) {
+               free(sdev->devargs.args);
+               sdev->devargs.args = NULL;
+       }
+}
+
+static int
+fs_count_device(struct rte_eth_dev *dev, const char *param,
+               uint8_t head __rte_unused)
+{
+       size_t b = 0;
+
+       while  (param[b] != '(' &&
+               param[b] != '\0')
+               b++;
+       if (strncmp(param, "dev", b) &&
+           strncmp(param, "exec", b)) {
+               ERROR("Unrecognized device type: %.*s", (int)b, param);
+               return -EINVAL;
+       }
+       PRIV(dev)->subs_tail += 1;
+       return 0;
+}
+
+int
+failsafe_args_count_subdevice(struct rte_eth_dev *dev,
+                       const char *params)
+{
+       return fs_parse_sub_devices(fs_count_device,
+                                   dev, params);
+}
drivers/net/failsafe/failsafe_eal.c new file +40 -0
new file mode 100644
index 0000000..6c3a811
@@ -0,0 +1,154 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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_malloc.h>
+
+#include "failsafe_private.h"
+
+static struct rte_eth_dev *
+fs_find_ethdev(const struct rte_device *dev)
+{

drivers/net/failsafe/failsafe_eal.c line 50

Quoted 10 lines
drivers/net/failsafe/failsafe_eal.c new file +10 -0
+       struct rte_eth_dev *eth_dev;
+       uint8_t i;
+
+       RTE_ETH_FOREACH_DEV(i) {
+               eth_dev = &rte_eth_devices[i];
+               if (eth_dev->device == dev)
+                       return eth_dev;
+       }
+       return NULL;
+}

Why don't you use rte_eth_dev_allocated() here?

Quoted 7 lines
drivers/net/failsafe/failsafe_eal.c new file +7 -0
+
+static int
+fs_bus_init(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       struct rte_device *rdev;
+       struct rte_devargs *da;

drivers/net/failsafe/failsafe_eal.c line 67

Quoted 10 lines
drivers/net/failsafe/failsafe_eal.c new file +10 -0
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV(sdev, i, dev) {
+               if (sdev->state != DEV_PARSED)
+                       continue;
+               da = &sdev->devargs;
+               rdev = rte_eal_hotplug_add(da->bus->name,
+                                          da->name,
+                                          da->args);

Why don't you track the bus name through your sub_device structure instead?

Quoted 1,127 lines
drivers/net/failsafe/failsafe_eal.c new file +87 -0
+               ret = rdev ? 0 : -rte_errno;
+               if (ret) {
+                       ERROR("sub_device %d probe failed %s%s%s", i,
+                             errno ? "(" : "",
+                             errno ? strerror(rte_errno) : "",
+                             errno ? ")" : "");
+                       continue;
+               }
+               ETH(sdev) = fs_find_ethdev(rdev);
+               if (ETH(sdev) == NULL) {
+                       ERROR("sub_device %d init went wrong", i);
+                       return -ENODEV;
+               }
+               sdev->dev = ETH(sdev)->device;
+               ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
+               sdev->state = DEV_PROBED;
+       }
+       return 0;
+}
+
+int
+failsafe_eal_init(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       ret = fs_bus_init(dev);
+       if (ret)
+               return ret;
+       /*
+        * We only update TX_SUBDEV if we are not started.
+        * If a sub_device is emitting, we will switch the TX_SUBDEV to the
+        * preferred port only upon starting it, so that the switch is smoother.
+        */
+       if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
+               if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
+                   (TX_SUBDEV(dev) == NULL ||
+                    (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
+                       DEBUG("Switching tx_dev to preferred sub_device");
+                       PRIV(dev)->subs_tx = 0;
+               }
+       } else {
+               if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
+                   TX_SUBDEV(dev) == NULL) {
+                       /* Using first probed device */
+                       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
+                               DEBUG("Switching tx_dev to sub_device %d",
+                                     i);
+                               PRIV(dev)->subs_tx = i;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int
+fs_bus_uninit(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev = NULL;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
+               ret = rte_eal_hotplug_remove(sdev->bus->name,
+                                            sdev->dev->name);
+               if (ret) {
+                       ERROR("Failed to remove requested device %s",
+                             sdev->dev->name);
+                       continue;
+               }
+               sdev->state = DEV_PROBED - 1;
+       }
+       return 0;
+}
+
+int
+failsafe_eal_uninit(struct rte_eth_dev *dev)
+{
+       int ret;
+
+       ret = fs_bus_uninit(dev);
+       if (ret)
+               return ret;
+       return 0;
+}
drivers/net/failsafe/failsafe_ops.c new file +663 -0
new file mode 100644
index 0000000..693162e
@@ -0,0 +1,663 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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 <assert.h>
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+
+#include "failsafe_private.h"
+
+static struct rte_eth_dev_info default_infos = {
+       .driver_name = pmd_failsafe_driver_name,
+       /* Max possible number of elements */
+       .max_rx_pktlen = UINT32_MAX,
+       .max_rx_queues = RTE_MAX_QUEUES_PER_PORT,
+       .max_tx_queues = RTE_MAX_QUEUES_PER_PORT,
+       .max_mac_addrs = FAILSAFE_MAX_ETHADDR,
+       .max_hash_mac_addrs = UINT32_MAX,
+       .max_vfs = UINT16_MAX,
+       .max_vmdq_pools = UINT16_MAX,
+       .rx_desc_lim = {
+               .nb_max = UINT16_MAX,
+               .nb_min = 0,
+               .nb_align = 1,
+               .nb_seg_max = UINT16_MAX,
+               .nb_mtu_seg_max = UINT16_MAX,
+       },
+       .tx_desc_lim = {
+               .nb_max = UINT16_MAX,
+               .nb_min = 0,
+               .nb_align = 1,
+               .nb_seg_max = UINT16_MAX,
+               .nb_mtu_seg_max = UINT16_MAX,
+       },
+       /* Set of understood capabilities */
+       .rx_offload_capa = 0x0,
+       .tx_offload_capa = 0x0,
+       .flow_type_rss_offloads = 0x0,
+};
+
+static int
+fs_dev_configure(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV(sdev, i, dev) {
+               if (sdev->state != DEV_PROBED)
+                       continue;
+               DEBUG("Configuring sub-device %d", i);
+               ret = rte_eth_dev_configure(PORT_ID(sdev),
+                                       dev->data->nb_rx_queues,
+                                       dev->data->nb_tx_queues,
+                                       &dev->data->dev_conf);
+               if (ret) {
+                       ERROR("Could not configure sub_device %d", i);
+                       return ret;
+               }
+               sdev->state = DEV_ACTIVE;
+       }
+       return 0;
+}
+
+static int
+fs_dev_start(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV(sdev, i, dev) {
+               if (sdev->state != DEV_ACTIVE)
+                       continue;
+               DEBUG("Starting sub_device %d", i);
+               ret = rte_eth_dev_start(PORT_ID(sdev));
+               if (ret)
+                       return ret;
+               sdev->state = DEV_STARTED;
+       }
+       if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
+               if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
+                       DEBUG("Switching tx_dev to preferred sub_device");
+                       PRIV(dev)->subs_tx = 0;
+               }
+       } else {
+               if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
+                   TX_SUBDEV(dev) == NULL) {
+                       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
+                               DEBUG("Switching tx_dev to sub_device %d", i);
+                               PRIV(dev)->subs_tx = i;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static void
+fs_dev_stop(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
+               rte_eth_dev_stop(PORT_ID(sdev));
+               sdev->state = DEV_STARTED - 1;
+       }
+}
+
+static int
+fs_dev_set_link_up(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling rte_eth_dev_set_link_up on sub_device %d", i);
+               ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_set_link_up failed for sub_device %d"
+                             " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int
+fs_dev_set_link_down(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling rte_eth_dev_set_link_down on sub_device %d", i);
+               ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_set_link_down failed for sub_device %d"
+                             " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static void fs_dev_free_queues(struct rte_eth_dev *dev);
+static void
+fs_dev_close(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Closing sub_device %d", i);
+               rte_eth_dev_close(PORT_ID(sdev));
+               sdev->state = DEV_ACTIVE - 1;
+       }
+       fs_dev_free_queues(dev);
+}
+
+static void
+fs_rx_queue_release(void *queue)
+{
+       struct rte_eth_dev *dev;
+       struct sub_device *sdev;
+       uint8_t i;
+       struct rxq *rxq;
+
+       if (queue == NULL)
+               return;
+       rxq = queue;
+       dev = rxq->priv->dev;
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               SUBOPS(sdev, rx_queue_release)
+                       (ETH(sdev)->data->rx_queues[rxq->qid]);
+       dev->data->rx_queues[rxq->qid] = NULL;
+       rte_free(rxq);
+}
+
+static int
+fs_rx_queue_setup(struct rte_eth_dev *dev,
+               uint16_t rx_queue_id,
+               uint16_t nb_rx_desc,
+               unsigned int socket_id,
+               const struct rte_eth_rxconf *rx_conf,
+               struct rte_mempool *mb_pool)
+{
+       struct sub_device *sdev;
+       struct rxq *rxq;
+       uint8_t i;
+       int ret;
+
+       rxq = dev->data->rx_queues[rx_queue_id];
+       if (rxq != NULL) {
+               fs_rx_queue_release(rxq);
+               dev->data->rx_queues[rx_queue_id] = NULL;
+       }
+       rxq = rte_zmalloc(NULL, sizeof(*rxq),
+                         RTE_CACHE_LINE_SIZE);
+       if (rxq == NULL)
+               return -ENOMEM;
+       rxq->qid = rx_queue_id;
+       rxq->socket_id = socket_id;
+       rxq->info.mp = mb_pool;
+       rxq->info.conf = *rx_conf;
+       rxq->info.nb_desc = nb_rx_desc;
+       rxq->priv = PRIV(dev);
+       dev->data->rx_queues[rx_queue_id] = rxq;
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               ret = rte_eth_rx_queue_setup(PORT_ID(sdev),
+                               rx_queue_id,
+                               nb_rx_desc, socket_id,
+                               rx_conf, mb_pool);
+               if (ret) {
+                       ERROR("RX queue setup failed for sub_device %d", i);
+                       goto free_rxq;
+               }
+       }
+       return 0;
+free_rxq:
+       fs_rx_queue_release(rxq);
+       return ret;
+}
+
+static void
+fs_tx_queue_release(void *queue)
+{
+       struct rte_eth_dev *dev;
+       struct sub_device *sdev;
+       uint8_t i;
+       struct txq *txq;
+
+       if (queue == NULL)
+               return;
+       txq = queue;
+       dev = txq->priv->dev;
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               SUBOPS(sdev, tx_queue_release)
+                       (ETH(sdev)->data->tx_queues[txq->qid]);
+       dev->data->tx_queues[txq->qid] = NULL;
+       rte_free(txq);
+}
+
+static int
+fs_tx_queue_setup(struct rte_eth_dev *dev,
+               uint16_t tx_queue_id,
+               uint16_t nb_tx_desc,
+               unsigned int socket_id,
+               const struct rte_eth_txconf *tx_conf)
+{
+       struct sub_device *sdev;
+       struct txq *txq;
+       uint8_t i;
+       int ret;
+
+       txq = dev->data->tx_queues[tx_queue_id];
+       if (txq != NULL) {
+               fs_tx_queue_release(txq);
+               dev->data->tx_queues[tx_queue_id] = NULL;
+       }
+       txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+                         RTE_CACHE_LINE_SIZE);
+       if (txq == NULL)
+               return -ENOMEM;
+       txq->qid = tx_queue_id;
+       txq->socket_id = socket_id;
+       txq->info.conf = *tx_conf;
+       txq->info.nb_desc = nb_tx_desc;
+       txq->priv = PRIV(dev);
+       dev->data->tx_queues[tx_queue_id] = txq;
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               ret = rte_eth_tx_queue_setup(PORT_ID(sdev),
+                               tx_queue_id,
+                               nb_tx_desc, socket_id,
+                               tx_conf);
+               if (ret) {
+                       ERROR("TX queue setup failed for sub_device %d", i);
+                       goto free_txq;
+               }
+       }
+       return 0;
+free_txq:
+       fs_tx_queue_release(txq);
+       return ret;
+}
+
+static void
+fs_dev_free_queues(struct rte_eth_dev *dev)
+{
+       uint16_t i;
+
+       for (i = 0; i < dev->data->nb_rx_queues; i++) {
+               fs_rx_queue_release(dev->data->rx_queues[i]);
+               dev->data->rx_queues[i] = NULL;
+       }
+       dev->data->nb_rx_queues = 0;
+       for (i = 0; i < dev->data->nb_tx_queues; i++) {
+               fs_tx_queue_release(dev->data->tx_queues[i]);
+               dev->data->tx_queues[i] = NULL;
+       }
+       dev->data->nb_tx_queues = 0;
+}
+
+static void
+fs_promiscuous_enable(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_promiscuous_enable(PORT_ID(sdev));
+}
+
+static void
+fs_promiscuous_disable(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_promiscuous_disable(PORT_ID(sdev));
+}
+
+static void
+fs_allmulticast_enable(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_allmulticast_enable(PORT_ID(sdev));
+}
+
+static void
+fs_allmulticast_disable(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_allmulticast_disable(PORT_ID(sdev));
+}
+
+static int
+fs_link_update(struct rte_eth_dev *dev,
+               int wait_to_complete)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling link_update on sub_device %d", i);
+               ret = (SUBOPS(sdev, link_update))(ETH(sdev), wait_to_complete);
+               if (ret && ret != -1) {
+                       ERROR("Link update failed for sub_device %d with error %d",
+                             i, ret);
+                       return ret;
+               }
+       }
+       if (TX_SUBDEV(dev)) {
+               struct rte_eth_link *l1;
+               struct rte_eth_link *l2;
+
+               l1 = &dev->data->dev_link;
+               l2 = &ETH(TX_SUBDEV(dev))->data->dev_link;
+               if (memcmp(l1, l2, sizeof(*l1))) {
+                       *l1 = *l2;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+static void
+fs_stats_get(struct rte_eth_dev *dev,
+            struct rte_eth_stats *stats)
+{
+       memset(stats, 0, sizeof(*stats));
+       if (TX_SUBDEV(dev) == NULL)
+               return;
+       rte_eth_stats_get(PORT_ID(TX_SUBDEV(dev)), stats);
+}
+
+static void
+fs_stats_reset(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_stats_reset(PORT_ID(sdev));
+}
+
+/**
+ * Fail-safe dev_infos_get rules:
+ *
+ * No sub_device:
+ *   Numerables:
+ *      Use the maximum possible values for any field, so as not
+ *      to impede any further configuration effort.
+ *   Capabilities:
+ *      Limits capabilities to those that are understood by the
+ *      fail-safe PMD. This understanding stems from the fail-safe
+ *      being capable of verifying that the related capability is
+ *      expressed within the device configuration (struct rte_eth_conf).
+ *
+ * At least one probed sub_device:
+ *   Numerables:
+ *      Uses values from the active probed sub_device
+ *      The rationale here is that if any sub_device is less capable
+ *      (for example concerning the number of queues) than the active
+ *      sub_device, then its subsequent configuration will fail.
+ *      It is impossible to foresee this failure when the failing sub_device
+ *      is supposed to be plugged-in later on, so the configuration process
+ *      is the single point of failure and error reporting.
+ *   Capabilities:
+ *      Uses a logical AND of RX capabilities among
+ *      all sub_devices and the default capabilities.
+ *      Uses a logical AND of TX capabilities among
+ *      the active probed sub_device and the default capabilities.
+ *
+ */
+static void
+fs_dev_infos_get(struct rte_eth_dev *dev,
+                 struct rte_eth_dev_info *infos)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       sdev = TX_SUBDEV(dev);
+       if (sdev == NULL) {
+               DEBUG("No probed device, using default infos");
+               rte_memcpy(&PRIV(dev)->infos, &default_infos,
+                          sizeof(default_infos));
+       } else {
+               uint32_t rx_offload_capa;
+
+               rx_offload_capa = default_infos.rx_offload_capa;
+               FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
+                       rte_eth_dev_info_get(PORT_ID(sdev),
+                                       &PRIV(dev)->infos);
+                       rx_offload_capa &= PRIV(dev)->infos.rx_offload_capa;
+               }
+               sdev = TX_SUBDEV(dev);
+               rte_eth_dev_info_get(PORT_ID(sdev), &PRIV(dev)->infos);
+               PRIV(dev)->infos.rx_offload_capa = rx_offload_capa;
+               PRIV(dev)->infos.tx_offload_capa &=
+                                       default_infos.tx_offload_capa;
+               PRIV(dev)->infos.flow_type_rss_offloads &=
+                                       default_infos.flow_type_rss_offloads;
+       }
+       rte_memcpy(infos, &PRIV(dev)->infos, sizeof(*infos));
+}
+
+static const uint32_t *
+fs_dev_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       struct rte_eth_dev *edev;
+
+       sdev = TX_SUBDEV(dev);
+       if (sdev == NULL)
+               return NULL;
+       edev = ETH(sdev);
+       /* ENOTSUP: counts as no supported ptypes */
+       if (SUBOPS(sdev, dev_supported_ptypes_get) == NULL)
+               return NULL;
+       /*
+        * The API does not permit to do a clean AND of all ptypes,
+        * It is also incomplete by design and we do not really care
+        * to have a best possible value in this context.
+        * We just return the ptypes of the device of highest
+        * priority, usually the PREFERRED device.
+        */
+       return SUBOPS(sdev, dev_supported_ptypes_get)(edev);
+}
+
+static int
+fs_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling rte_eth_dev_set_mtu on sub_device %d", i);
+               ret = rte_eth_dev_set_mtu(PORT_ID(sdev), mtu);
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_set_mtu failed for sub_device %d"
+                             " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int
+fs_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling rte_eth_dev_vlan_filter on sub_device %d", i);
+               ret = rte_eth_dev_vlan_filter(PORT_ID(sdev), vlan_id, on);
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_vlan_filter failed for sub_device %d"
+                             " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int
+fs_flow_ctrl_get(struct rte_eth_dev *dev,
+               struct rte_eth_fc_conf *fc_conf)
+{
+       struct sub_device *sdev;
+
+       sdev = TX_SUBDEV(dev);
+       if (sdev == NULL)
+               return 0;
+       if (SUBOPS(sdev, flow_ctrl_get) == NULL)
+               return -ENOTSUP;
+       return SUBOPS(sdev, flow_ctrl_get)(ETH(sdev), fc_conf);
+}
+
+static int
+fs_flow_ctrl_set(struct rte_eth_dev *dev,
+               struct rte_eth_fc_conf *fc_conf)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               DEBUG("Calling rte_eth_dev_flow_ctrl_set on sub_device %d", i);
+               ret = rte_eth_dev_flow_ctrl_set(PORT_ID(sdev), fc_conf);
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_flow_ctrl_set failed for sub_device %d"
+                             " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static void
+fs_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       /* No check: already done within the rte_eth_dev_mac_addr_remove
+        * call for the fail-safe device.
+        */
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_dev_mac_addr_remove(PORT_ID(sdev),
+                               &dev->data->mac_addrs[index]);
+       PRIV(dev)->mac_addr_pool[index] = 0;
+}
+
+static int
+fs_mac_addr_add(struct rte_eth_dev *dev,
+               struct ether_addr *mac_addr,
+               uint32_t index,
+               uint32_t vmdq)
+{
+       struct sub_device *sdev;
+       int ret;
+       uint8_t i;
+
+       assert(index < FAILSAFE_MAX_ETHADDR);
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+               ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), mac_addr, vmdq);
+               if (ret) {
+                       ERROR("Operation rte_eth_dev_mac_addr_add failed for sub_device %"
+                             PRIu8 " with error %d", i, ret);
+                       return ret;
+               }
+       }
+       if (index >= PRIV(dev)->nb_mac_addr) {
+               DEBUG("Growing mac_addrs array");
+               PRIV(dev)->nb_mac_addr = index;
+       }
+       PRIV(dev)->mac_addr_pool[index] = vmdq;
+       return 0;
+}
+
+static void
+fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+       struct sub_device *sdev;
+       uint8_t i;
+
+       FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE)
+               rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
+}
+
+const struct eth_dev_ops failsafe_ops = {
+       .dev_configure = fs_dev_configure,
+       .dev_start = fs_dev_start,
+       .dev_stop = fs_dev_stop,
+       .dev_set_link_down = fs_dev_set_link_down,
+       .dev_set_link_up = fs_dev_set_link_up,
+       .dev_close = fs_dev_close,
+       .promiscuous_enable = fs_promiscuous_enable,
+       .promiscuous_disable = fs_promiscuous_disable,
+       .allmulticast_enable = fs_allmulticast_enable,
+       .allmulticast_disable = fs_allmulticast_disable,
+       .link_update = fs_link_update,
+       .stats_get = fs_stats_get,
+       .stats_reset = fs_stats_reset,
+       .dev_infos_get = fs_dev_infos_get,
+       .dev_supported_ptypes_get = fs_dev_supported_ptypes_get,
+       .mtu_set = fs_mtu_set,
+       .vlan_filter_set = fs_vlan_filter_set,
+       .rx_queue_setup = fs_rx_queue_setup,
+       .tx_queue_setup = fs_tx_queue_setup,
+       .rx_queue_release = fs_rx_queue_release,
+       .tx_queue_release = fs_tx_queue_release,
+       .flow_ctrl_get = fs_flow_ctrl_get,
+       .flow_ctrl_set = fs_flow_ctrl_set,
+       .mac_addr_remove = fs_mac_addr_remove,
+       .mac_addr_add = fs_mac_addr_add,
+       .mac_addr_set = fs_mac_addr_set,
+};
drivers/net/failsafe/failsafe_private.h new file +227 -0
new file mode 100644
index 0000000..e7a7592
@@ -0,0 +1,227 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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.
+ */
+
+#ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
+#define _RTE_ETH_FAILSAFE_PRIVATE_H_
+
+#include <rte_dev.h>
+#include <rte_ethdev.h>
+#include <rte_devargs.h>
+
+#define FAILSAFE_DRIVER_NAME "Fail-safe PMD"
+
+#define PMD_FAILSAFE_MAC_KVARG "mac"
+#define PMD_FAILSAFE_PARAM_STRING      \
+       "dev(<ifc>),"                   \
+       "mac=mac_addr"                  \
+       ""
+
+#define FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS 2000
+
+#define FAILSAFE_MAX_ETHPORTS 2
+#define FAILSAFE_MAX_ETHADDR 128
+
+/* TYPES */
+
+struct rxq {
+       struct fs_priv *priv;
+       uint16_t qid;
+       /* id of last sub_device polled */
+       uint8_t last_polled;
+       unsigned int socket_id;
+       struct rte_eth_rxq_info info;
+};
+
+struct txq {
+       struct fs_priv *priv;
+       uint16_t qid;
+       unsigned int socket_id;
+       struct rte_eth_txq_info info;
+};
+
+enum dev_state {
+       DEV_UNDEFINED = 0,
+       DEV_PARSED,
+       DEV_PROBED,
+       DEV_ACTIVE,
+       DEV_STARTED,
+};
+
+struct sub_device {
+       /* Exhaustive DPDK device description */
+       struct rte_devargs devargs;
+       struct rte_bus *bus;
+       struct rte_device *dev;
+       struct rte_eth_dev *edev;
+       /* Device state machine */
+       enum dev_state state;
+};
+
+struct fs_priv {
+       struct rte_eth_dev *dev;
+       /*
+        * Set of sub_devices.
+        * subs[0] is the preferred device
+        * any other is just another slave
+        */
+       struct sub_device *subs;
+       uint8_t subs_head; /* if head == tail, no subs */
+       uint8_t subs_tail; /* first invalid */
+       uint8_t subs_tx; /* current emitting device */
+       uint8_t current_probed;
+       /* current number of mac_addr slots allocated. */
+       uint32_t nb_mac_addr;
+       struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
+       uint32_t mac_addr_pool[FAILSAFE_MAX_ETHADDR];
+       /* current capabilities */
+       struct rte_eth_dev_info infos;
+};
+
+/* RX / TX */
+
+uint16_t failsafe_rx_burst(void *rxq,
+               struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst(void *txq,
+               struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
+/* ARGS */
+
+int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
+void failsafe_args_free(struct rte_eth_dev *dev);
+int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+
+/* EAL */
+
+int failsafe_eal_init(struct rte_eth_dev *dev);
+int failsafe_eal_uninit(struct rte_eth_dev *dev);
+
+/* GLOBALS */
+
+extern const char pmd_failsafe_driver_name[];
+extern const struct eth_dev_ops failsafe_ops;
+extern int mac_from_arg;
+
+/* HELPERS */
+
+/* dev: (struct rte_eth_dev *) fail-safe device */
+#define PRIV(dev) \
+       ((struct fs_priv *)(dev)->data->dev_private)
+
+/* sdev: (struct sub_device *) */
+#define ETH(sdev) \
+       ((sdev)->edev)
+
+/* sdev: (struct sub_device *) */
+#define PORT_ID(sdev) \
+       (ETH(sdev)->data->port_id)
+
+/**
+ * Stateful iterator construct over fail-safe sub-devices:
+ * s:     (struct sub_device *), iterator
+ * i:     (uint8_t), increment
+ * dev:   (struct rte_eth_dev *), fail-safe ethdev
+ * state: (enum dev_state), minimum acceptable device state
+ */
+#define FOREACH_SUBDEV_ST(s, i, dev, state)                            \
+       for (i = fs_find_next((dev), 0, state);                         \
+            i < PRIV(dev)->subs_tail && (s = &PRIV(dev)->subs[i]);     \
+            i = fs_find_next((dev), i + 1, state))
+
+/**
+ * Iterator construct over fail-safe sub-devices:
+ * s:   (struct sub_device *), iterator
+ * i:   (uint8_t), increment
+ * dev: (struct rte_eth_dev *), fail-safe ethdev
+ */
+#define FOREACH_SUBDEV(s, i, dev)                      \
+       FOREACH_SUBDEV_ST(s, i, dev, DEV_UNDEFINED)
+
+/* dev: (struct rte_eth_dev *) fail-safe device */
+#define PREFERRED_SUBDEV(dev) \
+       (&PRIV(dev)->subs[0])
+
+/* dev: (struct rte_eth_dev *) fail-safe device */
+#define TX_SUBDEV(dev)                                                   \
+       (PRIV(dev)->subs_tx >= PRIV(dev)->subs_tail                ? NULL \
+        : (PRIV(dev)->subs[PRIV(dev)->subs_tx].state < DEV_PROBED ? NULL \
+        : &PRIV(dev)->subs[PRIV(dev)->subs_tx]))
+
+/**
+ * s:   (struct sub_device *)
+ * ops: (struct eth_dev_ops) member
+ */
+#define SUBOPS(s, ops) \
+       (ETH(s)->dev_ops->ops)
+
+#ifndef NDEBUG
+#include <stdio.h>
+#define DEBUG__(m, ...)                                                \
+       (fprintf(stderr, "%s:%d: %s(): " m "%c",                \
+                __FILE__, __LINE__, __func__, __VA_ARGS__),    \
+        (void)0)
+#define DEBUG_(...)                            \
+       (errno = ((int []){                     \
+               *(volatile int *)&errno,        \
+               (DEBUG__(__VA_ARGS__), 0)       \
+       })[0])
+#define DEBUG(...) DEBUG_(__VA_ARGS__, '\n')
+#define INFO(...) DEBUG(__VA_ARGS__)
+#define WARN(...) DEBUG(__VA_ARGS__)
+#define ERROR(...) DEBUG(__VA_ARGS__)
+#else
+#define DEBUG(...) ((void)0)
+#define LOG__(level, m, ...) \
+       RTE_LOG(level, PMD, "net_failsafe: " m "%c", __VA_ARGS__)
+#define LOG_(level, ...) LOG__(level, __VA_ARGS__, '\n')
+#define INFO(...) LOG_(INFO, __VA_ARGS__)
+#define WARN(...) LOG_(WARNING, "WARNING: " __VA_ARGS__)
+#define ERROR(...) LOG_(ERR, "ERROR: " __VA_ARGS__)
+#endif
+
+/* inlined functions */
+
+static inline uint8_t
+fs_find_next(struct rte_eth_dev *dev, uint8_t sid,
+               enum dev_state min_state)
+{
+       while (sid < PRIV(dev)->subs_tail) {
+               if (PRIV(dev)->subs[sid].state >= min_state)
+                       break;
+               sid++;
+       }
+       if (sid >= PRIV(dev)->subs_tail)
+               return PRIV(dev)->subs_tail;
+       return sid;
+}
+
+#endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */
drivers/net/failsafe/failsafe_rxtx.c new file +107 -0
new file mode 100644
index 0000000..a45b4e5
@@ -0,0 +1,107 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox.
+ *
+ *   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 6WIND S.A. 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_mbuf.h>
+#include <rte_ethdev.h>
+
+#include "failsafe_private.h"
+
+/*
+ * TODO: write fast version,
+ * without additional checks, to be activated once
+ * everything has been verified to comply.
+ */
+uint16_t
+failsafe_rx_burst(void *queue,
+                 struct rte_mbuf **rx_pkts,
+                 uint16_t nb_pkts)
+{
+       struct fs_priv *priv;
+       struct sub_device *sdev;
+       struct rxq *rxq;
+       void *sub_rxq;
+       uint16_t nb_rx;
+       uint8_t nb_polled, nb_subs;
+       uint8_t i;
+
+       rxq = queue;
+       priv = rxq->priv;
+       nb_subs = priv->subs_tail - priv->subs_head;
+       nb_polled = 0;
+       for (i = rxq->last_polled; nb_polled < nb_subs; nb_polled++) {
+               i++;
+               if (i == priv->subs_tail)
+                       i = priv->subs_head;
+               sdev = &priv->subs[i];
+               if (unlikely(ETH(sdev) == NULL))
+                       continue;
+               if (unlikely(ETH(sdev)->rx_pkt_burst == NULL))
+                       continue;
+               if (unlikely(sdev->state != DEV_STARTED))
+                       continue;
+               sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+               nb_rx = ETH(sdev)->
+                       rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+               if (nb_rx) {
+                       rxq->last_polled = i;
+                       return nb_rx;
+               }
+       }
+       return 0;
+}
+
+/*
+ * TODO: write fast version,
+ * without additional checks, to be activated once
+ * everything has been verified to comply.
+ */
+uint16_t
+failsafe_tx_burst(void *queue,
+                 struct rte_mbuf **tx_pkts,
+                 uint16_t nb_pkts)
+{
+       struct sub_device *sdev;
+       struct txq *txq;
+       void *sub_txq;
+
+       txq = queue;
+       sdev = TX_SUBDEV(txq->priv->dev);
+       if (unlikely(sdev == NULL))
+               return 0;
+       if (unlikely(ETH(sdev) == NULL))
+               return 0;
+       if (unlikely(ETH(sdev)->tx_pkt_burst == NULL))
+               return 0;
+       sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
+       return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+}
drivers/net/failsafe/rte_pmd_failsafe_version.map new file +4 -0
new file mode 100644
index 0000000..b6d2840
@@ -0,0 +1,4 @@
+DPDK_17.08 {
+
+       local: *;
+};
mk/rte.app.mk +1 -1
index dbd3614..d7581b7 100644
@@ -120,6 +120,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
--

2.1.4

#109 lore raw

Re: [PATCH v7 03/11] net/failsafe: add fail-safe PMD

Quoted 12 lines · Jan Blunck
Quoted 11 lines · Gaetan Rivet
drivers/net/failsafe/failsafe_args.c new file +11 -0
+static int
+fs_parse_device(struct sub_device *sdev, char *args)
+{
+       struct rte_devargs *d;
+       int ret;
+
+       d = &sdev->devargs;
+       DEBUG("%s", args);
+       ret = rte_eal_devargs_parse(args, d);
+       if (ret) {
+               DEBUG("devargs parsing failed with code %d", ret);
Quoted 10 lines

drivers/net/failsafe/failsafe_args.c line 93

Quoted 4 lines
drivers/net/failsafe/failsafe_args.c new file +4 -0
+               return ret;
+       }
+       sdev->bus = d->bus;
+       sdev->state = DEV_PARSED;

You seem to be mostly interested in the bus name for the device. Why don't you track this via your sub_device structure instead of using rte_devargs?

I don't understand. I track it in my sub_device structure by copying the info from the devargs? How would you get it otherwise?

Devargs still has to be used as a common format that can be parsed by EAL helpers. I could certainly parse it myself, but then I would have to follow any evolution of the parameter format, and I prefer to delegate this to the EAL.

Quoted 3 lines
Quoted 3 lines
drivers/net/failsafe/failsafe.c new file +3 -0
+       return 0;
+}
+

[...]

Quoted 7 lines
Quoted 7 lines
drivers/net/failsafe/failsafe_eal.c new file +7 -0
+static struct rte_eth_dev *
+fs_find_ethdev(const struct rte_device *dev)
+{
+       struct rte_eth_dev *eth_dev;
+       uint8_t i;
+
+       RTE_ETH_FOREACH_DEV(i) {
Quoted 10 lines

drivers/net/failsafe/failsafe_eal.c line 50

Quoted 6 lines
drivers/net/failsafe/failsafe_eal.c new file +6 -0
+               eth_dev = &rte_eth_devices[i];
+               if (eth_dev->device == dev)
+                       return eth_dev;
+       }
+       return NULL;
+}

Why don't you use rte_eth_dev_allocated() here?

IIRC, at the time I choose to roll out my own version, there was ambiguities about device names availability, with some devices using their rte_devargs name, others writing their own.

It has been stabilized it seems, and now I think rte_eth_dev_allocated could be used.

[...]

Quoted 11 lines
Quoted 11 lines
drivers/net/failsafe/failsafe_eal.c new file +11 -0
+
+static int
+fs_bus_init(struct rte_eth_dev *dev)
+{
+       struct sub_device *sdev;
+       struct rte_device *rdev;
+       struct rte_devargs *da;
+       uint8_t i;
+       int ret;
+
+       FOREACH_SUBDEV(sdev, i, dev) {
Quoted 10 lines

drivers/net/failsafe/failsafe_eal.c line 67

Quoted 6 lines
drivers/net/failsafe/failsafe_eal.c new file +6 -0
+               if (sdev->state != DEV_PARSED)
+                       continue;
+               da = &sdev->devargs;
+               rdev = rte_eal_hotplug_add(da->bus->name,
+                                          da->name,
+                                          da->args);

Why don't you track the bus name through your sub_device structure instead?

Do you mean

+ rdev = rte_eal_hotplug_add(sdev->bus->name,
+ da->name,
+ da->args);

instead? I guess for this example it was mostly for the sake of consistency, but the bus handle within the sub_device could be used.

Actually I dislike having a copy of an info. I have this info both within the sub_device directly and within the rte_devargs within the sub_device. It should be streamlined.

Signature · 2 lines
Gaëtan Rivet
6WIND
#110 lore raw

Re: [PATCH v7 03/11] net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

09/07/2017 03:47, Gaetan Rivet:

doc/guides/nics/fail_safe.rst line 122

Quoted 7 lines
doc/guides/nics/fail_safe.rst new file +7 -0
+#. Start testpmd
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0,nodeaction=r1:0:CREATE)' -- \
+         -i

It cannot work because rte_pci_scan is disabled with --no-pci. The PCI device will be unknown when adding it as slave of failsafe.

#111 lore raw

PATCH v7 4/11 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  19 +++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  71 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  32 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  60 ++++++++-
 8 files changed, 423 insertions(+), 43 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +19 -0
index 056f85f..c04891a 100644
@@ -102,6 +102,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **hotplug_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two slave upkeep round.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -131,3 +136,17 @@ Care must be taken, however, to respect the **ether** API concerning device
 access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
+
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
drivers/net/failsafe/Makefile +1 -0
index c759035..e27bfc0 100644
@@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +71 -0

83 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +32 -0
index f07d26e..8f334aa 100644
@@ -45,9 +45,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t hotplug_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -221,6 +223,24 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+fs_get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 fs_get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -252,6 +272,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -274,6 +295,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&fs_get_u64_arg, &hotplug_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -287,6 +318,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index 6c3a811..16871df 100644
@@ -88,37 +88,14 @@ fs_bus_init(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = fs_bus_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -150,5 +127,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = fs_bus_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 693162e..4044473 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_hotplug_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +58 -2

92 lines not on this page · raw message

Signature · 1 line
2.1.4
#112 lore raw

PATCH v7 5/11 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 99 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 130 insertions(+)
doc/guides/nics/fail_safe.rst +20 -0
index c04891a..1b6e110 100644
@@ -91,6 +91,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -126,6 +139,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          --vdev='net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0,nodeaction=r1:0:CREATE)' -- \
          -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +99 -0

126 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index 7910952..2a1535e 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index 8fb72fe..554d7a3 100644
@@ -44,6 +44,7 @@
 #define PMD_FAILSAFE_PLUG_IN_POLL_KVARG "hotplug_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"hotplug_poll=u64"		\
 	""
@@ -87,6 +88,8 @@ struct sub_device {
 	struct rte_eth_dev *edev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -135,6 +138,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#113 lore raw

PATCH v7 6/11 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   1 +
 drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 216 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 +++++
 drivers/net/failsafe/failsafe_private.h |  18 +++
 8 files changed, 337 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index 3c52823..9167b59 100644
@@ -13,6 +13,7 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index e27bfc0..3cccfe0 100644
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 888f07b..6557255 100644
@@ -177,6 +177,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +1 -0
index 16871df..86e16a6 100644
@@ -78,6 +78,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			ERROR("sub_device %d init went wrong", i);
 			return -ENODEV;
 		}
+		SUB_ID(sdev) = i;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
drivers/net/failsafe/failsafe_ether.c +70 -0

90 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +216 -0

216 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index 4044473..4cb2e90 100644
@@ -35,6 +35,7 @@
 #include <stdint.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -628,6 +629,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -655,4 +683,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +18 -0
index 554d7a3..f40ea2f 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
@@ -72,6 +74,14 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -86,6 +96,7 @@ struct sub_device {
 	struct rte_bus *bus;
 	struct rte_device *dev;
 	struct rte_eth_dev *edev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -104,6 +115,8 @@ struct fs_priv {
 	uint8_t subs_tail; /* first invalid */
 	uint8_t subs_tx; /* current emitting device */
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t hotplug_poll;
 extern int mac_from_arg;
 
@@ -170,6 +184,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	((sdev)->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#114 lore raw

PATCH v7 7/11 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +6 -0
index 9167b59..257f579 100644
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +129 -2

151 lines not on this page · raw message

Signature · 1 line
2.1.4
#115 lore raw

PATCH v7 8/11 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 124 ++++++++++++++++++++++++++------
 2 files changed, 112 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index f40ea2f..25a4dac 100644
@@ -141,11 +141,18 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev, int force_safe);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -299,6 +306,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev, 0);
 	rte_wmb();
 }
 
drivers/net/failsafe/failsafe_rxtx.c +104 -20

154 lines not on this page · raw message

Signature · 1 line
2.1.4
#116 lore raw

PATCH v7 9/11 net/failsafe: support device removal

In reply to Gaetan Rivet

Listen to INTR_RMV events issued by slaves.
Add atomic flags on slave queues to detect use of slave bursts function. If a removal is detected, set the recollection flag on this slave.

During a slave upkeep round, if its recollection flag is set and its burst functions are not in use by any thread, remove that slave.

---
 doc/guides/nics/fail_safe.rst           | 14 +++++
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_args.c    | 13 +++++
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   | 96 ++++++++++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_ops.c     | 38 +++++++++++--
 drivers/net/failsafe/failsafe_private.h | 72 ++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_rxtx.c    | 17 +++++-
 8 files changed, 234 insertions(+), 20 deletions(-)
doc/guides/nics/fail_safe.rst +14 -0
index 1b6e110..4154f0a 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation options
@@ -170,3 +176,11 @@ emit and receive packets. It will store any applied configuration, and try to
 apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
+
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
drivers/net/failsafe/failsafe.c +1 -0
index 6557255..4d35860 100644
@@ -132,6 +132,7 @@ fs_hotplug_alarm(void *arg)
 	if (!PRIV(dev)->pending_alarm)
 		return;
 	PRIV(dev)->pending_alarm = 0;
+	failsafe_dev_remove(dev);
 	FOREACH_SUBDEV(sdev, i, dev)
 		if (sdev->state != PRIV(dev)->state)
 			break;
drivers/net/failsafe/failsafe_args.c +13 -0
index c723ca3..dd55aaf 100644
@@ -443,6 +443,17 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				    dev, params);
 }
 
+static int
+fs_parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char devstr[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
+	return fs_parse_device(sdev, devstr);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -455,6 +466,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = fs_execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = fs_parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -1
index 86e16a6..3321dda 100644
@@ -79,6 +79,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			return -ENODEV;
 		}
 		SUB_ID(sdev) = i;
+		sdev->fs_dev = dev;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
@@ -96,7 +97,7 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 		return ret;
 	if (PRIV(dev)->state < DEV_PROBED)
 		PRIV(dev)->state = DEV_PROBED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
drivers/net/failsafe/failsafe_ether.c +90 -6

130 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +35 -3
index 5fb0135..2e1c798 100644
@@ -33,6 +33,8 @@
 
 #include <assert.h>
 #include <stdint.h>
+
+#include <rte_atomic.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
 #include <rte_flow.h>
@@ -204,9 +206,21 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
+		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
 					dev->data->nb_tx_queues,
@@ -215,6 +229,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
@@ -240,7 +264,7 @@ fs_dev_start(struct rte_eth_dev *dev)
 	}
 	if (PRIV(dev)->state < DEV_STARTED)
 		PRIV(dev)->state = DEV_STARTED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
@@ -351,10 +375,14 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,
 		fs_rx_queue_release(rxq);
 		dev->data->rx_queues[rx_queue_id] = NULL;
 	}
-	rxq = rte_zmalloc(NULL, sizeof(*rxq),
+	rxq = rte_zmalloc(NULL,
+			  sizeof(*rxq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (rxq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&rxq->refcnt[i]);
 	rxq->qid = rx_queue_id;
 	rxq->socket_id = socket_id;
 	rxq->info.mp = mb_pool;
@@ -414,10 +442,14 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,
 		fs_tx_queue_release(txq);
 		dev->data->tx_queues[tx_queue_id] = NULL;
 	}
-	txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+	txq = rte_zmalloc("ethdev TX queue",
+			  sizeof(*txq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (txq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&txq->refcnt[i]);
 	txq->qid = tx_queue_id;
 	txq->socket_id = socket_id;
 	txq->info.conf = *tx_conf;
drivers/net/failsafe/failsafe_private.h +64 -8

133 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c +15 -2
index c15025f..82a8c4e 100644
@@ -33,6 +33,7 @@
 
 #include <assert.h>
 
+#include <rte_atomic.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
 
@@ -113,8 +114,10 @@ failsafe_rx_burst(void *queue,
 		if (unlikely(fs_rx_unsafe(sdev)))
 			continue;
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -147,8 +150,10 @@ failsafe_rx_burst_fast(void *queue,
 		sdev = &priv->subs[i];
 		assert(!fs_rx_unsafe(sdev));
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -165,13 +170,17 @@ failsafe_tx_burst(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	if (unlikely(fs_tx_unsafe(sdev)))
 		return 0;
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
 
 uint16_t
@@ -182,10 +191,14 @@ failsafe_tx_burst_fast(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	assert(!fs_tx_unsafe(sdev));
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
Signature · 1 line
2.1.4
#117 lore raw

PATCH v7 10/11 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 23 +++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 46 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 257f579..251ce55 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
drivers/net/failsafe/failsafe.c +1 -0
index 4d35860..151f823 100644
@@ -240,6 +240,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index ea3105c..a694b4d 100644
@@ -387,3 +387,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 	sdev->remove = 1;
 	return 0;
 }
+
+int
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event __rte_unused,
+				void *cb_arg, void *out __rte_unused)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		return _rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL, NULL);
+	else
+		return 0;
+}
drivers/net/failsafe/failsafe_ops.c +23 -0
index 2e1c798..05221bc 100644
@@ -207,6 +207,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -219,6 +221,17 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
@@ -239,6 +252,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+						RTE_ETH_EVENT_INTR_LSC,
+						failsafe_eth_lsc_event_callback,
+						dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 6a8041d..6b34998 100644
@@ -179,6 +179,9 @@ void failsafe_dev_remove(struct rte_eth_dev *dev);
 int failsafe_eth_rmv_event_callback(uint8_t port_id,
 				    enum rte_eth_event_type type,
 				    void *arg, void *out);
+int failsafe_eth_lsc_event_callback(uint8_t port_id,
+				    enum rte_eth_event_type event,
+				    void *cb_arg, void *out);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#118 lore raw

PATCH v7 11/11 net/failsafe: support flow API isolation mode

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ether.c   | 34 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_flow.c    | 29 ++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  4 ++++
 3 files changed, 65 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ether.c +32 -2
index a694b4d..c8b9c8a 100644
@@ -74,6 +74,28 @@ fs_flow_complain(struct rte_flow_error *error)
 }
 
 static int
+eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_flow_error ferror;
+	int ret;
+
+	if (!PRIV(dev)->flow_isolated) {
+		DEBUG("Flow isolation already disabled");
+	} else {
+		DEBUG("Enabling flow isolation");
+		ret = rte_flow_isolate(PORT_ID(sdev),
+				       PRIV(dev)->flow_isolated,
+				       &ferror);
+		if (ret) {
+			fs_flow_complain(&ferror);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int
 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 		struct sub_device *sdev)
 {
@@ -334,9 +356,17 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	if (PRIV(dev)->state < DEV_ACTIVE)
 		return 0;
 	inactive = 0;
-	FOREACH_SUBDEV(sdev, i, dev)
-		if (sdev->state == DEV_PROBED)
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state == DEV_PROBED) {
 			inactive |= UINT32_C(1) << i;
+			ret = eth_dev_flow_isolate_set(dev, sdev);
+			if (ret) {
+				ERROR("Could not apply configuration to sub_device %d",
+				      i);
+				goto err_remove;
+			}
+		}
+	}
 	ret = dev->dev_ops->dev_configure(dev);
 	if (ret)
 		goto err_remove;
drivers/net/failsafe/failsafe_flow.c +29 -0
index d8f59a1..a5598ae 100644
@@ -207,10 +207,39 @@ fs_flow_query(struct rte_eth_dev *dev,
 	return -1;
 }
 
+static int
+fs_flow_isolate(struct rte_eth_dev *dev,
+		int set,
+		struct rte_flow_error *error)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state < DEV_PROBED)
+			continue;
+		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
+		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
+			WARN("flow isolation mode of sub_device %d in incoherent state.",
+				i);
+		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
+		if (ret) {
+			ERROR("Operation rte_flow_isolate failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+		sdev->flow_isolated = set;
+	}
+	PRIV(dev)->flow_isolated = set;
+	return 0;
+}
+
 const struct rte_flow_ops fs_flow_ops = {
 	.validate = fs_flow_validate,
 	.create = fs_flow_create,
 	.destroy = fs_flow_destroy,
 	.flush = fs_flow_flush,
 	.query = fs_flow_query,
+	.isolate = fs_flow_isolate,
 };
drivers/net/failsafe/failsafe_private.h +4 -0
index 6b34998..a071ad9 100644
@@ -108,6 +108,8 @@ struct sub_device {
 	struct rte_eth_dev *fs_dev;
 	/* flag calling for recollection */
 	volatile unsigned int remove:1;
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 struct fs_priv {
@@ -139,6 +141,8 @@ struct fs_priv {
 	 */
 	enum dev_state state;
 	unsigned int pending_alarm:1; /* An alarm is pending */
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 /* MISC */
Signature · 1 line
2.1.4
#119 lore raw

v8 cover introduce fail-safe PMD

In reply to Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

eal: complete attach / detach support
http://dpdk.org/ml/archives/dev/2017-May/066366.html
http://dpdk.org/dev/patchwork/patch/24522/

ethdev: add flow API rule copy function
http://dpdk.org/ml/archives/dev/2017-May/066145.html
http://dpdk.org/dev/patchwork/patch/24406/

ethdev: add isolated mode to flow API
http://dpdk.org/ml/archives/dev/2017-April/064327.html
http://dpdk.org/dev/patchwork/patch/23741/

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

 MAINTAINERS                                       |   5 +
 config/common_base                                |   6 +
 doc/guides/nics/fail_safe.rst                     | 199 +++++
 doc/guides/nics/features/failsafe.ini             |  32 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  78 ++
 drivers/net/failsafe/failsafe.c                   | 305 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 475 ++++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 118 +++
 drivers/net/failsafe/failsafe_ether.c             | 437 +++++++++++
 drivers/net/failsafe/failsafe_flow.c              | 245 ++++++
 drivers/net/failsafe/failsafe_ops.c               | 869 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 376 ++++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 204 +++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 lib/librte_ether/rte_ethdev.c                     |  19 +-
 lib/librte_ether/rte_ethdev.h                     |  14 +-
 mk/rte.app.mk                                     |   1 +
 19 files changed, 3375 insertions(+), 15 deletions(-)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
Signature · 1 line
2.1.4
#120 lore raw

PATCH v8 1/11 ethdev: add deferred intermediate device state

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index 76179fd..69896e9 100644
@@ -291,7 +291,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index fd6baf3..2adef76 100644
@@ -1607,6 +1607,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
#121 lore raw

PATCH v8 2/11 ethdev: count devices consistently

In reply to Gaetan Rivet

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

---
 lib/librte_ether/rte_ethdev.c | 16 +++++++++-------
 lib/librte_ether/rte_ethdev.h | 13 ++++++-------
 2 files changed, 15 insertions(+), 14 deletions(-)
lib/librte_ether/rte_ethdev.c +9 -7
index 69896e9..8f41a68 100644
@@ -72,7 +72,6 @@ static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
 struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
 static struct rte_eth_dev_data *rte_eth_dev_data;
 static uint8_t eth_dev_last_created_port;
-static uint8_t nb_ports;
 
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
@@ -210,7 +209,6 @@ eth_dev_get(uint8_t port_id)
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
 
 	eth_dev_last_created_port = port_id;
-	nb_ports++;
 
 	return eth_dev;
 }
@@ -283,7 +281,6 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 		return -EINVAL;
 
 	eth_dev->state = RTE_ETH_DEV_UNUSED;
-	nb_ports--;
 	return 0;
 }
 
@@ -308,7 +305,15 @@ rte_eth_dev_socket_id(uint8_t port_id)
 uint8_t
 rte_eth_dev_count(void)
 {
-	return nb_ports;
+	uint8_t p;
+	uint8_t count;
+
+	count = 0;
+
+	RTE_ETH_FOREACH_DEV(p)
+		count++;
+
+	return count;
 }
 
 int
@@ -341,9 +346,6 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
 		return -EINVAL;
 	}
 
-	if (!nb_ports)
-		return -ENODEV;
-
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!rte_eth_devices[i].device)
 			continue;
lib/librte_ether/rte_ethdev.h +6 -7
index 2adef76..a744ba7 100644
@@ -1742,13 +1742,12 @@ uint8_t rte_eth_find_next(uint8_t port_id);
 
 /**
  * Get the total number of Ethernet devices that have been successfully
- * initialized by the [matching] Ethernet driver during the PCI probing phase.
- * All devices whose port identifier is in the range
- * [0,  rte_eth_dev_count() - 1] can be operated on by network applications
- * immediately after invoking rte_eal_init().
- * If the application unplugs a port using hotplug function, The enabled port
- * numbers may be noncontiguous. In the case, the applications need to manage
- * enabled port by using the ``RTE_ETH_FOREACH_DEV()`` macro.
+ * initialized by the matching Ethernet driver during the PCI probing phase
+ * and that are available for applications to use. These devices must be
+ * accessed by using the ``RTE_ETH_FOREACH_DEV()`` macro to deal with
+ * non-contiguous ranges of devices.
+ * These non-contiguous ranges can be created by calls to hotplug functions or
+ * by some PMDs.
  *
  * @return
  *   - The total number of usable Ethernet devices.
Signature · 1 line
2.1.4
#122 lore raw

PATCH v8 3/11 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                                       |   5 +
 config/common_base                                |   6 +
 doc/guides/nics/fail_safe.rst                     | 146 +++++
 doc/guides/nics/features/failsafe.ini             |  24 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  76 +++
 drivers/net/failsafe/failsafe.c                   | 231 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 331 +++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 138 +++++
 drivers/net/failsafe/failsafe_ops.c               | 663 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 227 ++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 107 ++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 mk/rte.app.mk                                     |   1 +
 15 files changed, 1962 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
MAINTAINERS +5 -0
index 804ac04..2adaa1b 100644
@@ -336,6 +336,11 @@ F: drivers/net/enic/
 F: doc/guides/nics/enic.rst
 F: doc/guides/nics/features/enic.ini
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +6 -0
index 8ae6e92..9720b67 100644
@@ -420,6 +420,12 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG=n
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +146 -0

146 lines not on this page · raw message

doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..3c52823
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+Queue start/stop     = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 240d082..17eaaf4 100644
@@ -64,6 +64,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +2 -0
index 35ed813..d33c959 100644
@@ -59,6 +59,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DEPDIRS-ena = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DEPDIRS-enic = $(core-libs) librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
+DEPDIRS-failsafe = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DEPDIRS-fm10k = $(core-libs) librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
drivers/net/failsafe/Makefile new file +76 -0

76 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +231 -0

231 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +331 -0

331 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +138 -0

138 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +663 -0

663 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +227 -0

227 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

drivers/net/failsafe/rte_pmd_failsafe_version.map new file +4 -0
new file mode 100644
index 0000000..b6d2840
@@ -0,0 +1,4 @@
+DPDK_17.08 {
+
+	local: *;
+};
mk/rte.app.mk +1 -0
index e239581..cdcd778 100644
@@ -121,6 +121,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
Signature · 1 line
2.1.4
#123 lore raw

Re: [PATCH v8 03/11] net/failsafe: add fail-safe PMD

11/07/2017 01:19, Gaetan Rivet:

Quoted 2 lines
drivers/net/failsafe/failsafe_args.c new file +0 -0

[...]

Quoted 1 line

+#include <errno.h>

Do you really need errno in this file?

#124 lore raw

Re: [PATCH v8 03/11] net/failsafe: add fail-safe PMD

Quoted 7 lines · Thomas Monjalon

11/07/2017 01:19, Gaetan Rivet:

Quoted 2 lines
drivers/net/failsafe/failsafe_args.c new file +0 -0

[...]

Quoted 1 line

+#include <errno.h>

Do you really need errno in this file?

It's used for error handling on strtoull and popen. Why, is it a problem to include errno.h?

Signature · 2 lines
Gaëtan Rivet
6WIND
#125 lore raw

Re: [PATCH v8 03/11] net/failsafe: add fail-safe PMD

11/07/2017 23:48, Gaëtan Rivet:

Quoted 11 lines · Thomas Monjalon
Quoted 7 lines

11/07/2017 01:19, Gaetan Rivet:

Quoted 2 lines
drivers/net/failsafe/failsafe_args.c new file +0 -0

[...]

Quoted 1 line

+#include <errno.h>

Do you really need errno in this file?

It's used for error handling on strtoull and popen. Why, is it a problem to include errno.h?

I don't see errno used in this patch.
I think it is used in next patches.

#126 lore raw

Re: [PATCH v8 03/11] net/failsafe: add fail-safe PMD

Quoted 8 lines · Thomas Monjalon

11/07/2017 23:48, Gaëtan Rivet:

Quoted 7 lines · Thomas Monjalon
Quoted 6 lines

11/07/2017 01:19, Gaetan Rivet:

Quoted 2 lines
drivers/net/failsafe/failsafe_args.c new file +0 -0

[...]

Quoted 1 line

+#include <errno.h>

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

Do you really need errno in this file?

It's used for error handling on strtoull and popen. Why, is it a problem to include errno.h?

I don't see errno used in this patch.
I think it is used in next patches.

Ah, yes, you're right, sorry.
Will fix, thanks.

Signature · 2 lines
Gaëtan Rivet
6WIND
#127 lore raw

PATCH v8 4/11 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  19 +++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  71 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  32 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  60 ++++++++-
 8 files changed, 423 insertions(+), 43 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +19 -0
index 3b36eee..bbee1c2 100644
@@ -102,6 +102,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **hotplug_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two slave upkeep round.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -144,3 +149,17 @@ Care must be taken, however, to respect the **ether** API concerning device
 access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
+
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
drivers/net/failsafe/Makefile +1 -0
index c759035..e27bfc0 100644
@@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +71 -0

83 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +32 -0
index f07d26e..8f334aa 100644
@@ -45,9 +45,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t hotplug_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -221,6 +223,24 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+fs_get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 fs_get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -252,6 +272,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -274,6 +295,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&fs_get_u64_arg, &hotplug_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -287,6 +318,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index f4bd777..1bab3fc 100644
@@ -72,37 +72,14 @@ fs_bus_init(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = fs_bus_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -134,5 +111,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = fs_bus_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 693162e..4044473 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_hotplug_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +58 -2

92 lines not on this page · raw message

Signature · 1 line
2.1.4
#128 lore raw

PATCH v8 5/11 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 99 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 130 insertions(+)
doc/guides/nics/fail_safe.rst +20 -0
index bbee1c2..901b3cb 100644
@@ -91,6 +91,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -139,6 +152,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +99 -0

126 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index 7910952..2a1535e 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index 8fb72fe..554d7a3 100644
@@ -44,6 +44,7 @@
 #define PMD_FAILSAFE_PLUG_IN_POLL_KVARG "hotplug_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"hotplug_poll=u64"		\
 	""
@@ -87,6 +88,8 @@ struct sub_device {
 	struct rte_eth_dev *edev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -135,6 +138,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#129 lore raw

PATCH v8 6/11 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   1 +
 drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 216 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 +++++
 drivers/net/failsafe/failsafe_private.h |  18 +++
 8 files changed, 337 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index 3c52823..9167b59 100644
@@ -13,6 +13,7 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index e27bfc0..3cccfe0 100644
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 888f07b..6557255 100644
@@ -177,6 +177,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +1 -0
index 1bab3fc..31257b0 100644
@@ -62,6 +62,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			ERROR("sub_device %d init went wrong", i);
 			return -ENODEV;
 		}
+		SUB_ID(sdev) = i;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
drivers/net/failsafe/failsafe_ether.c +70 -0

90 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +216 -0

216 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index 4044473..4cb2e90 100644
@@ -35,6 +35,7 @@
 #include <stdint.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -628,6 +629,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -655,4 +683,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +18 -0
index 554d7a3..f40ea2f 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
@@ -72,6 +74,14 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -86,6 +96,7 @@ struct sub_device {
 	struct rte_bus *bus;
 	struct rte_device *dev;
 	struct rte_eth_dev *edev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -104,6 +115,8 @@ struct fs_priv {
 	uint8_t subs_tail; /* first invalid */
 	uint8_t subs_tx; /* current emitting device */
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t hotplug_poll;
 extern int mac_from_arg;
 
@@ -170,6 +184,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	((sdev)->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#130 lore raw

PATCH v8 7/11 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +6 -0
index 9167b59..257f579 100644
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +129 -2

151 lines not on this page · raw message

Signature · 1 line
2.1.4
#131 lore raw

PATCH v8 8/11 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 124 ++++++++++++++++++++++++++------
 2 files changed, 112 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index f40ea2f..25a4dac 100644
@@ -141,11 +141,18 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev, int force_safe);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -299,6 +306,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev, 0);
 	rte_wmb();
 }
 
drivers/net/failsafe/failsafe_rxtx.c +104 -20

154 lines not on this page · raw message

Signature · 1 line
2.1.4
#132 lore raw

PATCH v8 9/11 net/failsafe: support device removal

In reply to Gaetan Rivet

Listen to INTR_RMV events issued by slaves.
Add atomic flags on slave queues to detect use of slave bursts function. If a removal is detected, set the recollection flag on this slave.

During a slave upkeep round, if its recollection flag is set and its burst functions are not in use by any thread, remove that slave.

---
 doc/guides/nics/fail_safe.rst           | 14 +++++
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_args.c    | 13 +++++
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   | 96 ++++++++++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_ops.c     | 38 +++++++++++--
 drivers/net/failsafe/failsafe_private.h | 72 ++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_rxtx.c    | 17 +++++-
 8 files changed, 234 insertions(+), 20 deletions(-)
doc/guides/nics/fail_safe.rst +14 -0
index 901b3cb..2ad8f3e 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation options
@@ -183,3 +189,11 @@ emit and receive packets. It will store any applied configuration, and try to
 apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
+
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
drivers/net/failsafe/failsafe.c +1 -0
index 6557255..4d35860 100644
@@ -132,6 +132,7 @@ fs_hotplug_alarm(void *arg)
 	if (!PRIV(dev)->pending_alarm)
 		return;
 	PRIV(dev)->pending_alarm = 0;
+	failsafe_dev_remove(dev);
 	FOREACH_SUBDEV(sdev, i, dev)
 		if (sdev->state != PRIV(dev)->state)
 			break;
drivers/net/failsafe/failsafe_args.c +13 -0
index c723ca3..dd55aaf 100644
@@ -443,6 +443,17 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				    dev, params);
 }
 
+static int
+fs_parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char devstr[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
+	return fs_parse_device(sdev, devstr);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -455,6 +466,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = fs_execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = fs_parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -1
index 31257b0..d0954d9 100644
@@ -63,6 +63,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			return -ENODEV;
 		}
 		SUB_ID(sdev) = i;
+		sdev->fs_dev = dev;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
@@ -80,7 +81,7 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 		return ret;
 	if (PRIV(dev)->state < DEV_PROBED)
 		PRIV(dev)->state = DEV_PROBED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
drivers/net/failsafe/failsafe_ether.c +90 -6

130 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +35 -3
index 5fb0135..2e1c798 100644
@@ -33,6 +33,8 @@
 
 #include <assert.h>
 #include <stdint.h>
+
+#include <rte_atomic.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
 #include <rte_flow.h>
@@ -204,9 +206,21 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
+		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
 					dev->data->nb_tx_queues,
@@ -215,6 +229,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
@@ -240,7 +264,7 @@ fs_dev_start(struct rte_eth_dev *dev)
 	}
 	if (PRIV(dev)->state < DEV_STARTED)
 		PRIV(dev)->state = DEV_STARTED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
@@ -351,10 +375,14 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,
 		fs_rx_queue_release(rxq);
 		dev->data->rx_queues[rx_queue_id] = NULL;
 	}
-	rxq = rte_zmalloc(NULL, sizeof(*rxq),
+	rxq = rte_zmalloc(NULL,
+			  sizeof(*rxq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (rxq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&rxq->refcnt[i]);
 	rxq->qid = rx_queue_id;
 	rxq->socket_id = socket_id;
 	rxq->info.mp = mb_pool;
@@ -414,10 +442,14 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,
 		fs_tx_queue_release(txq);
 		dev->data->tx_queues[tx_queue_id] = NULL;
 	}
-	txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+	txq = rte_zmalloc("ethdev TX queue",
+			  sizeof(*txq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (txq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&txq->refcnt[i]);
 	txq->qid = tx_queue_id;
 	txq->socket_id = socket_id;
 	txq->info.conf = *tx_conf;
drivers/net/failsafe/failsafe_private.h +64 -8

133 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c +15 -2
index c15025f..82a8c4e 100644
@@ -33,6 +33,7 @@
 
 #include <assert.h>
 
+#include <rte_atomic.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
 
@@ -113,8 +114,10 @@ failsafe_rx_burst(void *queue,
 		if (unlikely(fs_rx_unsafe(sdev)))
 			continue;
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -147,8 +150,10 @@ failsafe_rx_burst_fast(void *queue,
 		sdev = &priv->subs[i];
 		assert(!fs_rx_unsafe(sdev));
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -165,13 +170,17 @@ failsafe_tx_burst(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	if (unlikely(fs_tx_unsafe(sdev)))
 		return 0;
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
 
 uint16_t
@@ -182,10 +191,14 @@ failsafe_tx_burst_fast(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	assert(!fs_tx_unsafe(sdev));
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
Signature · 1 line
2.1.4
#133 lore raw

PATCH v8 10/11 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 23 +++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 46 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 257f579..251ce55 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
drivers/net/failsafe/failsafe.c +1 -0
index 4d35860..151f823 100644
@@ -240,6 +240,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index ea3105c..a694b4d 100644
@@ -387,3 +387,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 	sdev->remove = 1;
 	return 0;
 }
+
+int
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event __rte_unused,
+				void *cb_arg, void *out __rte_unused)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		return _rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL, NULL);
+	else
+		return 0;
+}
drivers/net/failsafe/failsafe_ops.c +23 -0
index 2e1c798..05221bc 100644
@@ -207,6 +207,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -219,6 +221,17 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
@@ -239,6 +252,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+						RTE_ETH_EVENT_INTR_LSC,
+						failsafe_eth_lsc_event_callback,
+						dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 6a8041d..6b34998 100644
@@ -179,6 +179,9 @@ void failsafe_dev_remove(struct rte_eth_dev *dev);
 int failsafe_eth_rmv_event_callback(uint8_t port_id,
 				    enum rte_eth_event_type type,
 				    void *arg, void *out);
+int failsafe_eth_lsc_event_callback(uint8_t port_id,
+				    enum rte_eth_event_type event,
+				    void *cb_arg, void *out);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#134 lore raw

PATCH v8 11/11 net/failsafe: support flow API isolation mode

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ether.c   | 34 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_flow.c    | 29 ++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  4 ++++
 3 files changed, 65 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ether.c +32 -2
index a694b4d..c8b9c8a 100644
@@ -74,6 +74,28 @@ fs_flow_complain(struct rte_flow_error *error)
 }
 
 static int
+eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_flow_error ferror;
+	int ret;
+
+	if (!PRIV(dev)->flow_isolated) {
+		DEBUG("Flow isolation already disabled");
+	} else {
+		DEBUG("Enabling flow isolation");
+		ret = rte_flow_isolate(PORT_ID(sdev),
+				       PRIV(dev)->flow_isolated,
+				       &ferror);
+		if (ret) {
+			fs_flow_complain(&ferror);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int
 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 		struct sub_device *sdev)
 {
@@ -334,9 +356,17 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	if (PRIV(dev)->state < DEV_ACTIVE)
 		return 0;
 	inactive = 0;
-	FOREACH_SUBDEV(sdev, i, dev)
-		if (sdev->state == DEV_PROBED)
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state == DEV_PROBED) {
 			inactive |= UINT32_C(1) << i;
+			ret = eth_dev_flow_isolate_set(dev, sdev);
+			if (ret) {
+				ERROR("Could not apply configuration to sub_device %d",
+				      i);
+				goto err_remove;
+			}
+		}
+	}
 	ret = dev->dev_ops->dev_configure(dev);
 	if (ret)
 		goto err_remove;
drivers/net/failsafe/failsafe_flow.c +29 -0
index d8f59a1..a5598ae 100644
@@ -207,10 +207,39 @@ fs_flow_query(struct rte_eth_dev *dev,
 	return -1;
 }
 
+static int
+fs_flow_isolate(struct rte_eth_dev *dev,
+		int set,
+		struct rte_flow_error *error)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state < DEV_PROBED)
+			continue;
+		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
+		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
+			WARN("flow isolation mode of sub_device %d in incoherent state.",
+				i);
+		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
+		if (ret) {
+			ERROR("Operation rte_flow_isolate failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+		sdev->flow_isolated = set;
+	}
+	PRIV(dev)->flow_isolated = set;
+	return 0;
+}
+
 const struct rte_flow_ops fs_flow_ops = {
 	.validate = fs_flow_validate,
 	.create = fs_flow_create,
 	.destroy = fs_flow_destroy,
 	.flush = fs_flow_flush,
 	.query = fs_flow_query,
+	.isolate = fs_flow_isolate,
 };
drivers/net/failsafe/failsafe_private.h +4 -0
index 6b34998..a071ad9 100644
@@ -108,6 +108,8 @@ struct sub_device {
 	struct rte_eth_dev *fs_dev;
 	/* flag calling for recollection */
 	volatile unsigned int remove:1;
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 struct fs_priv {
@@ -139,6 +141,8 @@ struct fs_priv {
 	 */
 	enum dev_state state;
 	unsigned int pending_alarm:1; /* An alarm is pending */
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 /* MISC */
Signature · 1 line
2.1.4
#135 lore raw

v9 cover introduce fail-safe PMD

In reply to Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

eal: complete attach / detach support
http://dpdk.org/ml/archives/dev/2017-May/066366.html
http://dpdk.org/dev/patchwork/patch/24522/

ethdev: add flow API rule copy function
http://dpdk.org/ml/archives/dev/2017-May/066145.html
http://dpdk.org/dev/patchwork/patch/24406/

ethdev: add isolated mode to flow API
http://dpdk.org/ml/archives/dev/2017-April/064327.html
http://dpdk.org/dev/patchwork/patch/23741/

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

 MAINTAINERS                                       |   5 +
 config/common_base                                |   6 +
 doc/guides/nics/fail_safe.rst                     | 199 +++++
 doc/guides/nics/features/failsafe.ini             |  32 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  78 ++
 drivers/net/failsafe/failsafe.c                   | 305 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 472 ++++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 118 +++
 drivers/net/failsafe/failsafe_ether.c             | 437 +++++++++++
 drivers/net/failsafe/failsafe_flow.c              | 245 ++++++
 drivers/net/failsafe/failsafe_ops.c               | 869 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 376 ++++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 204 +++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 lib/librte_ether/rte_ethdev.c                     |  19 +-
 lib/librte_ether/rte_ethdev.h                     |  14 +-
 mk/rte.app.mk                                     |   1 +
 19 files changed, 3372 insertions(+), 15 deletions(-)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
Signature · 1 line
2.1.4
#136 lore raw

PATCH v9 1/11 ethdev: add deferred intermediate device state

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index 76179fd..69896e9 100644
@@ -291,7 +291,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index fd6baf3..2adef76 100644
@@ -1607,6 +1607,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
#137 lore raw

PATCH v9 2/11 ethdev: count devices consistently

In reply to Gaetan Rivet

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

---
 lib/librte_ether/rte_ethdev.c | 16 +++++++++-------
 lib/librte_ether/rte_ethdev.h | 13 ++++++-------
 2 files changed, 15 insertions(+), 14 deletions(-)
lib/librte_ether/rte_ethdev.c +9 -7
index 69896e9..8f41a68 100644
@@ -72,7 +72,6 @@ static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
 struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
 static struct rte_eth_dev_data *rte_eth_dev_data;
 static uint8_t eth_dev_last_created_port;
-static uint8_t nb_ports;
 
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
@@ -210,7 +209,6 @@ eth_dev_get(uint8_t port_id)
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
 
 	eth_dev_last_created_port = port_id;
-	nb_ports++;
 
 	return eth_dev;
 }
@@ -283,7 +281,6 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 		return -EINVAL;
 
 	eth_dev->state = RTE_ETH_DEV_UNUSED;
-	nb_ports--;
 	return 0;
 }
 
@@ -308,7 +305,15 @@ rte_eth_dev_socket_id(uint8_t port_id)
 uint8_t
 rte_eth_dev_count(void)
 {
-	return nb_ports;
+	uint8_t p;
+	uint8_t count;
+
+	count = 0;
+
+	RTE_ETH_FOREACH_DEV(p)
+		count++;
+
+	return count;
 }
 
 int
@@ -341,9 +346,6 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
 		return -EINVAL;
 	}
 
-	if (!nb_ports)
-		return -ENODEV;
-
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!rte_eth_devices[i].device)
 			continue;
lib/librte_ether/rte_ethdev.h +6 -7
index 2adef76..a744ba7 100644
@@ -1742,13 +1742,12 @@ uint8_t rte_eth_find_next(uint8_t port_id);
 
 /**
  * Get the total number of Ethernet devices that have been successfully
- * initialized by the [matching] Ethernet driver during the PCI probing phase.
- * All devices whose port identifier is in the range
- * [0,  rte_eth_dev_count() - 1] can be operated on by network applications
- * immediately after invoking rte_eal_init().
- * If the application unplugs a port using hotplug function, The enabled port
- * numbers may be noncontiguous. In the case, the applications need to manage
- * enabled port by using the ``RTE_ETH_FOREACH_DEV()`` macro.
+ * initialized by the matching Ethernet driver during the PCI probing phase
+ * and that are available for applications to use. These devices must be
+ * accessed by using the ``RTE_ETH_FOREACH_DEV()`` macro to deal with
+ * non-contiguous ranges of devices.
+ * These non-contiguous ranges can be created by calls to hotplug functions or
+ * by some PMDs.
  *
  * @return
  *   - The total number of usable Ethernet devices.
Signature · 1 line
2.1.4
#138 lore raw

PATCH v9 3/11 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                                       |   5 +
 config/common_base                                |   6 +
 doc/guides/nics/fail_safe.rst                     | 146 +++++
 doc/guides/nics/features/failsafe.ini             |  24 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  76 +++
 drivers/net/failsafe/failsafe.c                   | 231 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 331 +++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 138 +++++
 drivers/net/failsafe/failsafe_ops.c               | 663 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 227 ++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 107 ++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 mk/rte.app.mk                                     |   1 +
 15 files changed, 1962 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
MAINTAINERS +5 -0
index 804ac04..2adaa1b 100644
@@ -336,6 +336,11 @@ F: drivers/net/enic/
 F: doc/guides/nics/enic.rst
 F: doc/guides/nics/features/enic.ini
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +6 -0
index 8ae6e92..9720b67 100644
@@ -420,6 +420,12 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE_DEBUG=n
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +146 -0

146 lines not on this page · raw message

doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..3c52823
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+Queue start/stop     = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 240d082..17eaaf4 100644
@@ -64,6 +64,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +2 -0
index 35ed813..d33c959 100644
@@ -59,6 +59,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DEPDIRS-ena = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DEPDIRS-enic = $(core-libs) librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
+DEPDIRS-failsafe = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DEPDIRS-fm10k = $(core-libs) librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
drivers/net/failsafe/Makefile new file +76 -0

76 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +231 -0

231 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +331 -0

331 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +138 -0

138 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +663 -0

663 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +227 -0

227 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

drivers/net/failsafe/rte_pmd_failsafe_version.map new file +4 -0
new file mode 100644
index 0000000..b6d2840
@@ -0,0 +1,4 @@
+DPDK_17.08 {
+
+	local: *;
+};
mk/rte.app.mk +1 -0
index 5bb4290..c25fdd9 100644
@@ -121,6 +121,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
Signature · 1 line
2.1.4
#139 lore raw

Re: [PATCH v9 03/11] net/failsafe: add fail-safe PMD

12/07/2017 01:26, Gaetan Rivet:

Quoted 2 lines

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

There are some assert() in this code.
It does not compile:
fatal error: use of GNU statement expression extension
Please replace them with RTE_ASSERT (and remove assert.h includes). Thanks

#140 lore raw

PATCH v9 4/11 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  19 +++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  71 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  33 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  60 ++++++++-
 8 files changed, 424 insertions(+), 43 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +19 -0
index 3b36eee..bbee1c2 100644
@@ -102,6 +102,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **hotplug_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two slave upkeep round.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -144,3 +149,17 @@ Care must be taken, however, to respect the **ether** API concerning device
 access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
+
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
drivers/net/failsafe/Makefile +1 -0
index c759035..e27bfc0 100644
@@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +71 -0

83 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +33 -0
index 79e5bfa..2e60442 100644
@@ -32,6 +32,7 @@
  */
 
 #include <string.h>
+#include <errno.h>
 
 #include <rte_devargs.h>
 #include <rte_malloc.h>
@@ -45,9 +46,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t hotplug_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -221,6 +224,24 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+fs_get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 fs_get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -252,6 +273,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -274,6 +296,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&fs_get_u64_arg, &hotplug_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -287,6 +319,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index f4bd777..1bab3fc 100644
@@ -72,37 +72,14 @@ fs_bus_init(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = fs_bus_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -134,5 +111,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = fs_bus_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 693162e..4044473 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_hotplug_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +58 -2

92 lines not on this page · raw message

Signature · 1 line
2.1.4
#141 lore raw

PATCH v9 5/11 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 95 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 126 insertions(+)
doc/guides/nics/fail_safe.rst +20 -0
index bbee1c2..901b3cb 100644
@@ -91,6 +91,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -139,6 +152,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +95 -0

122 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index 7910952..2a1535e 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index 8fb72fe..554d7a3 100644
@@ -44,6 +44,7 @@
 #define PMD_FAILSAFE_PLUG_IN_POLL_KVARG "hotplug_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"hotplug_poll=u64"		\
 	""
@@ -87,6 +88,8 @@ struct sub_device {
 	struct rte_eth_dev *edev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -135,6 +138,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#142 lore raw

PATCH v9 6/11 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   1 +
 drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 216 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 +++++
 drivers/net/failsafe/failsafe_private.h |  18 +++
 8 files changed, 337 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index 3c52823..9167b59 100644
@@ -13,6 +13,7 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index e27bfc0..3cccfe0 100644
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 888f07b..6557255 100644
@@ -177,6 +177,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +1 -0
index 1bab3fc..31257b0 100644
@@ -62,6 +62,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			ERROR("sub_device %d init went wrong", i);
 			return -ENODEV;
 		}
+		SUB_ID(sdev) = i;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
drivers/net/failsafe/failsafe_ether.c +70 -0

90 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +216 -0

216 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index 4044473..4cb2e90 100644
@@ -35,6 +35,7 @@
 #include <stdint.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -628,6 +629,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -655,4 +683,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +18 -0
index 554d7a3..f40ea2f 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
@@ -72,6 +74,14 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -86,6 +96,7 @@ struct sub_device {
 	struct rte_bus *bus;
 	struct rte_device *dev;
 	struct rte_eth_dev *edev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -104,6 +115,8 @@ struct fs_priv {
 	uint8_t subs_tail; /* first invalid */
 	uint8_t subs_tx; /* current emitting device */
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t hotplug_poll;
 extern int mac_from_arg;
 
@@ -170,6 +184,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	((sdev)->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#143 lore raw

PATCH v9 7/11 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +6 -0
index 9167b59..257f579 100644
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +129 -2

151 lines not on this page · raw message

Signature · 1 line
2.1.4
#144 lore raw

PATCH v9 8/11 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 124 ++++++++++++++++++++++++++------
 2 files changed, 112 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index f40ea2f..25a4dac 100644
@@ -141,11 +141,18 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev, int force_safe);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -299,6 +306,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev, 0);
 	rte_wmb();
 }
 
drivers/net/failsafe/failsafe_rxtx.c +104 -20

154 lines not on this page · raw message

Signature · 1 line
2.1.4
#145 lore raw

PATCH v9 9/11 net/failsafe: support device removal

In reply to Gaetan Rivet

Listen to INTR_RMV events issued by slaves.
Add atomic flags on slave queues to detect use of slave bursts function. If a removal is detected, set the recollection flag on this slave.

During a slave upkeep round, if its recollection flag is set and its burst functions are not in use by any thread, remove that slave.

---
 doc/guides/nics/fail_safe.rst           | 14 +++++
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_args.c    | 13 +++++
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   | 96 ++++++++++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_ops.c     | 38 +++++++++++--
 drivers/net/failsafe/failsafe_private.h | 72 ++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_rxtx.c    | 17 +++++-
 8 files changed, 234 insertions(+), 20 deletions(-)
doc/guides/nics/fail_safe.rst +14 -0
index 901b3cb..2ad8f3e 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation options
@@ -183,3 +189,11 @@ emit and receive packets. It will store any applied configuration, and try to
 apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
+
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
drivers/net/failsafe/failsafe.c +1 -0
index 6557255..4d35860 100644
@@ -132,6 +132,7 @@ fs_hotplug_alarm(void *arg)
 	if (!PRIV(dev)->pending_alarm)
 		return;
 	PRIV(dev)->pending_alarm = 0;
+	failsafe_dev_remove(dev);
 	FOREACH_SUBDEV(sdev, i, dev)
 		if (sdev->state != PRIV(dev)->state)
 			break;
drivers/net/failsafe/failsafe_args.c +13 -0
index 2f400f8..fea299a 100644
@@ -440,6 +440,17 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				    dev, params);
 }
 
+static int
+fs_parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char devstr[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
+	return fs_parse_device(sdev, devstr);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -452,6 +463,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = fs_execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = fs_parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -1
index 31257b0..d0954d9 100644
@@ -63,6 +63,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			return -ENODEV;
 		}
 		SUB_ID(sdev) = i;
+		sdev->fs_dev = dev;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
@@ -80,7 +81,7 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 		return ret;
 	if (PRIV(dev)->state < DEV_PROBED)
 		PRIV(dev)->state = DEV_PROBED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
drivers/net/failsafe/failsafe_ether.c +90 -6

130 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +35 -3
index 5fb0135..2e1c798 100644
@@ -33,6 +33,8 @@
 
 #include <assert.h>
 #include <stdint.h>
+
+#include <rte_atomic.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
 #include <rte_flow.h>
@@ -204,9 +206,21 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
+		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
 					dev->data->nb_tx_queues,
@@ -215,6 +229,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
@@ -240,7 +264,7 @@ fs_dev_start(struct rte_eth_dev *dev)
 	}
 	if (PRIV(dev)->state < DEV_STARTED)
 		PRIV(dev)->state = DEV_STARTED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
@@ -351,10 +375,14 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,
 		fs_rx_queue_release(rxq);
 		dev->data->rx_queues[rx_queue_id] = NULL;
 	}
-	rxq = rte_zmalloc(NULL, sizeof(*rxq),
+	rxq = rte_zmalloc(NULL,
+			  sizeof(*rxq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (rxq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&rxq->refcnt[i]);
 	rxq->qid = rx_queue_id;
 	rxq->socket_id = socket_id;
 	rxq->info.mp = mb_pool;
@@ -414,10 +442,14 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,
 		fs_tx_queue_release(txq);
 		dev->data->tx_queues[tx_queue_id] = NULL;
 	}
-	txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+	txq = rte_zmalloc("ethdev TX queue",
+			  sizeof(*txq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (txq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&txq->refcnt[i]);
 	txq->qid = tx_queue_id;
 	txq->socket_id = socket_id;
 	txq->info.conf = *tx_conf;
drivers/net/failsafe/failsafe_private.h +64 -8

133 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c +15 -2
index c15025f..82a8c4e 100644
@@ -33,6 +33,7 @@
 
 #include <assert.h>
 
+#include <rte_atomic.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
 
@@ -113,8 +114,10 @@ failsafe_rx_burst(void *queue,
 		if (unlikely(fs_rx_unsafe(sdev)))
 			continue;
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -147,8 +150,10 @@ failsafe_rx_burst_fast(void *queue,
 		sdev = &priv->subs[i];
 		assert(!fs_rx_unsafe(sdev));
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -165,13 +170,17 @@ failsafe_tx_burst(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	if (unlikely(fs_tx_unsafe(sdev)))
 		return 0;
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
 
 uint16_t
@@ -182,10 +191,14 @@ failsafe_tx_burst_fast(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	assert(!fs_tx_unsafe(sdev));
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
Signature · 1 line
2.1.4
#146 lore raw

PATCH v9 10/11 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 23 +++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 46 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 257f579..251ce55 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
drivers/net/failsafe/failsafe.c +1 -0
index 4d35860..151f823 100644
@@ -240,6 +240,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index ea3105c..a694b4d 100644
@@ -387,3 +387,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 	sdev->remove = 1;
 	return 0;
 }
+
+int
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event __rte_unused,
+				void *cb_arg, void *out __rte_unused)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		return _rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL, NULL);
+	else
+		return 0;
+}
drivers/net/failsafe/failsafe_ops.c +23 -0
index 2e1c798..05221bc 100644
@@ -207,6 +207,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -219,6 +221,17 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
@@ -239,6 +252,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+						RTE_ETH_EVENT_INTR_LSC,
+						failsafe_eth_lsc_event_callback,
+						dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 6a8041d..6b34998 100644
@@ -179,6 +179,9 @@ void failsafe_dev_remove(struct rte_eth_dev *dev);
 int failsafe_eth_rmv_event_callback(uint8_t port_id,
 				    enum rte_eth_event_type type,
 				    void *arg, void *out);
+int failsafe_eth_lsc_event_callback(uint8_t port_id,
+				    enum rte_eth_event_type event,
+				    void *cb_arg, void *out);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#147 lore raw

PATCH v9 11/11 net/failsafe: support flow API isolation mode

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ether.c   | 34 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_flow.c    | 29 ++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  4 ++++
 3 files changed, 65 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ether.c +32 -2
index a694b4d..c8b9c8a 100644
@@ -74,6 +74,28 @@ fs_flow_complain(struct rte_flow_error *error)
 }
 
 static int
+eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_flow_error ferror;
+	int ret;
+
+	if (!PRIV(dev)->flow_isolated) {
+		DEBUG("Flow isolation already disabled");
+	} else {
+		DEBUG("Enabling flow isolation");
+		ret = rte_flow_isolate(PORT_ID(sdev),
+				       PRIV(dev)->flow_isolated,
+				       &ferror);
+		if (ret) {
+			fs_flow_complain(&ferror);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int
 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 		struct sub_device *sdev)
 {
@@ -334,9 +356,17 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	if (PRIV(dev)->state < DEV_ACTIVE)
 		return 0;
 	inactive = 0;
-	FOREACH_SUBDEV(sdev, i, dev)
-		if (sdev->state == DEV_PROBED)
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state == DEV_PROBED) {
 			inactive |= UINT32_C(1) << i;
+			ret = eth_dev_flow_isolate_set(dev, sdev);
+			if (ret) {
+				ERROR("Could not apply configuration to sub_device %d",
+				      i);
+				goto err_remove;
+			}
+		}
+	}
 	ret = dev->dev_ops->dev_configure(dev);
 	if (ret)
 		goto err_remove;
drivers/net/failsafe/failsafe_flow.c +29 -0
index d8f59a1..a5598ae 100644
@@ -207,10 +207,39 @@ fs_flow_query(struct rte_eth_dev *dev,
 	return -1;
 }
 
+static int
+fs_flow_isolate(struct rte_eth_dev *dev,
+		int set,
+		struct rte_flow_error *error)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state < DEV_PROBED)
+			continue;
+		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
+		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
+			WARN("flow isolation mode of sub_device %d in incoherent state.",
+				i);
+		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
+		if (ret) {
+			ERROR("Operation rte_flow_isolate failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+		sdev->flow_isolated = set;
+	}
+	PRIV(dev)->flow_isolated = set;
+	return 0;
+}
+
 const struct rte_flow_ops fs_flow_ops = {
 	.validate = fs_flow_validate,
 	.create = fs_flow_create,
 	.destroy = fs_flow_destroy,
 	.flush = fs_flow_flush,
 	.query = fs_flow_query,
+	.isolate = fs_flow_isolate,
 };
drivers/net/failsafe/failsafe_private.h +4 -0
index 6b34998..a071ad9 100644
@@ -108,6 +108,8 @@ struct sub_device {
 	struct rte_eth_dev *fs_dev;
 	/* flag calling for recollection */
 	volatile unsigned int remove:1;
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 struct fs_priv {
@@ -139,6 +141,8 @@ struct fs_priv {
 	 */
 	enum dev_state state;
 	unsigned int pending_alarm:1; /* An alarm is pending */
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 /* MISC */
Signature · 1 line
2.1.4
#148 lore raw

v10 cover introduce fail-safe PMD

In reply to Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

eal: complete attach / detach support
http://dpdk.org/ml/archives/dev/2017-May/066366.html
http://dpdk.org/dev/patchwork/patch/24522/

ethdev: add flow API rule copy function
http://dpdk.org/ml/archives/dev/2017-May/066145.html
http://dpdk.org/dev/patchwork/patch/24406/

ethdev: add isolated mode to flow API
http://dpdk.org/ml/archives/dev/2017-April/064327.html
http://dpdk.org/dev/patchwork/patch/23741/

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

 MAINTAINERS                                       |   5 +
 config/common_base                                |   5 +
 doc/guides/nics/fail_safe.rst                     | 195 +++++
 doc/guides/nics/features/failsafe.ini             |  32 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  68 ++
 drivers/net/failsafe/failsafe.c                   | 306 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 472 ++++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 118 +++
 drivers/net/failsafe/failsafe_ether.c             | 437 +++++++++++
 drivers/net/failsafe/failsafe_flow.c              | 244 ++++++
 drivers/net/failsafe/failsafe_ops.c               | 869 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 359 +++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 203 +++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 lib/librte_ether/rte_ethdev.c                     |  19 +-
 lib/librte_ether/rte_ethdev.h                     |  14 +-
 mk/rte.app.mk                                     |   1 +
 19 files changed, 3339 insertions(+), 15 deletions(-)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
Signature · 1 line
2.1.4
#149 lore raw

PATCH v10 1/11 ethdev: add deferred intermediate device state

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index a1b7447..81b398d 100644
@@ -291,7 +291,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index f683727..774408c 100644
@@ -1613,6 +1613,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
#150 lore raw

PATCH v10 2/11 ethdev: count devices consistently

In reply to Gaetan Rivet

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

---
 lib/librte_ether/rte_ethdev.c | 16 +++++++++-------
 lib/librte_ether/rte_ethdev.h | 13 ++++++-------
 2 files changed, 15 insertions(+), 14 deletions(-)
lib/librte_ether/rte_ethdev.c +9 -7
index 81b398d..d4ebb1b 100644
@@ -72,7 +72,6 @@ static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
 struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
 static struct rte_eth_dev_data *rte_eth_dev_data;
 static uint8_t eth_dev_last_created_port;
-static uint8_t nb_ports;
 
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
@@ -210,7 +209,6 @@ eth_dev_get(uint8_t port_id)
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
 
 	eth_dev_last_created_port = port_id;
-	nb_ports++;
 
 	return eth_dev;
 }
@@ -283,7 +281,6 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 		return -EINVAL;
 
 	eth_dev->state = RTE_ETH_DEV_UNUSED;
-	nb_ports--;
 	return 0;
 }
 
@@ -308,7 +305,15 @@ rte_eth_dev_socket_id(uint8_t port_id)
 uint8_t
 rte_eth_dev_count(void)
 {
-	return nb_ports;
+	uint8_t p;
+	uint8_t count;
+
+	count = 0;
+
+	RTE_ETH_FOREACH_DEV(p)
+		count++;
+
+	return count;
 }
 
 int
@@ -341,9 +346,6 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
 		return -EINVAL;
 	}
 
-	if (!nb_ports)
-		return -ENODEV;
-
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!rte_eth_devices[i].device)
 			continue;
lib/librte_ether/rte_ethdev.h +6 -7
index 774408c..3ee20a8 100644
@@ -1748,13 +1748,12 @@ uint8_t rte_eth_find_next(uint8_t port_id);
 
 /**
  * Get the total number of Ethernet devices that have been successfully
- * initialized by the [matching] Ethernet driver during the PCI probing phase.
- * All devices whose port identifier is in the range
- * [0,  rte_eth_dev_count() - 1] can be operated on by network applications
- * immediately after invoking rte_eal_init().
- * If the application unplugs a port using hotplug function, The enabled port
- * numbers may be noncontiguous. In the case, the applications need to manage
- * enabled port by using the ``RTE_ETH_FOREACH_DEV()`` macro.
+ * initialized by the matching Ethernet driver during the PCI probing phase
+ * and that are available for applications to use. These devices must be
+ * accessed by using the ``RTE_ETH_FOREACH_DEV()`` macro to deal with
+ * non-contiguous ranges of devices.
+ * These non-contiguous ranges can be created by calls to hotplug functions or
+ * by some PMDs.
  *
  * @return
  *   - The total number of usable Ethernet devices.
Signature · 1 line
2.1.4
#151 lore raw

Re: [PATCH v10 02/11] ethdev: count devices consistently

Quoted 4 lines · Gaetan Rivet

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

First two patches updates ethdev, I believe to get them via next-net, an explicit ACK required.

Thanks,
ferruh

#152 lore raw

PATCH v10 3/11 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                                       |   5 +
 config/common_base                                |   5 +
 doc/guides/nics/fail_safe.rst                     | 142 +++++
 doc/guides/nics/features/failsafe.ini             |  24 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  66 +++
 drivers/net/failsafe/failsafe.c                   | 232 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 331 +++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 138 +++++
 drivers/net/failsafe/failsafe_ops.c               | 664 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 210 +++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 107 ++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 mk/rte.app.mk                                     |   1 +
 15 files changed, 1932 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
MAINTAINERS +5 -0
index 368973a..294b8b0 100644
@@ -341,6 +341,11 @@ F: drivers/net/enic/
 F: doc/guides/nics/enic.rst
 F: doc/guides/nics/features/enic.ini
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +5 -0
index 8ae6e92..7805605 100644
@@ -420,6 +420,11 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +142 -0

142 lines not on this page · raw message

doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..3c52823
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+Queue start/stop     = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 240d082..17eaaf4 100644
@@ -64,6 +64,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +2 -0
index 35ed813..d33c959 100644
@@ -59,6 +59,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DEPDIRS-ena = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DEPDIRS-enic = $(core-libs) librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
+DEPDIRS-failsafe = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DEPDIRS-fm10k = $(core-libs) librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
drivers/net/failsafe/Makefile new file +66 -0

66 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +232 -0

232 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +331 -0

331 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +138 -0

138 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +664 -0

664 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +210 -0

210 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

drivers/net/failsafe/rte_pmd_failsafe_version.map new file +4 -0
new file mode 100644
index 0000000..b6d2840
@@ -0,0 +1,4 @@
+DPDK_17.08 {
+
+	local: *;
+};
mk/rte.app.mk +1 -0
index 5bb4290..c25fdd9 100644
@@ -121,6 +121,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
Signature · 1 line
2.1.4
#153 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

Hi Gaetan,

15/07/2017 19:57, Gaetan Rivet:

doc/guides/nics/fail_safe.rst line 119

Quoted 8 lines
doc/guides/nics/fail_safe.rst new file +8 -0
+#. Start testpmd. The slave device should be blacklisted from normal EAL
+   operations to avoid probing it twice when in PCI blacklist mode.
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 \
+         -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
+         -b 84:00.0 -b 00:04.0 -- -i

It is weird to use -w to declare the failsafe device. And I think it does not work with -w.
Should it be changed to --vdev?

#154 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

Quoted 15 lines · Thomas Monjalon

Hi Gaetan,

15/07/2017 19:57, Gaetan Rivet:

doc/guides/nics/fail_safe.rst line 119

Quoted 8 lines
doc/guides/nics/fail_safe.rst new file +8 -0
+#. Start testpmd. The slave device should be blacklisted from normal EAL
+   operations to avoid probing it twice when in PCI blacklist mode.
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 \
+         -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
+         -b 84:00.0 -b 00:04.0 -- -i

It is weird to use -w to declare the failsafe device. And I think it does not work with -w.
Should it be changed to --vdev?

It did work before [1], and it was a way to showcase the new format, but with [1] applied, then it should come back to --vdev indeed.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071361.html

Signature · 2 lines
Gaëtan Rivet
6WIND
#155 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet
Quoted 6 lines · Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

Quoted 8 lines

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

All PMD in a single patch is hard to review, I am sure some details missed during the review, but taking account the histroy of the PMD I accept this as it is, but I will rely on your support to fix issues in the future.

Quoted 3 lines

<...>

doc/guides/nics/fail_safe.rst line 110

Quoted 10 lines
doc/guides/nics/fail_safe.rst new file +10 -0
+Usage example
+~~~~~~~~~~~~~
+
+This section shows some example of using **testpmd** with a fail-safe PMD.
+
+#. Request huge pages:
+
+   .. code-block:: console
+
+      echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

I think this is extra for usage sample, if you want there is generic guide [1] that you ca reference.

[1]
http://dpdk.org/doc/guides/nics/build_and_test.html

doc/guides/nics/fail_safe.rst line 119

Quoted 9 lines
doc/guides/nics/fail_safe.rst new file +9 -0
+
+#. Start testpmd. The slave device should be blacklisted from normal EAL
+   operations to avoid probing it twice when in PCI blacklist mode.
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 \
+         -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
+         -b 84:00.0 -b 00:04.0 -- -i

Do you think does it make sense to stress sub-device shouldn't be probed by EAL, I believe it is not clear above.

Quoted 13 lines
doc/guides/nics/fail_safe.rst new file +13 -0
+
+   Note that PCI blacklist mode is the default PCI operating mode. In this
+   configuration, the fail-safe cannot proceed with its slaves if they have
+   been probed beforehand.
+
+#. Alternatively, it can be used alongside any other device in whitelist mode.
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 \
+         -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
+         -w 81:00.0 -- -i
+

<...>

doc/guides/nics/features/failsafe.ini line 16

Quoted 9 lines

+[Features]

doc/guides/nics/features/failsafe.ini new file +6 -0
+Link status          = Y
 
+MTU update           = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
 
+VLAN filter          = Y
+Packet type parsing  = Y

I am not sure how to document some of these features, because they depends on sub-device capability. I guess if sub-device doesn't support packet type parsing, this feature won't be supported?

Review

Quoted 7 lines
(quoted diff) +6 -0
+Basic stats          = Y
 
+Stats per queue      = Y
+Unicast MAC filter   = Y
+Queue start/stop     = Y
+Jumbo frame          = Y
+Multicast MAC filter = Y

Is above ones supported by PMD, I don't see them unless I miss something.

+ "Flow Control" seems supported.

<...>

drivers/net/failsafe/Makefile line 54

Quoted 5 lines
drivers/net/failsafe/Makefile new file +5 -0
+# This lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_kvargs
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += lib/librte_mbuf

DEPDIRS-y no more used, can be removed.

drivers/net/failsafe/Makefile line 57

Quoted 3 lines
drivers/net/failsafe/Makefile new file +3 -0
+
+# Basic CFLAGS:
+CFLAGS += -std=gnu99 -Wall -Wextra

-Wall should be coming from $(WERROR_FLAGS), no need to add here.

And are you sure about gnu99, mlx drivers tends to enforce a standard and they updated to c11, do you want to do same here.

drivers/net/failsafe/Makefile line 61

Quoted 4 lines
drivers/net/failsafe/Makefile new file +4 -0
+CFLAGS += -O3
+CFLAGS += -I.
+CFLAGS += -D_DEFAULT_SOURCE
+CFLAGS += -D_XOPEN_SOURCE=700

Is there a reason for these variables, or are these copy-paste?

drivers/net/failsafe/Makefile line 64

Quoted 3 lines
drivers/net/failsafe/Makefile new file +3 -0
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -Wno-strict-prototypes
+CFLAGS += -pedantic -DPEDANTIC

Again, just question, is pedantic mode intentional, or copy-paste?

<...>

Quoted 8 lines
drivers/net/failsafe/failsafe.c new file +8 -0
+static int
+fs_eth_dev_create(struct rte_vdev_device *vdev)
+{
+	struct rte_eth_dev *dev;
+	struct ether_addr *mac;
+	struct fs_priv *priv;
+	struct sub_device *sdev;
+	const char *params;

drivers/net/failsafe/failsafe.c line 101

Quoted 10 lines
drivers/net/failsafe/failsafe.c new file +10 -0
+	unsigned int socket_id;
+	uint8_t i;
+	int ret;
+
+	dev = NULL;
+	priv = NULL;
+	params = rte_vdev_device_args(vdev);
+	socket_id = rte_socket_id();
+	INFO("Creating fail-safe device on NUMA socket %u",
+	     socket_id);

No line break required.

drivers/net/failsafe/failsafe.c line 108

Quoted 7 lines
drivers/net/failsafe/failsafe.c new file +7 -0
+	dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
+	if (dev == NULL) {
+		ERROR("Unable to allocate rte_eth_dev");
+		return -1;
+	}
+	priv = dev->data->dev_private;
+	PRIV(dev)->dev = dev;

Altough this is valid, what about?

priv = PRIV(dev);
priv->dev = dev;

drivers/net/failsafe/failsafe.c line 110

Quoted 2 lines
drivers/net/failsafe/failsafe.c new file +2 -0
+	dev->dev_ops = &failsafe_ops;
+	TAILQ_INIT(&dev->link_intr_cbs);

Not required, rte_eth_dev_allocate() initializes this.

drivers/net/failsafe/failsafe.c line 111

Quoted 1 line
drivers/net/failsafe/failsafe.c new file +1 -0
+	dev->data->dev_flags = 0x0;

Not required to set zero, dev->data already memset to zero.

drivers/net/failsafe/failsafe.c line 117

Quoted 6 lines
drivers/net/failsafe/failsafe.c new file +6 -0
+	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
+	dev->data->dev_link = eth_link;
+	PRIV(dev)->nb_mac_addr = 1;
+	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
+	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
+	if (params == NULL) {

I would prefer input control as first thing in the function, before allocating the device.

drivers/net/failsafe/failsafe.c line 121

Quoted 4 lines
drivers/net/failsafe/failsafe.c new file +4 -0
+		ERROR("This PMD requires sub-devices, none provided");
+		goto free_dev;
+	}
+	ret = fs_sub_device_create(dev, params);

This function looks like just allocates memory for sub devices, does it make sense to rename it as fs_sub_device_alloc()?

Quoted 4 lines
drivers/net/failsafe/failsafe.c new file +4 -0
+	if (ret) {
+		ERROR("Could not allocate sub_devices");
+		goto free_dev;
+	}

<...>

drivers/net/failsafe/failsafe.c line 177

Quoted 6 lines
drivers/net/failsafe/failsafe.c new file +6 -0
+free_args:
+	failsafe_args_free(dev);
+free_subs:
+	fs_sub_device_free(dev);
+free_dev:
+	rte_eth_dev_release_port(dev);

Device private data should be freed.

Quoted 2 lines
(quoted diff) +2 -0
+	return -1;
+}

<...>

drivers/net/failsafe/failsafe.c line 207

Quoted 8 lines
drivers/net/failsafe/failsafe.c new file +8 -0
+static int
+rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
+{
+	const char *name;
+
+	name = rte_vdev_device_name(vdev);
+	if (vdev == NULL)
+		return -EINVAL;

I think you don't need this check, if name is NULL, probe shouldn't be called, same for remove().

drivers/net/failsafe/failsafe.c line 209

Quoted 2 lines
drivers/net/failsafe/failsafe.c new file +2 -0
+	INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
+			name);

Line break not required.

<...>

drivers/net/failsafe/failsafe.c line 231

Quoted 2 lines
drivers/net/failsafe/failsafe.c new file +2 -0
+RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
+RTE_PMD_REGISTER_ALIAS(net_failsafe, eth_failsafe);

I belive alias is not required for new PMDs, this is for backward compability for old drivers.

<...>

drivers/net/failsafe/failsafe_args.c line 243

Quoted 5 lines
drivers/net/failsafe/failsafe_args.c new file +5 -0
+int
+failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
+{
+	struct fs_priv *priv;
+	char mut_params[DEVARGS_MAXLEN] = "";

Out of curiosity, what does "mut" stands for?

drivers/net/failsafe/failsafe_args.c line 250

Quoted 7 lines
drivers/net/failsafe/failsafe_args.c new file +7 -0
+	struct rte_kvargs *kvlist = NULL;
+	unsigned int arg_count;
+	size_t n;
+	int ret;
+
+	if (dev == NULL || params == NULL)
+		return -EINVAL;

This check looks like redundant.

drivers/net/failsafe/failsafe_args.c line 255

Quoted 5 lines
drivers/net/failsafe/failsafe_args.c new file +5 -0
+	priv = PRIV(dev);
+	ret = 0;
+	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
+	/* default parameters */
+	mac_from_arg = 0;

This is global value, I believe it is better to set default value where variable defined with a comment. Here is easy to miss the default value.

drivers/net/failsafe/failsafe_args.c line 263

Quoted 8 lines
drivers/net/failsafe/failsafe_args.c new file +8 -0
+	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
+	if (n >= sizeof(mut_params)) {
+		ERROR("Parameter string too long (>=%zu)",
+				sizeof(mut_params));
+		return -ENOMEM;
+	}
+	ret = fs_parse_sub_devices(fs_parse_device_param,
+				   dev, params);

Why the device argument is not defined as dev=xxx, instead of current dev(xxx).

"dev=xxx" will be compatible with rest of the argument usage, and it will be possible to use kvargs to parse it, which will make this code simpler I believe.

What is the reason of using different syntax?

Quoted 15 lines
drivers/net/failsafe/failsafe_args.c new file +15 -0
+	if (ret < 0)
+		return ret;
+	ret = fs_remove_sub_devices_definition(mut_params);
+	if (ret < 0)
+		return ret;
+	if (strnlen(mut_params, sizeof(mut_params)) > 0) {
+		kvlist = rte_kvargs_parse(mut_params,
+				pmd_failsafe_init_parameters);
+		if (kvlist == NULL) {
+			ERROR("Error parsing parameters, usage:\n"
+				PMD_FAILSAFE_PARAM_STRING);
+			return -1;
+		}
+		/* MAC addr */
+		arg_count = rte_kvargs_count(kvlist,

drivers/net/failsafe/failsafe_args.c line 288

Quoted 10 lines
drivers/net/failsafe/failsafe_args.c new file +10 -0
+				PMD_FAILSAFE_MAC_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_MAC_KVARG,
+					&fs_get_mac_addr_arg,
+					&dev->data->mac_addrs[0]);
+			if (ret < 0)
+				goto free_kvlist;
+			mac_from_arg = 1;
+		}

Is ignoring the case mac defined more than once intentional?

Quoted 6 lines
drivers/net/failsafe/failsafe_args.c new file +6 -0
+	}
+free_kvlist:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+

<...>

drivers/net/failsafe/failsafe_args.c line 317

Quoted 11 lines
drivers/net/failsafe/failsafe_args.c new file +11 -0
+static int
+fs_count_device(struct rte_eth_dev *dev, const char *param,
+		uint8_t head __rte_unused)
+{
+	size_t b = 0;
+
+	while  (param[b] != '(' &&
+		param[b] != '\0')
+		b++;
+	if (strncmp(param, "dev", b) &&
+	    strncmp(param, "exec", b)) {

I believe param "exec" will be introduced in further patches?

Quoted 7 lines
drivers/net/failsafe/failsafe_args.c new file +7 -0
+		ERROR("Unrecognized device type: %.*s", (int)b, param);
+		return -EINVAL;
+	}
+	PRIV(dev)->subs_tail += 1;
+	return 0;
+}
+

<...>

drivers/net/failsafe/failsafe_eal.c line 46

Quoted 9 lines
drivers/net/failsafe/failsafe_eal.c new file +9 -0
+static int
+fs_bus_init(struct rte_eth_dev *dev)
+{
+	struct sub_device *sdev;
+	struct rte_devargs *da;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {

Can FOREACH_SUBDEV_ST(..., DEV_PARSED) be used here?

And what do you think renaming "FOREACH_SUBDEV_ST" to "FOREACH_SUBDEV_STATE"?

Quoted 6 lines
drivers/net/failsafe/failsafe_eal.c new file +6 -0
+		if (sdev->state != DEV_PARSED)
+			continue;
+		da = &sdev->devargs;
+		ret = rte_eal_hotplug_add(da->bus->name,
+					  da->name,
+					  da->args);

<...>

drivers/net/failsafe/failsafe_eal.c

Quoted 6 lines
drivers/net/failsafe/failsafe_eal.c new file +6 -0
+	/*
+	 * We only update TX_SUBDEV if we are not started.
+	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
+	 * preferred port only upon starting it, so that the switch is smoother.
+	 */
+	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) 

Can you please document concept of the "prefered sub device" in documentation?

Quoted 6 lines
drivers/net/failsafe/failsafe_eal.c new file +6 -0
+		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
+		    (TX_SUBDEV(dev) == NULL ||
+		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
+			DEBUG("Switching tx_dev to preferred sub_device");
+			PRIV(dev)->subs_tx = 0;
+		}

<...>

drivers/net/failsafe/failsafe_ops.c line 43

Quoted 2 lines
drivers/net/failsafe/failsafe_ops.c new file +2 -0
+static struct rte_eth_dev_info default_infos = {
+	.driver_name = pmd_failsafe_driver_name,

This should be dev->device->driver->name, but already overwriiten by rte_eth_dev_info_get() so you can drop this.

Quoted 1 line
drivers/net/failsafe/failsafe_ops.c new file +1 -0
+	/* Max possible number of elements */

<...>

drivers/net/failsafe/failsafe_ops.c line 190

Quoted 4 lines
drivers/net/failsafe/failsafe_ops.c new file +4 -0
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Closing sub_device %d", i);
+		rte_eth_dev_close(PORT_ID(sdev));
+		sdev->state = DEV_ACTIVE - 1;

Should it be better to set state to DEV_PROBED? Instead of calculation.

Quoted 4 lines
drivers/net/failsafe/failsafe_ops.c new file +4 -0
+	}
+	fs_dev_free_queues(dev);
+}
+

<...>

drivers/net/failsafe/failsafe_ops.c line 413

Quoted 5 lines
drivers/net/failsafe/failsafe_ops.c new file +5 -0
+static void
+fs_stats_get(struct rte_eth_dev *dev,
+	     struct rte_eth_stats *stats)
+{
+	memset(stats, 0, sizeof(*stats));

memset not required, done by API

Quoted 5 lines
drivers/net/failsafe/failsafe_ops.c new file +5 -0
+	if (TX_SUBDEV(dev) == NULL)
+		return;
+	rte_eth_stats_get(PORT_ID(TX_SUBDEV(dev)), stats);
+}
+

<...>

drivers/net/failsafe/failsafe_ops.c line 481

Quoted 3 lines
drivers/net/failsafe/failsafe_ops.c new file +3 -0
+		sdev = TX_SUBDEV(dev);
+		rte_eth_dev_info_get(PORT_ID(sdev), &PRIV(dev)->infos);
+		PRIV(dev)->infos.rx_offload_capa = rx_offload_capa;

Is intention &= ?

Quoted 7 lines
drivers/net/failsafe/failsafe_ops.c new file +7 -0
+		PRIV(dev)->infos.tx_offload_capa &=
+					default_infos.tx_offload_capa;
+		PRIV(dev)->infos.flow_type_rss_offloads &=
+					default_infos.flow_type_rss_offloads;
+	}
+	rte_memcpy(infos, &PRIV(dev)->infos, sizeof(*infos));
+}

<...>

drivers/net/failsafe/failsafe_ops.c line 525

Quoted 6 lines
drivers/net/failsafe/failsafe_ops.c new file +6 -0
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_set_mtu on sub_device %d", i);
+		ret = rte_eth_dev_set_mtu(PORT_ID(sdev), mtu);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_set_mtu failed for sub_device %d"
+			      " with error %d", i, ret);

You can prefer to not break the log message.

Quoted 5 lines
drivers/net/failsafe/failsafe.c new file +5 -0
+			return ret;
+		}
+	}
+	return 0;
+}

<...>

drivers/net/failsafe/failsafe_private.h line 49

Quoted 2 lines
drivers/net/failsafe/failsafe_private.h new file +2 -0
+
+#define FAILSAFE_PLUGIN_DEFAULT_TIMEOUT_MS 2000

Is this related to next patches in the set?

<...>

drivers/net/failsafe/failsafe_private.h line 73

Quoted 2 lines
drivers/net/failsafe/failsafe_private.h new file +2 -0
+enum dev_state {
+	DEV_UNDEFINED = 0,

Setting value not required.

Quoted 5 lines
drivers/net/failsafe/failsafe_private.h new file +5 -0
+	DEV_PARSED,
+	DEV_PROBED,
+	DEV_ACTIVE,
+	DEV_STARTED,
+};

<...>

#156 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

Quoted 13 lines · Ferruh Yigit
Quoted 12 lines · Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Quoted 8 lines
Quoted 2 lines

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

All PMD in a single patch is hard to review, I am sure some details missed during the review, but taking account the histroy of the PMD I accept this as it is, but I will rely on your support to fix issues in the future.

Sure, sorry for having this one first big patch.
I thought about having a skeleton patch first, but found it made little sense. I tried to restrict this version to the bare functionalities, adding the others afterward.

I will fix any issues. From what I've seen I agree with almost all of your remarks and will send a new version shortly. In the meantime, I will answer in this email a few clarifying questions.

<...>

Quoted 7 lines

doc/guides/nics/features/failsafe.ini line 16

Quoted 2 lines
doc/guides/nics/features/failsafe.ini new file +2 -0
+VLAN filter          = Y
+Packet type parsing  = Y

I am not sure how to document some of these features, because they depends on sub-device capability. I guess if sub-device doesn't support packet type parsing, this feature won't be supported?

Yes, supporting a feature for the fail-safe means that there is some verification and synchronization code related to this feature. All sub_device should have feature parity, and the features of the fail-safe are limited to those of the sub_devices.

I thought advertizing the support made sense as there was some code related to it in the fail-safe.

Quoted 8 lines

drivers/net/failsafe/failsafe_args.c line 243

Quoted 5 lines
drivers/net/failsafe/failsafe_args.c new file +5 -0
+int
+failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
+{
+	struct fs_priv *priv;
+	char mut_params[DEVARGS_MAXLEN] = "";

Out of curiosity, what does "mut" stands for?

This is the mutable version of params.

<...>

Quoted 12 lines

drivers/net/failsafe/failsafe_args.c line 263

Quoted 8 lines
drivers/net/failsafe/failsafe_args.c new file +8 -0
+	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
+	if (n >= sizeof(mut_params)) {
+		ERROR("Parameter string too long (>=%zu)",
+				sizeof(mut_params));
+		return -ENOMEM;
+	}
+	ret = fs_parse_sub_devices(fs_parse_device_param,
+				   dev, params);

Why the device argument is not defined as dev=xxx, instead of current dev(xxx).

Quoted 6 lines

"dev=xxx" will be compatible with rest of the argument usage, and it will be possible to use kvargs to parse it, which will make this code simpler I believe.

What is the reason of using different syntax?

Using the dev() syntax allows the user to explicitly set the limits of the sub_device declaration, clarifying for which device each kvargs is.

The issue is that the kvargs library does not allow to set state informations in the parser depending on the position in the kvlist. An alternative would have been for example to restrict the kvargs to that of the last declared dev=, however, this means multi-stage kvargs parsing, which mean pre-processing of the parameter list, etc...

An example:

net_failsafe0,dev=net_tap0,iface=tap0,mac=00:01:02:03:04:05 net_failsafe0,dev(net_tap0,iface=tap0),mac=00:01:02:03:04:05

This is much simpler to parse this way, and much clearer I think for users.

The kvargs library was not designed with recursive PMDs in mind.

<...>

Quoted 12 lines

drivers/net/failsafe/failsafe_eal.c line 46

Quoted 9 lines
drivers/net/failsafe/failsafe_eal.c new file +9 -0
+static int
+fs_bus_init(struct rte_eth_dev *dev)
+{
+	struct sub_device *sdev;
+	struct rte_devargs *da;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {

Can FOREACH_SUBDEV_ST(..., DEV_PARSED) be used here?

I could use it, this would restrict the iteration only to sub_devices being at least of the state DEV_PARSED. However, in the check just below:

+ if (sdev->state != DEV_PARSED)
+ continue;

I would have to pass on any device being in a state higher than DEV_PARSED. Thus, using FOREACH_SUBDEV_ST would not simplify the code flow. By using FOREACH_SUBDEV() directly, the reader at least has a simpler parsing to do of my intent:

foreach subdev not "parsed".

Quoted 3 lines

And what do you think renaming "FOREACH_SUBDEV_ST" to "FOREACH_SUBDEV_STATE"?

Sure, I pushed for brievity but it might be easier to read.

<...>

Quoted 7 lines

drivers/net/failsafe/failsafe_ops.c line 190

Quoted 4 lines
drivers/net/failsafe/failsafe_ops.c new file +4 -0
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Closing sub_device %d", i);
+		rte_eth_dev_close(PORT_ID(sdev));
+		sdev->state = DEV_ACTIVE - 1;

Should it be better to set state to DEV_PROBED? Instead of calculation.

I wanted to be able to add / remove device states without having to rewrite each of those state changes (there are a few in several places). If I insert a new device state between ACTIVE and PROBED, setting to DEV_PROBED would still be valid (no compile error), but it would be a bug. It would be very easy to miss a reference to this specific state.

Those states bugs are a little hard to find at runtime, they usually have subtle side-effects.

I can change it if you prefer, but I would probably introduce a helper in the form of fs_dev_state_prev/next, thus having a single place to check for any changes.

Signature · 2 lines
Gaëtan Rivet
6WIND
#157 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

In reply to Ferruh Yigit

On Mon, Jul 17, 2017 at 02:56:54PM +0100, Ferruh Yigit wrote:

<...>

Quoted 8 lines

doc/guides/nics/features/failsafe.ini line 14

Quoted 5 lines
doc/guides/nics/features/failsafe.ini new file +5 -0
+Stats per queue      = Y
+Unicast MAC filter   = Y
+Queue start/stop     = Y
+Jumbo frame          = Y
+Multicast MAC filter = Y

Is above ones supported by PMD, I don't see them unless I miss something.

Queue start/stop was an error.
All others are supported as long as the slave support it.

<...>

Quoted 6 lines

drivers/net/failsafe/failsafe_ops.c line 481

Quoted 3 lines
drivers/net/failsafe/failsafe_ops.c new file +3 -0
+		sdev = TX_SUBDEV(dev);
+		rte_eth_dev_info_get(PORT_ID(sdev), &PRIV(dev)->infos);
+		PRIV(dev)->infos.rx_offload_capa = rx_offload_capa;

Is intention &= ?

rx_offload_capa is already set a little higher, and then an AND is done on it with all slaves. The "=" is correct here. Thanks for asking though, it's always useful to check :).

---

I fixed all other remarks. I will wait a little for any possible additional changes you might want to point before sending the new version.

Signature · 2 lines
Gaëtan Rivet
6WIND
#158 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

On 7/18/2017 12:17 AM, Gaëtan Rivet wrote:
<...>

Quoted 4 lines

I fixed all other remarks. I will wait a little for any possible additional changes you might want to point before sending the new version.

OK, there were some patches from Thomas addition to failsafe patchset, are they all clarified, merged or rejected for this patchset?

#159 lore raw

Re: [PATCH v10 03/11] net/failsafe: add fail-safe PMD

Quoted 10 lines · Ferruh Yigit

On 7/18/2017 12:17 AM, Gaëtan Rivet wrote:
<...>

Quoted 4 lines

I fixed all other remarks. I will wait a little for any possible additional changes you might want to point before sending the new version.

OK, there were some patches from Thomas addition to failsafe patchset, are they all clarified, merged or rejected for this patchset?

The patch he sent last week is postponed. It does not work as it is, and the fix requires additional API / dev. We will look into it next release.

Signature · 2 lines
Gaëtan Rivet
6WIND
#160 lore raw

PATCH v10 4/11 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  19 +++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  71 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  33 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  60 ++++++++-
 8 files changed, 424 insertions(+), 43 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +19 -0
index 5c8a93b..5ec3031 100644
@@ -98,6 +98,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **hotplug_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two slave upkeep round.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -140,3 +145,17 @@ Care must be taken, however, to respect the **ether** API concerning device
 access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
+
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
drivers/net/failsafe/Makefile +1 -0
index 2b5e5f8..f963ffb 100644
@@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +71 -0

83 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +33 -0
index 79e5bfa..2e60442 100644
@@ -32,6 +32,7 @@
  */
 
 #include <string.h>
+#include <errno.h>
 
 #include <rte_devargs.h>
 #include <rte_malloc.h>
@@ -45,9 +46,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t hotplug_poll;
 int mac_from_arg;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -221,6 +224,24 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+fs_get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 fs_get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -252,6 +273,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
+	hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
 	mac_from_arg = 0;
 	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
 	if (n >= sizeof(mut_params)) {
@@ -274,6 +296,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_PLUG_IN_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_PLUG_IN_POLL_KVARG,
+					&fs_get_u64_arg, &hotplug_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -287,6 +319,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index f4bd777..1bab3fc 100644
@@ -72,37 +72,14 @@ fs_bus_init(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = fs_bus_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -134,5 +111,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = fs_bus_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 91e2193..3112bc8 100644
@@ -90,6 +90,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -109,21 +111,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -133,6 +123,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -184,6 +175,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_hotplug_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +58 -2

92 lines not on this page · raw message

Signature · 1 line
2.1.4
#161 lore raw

PATCH v10 5/11 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 95 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 126 insertions(+)
doc/guides/nics/fail_safe.rst +20 -0
index 5ec3031..be73d7e 100644
@@ -87,6 +87,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -135,6 +148,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +95 -0

122 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index 7910952..2a1535e 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index de77739..8b99d61 100644
@@ -44,6 +44,7 @@
 #define PMD_FAILSAFE_PLUG_IN_POLL_KVARG "hotplug_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"hotplug_poll=u64"		\
 	""
@@ -87,6 +88,8 @@ struct sub_device {
 	struct rte_eth_dev *edev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -135,6 +138,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#162 lore raw

Re: [PATCH v10 05/11] net/failsafe: add flexible device definition

Quoted 42 lines · Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 95 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 126 insertions(+)
doc/guides/nics/fail_safe.rst +13 -0
index 5ec3031..be73d7e 100644
@@ -87,6 +87,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe

doc/guides/nics/fail_safe.rst This section shows some example of using **testpmd** with a fail-safe PMD. · line 156

Quoted 9 lines
doc/guides/nics/fail_safe.rst +6 -0
@@ -135,6 +148,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i

Hi Gaetan,

What is the usecase for this feature.

How this is different from --vdev='net_failsafe0,dev(echo 84:00.0)' ?

#163 lore raw

Re: [PATCH v10 05/11] net/failsafe: add flexible device definition

Hi Ferruh,

(Thanks for the review by the way, I will answer the other more lengthy emails in due time)

Quoted 55 lines · Ferruh Yigit
Quoted 42 lines · Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 95 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 126 insertions(+)
doc/guides/nics/fail_safe.rst +13 -0
index 5ec3031..be73d7e 100644
@@ -87,6 +87,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe

doc/guides/nics/fail_safe.rst This section shows some example of using **testpmd** with a fail-safe PMD. · line 156

Quoted 9 lines
doc/guides/nics/fail_safe.rst +6 -0
@@ -135,6 +148,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i

Hi Gaetan,

Quoted 3 lines

What is the usecase for this feature.

How this is different from --vdev='net_failsafe0,dev(echo 84:00.0)' ?

This version would be interpreted once, at the launch of the fail-safe PMD.

The exec option will execute the command again each time the fail-safe tries to probe the sub_device. This means that in a live VM migration context, the sub_device can change PCI address (for example), and still be matched by the command using other identifying info (MAC address, class_id, ...).

It must be reinterpreted upon plugin of the sub_device, as the output would change from the time the fail-safe was started.

Signature · 2 lines
Gaëtan Rivet
6WIND
#164 lore raw

Re: [PATCH v10 05/11] net/failsafe: add flexible device definition

Quoted 68 lines · Gaëtan Rivet

Hi Ferruh,

(Thanks for the review by the way, I will answer the other more lengthy emails in due time)

Quoted 55 lines · Ferruh Yigit
Quoted 42 lines · Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 95 +++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 126 insertions(+)
doc/guides/nics/fail_safe.rst +13 -0
index 5ec3031..be73d7e 100644
@@ -87,6 +87,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe

doc/guides/nics/fail_safe.rst This section shows some example of using **testpmd** with a fail-safe PMD. · line 156

Quoted 9 lines
doc/guides/nics/fail_safe.rst +6 -0
@@ -135,6 +148,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          -w 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i

Hi Gaetan,

Quoted 3 lines

What is the usecase for this feature.

How this is different from --vdev='net_failsafe0,dev(echo 84:00.0)' ?

This version would be interpreted once, at the launch of the fail-safe PMD.

Quoted 8 lines

The exec option will execute the command again each time the fail-safe tries to probe the sub_device. This means that in a live VM migration context, the sub_device can change PCI address (for example), and still be matched by the command using other identifying info (MAC address, class_id, ...).

It must be reinterpreted upon plugin of the sub_device, as the output would change from the time the fail-safe was started.

Make sense, thanks for clarification.

#165 lore raw

PATCH v10 6/11 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   1 +
 drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 215 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 +++++
 drivers/net/failsafe/failsafe_private.h |  18 +++
 8 files changed, 336 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index 3c52823..9167b59 100644
@@ -13,6 +13,7 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index f963ffb..dc07264 100644
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 73be3d7..5d35079 100644
@@ -178,6 +178,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	if (params == NULL) {
drivers/net/failsafe/failsafe_eal.c +1 -0
index 1bab3fc..31257b0 100644
@@ -62,6 +62,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			ERROR("sub_device %d init went wrong", i);
 			return -ENODEV;
 		}
+		SUB_ID(sdev) = i;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
drivers/net/failsafe/failsafe_ether.c +70 -0

90 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +215 -0

215 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index 3112bc8..0c8aa35 100644
@@ -36,6 +36,7 @@
 #include <rte_debug.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -629,6 +630,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -656,4 +684,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +18 -0
index 8b99d61..af1e380 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
@@ -72,6 +74,14 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED = 0,
 	DEV_PARSED,
@@ -86,6 +96,7 @@ struct sub_device {
 	struct rte_bus *bus;
 	struct rte_device *dev;
 	struct rte_eth_dev *edev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -104,6 +115,8 @@ struct fs_priv {
 	uint8_t subs_tail; /* first invalid */
 	uint8_t subs_tx; /* current emitting device */
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t hotplug_poll;
 extern int mac_from_arg;
 
@@ -170,6 +184,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	((sdev)->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#166 lore raw

Re: [PATCH v10 06/11] net/failsafe: support flow API

Quoted 2 lines · Gaetan Rivet

<...>

drivers/net/failsafe/failsafe_flow.c line 113

Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+
+	flow = fs_flow_allocate(attr, patterns, actions);
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
+				attr, patterns, actions, error);

Should SUB_ID(sdev) used here? And in related functions. flow->flows[SUB_ID(sdev)] = ...

Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+		if (flow->flows[i] == NULL) {
+			ERROR("Failed to create flow on sub_device %d",
+				i);
+			goto err;
+		}

<...>

#167 lore raw

Re: [PATCH v10 06/11] net/failsafe: support flow API

Quoted 6 lines · Ferruh Yigit
Quoted 2 lines · Gaetan Rivet

<...>

Quoted 9 lines

drivers/net/failsafe/failsafe_flow.c line 113

Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+
+	flow = fs_flow_allocate(attr, patterns, actions);
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
+				attr, patterns, actions, error);

Should SUB_ID(sdev) used here? And in related functions. flow->flows[SUB_ID(sdev)] = ...

The SUB_ID(sdev) is the index in the sub_device array allocated in private data for the fail-safe. It is also used for the sub_rte_flow in the rte_flow (which sports an array of rte_flow pointers for each sub_device).

PORT_ID(sdev) is the index in the rte_eth_devices array, meaning that the rte_flow_create function is actually called using the public API on the port.

This allows to trigger the additional operations usually done within the ether API (storing the configuration in the eth_dev_data structure, some side management), and following eventual changes automatically from the fail-safe level.

Quoted 7 lines
Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+		if (flow->flows[i] == NULL) {
+			ERROR("Failed to create flow on sub_device %d",
+				i);
+			goto err;
+		}

<...>

Signature · 2 lines
Gaëtan Rivet
6WIND
#168 lore raw

Re: [PATCH v10 06/11] net/failsafe: support flow API

Quoted 17 lines · Gaëtan Rivet
Quoted 6 lines · Ferruh Yigit
Quoted 2 lines · Gaetan Rivet

<...>

Quoted 9 lines

drivers/net/failsafe/failsafe_flow.c line 113

Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+
+	flow = fs_flow_allocate(attr, patterns, actions);
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
+				attr, patterns, actions, error);

Should SUB_ID(sdev) used here? And in related functions. flow->flows[SUB_ID(sdev)] = ...

Quoted 4 lines

The SUB_ID(sdev) is the index in the sub_device array allocated in private data for the fail-safe. It is also used for the sub_rte_flow in the rte_flow (which sports an array of rte_flow pointers for each sub_device).

I got this part, let me ask another way, is it always guarantied, even after some hotplug, "i" in FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) will be same with SUB_ID(sdev) ?

Quoted 18 lines

PORT_ID(sdev) is the index in the rte_eth_devices array, meaning that the rte_flow_create function is actually called using the public API on the port.

This allows to trigger the additional operations usually done within the ether API (storing the configuration in the eth_dev_data structure, some side management), and following eventual changes automatically from the fail-safe level.

Quoted 7 lines
Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+		if (flow->flows[i] == NULL) {
+			ERROR("Failed to create flow on sub_device %d",
+				i);
+			goto err;
+		}

<...>

#169 lore raw

Re: [PATCH v10 06/11] net/failsafe: support flow API

Quoted 18 lines · Ferruh Yigit
Quoted 17 lines · Gaëtan Rivet
Quoted 15 lines · Ferruh Yigit
Quoted 2 lines · Gaetan Rivet

<...>

drivers/net/failsafe/failsafe_flow.c line 113

Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+
+	flow = fs_flow_allocate(attr, patterns, actions);
+	FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {
+		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
+				attr, patterns, actions, error);

Should SUB_ID(sdev) used here? And in related functions. flow->flows[SUB_ID(sdev)] = ...

Quoted 9 lines
Quoted 4 lines

The SUB_ID(sdev) is the index in the sub_device array allocated in private data for the fail-safe. It is also used for the sub_rte_flow in the rte_flow (which sports an array of rte_flow pointers for each sub_device).

I got this part, let me ask another way, is it always guarantied, even after some hotplug, "i" in FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) will be same with SUB_ID(sdev) ?

Ah, yes. Sub_device slots are static, allocated once at launch and reserved for only one device corresponding to its declaration.

Thus, the PORT_ID() can change, but the SUB_ID() is always the same.

Quoted 19 lines
Quoted 18 lines

PORT_ID(sdev) is the index in the rte_eth_devices array, meaning that the rte_flow_create function is actually called using the public API on the port.

This allows to trigger the additional operations usually done within the ether API (storing the configuration in the eth_dev_data structure, some side management), and following eventual changes automatically from the fail-safe level.

Quoted 7 lines
Quoted 5 lines
drivers/net/failsafe/failsafe_flow.c new file +5 -0
+		if (flow->flows[i] == NULL) {
+			ERROR("Failed to create flow on sub_device %d",
+				i);
+			goto err;
+		}

<...>

Signature · 2 lines
Gaëtan Rivet
6WIND
#170 lore raw

PATCH v10 7/11 net/failsafe: support offload capabilities

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +6 -0
index 9167b59..257f579 100644
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +129 -2

151 lines not on this page · raw message

Signature · 1 line
2.1.4
#171 lore raw

Re: [PATCH v10 07/11] net/failsafe: support offload capabilities

Quoted 12 lines · Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +0 -0
index 9167b59..257f579 100644

doc/guides/nics/features/failsafe.ini Unicast MAC filter = Y · line 22

Quoted 9 lines
doc/guides/nics/features/failsafe.ini +6 -0
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y

As previous comment on features, these are advertised as supported but depends on sub-devices.

Overall I don't know what does these mean for failsafe like abstract device.

Quoted 14 lines
doc/guides/nics/features/failsafe.ini +0 -0
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +1 -2
index 0c8aa35..654b411 100644
@@ -64,22 +64,149 @@ static struct rte_eth_dev_info default_infos = {
 		.nb_seg_max = UINT16_MAX,
 		.nb_mtu_seg_max = UINT16_MAX,
 	},
-	/* Set of understood capabilities */
-	.rx_offload_capa = 0x0,
+	/*

drivers/net/failsafe/failsafe_ops.c static struct rte_eth_dev_info default_infos = { · line 77

Quoted 10 lines
drivers/net/failsafe/failsafe_ops.c +10 -0
+	 * Set of capabilities that can be verified upon
+	 * configuring a sub-device.
+	 */
+	.rx_offload_capa =
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_QINQ_STRIP |
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_LRO,

These are not dynamic, even though some may be disabled via fs_port_disable_offload() same these values will be returned to the application, which is wrong.

drivers/net/failsafe/failsafe_ops.c static struct rte_eth_dev_info default_infos = { · line 78

Quoted 1 line
drivers/net/failsafe/failsafe_ops.c +0 -0
 	.tx_offload_capa = 0x0,

Claiming support for most of the offloads means supporting it both for Rx and Tx path. This patch only takes account the Rx ones.

Quoted 3 lines
drivers/net/failsafe/failsafe_ops.c +0 -0
 	.flow_type_rss_offloads = 0x0,
 };
 

<...>

#172 lore raw

Re: [PATCH v10 07/11] net/failsafe: support offload capabilities

Quoted 26 lines · Ferruh Yigit
Quoted 12 lines · Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini |   6 ++
 drivers/net/failsafe/failsafe_ops.c   | 131 +++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 2 deletions(-)
doc/guides/nics/features/failsafe.ini +0 -0
index 9167b59..257f579 100644

doc/guides/nics/features/failsafe.ini Unicast MAC filter = Y · line 22

Quoted 9 lines
doc/guides/nics/features/failsafe.ini +6 -0
@@ -14,6 +14,12 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow API             = Y
+VLAN offload         = Y
+QinQ offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Inner L3 checksum    = Y
+Inner L4 checksum    = Y

As previous comment on features, these are advertised as supported but depends on sub-devices.

Quoted 2 lines

Overall I don't know what does these mean for failsafe like abstract device.

We should look into this.

The rationale for features in fail-safe was that

- If the slave supported the feature, and using it with the fail-safe did not impair the feature, then the fail-safe was transparent as far as this feature was concerned --> support = Y.

Meaning that users would be able to use this feature with the fail-safe.

- If any slave did not support the feature, it would be dynamically disabled when it made sense, or ENOTSUPP is returned if an ops is missing (checked automatically by calling the ether API).

In the end, the feature matrix is used by the user to check whether the feature is available using this PMD. Disabling all features in the matrix for the fail-safe does not help the user at all, as they should then check manually / look at the code.

On the other hand, the possible issue is that some users might expect that the fail-safe could emulate in software missing features. The usefullness of having the matrix to compare against other PMDs features outweight this possibility as I find this assumption far-fetched, but I can always remove the feature support for the moment and we will see afterward how to deal with it.

Quoted 20 lines
Quoted 20 lines
doc/guides/nics/features/failsafe.ini +0 -0
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/failsafe_ops.c +7 -2
index 0c8aa35..654b411 100644
@@ -64,22 +64,149 @@ static struct rte_eth_dev_info default_infos = {
 		.nb_seg_max = UINT16_MAX,
 		.nb_mtu_seg_max = UINT16_MAX,
 	},
-	/* Set of understood capabilities */
-	.rx_offload_capa = 0x0,
+	/*
+	 * Set of capabilities that can be verified upon
+	 * configuring a sub-device.
+	 */
+	.rx_offload_capa =
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_QINQ_STRIP |
Quoted 9 lines

drivers/net/failsafe/failsafe_ops.c static struct rte_eth_dev_info default_infos = { · line 77

Quoted 4 lines
drivers/net/failsafe/failsafe_ops.c +4 -0
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_LRO,

These are not dynamic, even though some may be disabled via fs_port_disable_offload() same these values will be returned to the application, which is wrong.

These are the default rx_offload_capa. This flag value is AND-ed with that of the slaves before being returned. A slave is assured to be present at all time, so it will be restricted to the common set between the fail-safe and the slave features.

Quoted 5 lines

drivers/net/failsafe/failsafe_ops.c static struct rte_eth_dev_info default_infos = { · line 78

Quoted 1 line
drivers/net/failsafe/failsafe_ops.c +0 -0
 	.tx_offload_capa = 0x0,

Claiming support for most of the offloads means supporting it both for Rx and Tx path. This patch only takes account the Rx ones.

Ah I did not know. I will remove the feature support for offloads, the same work that was done with Rx will be done with Tx.

Quoted 6 lines
Quoted 3 lines
drivers/net/failsafe/failsafe_ops.c +0 -0
 	.flow_type_rss_offloads = 0x0,
 };
 

<...>

Signature · 2 lines
Gaëtan Rivet
6WIND
#173 lore raw

PATCH v10 8/11 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 123 ++++++++++++++++++++++++++------
 2 files changed, 111 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index af1e380..2ebe03f 100644
@@ -141,11 +141,18 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev, int force_safe);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -282,6 +289,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev, 0);
 	rte_wmb();
 }
 
drivers/net/failsafe/failsafe_rxtx.c +103 -20

153 lines not on this page · raw message

Signature · 1 line
2.1.4
#174 lore raw

PATCH v10 9/11 net/failsafe: support device removal

In reply to Gaetan Rivet

Listen to INTR_RMV events issued by slaves.
Add atomic flags on slave queues to detect use of slave bursts function. If a removal is detected, set the recollection flag on this slave.

During a slave upkeep round, if its recollection flag is set and its burst functions are not in use by any thread, remove that slave.

---
 doc/guides/nics/fail_safe.rst           | 14 +++++
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_args.c    | 13 +++++
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   | 96 ++++++++++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_ops.c     | 37 +++++++++++--
 drivers/net/failsafe/failsafe_private.h | 72 ++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_rxtx.c    | 17 +++++-
 8 files changed, 233 insertions(+), 20 deletions(-)
doc/guides/nics/fail_safe.rst +14 -0
index be73d7e..12d3ed8 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation option
@@ -179,3 +185,11 @@ emit and receive packets. It will store any applied configuration, and try to
 apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
+
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
drivers/net/failsafe/failsafe.c +1 -0
index 5d35079..611bd83 100644
@@ -142,6 +142,7 @@ fs_hotplug_alarm(void *arg)
 		if (ret)
 			ERROR("Unable to synchronize sub_device state");
 	}
+	failsafe_dev_remove(dev);
 	ret = failsafe_hotplug_alarm_install(dev);
 	if (ret)
 		ERROR("Unable to set up next alarm");
drivers/net/failsafe/failsafe_args.c +13 -0
index f939687..0d5be79 100644
@@ -440,6 +440,17 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				    dev, params);
 }
 
+static int
+fs_parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char devstr[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
+	return fs_parse_device(sdev, devstr);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -452,6 +463,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = fs_execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = fs_parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -1
index 31257b0..d0954d9 100644
@@ -63,6 +63,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			return -ENODEV;
 		}
 		SUB_ID(sdev) = i;
+		sdev->fs_dev = dev;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
@@ -80,7 +81,7 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 		return ret;
 	if (PRIV(dev)->state < DEV_PROBED)
 		PRIV(dev)->state = DEV_PROBED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
drivers/net/failsafe/failsafe_ether.c +90 -6

130 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +34 -3
index 654b411..06459ed 100644
@@ -34,6 +34,7 @@
 #include <stdint.h>
 
 #include <rte_debug.h>
+#include <rte_atomic.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
 #include <rte_flow.h>
@@ -205,9 +206,21 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
+		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
 					dev->data->nb_tx_queues,
@@ -216,6 +229,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
@@ -241,7 +264,7 @@ fs_dev_start(struct rte_eth_dev *dev)
 	}
 	if (PRIV(dev)->state < DEV_STARTED)
 		PRIV(dev)->state = DEV_STARTED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
@@ -352,10 +375,14 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,
 		fs_rx_queue_release(rxq);
 		dev->data->rx_queues[rx_queue_id] = NULL;
 	}
-	rxq = rte_zmalloc(NULL, sizeof(*rxq),
+	rxq = rte_zmalloc(NULL,
+			  sizeof(*rxq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (rxq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&rxq->refcnt[i]);
 	rxq->qid = rx_queue_id;
 	rxq->socket_id = socket_id;
 	rxq->info.mp = mb_pool;
@@ -415,10 +442,14 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,
 		fs_tx_queue_release(txq);
 		dev->data->tx_queues[tx_queue_id] = NULL;
 	}
-	txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+	txq = rte_zmalloc("ethdev TX queue",
+			  sizeof(*txq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (txq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&txq->refcnt[i]);
 	txq->qid = tx_queue_id;
 	txq->socket_id = socket_id;
 	txq->info.conf = *tx_conf;
drivers/net/failsafe/failsafe_private.h +64 -8

133 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c +15 -2
index 5e380fe..7311421 100644
@@ -31,6 +31,7 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <rte_atomic.h>
 #include <rte_debug.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
@@ -112,8 +113,10 @@ failsafe_rx_burst(void *queue,
 		if (unlikely(fs_rx_unsafe(sdev)))
 			continue;
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -146,8 +149,10 @@ failsafe_rx_burst_fast(void *queue,
 		sdev = &priv->subs[i];
 		RTE_ASSERT(!fs_rx_unsafe(sdev));
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -164,13 +169,17 @@ failsafe_tx_burst(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	if (unlikely(fs_tx_unsafe(sdev)))
 		return 0;
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
 
 uint16_t
@@ -181,10 +190,14 @@ failsafe_tx_burst_fast(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	RTE_ASSERT(!fs_tx_unsafe(sdev));
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
Signature · 1 line
2.1.4
#175 lore raw

PATCH v10 10/11 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 23 +++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 46 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 257f579..251ce55 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
drivers/net/failsafe/failsafe.c +1 -0
index 611bd83..93b78a8 100644
@@ -241,6 +241,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index ea3105c..a694b4d 100644
@@ -387,3 +387,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 	sdev->remove = 1;
 	return 0;
 }
+
+int
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event __rte_unused,
+				void *cb_arg, void *out __rte_unused)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		return _rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL, NULL);
+	else
+		return 0;
+}
drivers/net/failsafe/failsafe_ops.c +23 -0
index 06459ed..6c4d8e3 100644
@@ -207,6 +207,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -219,6 +221,17 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
@@ -239,6 +252,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+						RTE_ETH_EVENT_INTR_LSC,
+						failsafe_eth_lsc_event_callback,
+						dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 62881f6..a9cddbc 100644
@@ -179,6 +179,9 @@ void failsafe_dev_remove(struct rte_eth_dev *dev);
 int failsafe_eth_rmv_event_callback(uint8_t port_id,
 				    enum rte_eth_event_type type,
 				    void *arg, void *out);
+int failsafe_eth_lsc_event_callback(uint8_t port_id,
+				    enum rte_eth_event_type event,
+				    void *cb_arg, void *out);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#176 lore raw

PATCH v10 11/11 net/failsafe: support flow API isolation mode

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ether.c   | 34 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_flow.c    | 29 ++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  4 ++++
 3 files changed, 65 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ether.c +32 -2
index a694b4d..c8b9c8a 100644
@@ -74,6 +74,28 @@ fs_flow_complain(struct rte_flow_error *error)
 }
 
 static int
+eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_flow_error ferror;
+	int ret;
+
+	if (!PRIV(dev)->flow_isolated) {
+		DEBUG("Flow isolation already disabled");
+	} else {
+		DEBUG("Enabling flow isolation");
+		ret = rte_flow_isolate(PORT_ID(sdev),
+				       PRIV(dev)->flow_isolated,
+				       &ferror);
+		if (ret) {
+			fs_flow_complain(&ferror);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int
 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 		struct sub_device *sdev)
 {
@@ -334,9 +356,17 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	if (PRIV(dev)->state < DEV_ACTIVE)
 		return 0;
 	inactive = 0;
-	FOREACH_SUBDEV(sdev, i, dev)
-		if (sdev->state == DEV_PROBED)
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state == DEV_PROBED) {
 			inactive |= UINT32_C(1) << i;
+			ret = eth_dev_flow_isolate_set(dev, sdev);
+			if (ret) {
+				ERROR("Could not apply configuration to sub_device %d",
+				      i);
+				goto err_remove;
+			}
+		}
+	}
 	ret = dev->dev_ops->dev_configure(dev);
 	if (ret)
 		goto err_remove;
drivers/net/failsafe/failsafe_flow.c +29 -0
index 8547e51..5217adf 100644
@@ -206,10 +206,39 @@ fs_flow_query(struct rte_eth_dev *dev,
 	return -1;
 }
 
+static int
+fs_flow_isolate(struct rte_eth_dev *dev,
+		int set,
+		struct rte_flow_error *error)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state < DEV_PROBED)
+			continue;
+		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
+		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
+			WARN("flow isolation mode of sub_device %d in incoherent state.",
+				i);
+		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
+		if (ret) {
+			ERROR("Operation rte_flow_isolate failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+		sdev->flow_isolated = set;
+	}
+	PRIV(dev)->flow_isolated = set;
+	return 0;
+}
+
 const struct rte_flow_ops fs_flow_ops = {
 	.validate = fs_flow_validate,
 	.create = fs_flow_create,
 	.destroy = fs_flow_destroy,
 	.flush = fs_flow_flush,
 	.query = fs_flow_query,
+	.isolate = fs_flow_isolate,
 };
drivers/net/failsafe/failsafe_private.h +4 -0
index a9cddbc..1bff123 100644
@@ -108,6 +108,8 @@ struct sub_device {
 	struct rte_eth_dev *fs_dev;
 	/* flag calling for recollection */
 	volatile unsigned int remove:1;
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 struct fs_priv {
@@ -139,6 +141,8 @@ struct fs_priv {
 	 */
 	enum dev_state state;
 	unsigned int pending_alarm:1; /* An alarm is pending */
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 /* MISC */
Signature · 1 line
2.1.4
#177 lore raw

v11 cover introduce fail-safe PMD

In reply to Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

[dpdk-dev] [PATCH v4 0/8] fix hotplug API
http://dpdk.org/ml/archives/dev/2017-July/071340.html

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

v10 --> v11

- Added Glossary in documentation.
- Fixed issues oulined in [1].
- Removed Rx offload advertizement in feature matrix.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071406.html

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support Rx offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

 MAINTAINERS                                       |   5 +
 config/common_base                                |   5 +
 doc/guides/nics/fail_safe.rst                     | 221 ++++++
 doc/guides/nics/features/failsafe.ini             |  26 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  60 ++
 drivers/net/failsafe/failsafe.c                   | 299 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 468 ++++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 118 +++
 drivers/net/failsafe/failsafe_ether.c             | 437 +++++++++++
 drivers/net/failsafe/failsafe_flow.c              | 244 ++++++
 drivers/net/failsafe/failsafe_ops.c               | 867 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 359 +++++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 203 +++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 lib/librte_ether/rte_ethdev.c                     |  19 +-
 lib/librte_ether/rte_ethdev.h                     |  14 +-
 mk/rte.app.mk                                     |   1 +
 19 files changed, 3338 insertions(+), 15 deletions(-)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
Signature · 1 line
2.1.4
#178 lore raw

PATCH v11 1/11 ethdev: add deferred intermediate device state

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

---
 lib/librte_ether/rte_ethdev.c | 3 ++-
 lib/librte_ether/rte_ethdev.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
index a1b7447..81b398d 100644
@@ -291,7 +291,8 @@ int
 rte_eth_dev_is_valid_port(uint8_t port_id)
 {
 	if (port_id >= RTE_MAX_ETHPORTS ||
-	    rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)
+	    (rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED &&
+	     rte_eth_devices[port_id].state != RTE_ETH_DEV_DEFERRED))
 		return 0;
 	else
 		return 1;
lib/librte_ether/rte_ethdev.h +1 -0
index 224f485..7b69ddf 100644
@@ -1611,6 +1611,7 @@ struct rte_eth_rxtx_callback {
 enum rte_eth_dev_state {
 	RTE_ETH_DEV_UNUSED = 0,
 	RTE_ETH_DEV_ATTACHED,
+	RTE_ETH_DEV_DEFERRED,
 };
 
 /**
Signature · 1 line
2.1.4
Acked-by on v11 1/11
#179 lore raw

Re: [PATCH v11 01/11] ethdev: add deferred intermediate device state

18/07/2017 15:48, Gaetan Rivet:

Quoted 10 lines

This device state means that the device is managed externally, by whichever party has set this state (PMD or application).

Note: this new device state is only an information. The related device structure and operators are still valid and can be used normally.

It is however made private by device management helpers within ethdev, making the device invisible to applications.

Ferruh, it can be taken in next-net as part of failsafe series. Thanks

#180 lore raw

PATCH v11 2/11 ethdev: count devices consistently

In reply to Gaetan Rivet

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

---
 lib/librte_ether/rte_ethdev.c | 16 +++++++++-------
 lib/librte_ether/rte_ethdev.h | 13 ++++++-------
 2 files changed, 15 insertions(+), 14 deletions(-)
lib/librte_ether/rte_ethdev.c +9 -7
index 81b398d..d4ebb1b 100644
@@ -72,7 +72,6 @@ static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
 struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
 static struct rte_eth_dev_data *rte_eth_dev_data;
 static uint8_t eth_dev_last_created_port;
-static uint8_t nb_ports;
 
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
@@ -210,7 +209,6 @@ eth_dev_get(uint8_t port_id)
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
 
 	eth_dev_last_created_port = port_id;
-	nb_ports++;
 
 	return eth_dev;
 }
@@ -283,7 +281,6 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 		return -EINVAL;
 
 	eth_dev->state = RTE_ETH_DEV_UNUSED;
-	nb_ports--;
 	return 0;
 }
 
@@ -308,7 +305,15 @@ rte_eth_dev_socket_id(uint8_t port_id)
 uint8_t
 rte_eth_dev_count(void)
 {
-	return nb_ports;
+	uint8_t p;
+	uint8_t count;
+
+	count = 0;
+
+	RTE_ETH_FOREACH_DEV(p)
+		count++;
+
+	return count;
 }
 
 int
@@ -341,9 +346,6 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
 		return -EINVAL;
 	}
 
-	if (!nb_ports)
-		return -ENODEV;
-
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!rte_eth_devices[i].device)
 			continue;
lib/librte_ether/rte_ethdev.h +6 -7
index 7b69ddf..45aae74 100644
@@ -1746,13 +1746,12 @@ uint8_t rte_eth_find_next(uint8_t port_id);
 
 /**
  * Get the total number of Ethernet devices that have been successfully
- * initialized by the [matching] Ethernet driver during the PCI probing phase.
- * All devices whose port identifier is in the range
- * [0,  rte_eth_dev_count() - 1] can be operated on by network applications
- * immediately after invoking rte_eal_init().
- * If the application unplugs a port using hotplug function, The enabled port
- * numbers may be noncontiguous. In the case, the applications need to manage
- * enabled port by using the ``RTE_ETH_FOREACH_DEV()`` macro.
+ * initialized by the matching Ethernet driver during the PCI probing phase
+ * and that are available for applications to use. These devices must be
+ * accessed by using the ``RTE_ETH_FOREACH_DEV()`` macro to deal with
+ * non-contiguous ranges of devices.
+ * These non-contiguous ranges can be created by calls to hotplug functions or
+ * by some PMDs.
  *
  * @return
  *   - The total number of usable Ethernet devices.
Signature · 1 line
2.1.4
Acked-by on v11 2/11
#181 lore raw

Re: [PATCH v11 02/11] ethdev: count devices consistently

18/07/2017 15:48, Gaetan Rivet:

Quoted 4 lines

Make the rte_eth_dev_count() return the number of available devices even after some are detached by the hotplug API or put in a deferred state.

Ferruh, it can be taken in next-net as part of failsafe series. Thanks

#182 lore raw

PATCH v11 3/11 net/failsafe: add fail-safe PMD

In reply to Gaetan Rivet

Introduce the fail-safe poll mode driver initialization and enable its build infrastructure.

This PMD allows for applications to benefit from true hot-plugging support without having to implement it.

It intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back. It also allows defining a contingency to the removal of a device, by designating a fail-over device that will take on transmitting operations if the preferred device is removed.

Applications only see a fail-safe instance, without caring for underlying activity ensuring their continued operations.

---
 MAINTAINERS                                       |   5 +
 config/common_base                                |   5 +
 doc/guides/nics/fail_safe.rst                     | 163 ++++++
 doc/guides/nics/features/failsafe.ini             |  24 +
 doc/guides/nics/index.rst                         |   1 +
 drivers/net/Makefile                              |   2 +
 drivers/net/failsafe/Makefile                     |  58 ++
 drivers/net/failsafe/failsafe.c                   | 225 ++++++++
 drivers/net/failsafe/failsafe_args.c              | 327 +++++++++++
 drivers/net/failsafe/failsafe_eal.c               | 138 +++++
 drivers/net/failsafe/failsafe_ops.c               | 662 ++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h           | 208 +++++++
 drivers/net/failsafe/failsafe_rxtx.c              | 107 ++++
 drivers/net/failsafe/rte_pmd_failsafe_version.map |   4 +
 mk/rte.app.mk                                     |   1 +
 15 files changed, 1930 insertions(+)
 create mode 100644 doc/guides/nics/fail_safe.rst
 create mode 100644 doc/guides/nics/features/failsafe.ini
 create mode 100644 drivers/net/failsafe/Makefile
 create mode 100644 drivers/net/failsafe/failsafe.c
 create mode 100644 drivers/net/failsafe/failsafe_args.c
 create mode 100644 drivers/net/failsafe/failsafe_eal.c
 create mode 100644 drivers/net/failsafe/failsafe_ops.c
 create mode 100644 drivers/net/failsafe/failsafe_private.h
 create mode 100644 drivers/net/failsafe/failsafe_rxtx.c
 create mode 100644 drivers/net/failsafe/rte_pmd_failsafe_version.map
MAINTAINERS +5 -0
index 875bee0..3352c5e 100644
@@ -349,6 +349,11 @@ F: drivers/net/enic/
 F: doc/guides/nics/enic.rst
 F: doc/guides/nics/features/enic.ini
 
+Fail-safe PMD
+M: Gaetan Rivet <[email protected]>
+F: drivers/net/failsafe/
+F: doc/guides/nics/fail_safe.rst
+
 Intel e1000
 M: Wenzhuo Lu <[email protected]>
 F: drivers/net/e1000/
config/common_base +5 -0
index 8ae6e92..7805605 100644
@@ -420,6 +420,11 @@ CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 CONFIG_RTE_LIBRTE_PMD_NULL=y
 
 #
+# Compile fail-safe PMD
+#
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
doc/guides/nics/fail_safe.rst new file +163 -0

163 lines not on this page · raw message

doc/guides/nics/features/failsafe.ini new file +24 -0
new file mode 100644
index 0000000..cf3e1af
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'fail-safe' poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+VLAN filter          = Y
+Flow control         = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv7                = Y
+ARMv8                = Y
+Power8               = Y
+x86-32               = Y
+x86-64               = Y
+Usage doc            = Y
doc/guides/nics/index.rst +1 -0
index 240d082..17eaaf4 100644
@@ -64,6 +64,7 @@ Network Interface Controller Drivers
     vhost
     vmxnet3
     pcap_ring
+    fail_safe
 
 **Figures**
 
drivers/net/Makefile +2 -0
index 35ed813..d33c959 100644
@@ -59,6 +59,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENA_PMD) += ena
 DEPDIRS-ena = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DEPDIRS-enic = $(core-libs) librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
+DEPDIRS-failsafe = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
 DEPDIRS-fm10k = $(core-libs) librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
drivers/net/failsafe/Makefile new file +58 -0

58 lines not on this page · raw message

drivers/net/failsafe/failsafe.c new file +225 -0

225 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c new file +327 -0

327 lines not on this page · raw message

drivers/net/failsafe/failsafe_eal.c new file +138 -0

138 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c new file +662 -0

662 lines not on this page · raw message

drivers/net/failsafe/failsafe_private.h new file +208 -0

208 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c new file +107 -0

107 lines not on this page · raw message

drivers/net/failsafe/rte_pmd_failsafe_version.map new file +4 -0
new file mode 100644
index 0000000..b6d2840
@@ -0,0 +1,4 @@
+DPDK_17.08 {
+
+	local: *;
+};
mk/rte.app.mk +1 -0
index 5bb4290..c25fdd9 100644
@@ -121,6 +121,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_E1000_PMD)      += -lrte_pmd_e1000
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENA_PMD)        += -lrte_pmd_ena
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE)   += -lrte_pmd_failsafe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
Signature · 1 line
2.1.4
#183 lore raw

PATCH v11 4/11 net/failsafe: add plug-in support

In reply to Gaetan Rivet

Periodically check for the existence of a device.
If a device has not been initialized and exists on the system, then it is probed and configured.

The configuration process strives to synchronize the states between the plugged-in sub-device and the fail-safe device.

---
 doc/guides/nics/fail_safe.rst           |  23 ++++
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |  71 ++++++++++
 drivers/net/failsafe/failsafe_args.c    |  32 +++++
 drivers/net/failsafe/failsafe_eal.c     |  30 +----
 drivers/net/failsafe/failsafe_ether.c   | 228 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  25 ++--
 drivers/net/failsafe/failsafe_private.h |  60 ++++++++-
 8 files changed, 428 insertions(+), 42 deletions(-)
 create mode 100644 drivers/net/failsafe/failsafe_ether.c
doc/guides/nics/fail_safe.rst +23 -0
index c20696e..0005892 100644
@@ -98,6 +98,11 @@ Fail-safe command line parameters
   address is generated, that will be subsequently applied to all sub-device once
   they are probed.
 
+- **hotplug_poll** parameter [UINT64] (default **2000**)
+
+  This parameter allows the user to configure the amount of time in milliseconds
+  between two slave upkeep round.
+
 Usage example
 ~~~~~~~~~~~~~
 
@@ -140,6 +145,20 @@ access, and in particular, using the ``RTE_ETH_FOREACH_DEV`` macro to iterate
 over ethernet devices, instead of directly accessing them or by writing one's
 own device iterator.
 
+Plug-in feature
+---------------
+
+A sub-device can be defined without existing on the system when the fail-safe
+PMD is initialized. Upon probing this device, the fail-safe PMD will detect its
+absence and postpone its use. It will then register for a periodic check on any
+missing sub-device.
+
+During this time, the fail-safe PMD can be used normally, configured and told to
+emit and receive packets. It will store any applied configuration, and try to
+apply it upon the probing of its missing sub-device. After this configuration
+pass, the new sub-device will be synchronized with other sub-devices, i.e. be
+started if the fail-safe PMD has been started by the user before.
+
 Fail-safe glossary
 ------------------
 
@@ -153,6 +172,10 @@ Preferred device : Primary device
     It is the main sub-device and is used as target for configuration
     operations if there is any ambiguity.
 
+Upkeep round
+    Periodical process when slaves are serviced. Each devices having a state
+    different to that of the fail-safe device itself, is synchronized with it.
+
 Slave
     In the context of the fail-safe PMD, synonymous to sub-device.
 
drivers/net/failsafe/Makefile +1 -0
index f940c14..3488198 100644
@@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +71 -0

83 lines not on this page · raw message

drivers/net/failsafe/failsafe_args.c +32 -0
index bde8f2d..733344e 100644
@@ -32,6 +32,7 @@
  */
 
 #include <string.h>
+#include <errno.h>
 
 #include <rte_devargs.h>
 #include <rte_malloc.h>
@@ -45,9 +46,11 @@
 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
 		uint8_t head);
 
+uint64_t hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
 int mac_from_arg = 0;
 
 const char *pmd_failsafe_init_parameters[] = {
+	PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
 	PMD_FAILSAFE_MAC_KVARG,
 	NULL,
 };
@@ -221,6 +224,24 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 }
 
 static int
+fs_get_u64_arg(const char *key __rte_unused,
+		const char *value, void *out)
+{
+	uint64_t *u64 = out;
+	char *endptr = NULL;
+
+	if ((value == NULL) || (out == NULL))
+		return -EINVAL;
+	errno = 0;
+	*u64 = strtoull(value, &endptr, 0);
+	if (errno != 0)
+		return -errno;
+	if (endptr == value)
+		return -1;
+	return 0;
+}
+
+static int
 fs_get_mac_addr_arg(const char *key __rte_unused,
 		const char *value, void *out)
 {
@@ -271,6 +292,16 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 				PMD_FAILSAFE_PARAM_STRING);
 			return -1;
 		}
+		/* PLUG_IN event poll timer */
+		arg_count = rte_kvargs_count(kvlist,
+				PMD_FAILSAFE_HOTPLUG_POLL_KVARG);
+		if (arg_count == 1) {
+			ret = rte_kvargs_process(kvlist,
+					PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
+					&fs_get_u64_arg, &hotplug_poll);
+			if (ret < 0)
+				goto free_kvlist;
+		}
 		/* MAC addr */
 		arg_count = rte_kvargs_count(kvlist,
 				PMD_FAILSAFE_MAC_KVARG);
@@ -284,6 +315,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 			mac_from_arg = 1;
 		}
 	}
+	PRIV(dev)->state = DEV_PARSED;
 free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
drivers/net/failsafe/failsafe_eal.c +4 -26
index a74edea..8a3836c 100644
@@ -72,37 +72,14 @@ fs_bus_init(struct rte_eth_dev *dev)
 int
 failsafe_eal_init(struct rte_eth_dev *dev)
 {
-	struct sub_device *sdev;
-	uint8_t i;
 	int ret;
 
 	ret = fs_bus_init(dev);
 	if (ret)
 		return ret;
-	/*
-	 * We only update TX_SUBDEV if we are not started.
-	 * If a sub_device is emitting, we will switch the TX_SUBDEV to the
-	 * preferred port only upon starting it, so that the switch is smoother.
-	 */
-	if (PREFERRED_SUBDEV(dev)->state >= DEV_PROBED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev) &&
-		    (TX_SUBDEV(dev) == NULL ||
-		     (TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED))) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_PROBED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			/* Using first probed device */
-			FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
-				DEBUG("Switching tx_dev to sub_device %d",
-				      i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_PROBED)
+		PRIV(dev)->state = DEV_PROBED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -134,5 +111,6 @@ failsafe_eal_uninit(struct rte_eth_dev *dev)
 	ret = fs_bus_uninit(dev);
 	if (ret)
 		return ret;
+	PRIV(dev)->state = DEV_PROBED - 1;
 	return 0;
 }
drivers/net/failsafe/failsafe_ether.c new file +228 -0

228 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +10 -15
index 2d9e057..fdef019 100644
@@ -89,6 +89,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 		sdev->state = DEV_ACTIVE;
 	}
+	if (PRIV(dev)->state < DEV_ACTIVE)
+		PRIV(dev)->state = DEV_ACTIVE;
 	return 0;
 }
 
@@ -108,21 +110,9 @@ fs_dev_start(struct rte_eth_dev *dev)
 			return ret;
 		sdev->state = DEV_STARTED;
 	}
-	if (PREFERRED_SUBDEV(dev)->state == DEV_STARTED) {
-		if (TX_SUBDEV(dev) != PREFERRED_SUBDEV(dev)) {
-			DEBUG("Switching tx_dev to preferred sub_device");
-			PRIV(dev)->subs_tx = 0;
-		}
-	} else {
-		if ((TX_SUBDEV(dev) && TX_SUBDEV(dev)->state < DEV_STARTED) ||
-		    TX_SUBDEV(dev) == NULL) {
-			FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_STARTED) {
-				DEBUG("Switching tx_dev to sub_device %d", i);
-				PRIV(dev)->subs_tx = i;
-				break;
-			}
-		}
-	}
+	if (PRIV(dev)->state < DEV_STARTED)
+		PRIV(dev)->state = DEV_STARTED;
+	fs_switch_dev(dev);
 	return 0;
 }
 
@@ -132,6 +122,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	PRIV(dev)->state = DEV_STARTED - 1;
 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_STARTED) {
 		rte_eth_dev_stop(PORT_ID(sdev));
 		sdev->state = DEV_STARTED - 1;
@@ -183,6 +174,10 @@ fs_dev_close(struct rte_eth_dev *dev)
 	struct sub_device *sdev;
 	uint8_t i;
 
+	failsafe_hotplug_alarm_cancel(dev);
+	if (PRIV(dev)->state == DEV_STARTED)
+		dev->dev_ops->dev_stop(dev);
+	PRIV(dev)->state = DEV_ACTIVE - 1;
 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
 		DEBUG("Closing sub_device %d", i);
 		rte_eth_dev_close(PORT_ID(sdev));
drivers/net/failsafe/failsafe_private.h +59 -1

92 lines not on this page · raw message

Signature · 1 line
2.1.4
#184 lore raw

PATCH v11 5/11 net/failsafe: add flexible device definition

In reply to Gaetan Rivet

Add the "exec" device type.
The parameters given to this type of device will be executed in a shell. The output of this command is then used as a definition for a device.

That command can be re-interpreted if the related device is not plugged-in. It allows for a device definition to react to system changes (e.g. changing PCI bus for a given device).

---
 doc/guides/nics/fail_safe.rst           | 20 +++++++
 drivers/net/failsafe/failsafe_args.c    | 98 ++++++++++++++++++++++++++++++++-
 drivers/net/failsafe/failsafe_ether.c   |  7 +++
 drivers/net/failsafe/failsafe_private.h |  4 ++
 4 files changed, 128 insertions(+), 1 deletion(-)
doc/guides/nics/fail_safe.rst +20 -0
index 0005892..c81f06a 100644
@@ -87,6 +87,19 @@ Fail-safe command line parameters
   additional sub-device parameters if need be. They will be passed on to the
   sub-device.
 
+- **exec(<shell command>)** parameter
+
+  This parameter allows the user to provide a command to the fail-safe PMD to
+  execute and define a sub-device.
+  It is done within a regular shell context.
+  The first line of its output is read by the fail-safe PMD and otherwise
+  interpreted as if passed by the regular **dev** parameter.
+  Any other line is discarded.
+  If the command fail or output an incorrect string, the sub-device is not
+  initialized.
+  All commas within the ``shell command`` are replaced by spaces before
+  executing the command. This helps using scripts to specify devices.
+
 - **mac** parameter [MAC address]
 
   This parameter allows the user to set a default MAC address to the fail-safe
@@ -134,6 +147,13 @@ This section shows some example of using **testpmd** with a fail-safe PMD.
          --vdev 'net_failsafe0,mac=de:ad:be:ef:01:02,dev(84:00.0),dev(net_ring0)'
          -w 81:00.0 -- -i
 
+#. Start testpmd using a flexible device definition
+
+   .. code-block:: console
+
+      $RTE_TARGET/build/app/testpmd -c 0xff -n 4 --no-pci \
+         --vdev='net_failsafe0,exec(echo 84:00.0)' -- -i
+
 Using the Fail-safe PMD from an application
 -------------------------------------------
 
drivers/net/failsafe/failsafe_args.c +97 -1

131 lines not on this page · raw message

drivers/net/failsafe/failsafe_ether.c +7 -0
index 7910952..2a1535e 100644
@@ -188,6 +188,13 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	int ret;
 	uint8_t i;
 
+	if (PRIV(dev)->state < DEV_PARSED)
+		return 0;
+
+	ret = failsafe_args_parse_subs(dev);
+	if (ret)
+		return ret;
+
 	if (PRIV(dev)->state < DEV_PROBED)
 		return 0;
 	ret = failsafe_eal_init(dev);
drivers/net/failsafe/failsafe_private.h +4 -0
index a46d1ea..2342646 100644
@@ -44,6 +44,7 @@
 #define PMD_FAILSAFE_HOTPLUG_POLL_KVARG "hotplug_poll"
 #define PMD_FAILSAFE_PARAM_STRING	\
 	"dev(<ifc>),"			\
+	"exec(<shell command>),"	\
 	"mac=mac_addr,"			\
 	"hotplug_poll=u64"		\
 	""
@@ -87,6 +88,8 @@ struct sub_device {
 	struct rte_eth_dev *edev;
 	/* Device state machine */
 	enum dev_state state;
+	/* Some device are defined as a command line */
+	char *cmdline;
 };
 
 struct fs_priv {
@@ -135,6 +138,7 @@ uint16_t failsafe_tx_burst(void *txq,
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
 void failsafe_args_free(struct rte_eth_dev *dev);
 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params);
+int failsafe_args_parse_subs(struct rte_eth_dev *dev);
 
 /* EAL */
 
Signature · 1 line
2.1.4
#185 lore raw

PATCH v11 6/11 net/failsafe: support flow API

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |   1 +
 drivers/net/failsafe/Makefile           |   1 +
 drivers/net/failsafe/failsafe.c         |   1 +
 drivers/net/failsafe/failsafe_eal.c     |   1 +
 drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++
 drivers/net/failsafe/failsafe_flow.c    | 215 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  29 +++++
 drivers/net/failsafe/failsafe_private.h |  18 +++
 8 files changed, 336 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_flow.c
doc/guides/nics/features/failsafe.ini +1 -0
index cf3e1af..2e802aa 100644
@@ -13,6 +13,7 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 VLAN filter          = Y
 Flow control         = Y
+Flow API             = Y
 Packet type parsing  = Y
 Basic stats          = Y
 Stats per queue      = Y
drivers/net/failsafe/Makefile +1 -0
index 3488198..cec33df 100644
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 
 # No exported include files
 
drivers/net/failsafe/failsafe.c +1 -0
index 8db6355..12d79ac 100644
@@ -179,6 +179,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 	dev->data->dev_link = eth_link;
 	PRIV(dev)->nb_mac_addr = 1;
+	TAILQ_INIT(&PRIV(dev)->flow_list);
 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 	ret = fs_sub_device_alloc(dev, params);
drivers/net/failsafe/failsafe_eal.c +1 -0
index 8a3836c..d11ea67 100644
@@ -62,6 +62,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			ERROR("sub_device %d init went wrong", i);
 			return -ENODEV;
 		}
+		SUB_ID(sdev) = i;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
drivers/net/failsafe/failsafe_ether.c +70 -0

90 lines not on this page · raw message

drivers/net/failsafe/failsafe_flow.c new file +215 -0

215 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +29 -0
index fdef019..223f26a 100644
@@ -36,6 +36,7 @@
 #include <rte_debug.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_flow.h>
 
 #include "failsafe_private.h"
 
@@ -627,6 +628,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 		rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
 }
 
+static int
+fs_filter_ctrl(struct rte_eth_dev *dev,
+		enum rte_filter_type type,
+		enum rte_filter_op op,
+		void *arg)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	if (type == RTE_ETH_FILTER_GENERIC &&
+	    op == RTE_ETH_FILTER_GET) {
+		*(const void **)arg = &fs_flow_ops;
+		return 0;
+	}
+	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
+		DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
+		ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
+		if (ret) {
+			ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 const struct eth_dev_ops failsafe_ops = {
 	.dev_configure = fs_dev_configure,
 	.dev_start = fs_dev_start,
@@ -654,4 +682,5 @@ const struct eth_dev_ops failsafe_ops = {
 	.mac_addr_remove = fs_mac_addr_remove,
 	.mac_addr_add = fs_mac_addr_add,
 	.mac_addr_set = fs_mac_addr_set,
+	.filter_ctrl = fs_filter_ctrl,
 };
drivers/net/failsafe/failsafe_private.h +18 -0
index 2342646..82d969d 100644
@@ -34,6 +34,8 @@
 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_
 #define _RTE_ETH_FAILSAFE_PRIVATE_H_
 
+#include <sys/queue.h>
+
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
@@ -72,6 +74,14 @@ struct txq {
 	struct rte_eth_txq_info info;
 };
 
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	/* sub_flows */
+	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
+	/* flow description for synchronization */
+	struct rte_flow_desc *fd;
+};
+
 enum dev_state {
 	DEV_UNDEFINED,
 	DEV_PARSED,
@@ -86,6 +96,7 @@ struct sub_device {
 	struct rte_bus *bus;
 	struct rte_device *dev;
 	struct rte_eth_dev *edev;
+	uint8_t sid;
 	/* Device state machine */
 	enum dev_state state;
 	/* Some device are defined as a command line */
@@ -104,6 +115,8 @@ struct fs_priv {
 	uint8_t subs_tail; /* first invalid */
 	uint8_t subs_tx; /* current emitting device */
 	uint8_t current_probed;
+	/* flow mapping */
+	TAILQ_HEAD(sub_flows, rte_flow) flow_list;
 	/* current number of mac_addr slots allocated. */
 	uint32_t nb_mac_addr;
 	struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];
@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);
 
 extern const char pmd_failsafe_driver_name[];
 extern const struct eth_dev_ops failsafe_ops;
+extern const struct rte_flow_ops fs_flow_ops;
 extern uint64_t hotplug_poll;
 extern int mac_from_arg;
 
@@ -170,6 +184,10 @@ extern int mac_from_arg;
 #define PORT_ID(sdev) \
 	(ETH(sdev)->data->port_id)
 
+/* sdev: (struct sub_device *) */
+#define SUB_ID(sdev) \
+	((sdev)->sid)
+
 /**
  * Stateful iterator construct over fail-safe sub-devices:
  * s:     (struct sub_device *), iterator
Signature · 1 line
2.1.4
#186 lore raw

PATCH v11 7/11 net/failsafe: support Rx offload capabilities

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ops.c | 131 +++++++++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ops.c +129 -2
index 223f26a..ac3257e 100644
@@ -63,22 +63,149 @@ static struct rte_eth_dev_info default_infos = {
 		.nb_seg_max = UINT16_MAX,
 		.nb_mtu_seg_max = UINT16_MAX,
 	},
-	/* Set of understood capabilities */
-	.rx_offload_capa = 0x0,
+	/*
+	 * Set of capabilities that can be verified upon
+	 * configuring a sub-device.
+	 */
+	.rx_offload_capa =
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_QINQ_STRIP |
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_LRO,
 	.tx_offload_capa = 0x0,
 	.flow_type_rss_offloads = 0x0,
 };
 
+/**
+ * Check whether a specific offloading capability
+ * is supported by a sub_device.
+ *
+ * @return
+ *   0: all requested capabilities are supported by the sub_device
+ *   positive value: This flag at least is not supported by the sub_device
+ */
+static int
+fs_port_offload_validate(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_eth_dev_info infos = {0};
+	struct rte_eth_conf *cf;
+	uint32_t cap;
+
+	cf = &dev->data->dev_conf;
+	SUBOPS(sdev, dev_infos_get)(ETH(sdev), &infos);
+	/* RX capabilities */
+	cap = infos.rx_offload_capa;
+	if (cf->rxmode.hw_vlan_strip &&
+	    ((cap & DEV_RX_OFFLOAD_VLAN_STRIP) == 0)) {
+		WARN("VLAN stripping offload requested but not supported by sub_device %d",
+		      SUB_ID(sdev));
+		return DEV_RX_OFFLOAD_VLAN_STRIP;
+	}
+	if (cf->rxmode.hw_ip_checksum &&
+	    ((cap & (DEV_RX_OFFLOAD_IPV4_CKSUM |
+		     DEV_RX_OFFLOAD_UDP_CKSUM |
+		     DEV_RX_OFFLOAD_TCP_CKSUM)) !=
+	     (DEV_RX_OFFLOAD_IPV4_CKSUM |
+	      DEV_RX_OFFLOAD_UDP_CKSUM |
+	      DEV_RX_OFFLOAD_TCP_CKSUM))) {
+		WARN("IP checksum offload requested but not supported by sub_device %d",
+		      SUB_ID(sdev));
+		return DEV_RX_OFFLOAD_IPV4_CKSUM |
+		       DEV_RX_OFFLOAD_UDP_CKSUM |
+		       DEV_RX_OFFLOAD_TCP_CKSUM;
+	}
+	if (cf->rxmode.enable_lro &&
+	    ((cap & DEV_RX_OFFLOAD_TCP_LRO) == 0)) {
+		WARN("TCP LRO offload requested but not supported by sub_device %d",
+		      SUB_ID(sdev));
+		return DEV_RX_OFFLOAD_TCP_LRO;
+	}
+	if (cf->rxmode.hw_vlan_extend &&
+	    ((cap & DEV_RX_OFFLOAD_QINQ_STRIP) == 0)) {
+		WARN("Stacked VLAN stripping offload requested but not supported by sub_device %d",
+		      SUB_ID(sdev));
+		return DEV_RX_OFFLOAD_QINQ_STRIP;
+	}
+	/* TX capabilities */
+	/* Nothing to do, no tx capa supported */
+	return 0;
+}
+
+/*
+ * Disable the dev_conf flag related to an offload capability flag
+ * within an ethdev configuration.
+ */
+static int
+fs_port_disable_offload(struct rte_eth_conf *cf,
+			uint32_t ol_cap)
+{
+	switch (ol_cap) {
+	case DEV_RX_OFFLOAD_VLAN_STRIP:
+		INFO("Disabling VLAN stripping offload");
+		cf->rxmode.hw_vlan_strip = 0;
+		break;
+	case DEV_RX_OFFLOAD_IPV4_CKSUM:
+	case DEV_RX_OFFLOAD_UDP_CKSUM:
+	case DEV_RX_OFFLOAD_TCP_CKSUM:
+	case (DEV_RX_OFFLOAD_IPV4_CKSUM |
+	      DEV_RX_OFFLOAD_UDP_CKSUM |
+	      DEV_RX_OFFLOAD_TCP_CKSUM):
+		INFO("Disabling IP checksum offload");
+		cf->rxmode.hw_ip_checksum = 0;
+		break;
+	case DEV_RX_OFFLOAD_TCP_LRO:
+		INFO("Disabling TCP LRO offload");
+		cf->rxmode.enable_lro = 0;
+		break;
+	case DEV_RX_OFFLOAD_QINQ_STRIP:
+		INFO("Disabling stacked VLAN stripping offload");
+		cf->rxmode.hw_vlan_extend = 0;
+		break;
+	default:
+		DEBUG("Unable to disable offload capability: %" PRIx32,
+		      ol_cap);
+		return -1;
+	}
+	return 0;
+}
+
 static int
 fs_dev_configure(struct rte_eth_dev *dev)
 {
 	struct sub_device *sdev;
 	uint8_t i;
+	int capa_flag;
 	int ret;
 
 	FOREACH_SUBDEV(sdev, i, dev) {
 		if (sdev->state != DEV_PROBED)
 			continue;
+		DEBUG("Checking capabilities for sub_device %d", i);
+		while ((capa_flag = fs_port_offload_validate(dev, sdev))) {
+			/*
+			 * Refuse to change configuration if multiple devices
+			 * are present and we already have configured at least
+			 * some of them.
+			 */
+			if (PRIV(dev)->state >= DEV_ACTIVE &&
+			    PRIV(dev)->subs_tail > 1) {
+				ERROR("device already configured, cannot fix live configuration");
+				return -1;
+			}
+			ret = fs_port_disable_offload(&dev->data->dev_conf,
+						      capa_flag);
+			if (ret) {
+				ERROR("Unable to disable offload capability");
+				return ret;
+			}
+		}
+	}
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state != DEV_PROBED)
+			continue;
 		DEBUG("Configuring sub-device %d", i);
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
Signature · 1 line
2.1.4
#187 lore raw

PATCH v11 8/11 net/failsafe: add fast burst functions

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_private.h |   8 +++
 drivers/net/failsafe/failsafe_rxtx.c    | 123 ++++++++++++++++++++++++++------
 2 files changed, 111 insertions(+), 20 deletions(-)
drivers/net/failsafe/failsafe_private.h +8 -0
index 82d969d..aac4754 100644
@@ -141,11 +141,18 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
 
 /* RX / TX */
 
+void set_burst_fn(struct rte_eth_dev *dev, int force_safe);
+
 uint16_t failsafe_rx_burst(void *rxq,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t failsafe_tx_burst(void *txq,
 		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 
+uint16_t failsafe_rx_burst_fast(void *rxq,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t failsafe_tx_burst_fast(void *txq,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
 /* ARGS */
 
 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -282,6 +289,7 @@ fs_switch_dev(struct rte_eth_dev *dev)
 	} else {
 		return;
 	}
+	set_burst_fn(dev, 0);
 	rte_wmb();
 }
 
drivers/net/failsafe/failsafe_rxtx.c +103 -20

153 lines not on this page · raw message

Signature · 1 line
2.1.4
#188 lore raw

PATCH v11 9/11 net/failsafe: support device removal

In reply to Gaetan Rivet

Listen to INTR_RMV events issued by slaves.
Add atomic flags on slave queues to detect use of slave bursts function. If a removal is detected, set the recollection flag on this slave.

During a slave upkeep round, if its recollection flag is set and its burst functions are not in use by any thread, remove that slave.

---
 doc/guides/nics/fail_safe.rst           | 15 ++++++
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_args.c    | 13 +++++
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   | 96 ++++++++++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_ops.c     | 37 +++++++++++--
 drivers/net/failsafe/failsafe_private.h | 72 ++++++++++++++++++++++---
 drivers/net/failsafe/failsafe_rxtx.c    | 17 +++++-
 8 files changed, 234 insertions(+), 20 deletions(-)
doc/guides/nics/fail_safe.rst +15 -0
index c81f06a..34ecae2 100644
@@ -51,6 +51,12 @@ The Fail-safe PMD only supports a limited set of features. If you plan to use a
 device underneath the Fail-safe PMD with a specific feature, this feature must
 be supported by the Fail-safe PMD to avoid throwing any error.
 
+A notable exception is the device removal feature. The fail-safe PMD being a
+virtual device, it cannot currently be removed in the sense of a specific bus
+hotplug, like for PCI for example. It will however enable this feature for its
+sub-device automatically, detecting those that are capable and register the
+relevant callback for such event.
+
 Check the feature matrix for the complete set of supported features.
 
 Compilation option
@@ -179,6 +185,14 @@ apply it upon the probing of its missing sub-device. After this configuration
 pass, the new sub-device will be synchronized with other sub-devices, i.e. be
 started if the fail-safe PMD has been started by the user before.
 
+Plug-out feature
+----------------
+
+A sub-device supporting the device removal event can be removed from its bus at
+any time. The fail-safe PMD will register a callback for such event and react
+accordingly. It will try to safely stop, close and uninit the sub-device having
+emitted this event, allowing it to free its eventual resources.
+
 Fail-safe glossary
 ------------------
 
@@ -195,6 +209,7 @@ Preferred device : Primary device
 Upkeep round
     Periodical process when slaves are serviced. Each devices having a state
     different to that of the fail-safe device itself, is synchronized with it.
+    Additionally, each slave having the remove flag set are cleaned-up.
 
 Slave
     In the context of the fail-safe PMD, synonymous to sub-device.
drivers/net/failsafe/failsafe.c +1 -0
index 12d79ac..7628c21 100644
@@ -142,6 +142,7 @@ fs_hotplug_alarm(void *arg)
 		if (ret)
 			ERROR("Unable to synchronize sub_device state");
 	}
+	failsafe_dev_remove(dev);
 	ret = failsafe_hotplug_alarm_install(dev);
 	if (ret)
 		ERROR("Unable to set up next alarm");
drivers/net/failsafe/failsafe_args.c +13 -0
index ec3db55..932e371 100644
@@ -436,6 +436,17 @@ failsafe_args_count_subdevice(struct rte_eth_dev *dev,
 				    dev, params);
 }
 
+static int
+fs_parse_sub_device(struct sub_device *sdev)
+{
+	struct rte_devargs *da;
+	char devstr[DEVARGS_MAXLEN] = "";
+
+	da = &sdev->devargs;
+	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
+	return fs_parse_device(sdev, devstr);
+}
+
 int
 failsafe_args_parse_subs(struct rte_eth_dev *dev)
 {
@@ -448,6 +459,8 @@ failsafe_args_parse_subs(struct rte_eth_dev *dev)
 			continue;
 		if (sdev->cmdline)
 			ret = fs_execute_cmd(sdev, sdev->cmdline);
+		else
+			ret = fs_parse_sub_device(sdev);
 		if (ret == 0)
 			sdev->state = DEV_PARSED;
 	}
drivers/net/failsafe/failsafe_eal.c +2 -1
index d11ea67..c8f4318 100644
@@ -63,6 +63,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			return -ENODEV;
 		}
 		SUB_ID(sdev) = i;
+		sdev->fs_dev = dev;
 		sdev->dev = ETH(sdev)->device;
 		ETH(sdev)->state = RTE_ETH_DEV_DEFERRED;
 		sdev->state = DEV_PROBED;
@@ -80,7 +81,7 @@ failsafe_eal_init(struct rte_eth_dev *dev)
 		return ret;
 	if (PRIV(dev)->state < DEV_PROBED)
 		PRIV(dev)->state = DEV_PROBED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
drivers/net/failsafe/failsafe_ether.c +90 -6

130 lines not on this page · raw message

drivers/net/failsafe/failsafe_ops.c +34 -3
index ac3257e..e8edf15 100644
@@ -34,6 +34,7 @@
 #include <stdint.h>
 
 #include <rte_debug.h>
+#include <rte_atomic.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
 #include <rte_flow.h>
@@ -204,9 +205,21 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		}
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
+		int rmv_interrupt = 0;
+
 		if (sdev->state != DEV_PROBED)
 			continue;
+
+		rmv_interrupt = ETH(sdev)->data->dev_flags &
+				RTE_ETH_DEV_INTR_RMV;
+		if (rmv_interrupt) {
+			DEBUG("Enabling RMV interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.rmv = 1;
+		} else {
+			DEBUG("sub_device %d does not support RMV event", i);
+		}
 		DEBUG("Configuring sub-device %d", i);
+		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
 					dev->data->nb_rx_queues,
 					dev->data->nb_tx_queues,
@@ -215,6 +228,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 			ERROR("Could not configure sub_device %d", i);
 			return ret;
 		}
+		if (rmv_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+					RTE_ETH_EVENT_INTR_RMV,
+					failsafe_eth_rmv_event_callback,
+					sdev);
+			if (ret)
+				WARN("Failed to register RMV callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.rmv = 0;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
@@ -240,7 +263,7 @@ fs_dev_start(struct rte_eth_dev *dev)
 	}
 	if (PRIV(dev)->state < DEV_STARTED)
 		PRIV(dev)->state = DEV_STARTED;
-	fs_switch_dev(dev);
+	fs_switch_dev(dev, NULL);
 	return 0;
 }
 
@@ -351,10 +374,14 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,
 		fs_rx_queue_release(rxq);
 		dev->data->rx_queues[rx_queue_id] = NULL;
 	}
-	rxq = rte_zmalloc(NULL, sizeof(*rxq),
+	rxq = rte_zmalloc(NULL,
+			  sizeof(*rxq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (rxq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&rxq->refcnt[i]);
 	rxq->qid = rx_queue_id;
 	rxq->socket_id = socket_id;
 	rxq->info.mp = mb_pool;
@@ -414,10 +441,14 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,
 		fs_tx_queue_release(txq);
 		dev->data->tx_queues[tx_queue_id] = NULL;
 	}
-	txq = rte_zmalloc("ethdev TX queue", sizeof(*txq),
+	txq = rte_zmalloc("ethdev TX queue",
+			  sizeof(*txq) +
+			  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
 			  RTE_CACHE_LINE_SIZE);
 	if (txq == NULL)
 		return -ENOMEM;
+	FOREACH_SUBDEV(sdev, i, dev)
+		rte_atomic64_init(&txq->refcnt[i]);
 	txq->qid = tx_queue_id;
 	txq->socket_id = socket_id;
 	txq->info.conf = *tx_conf;
drivers/net/failsafe/failsafe_private.h +64 -8

133 lines not on this page · raw message

drivers/net/failsafe/failsafe_rxtx.c +15 -2
index 5e380fe..7311421 100644
@@ -31,6 +31,7 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <rte_atomic.h>
 #include <rte_debug.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
@@ -112,8 +113,10 @@ failsafe_rx_burst(void *queue,
 		if (unlikely(fs_rx_unsafe(sdev)))
 			continue;
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -146,8 +149,10 @@ failsafe_rx_burst_fast(void *queue,
 		sdev = &priv->subs[i];
 		RTE_ASSERT(!fs_rx_unsafe(sdev));
 		sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
+		FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
 		nb_rx = ETH(sdev)->
 			rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
+		FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
 		if (nb_rx) {
 			rxq->last_polled = i;
 			return nb_rx;
@@ -164,13 +169,17 @@ failsafe_tx_burst(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	if (unlikely(fs_tx_unsafe(sdev)))
 		return 0;
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
 
 uint16_t
@@ -181,10 +190,14 @@ failsafe_tx_burst_fast(void *queue,
 	struct sub_device *sdev;
 	struct txq *txq;
 	void *sub_txq;
+	uint16_t nb_tx;
 
 	txq = queue;
 	sdev = TX_SUBDEV(txq->priv->dev);
 	RTE_ASSERT(!fs_tx_unsafe(sdev));
 	sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
-	return ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_P(txq->refcnt[sdev->sid]);
+	nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
+	FS_ATOMIC_V(txq->refcnt[sdev->sid]);
+	return nb_tx;
 }
Signature · 1 line
2.1.4
#189 lore raw

PATCH v11 10/11 net/failsafe: support link status change event

In reply to Gaetan Rivet
---
 doc/guides/nics/features/failsafe.ini   |  1 +
 drivers/net/failsafe/failsafe.c         |  1 +
 drivers/net/failsafe/failsafe_ether.c   | 18 ++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     | 23 +++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  3 +++
 5 files changed, 46 insertions(+)
doc/guides/nics/features/failsafe.ini +1 -0
index 2e802aa..a42e344 100644
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 MTU update           = Y
 Jumbo frame          = Y
 Promiscuous mode     = Y
drivers/net/failsafe/failsafe.c +1 -0
index 7628c21..6006bef 100644
@@ -238,6 +238,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)
 		mac->addr_bytes[0], mac->addr_bytes[1],
 		mac->addr_bytes[2], mac->addr_bytes[3],
 		mac->addr_bytes[4], mac->addr_bytes[5]);
+	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 	return 0;
 free_args:
 	failsafe_args_free(dev);
drivers/net/failsafe/failsafe_ether.c +18 -0
index 359b8c9..d205f61 100644
@@ -387,3 +387,21 @@ failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
 	sdev->remove = 1;
 	return 0;
 }
+
+int
+failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
+				enum rte_eth_event_type event __rte_unused,
+				void *cb_arg, void *out __rte_unused)
+{
+	struct rte_eth_dev *dev = cb_arg;
+	int ret;
+
+	ret = dev->dev_ops->link_update(dev, 0);
+	/* We must pass on the LSC event */
+	if (ret)
+		return _rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL, NULL);
+	else
+		return 0;
+}
drivers/net/failsafe/failsafe_ops.c +23 -0
index e8edf15..ff9ad15 100644
@@ -206,6 +206,8 @@ fs_dev_configure(struct rte_eth_dev *dev)
 	}
 	FOREACH_SUBDEV(sdev, i, dev) {
 		int rmv_interrupt = 0;
+		int lsc_interrupt = 0;
+		int lsc_enabled;
 
 		if (sdev->state != DEV_PROBED)
 			continue;
@@ -218,6 +220,17 @@ fs_dev_configure(struct rte_eth_dev *dev)
 		} else {
 			DEBUG("sub_device %d does not support RMV event", i);
 		}
+		lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
+		lsc_interrupt = lsc_enabled &&
+				(ETH(sdev)->data->dev_flags &
+				 RTE_ETH_DEV_INTR_LSC);
+		if (lsc_interrupt) {
+			DEBUG("Enabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 1;
+		} else if (lsc_enabled && !lsc_interrupt) {
+			DEBUG("Disabling LSC interrupts for sub_device %d", i);
+			dev->data->dev_conf.intr_conf.lsc = 0;
+		}
 		DEBUG("Configuring sub-device %d", i);
 		sdev->remove = 0;
 		ret = rte_eth_dev_configure(PORT_ID(sdev),
@@ -238,6 +251,16 @@ fs_dev_configure(struct rte_eth_dev *dev)
 				     SUB_ID(sdev));
 		}
 		dev->data->dev_conf.intr_conf.rmv = 0;
+		if (lsc_interrupt) {
+			ret = rte_eth_dev_callback_register(PORT_ID(sdev),
+						RTE_ETH_EVENT_INTR_LSC,
+						failsafe_eth_lsc_event_callback,
+						dev);
+			if (ret)
+				WARN("Failed to register LSC callback for sub_device %d",
+				     SUB_ID(sdev));
+		}
+		dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
 		sdev->state = DEV_ACTIVE;
 	}
 	if (PRIV(dev)->state < DEV_ACTIVE)
drivers/net/failsafe/failsafe_private.h +3 -0
index 80bbc61..2c52d2b 100644
@@ -179,6 +179,9 @@ void failsafe_dev_remove(struct rte_eth_dev *dev);
 int failsafe_eth_rmv_event_callback(uint8_t port_id,
 				    enum rte_eth_event_type type,
 				    void *arg, void *out);
+int failsafe_eth_lsc_event_callback(uint8_t port_id,
+				    enum rte_eth_event_type event,
+				    void *cb_arg, void *out);
 
 /* GLOBALS */
 
Signature · 1 line
2.1.4
#190 lore raw

PATCH v11 11/11 net/failsafe: support flow API isolation mode

In reply to Gaetan Rivet
---
 drivers/net/failsafe/failsafe_ether.c   | 34 +++++++++++++++++++++++++++++++--
 drivers/net/failsafe/failsafe_flow.c    | 29 ++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_private.h |  4 ++++
 3 files changed, 65 insertions(+), 2 deletions(-)
drivers/net/failsafe/failsafe_ether.c +32 -2
index d205f61..a3a8cce 100644
@@ -74,6 +74,28 @@ fs_flow_complain(struct rte_flow_error *error)
 }
 
 static int
+eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
+			 struct sub_device *sdev)
+{
+	struct rte_flow_error ferror;
+	int ret;
+
+	if (!PRIV(dev)->flow_isolated) {
+		DEBUG("Flow isolation already disabled");
+	} else {
+		DEBUG("Enabling flow isolation");
+		ret = rte_flow_isolate(PORT_ID(sdev),
+				       PRIV(dev)->flow_isolated,
+				       &ferror);
+		if (ret) {
+			fs_flow_complain(&ferror);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int
 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 		struct sub_device *sdev)
 {
@@ -334,9 +356,17 @@ failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
 	if (PRIV(dev)->state < DEV_ACTIVE)
 		return 0;
 	inactive = 0;
-	FOREACH_SUBDEV(sdev, i, dev)
-		if (sdev->state == DEV_PROBED)
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state == DEV_PROBED) {
 			inactive |= UINT32_C(1) << i;
+			ret = eth_dev_flow_isolate_set(dev, sdev);
+			if (ret) {
+				ERROR("Could not apply configuration to sub_device %d",
+				      i);
+				goto err_remove;
+			}
+		}
+	}
 	ret = dev->dev_ops->dev_configure(dev);
 	if (ret)
 		goto err_remove;
drivers/net/failsafe/failsafe_flow.c +29 -0
index 0098672..153ceee 100644
@@ -206,10 +206,39 @@ fs_flow_query(struct rte_eth_dev *dev,
 	return -1;
 }
 
+static int
+fs_flow_isolate(struct rte_eth_dev *dev,
+		int set,
+		struct rte_flow_error *error)
+{
+	struct sub_device *sdev;
+	uint8_t i;
+	int ret;
+
+	FOREACH_SUBDEV(sdev, i, dev) {
+		if (sdev->state < DEV_PROBED)
+			continue;
+		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
+		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
+			WARN("flow isolation mode of sub_device %d in incoherent state.",
+				i);
+		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
+		if (ret) {
+			ERROR("Operation rte_flow_isolate failed for sub_device %d"
+			      " with error %d", i, ret);
+			return ret;
+		}
+		sdev->flow_isolated = set;
+	}
+	PRIV(dev)->flow_isolated = set;
+	return 0;
+}
+
 const struct rte_flow_ops fs_flow_ops = {
 	.validate = fs_flow_validate,
 	.create = fs_flow_create,
 	.destroy = fs_flow_destroy,
 	.flush = fs_flow_flush,
 	.query = fs_flow_query,
+	.isolate = fs_flow_isolate,
 };
drivers/net/failsafe/failsafe_private.h +4 -0
index 2c52d2b..0361cf4 100644
@@ -108,6 +108,8 @@ struct sub_device {
 	struct rte_eth_dev *fs_dev;
 	/* flag calling for recollection */
 	volatile unsigned int remove:1;
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 struct fs_priv {
@@ -139,6 +141,8 @@ struct fs_priv {
 	 */
 	enum dev_state state;
 	unsigned int pending_alarm:1; /* An alarm is pending */
+	/* flow isolation state */
+	int flow_isolated:1;
 };
 
 /* MISC */
Signature · 1 line
2.1.4
#191 lore raw
In reply to Gaetan Rivet
Quoted 117 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

[dpdk-dev] [PATCH v4 0/8] fix hotplug API
http://dpdk.org/ml/archives/dev/2017-July/071340.html

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

v10 --> v11

- Added Glossary in documentation.
- Fixed issues oulined in [1].
- Removed Rx offload advertizement in feature matrix.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071406.html

Quoted 12 lines

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support Rx offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

Series applied to dpdk-next-net/master, thanks.

#192 lore raw
Quoted 131 lines · Ferruh Yigit
Quoted 117 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

[dpdk-dev] [PATCH v4 0/8] fix hotplug API
http://dpdk.org/ml/archives/dev/2017-July/071340.html

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

v10 --> v11

- Added Glossary in documentation.
- Fixed issues oulined in [1].
- Removed Rx offload advertizement in feature matrix.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071406.html

Quoted 12 lines

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support Rx offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

Quoted 1 line

Series applied to dpdk-next-net/master, thanks.

Hi Gaetan,

Can you please send a patch to update release notes to announce the new PMD?

And can you also send a web page to list the PMD within supported NICs [1]?

Thanks,
ferruh

[1]
http://dpdk.org/doc/nics

#193 lore raw
Quoted 132 lines · Ferruh Yigit
Quoted 131 lines · Ferruh Yigit
Quoted 129 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

[dpdk-dev] [PATCH v4 0/8] fix hotplug API
http://dpdk.org/ml/archives/dev/2017-July/071340.html

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

v10 --> v11

- Added Glossary in documentation.
- Fixed issues oulined in [1].
- Removed Rx offload advertizement in feature matrix.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071406.html

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support Rx offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

Quoted 6 lines
Quoted 1 line

Series applied to dpdk-next-net/master, thanks.

Hi Gaetan,

Can you please send a patch to update release notes to announce the new PMD?

Hi Ferruh,

Sure

Quoted 2 lines

And can you also send a web page to list the PMD within supported NICs [1]?

How can I do that? Is there a git repository for dpdk.org I can propose a patch for?

Quoted 5 lines

Thanks,
ferruh

[1]
http://dpdk.org/doc/nics

Signature · 2 lines
Gaëtan Rivet
6WIND
#194 lore raw
Quoted 142 lines · Gaëtan Rivet
Quoted 132 lines · Ferruh Yigit
Quoted 131 lines · Ferruh Yigit
Quoted 129 lines · Gaetan Rivet

This PMD intercepts and manages Ethernet device removal events issued by slave PMDs and re-initializes them transparently when brought back so that existing applications do not need to be modified to benefit from true hot-plugging support.

The stacked PMD approach shares many similarities with the bonding PMD but with a different purpose. While bonding provides the ability to group several links into a single logical device for enhanced throughput and supports fail-over at link level, this one manages the sudden disappearance of the underlying device; it guarantees applications face a valid device in working order at all times.

Each fail-safe instance is configured to run atop one or several devices, with one defined as the preferred device. Hot-plug events are handled on all of them, and Tx is always directed to the preferred device if present or to the next available failover device (Rx is always performed on all devices for simplicity).

Moreover, the configured slaves (preferred or failover) do not need to be present at initialization time and may appear later.

Slaves configuration is continuously synchronized with that of the virtual device, which exposes their common set of capabilities to the application. Failure to apply the current configuration state to a slave for any reason simply reschedules its initialization.

This patchset depends on:

[dpdk-dev] [PATCH v4 0/8] fix hotplug API
http://dpdk.org/ml/archives/dev/2017-July/071340.html

v1 --> v2:

- Wrote documentation
- Fixed commit logs, signed-off-by
- Added LSC event support
- A few minor fixes

v2 --> v3:

- Numerous bug fixes.
- Complete sub-EAL rework to follow new bus API.
- burst protection on sub removal.
- more flexible sub definition.
- flow isolated mode support.

v3 --> v4:

- Split back commits
net/failsafe: add fast burst functions net/failsafe: support device removal
That were squashed by error during a rebase
- Fix segfault on port plugin
- Fix isolate mode support for MLX4 ports plugin

v4 --> v5:

- Follow new plug / unplug API.

v5 --> v6:

- Follow new hotplug API.
- Improve usability of hotplug API.
- Fix rte_dev hotplug API implementation.
- Introduce rte_eal_devargs_rmv API as EXPERIMENTAL.
- Use it to clean up resources on hotplug_remove.
- Fix hotplug implementation and support un pci bus. The scan was not idempotent, nor clean. Neither were the device fields.
- Implement plug operation for vdev bus.
This is needed for hotplug support and to make the EAL independent from vdev-specific API.
- Remove useless parameters from plug / unplug API.

This patchset is fairly big and complex. The hotplug API has been rushed and has never been tested outside of the special case of vdev bus.

These evolutions are proposed alongside this PMD as only this PMD allows to test this API at the moment, and without those evolutions this PMD cannot be used.

v6 --> v7

- Split the series in three, with
vlan filter configuration store standing alone Hotplug API fixes separated
Fail-safe PMD on its own.

These changes should ease integration.

v7 --> v8

- Fix usage examples in documentation.
- Use rte_eth_dev_allocated when relevant.

v8 --> v9

- Use calloc instead of rte_realloc for command line parsing.
- Include errno only when necessary.

v9 --> v10

- Fix rte_flow description double-free issue. Thanks Raslan for finding the issue :)
- Use RTE_ASSERT instead of assert.
Integrate the debug log of the fail-safe to RTE_LOG_DEBUG macro as well, allowing dynamic log levels.
- Remove devices post-state-sync during slave upkeep, to avoid a useless early probe attempt.

v10 --> v11

- Added Glossary in documentation.
- Fixed issues oulined in [1].
- Removed Rx offload advertizement in feature matrix.

[1]: http://dpdk.org/ml/archives/dev/2017-July/071406.html

Gaetan Rivet (11):
ethdev: add deferred intermediate device state
ethdev: count devices consistently
net/failsafe: add fail-safe PMD
net/failsafe: add plug-in support
net/failsafe: add flexible device definition
net/failsafe: support flow API
net/failsafe: support Rx offload capabilities
net/failsafe: add fast burst functions
net/failsafe: support device removal
net/failsafe: support link status change event
net/failsafe: support flow API isolation mode

Quoted 6 lines
Quoted 1 line

Series applied to dpdk-next-net/master, thanks.

Hi Gaetan,

Can you please send a patch to update release notes to announce the new PMD?

Hi Ferruh,

Quoted 7 lines

Sure

Quoted 2 lines

And can you also send a web page to list the PMD within supported NICs [1]?

How can I do that? Is there a git repository for dpdk.org I can propose a patch for?

Yes there is a dpdk-web repo: http://dpdk.org/browse/tools/dpdk-web/

Quoted 7 lines
Quoted 6 lines

Thanks,
ferruh

[1]
http://dpdk.org/doc/nics