get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/26612/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 26612,
    "url": "https://patches.dpdk.org/api/patches/26612/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/a58bc82fb1f2fc2743aaa370a79f7a159a618ee2.1499384906.git.gaetan.rivet@6wind.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<a58bc82fb1f2fc2743aaa370a79f7a159a618ee2.1499384906.git.gaetan.rivet@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/a58bc82fb1f2fc2743aaa370a79f7a159a618ee2.1499384906.git.gaetan.rivet@6wind.com",
    "date": "2017-07-07T00:09:32",
    "name": "[dpdk-dev,v6,18/23] net/failsafe: support flow API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c697eb3bee36722c99e88cd076494e103d17391b",
    "submitter": {
        "id": 269,
        "url": "https://patches.dpdk.org/api/people/269/?format=api",
        "name": "Gaëtan Rivet",
        "email": "gaetan.rivet@6wind.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/a58bc82fb1f2fc2743aaa370a79f7a159a618ee2.1499384906.git.gaetan.rivet@6wind.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/26612/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/26612/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 994507D21;\n\tFri,  7 Jul 2017 02:11:02 +0200 (CEST)",
            "from mail-wr0-f178.google.com (mail-wr0-f178.google.com\n\t[209.85.128.178]) by dpdk.org (Postfix) with ESMTP id 221917CC6\n\tfor <dev@dpdk.org>; Fri,  7 Jul 2017 02:10:24 +0200 (CEST)",
            "by mail-wr0-f178.google.com with SMTP id r103so24429416wrb.0\n\tfor <dev@dpdk.org>; Thu, 06 Jul 2017 17:10:24 -0700 (PDT)",
            "from bidouze.dev.6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\tf45sm2391166wrf.2.2017.07.06.17.10.22\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tThu, 06 Jul 2017 17:10:22 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:in-reply-to:references;\n\tbh=6o7m7kxBdpLhMTlxOFLH8aYOEoD492O9r+haQ1heD3E=;\n\tb=KDJhyM1slDkJ1mi6iwJxX6kQhV8rwiAZSIYCbLgGBHSZbjw2r3oqzlXJEODB1h9DSP\n\tKf//xYrBQPaEebr5J1M+ERsGmVOTxY0KMED8YTWtaHGK7yTayenVOEVxO9Fy/wnnA5ni\n\tYDEimnJMIpg0z5NbDzkRE7i+foS2ntTPlODS+hNu8yW6hXoIVYjU5HDjokBXWIb9AQov\n\tw15q66pwcqPpVNPcPf2ruvdxbf2SXVXXYy5J5sPlGKwDQbkTi3ursjYj5SxboXJXcy8X\n\tBiBVmpO9uGrAFJYa0kMve05NyQahW28TcOnpmTJ1cSpqcl55Y37BCeMnh8Gr47xGM4iT\n\tmsgg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:in-reply-to:references;\n\tbh=6o7m7kxBdpLhMTlxOFLH8aYOEoD492O9r+haQ1heD3E=;\n\tb=kBf4BBw0+hiky0cXH6CYaJLfB0OUSL2qhUutSUythE2ckcsoiEE77PxFVIBx3z+v5I\n\tOt8OUb6efIpzoxpdOH5nggbgigvVfE12QCBegkWWPOSjDVxTQCwPYN9ZCkCI4elI2v0T\n\tLjWcubgc4LebxiDMHfLjeuNkbMHJIfPIEixKoKB2jupAbOgG805sH7bo2yIids3oTcAG\n\tkK+wjsVhJFpRWeNY++1xxx62R+mi8DtD59UdHeznNBPfZLw/cUsmK8QI4dhq2ycX0nHW\n\thmuIc11MnGFrauSGeil94oYDy955jdCQ/rMePN74yCooBFSdDtnJkCwwc4uLKzynsqTG\n\t7ADw==",
        "X-Gm-Message-State": "AIVw110cXKMlYWfIWp+k1OlFuDheVlGrokLjrdrfYuUmxDWdt28Puefj\n\tFuSW1jL4OgjlLF4XBMg=",
        "X-Received": "by 10.28.66.67 with SMTP id p64mr267006wma.93.1499386223280;\n\tThu, 06 Jul 2017 17:10:23 -0700 (PDT)",
        "From": "Gaetan Rivet <gaetan.rivet@6wind.com>",
        "To": "dev@dpdk.org",
        "Cc": "Gaetan Rivet <gaetan.rivet@6wind.com>",
        "Date": "Fri,  7 Jul 2017 02:09:32 +0200",
        "Message-Id": "<a58bc82fb1f2fc2743aaa370a79f7a159a618ee2.1499384906.git.gaetan.rivet@6wind.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": [
            "<cover.1499385281.git.gaetan.rivet@6wind.com>",
            "<cover.1499384906.git.gaetan.rivet@6wind.com>"
        ],
        "References": [
            "<cover.1496877105.git.gaetan.rivet@6wind.com>\n\t<cover.1499385281.git.gaetan.rivet@6wind.com>",
            "<cover.1499384906.git.gaetan.rivet@6wind.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v6 18/23] net/failsafe: support flow API",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>\nAcked-by: Olga Shern <olgas@mellanox.com>\n---\n doc/guides/nics/features/failsafe.ini   |   1 +\n drivers/net/failsafe/Makefile           |   1 +\n drivers/net/failsafe/failsafe.c         |   1 +\n drivers/net/failsafe/failsafe_eal.c     |   1 +\n drivers/net/failsafe/failsafe_ether.c   |  70 +++++++++++\n drivers/net/failsafe/failsafe_flow.c    | 216 ++++++++++++++++++++++++++++++++\n drivers/net/failsafe/failsafe_ops.c     |  29 +++++\n drivers/net/failsafe/failsafe_private.h |  18 +++\n 8 files changed, 337 insertions(+)\n create mode 100644 drivers/net/failsafe/failsafe_flow.c",
    "diff": "diff --git a/doc/guides/nics/features/failsafe.ini b/doc/guides/nics/features/failsafe.ini\nindex 3c52823..9167b59 100644\n--- a/doc/guides/nics/features/failsafe.ini\n+++ b/doc/guides/nics/features/failsafe.ini\n@@ -13,6 +13,7 @@ Allmulticast mode    = Y\n Unicast MAC filter   = Y\n Multicast MAC filter = Y\n VLAN filter          = Y\n+Flow API             = Y\n Packet type parsing  = Y\n Basic stats          = Y\n Stats per queue      = Y\ndiff --git a/drivers/net/failsafe/Makefile b/drivers/net/failsafe/Makefile\nindex e27bfc0..3cccfe0 100644\n--- a/drivers/net/failsafe/Makefile\n+++ b/drivers/net/failsafe/Makefile\n@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_eal.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ops.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c\n \n # No exported include files\n \ndiff --git a/drivers/net/failsafe/failsafe.c b/drivers/net/failsafe/failsafe.c\nindex 888f07b..6557255 100644\n--- a/drivers/net/failsafe/failsafe.c\n+++ b/drivers/net/failsafe/failsafe.c\n@@ -177,6 +177,7 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)\n \tdev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];\n \tdev->data->dev_link = eth_link;\n \tPRIV(dev)->nb_mac_addr = 1;\n+\tTAILQ_INIT(&PRIV(dev)->flow_list);\n \tdev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;\n \tdev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;\n \tif (params == NULL) {\ndiff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c\nindex 16871df..86e16a6 100644\n--- a/drivers/net/failsafe/failsafe_eal.c\n+++ b/drivers/net/failsafe/failsafe_eal.c\n@@ -78,6 +78,7 @@ fs_bus_init(struct rte_eth_dev *dev)\n \t\t\tERROR(\"sub_device %d init went wrong\", i);\n \t\t\treturn -ENODEV;\n \t\t}\n+\t\tSUB_ID(sdev) = i;\n \t\tsdev->dev = ETH(sdev)->device;\n \t\tETH(sdev)->state = RTE_ETH_DEV_DEFERRED;\n \t\tsdev->state = DEV_PROBED;\ndiff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c\nindex 2a1535e..2958207 100644\n--- a/drivers/net/failsafe/failsafe_ether.c\n+++ b/drivers/net/failsafe/failsafe_ether.c\n@@ -33,8 +33,46 @@\n \n #include <unistd.h>\n \n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+\n #include \"failsafe_private.h\"\n \n+/** Print a message out of a flow error. */\n+static int\n+fs_flow_complain(struct rte_flow_error *error)\n+{\n+\tstatic const char *const errstrlist[] = {\n+\t\t[RTE_FLOW_ERROR_TYPE_NONE] = \"no error\",\n+\t\t[RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = \"cause unspecified\",\n+\t\t[RTE_FLOW_ERROR_TYPE_HANDLE] = \"flow rule (handle)\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = \"group field\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = \"priority field\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = \"ingress field\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = \"egress field\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ATTR] = \"attributes structure\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ITEM_NUM] = \"pattern length\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ITEM] = \"specific pattern item\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ACTION_NUM] = \"number of actions\",\n+\t\t[RTE_FLOW_ERROR_TYPE_ACTION] = \"specific action\",\n+\t};\n+\tconst char *errstr;\n+\tchar buf[32];\n+\tint err = rte_errno;\n+\n+\tif ((unsigned int)error->type >= RTE_DIM(errstrlist) ||\n+\t\t\t!errstrlist[error->type])\n+\t\terrstr = \"unknown type\";\n+\telse\n+\t\terrstr = errstrlist[error->type];\n+\tERROR(\"Caught error type %d (%s): %s%s\\n\",\n+\t\terror->type, errstr,\n+\t\terror->cause ? (snprintf(buf, sizeof(buf), \"cause: %p, \",\n+\t\t\t\terror->cause), buf) : \"\",\n+\t\terror->message ? error->message : \"(no stated reason)\");\n+\treturn -err;\n+}\n+\n static int\n fs_eth_dev_conf_apply(struct rte_eth_dev *dev,\n \t\tstruct sub_device *sdev)\n@@ -42,6 +80,8 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,\n \tstruct rte_eth_dev *edev;\n \tstruct rte_vlan_filter_conf *vfc1;\n \tstruct rte_vlan_filter_conf *vfc2;\n+\tstruct rte_flow *flow;\n+\tstruct rte_flow_error ferror;\n \tuint32_t i;\n \tint ret;\n \n@@ -177,6 +217,36 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,\n \t} else {\n \t\tDEBUG(\"VLAN filter already set\");\n \t}\n+\t/* rte_flow */\n+\tif (TAILQ_EMPTY(&PRIV(dev)->flow_list)) {\n+\t\tDEBUG(\"rte_flow already set\");\n+\t} else {\n+\t\tDEBUG(\"Resetting rte_flow configuration\");\n+\t\tret = rte_flow_flush(PORT_ID(sdev), &ferror);\n+\t\tif (ret) {\n+\t\t\tfs_flow_complain(&ferror);\n+\t\t\treturn ret;\n+\t\t}\n+\t\ti = 0;\n+\t\trte_errno = 0;\n+\t\tDEBUG(\"Configuring rte_flow\");\n+\t\tTAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) {\n+\t\t\tDEBUG(\"Creating flow #%\" PRIu32, i++);\n+\t\t\tflow->flows[SUB_ID(sdev)] =\n+\t\t\t\trte_flow_create(PORT_ID(sdev),\n+\t\t\t\t\t\t&flow->fd->attr,\n+\t\t\t\t\t\tflow->fd->items,\n+\t\t\t\t\t\tflow->fd->actions,\n+\t\t\t\t\t\t&ferror);\n+\t\t\tret = rte_errno;\n+\t\t\tif (ret)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tif (ret) {\n+\t\t\tfs_flow_complain(&ferror);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n \treturn 0;\n }\n \ndiff --git a/drivers/net/failsafe/failsafe_flow.c b/drivers/net/failsafe/failsafe_flow.c\nnew file mode 100644\nindex 0000000..d8f59a1\n--- /dev/null\n+++ b/drivers/net/failsafe/failsafe_flow.c\n@@ -0,0 +1,216 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright 2017 6WIND S.A.\n+ *   Copyright 2017 Mellanox.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of 6WIND S.A. nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <sys/queue.h>\n+\n+#include <rte_malloc.h>\n+#include <rte_tailq.h>\n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+\n+#include \"failsafe_private.h\"\n+\n+static struct rte_flow *\n+fs_flow_allocate(const struct rte_flow_attr *attr,\n+\t\t const struct rte_flow_item *items,\n+\t\t const struct rte_flow_action *actions)\n+{\n+\tstruct rte_flow *flow;\n+\tsize_t fdsz;\n+\n+\tfdsz = rte_flow_copy(NULL, 0, attr, items, actions);\n+\tflow = rte_zmalloc(NULL,\n+\t\t\t   sizeof(struct rte_flow) + fdsz,\n+\t\t\t   RTE_CACHE_LINE_SIZE);\n+\tif (flow == NULL) {\n+\t\tERROR(\"Could not allocate new flow\");\n+\t\treturn NULL;\n+\t}\n+\tflow->fd = (void *)((uintptr_t)flow + sizeof(*flow));\n+\tif (rte_flow_copy(flow->fd, fdsz, attr, items, actions) != fdsz) {\n+\t\tERROR(\"Failed to copy flow description\");\n+\t\trte_free(flow);\n+\t\treturn NULL;\n+\t}\n+\treturn flow;\n+}\n+\n+static void\n+fs_flow_release(struct rte_flow **flow)\n+{\n+\trte_free((*flow)->fd);\n+\trte_free(*flow);\n+\t*flow = NULL;\n+}\n+\n+static int\n+fs_flow_validate(struct rte_eth_dev *dev,\n+\t\t const struct rte_flow_attr *attr,\n+\t\t const struct rte_flow_item patterns[],\n+\t\t const struct rte_flow_action actions[],\n+\t\t struct rte_flow_error *error)\n+{\n+\tstruct sub_device *sdev;\n+\tuint8_t i;\n+\tint ret;\n+\n+\tFOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {\n+\t\tDEBUG(\"Calling rte_flow_validate on sub_device %d\", i);\n+\t\tret = rte_flow_validate(PORT_ID(sdev),\n+\t\t\t\tattr, patterns, actions, error);\n+\t\tif (ret) {\n+\t\t\tERROR(\"Operation rte_flow_validate failed for sub_device %d\"\n+\t\t\t      \" with error %d\", i, ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static struct rte_flow *\n+fs_flow_create(struct rte_eth_dev *dev,\n+\t       const struct rte_flow_attr *attr,\n+\t       const struct rte_flow_item patterns[],\n+\t       const struct rte_flow_action actions[],\n+\t       struct rte_flow_error *error)\n+{\n+\tstruct sub_device *sdev;\n+\tstruct rte_flow *flow;\n+\tuint8_t i;\n+\n+\tflow = fs_flow_allocate(attr, patterns, actions);\n+\tFOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {\n+\t\tflow->flows[i] = rte_flow_create(PORT_ID(sdev),\n+\t\t\t\tattr, patterns, actions, error);\n+\t\tif (flow->flows[i] == NULL) {\n+\t\t\tERROR(\"Failed to create flow on sub_device %d\",\n+\t\t\t\ti);\n+\t\t\tgoto err;\n+\t\t}\n+\t}\n+\tTAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next);\n+\treturn flow;\n+err:\n+\tFOREACH_SUBDEV(sdev, i, dev) {\n+\t\tif (flow->flows[i] != NULL)\n+\t\t\trte_flow_destroy(PORT_ID(sdev),\n+\t\t\t\tflow->flows[i], error);\n+\t}\n+\tfs_flow_release(&flow);\n+\treturn NULL;\n+}\n+\n+static int\n+fs_flow_destroy(struct rte_eth_dev *dev,\n+\t\tstruct rte_flow *flow,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tstruct sub_device *sdev;\n+\tuint8_t i;\n+\tint ret;\n+\n+\tif (flow == NULL) {\n+\t\tERROR(\"Invalid flow\");\n+\t\treturn -EINVAL;\n+\t}\n+\tret = 0;\n+\tFOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {\n+\t\tint local_ret;\n+\n+\t\tif (flow->flows[i] == NULL)\n+\t\t\tcontinue;\n+\t\tlocal_ret = rte_flow_destroy(PORT_ID(sdev),\n+\t\t\t\tflow->flows[i], error);\n+\t\tif (local_ret) {\n+\t\t\tERROR(\"Failed to destroy flow on sub_device %d: %d\",\n+\t\t\t\t\ti, local_ret);\n+\t\t\tif (ret == 0)\n+\t\t\t\tret = local_ret;\n+\t\t}\n+\t}\n+\tTAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);\n+\trte_free(flow);\n+\treturn ret;\n+}\n+\n+static int\n+fs_flow_flush(struct rte_eth_dev *dev,\n+\t      struct rte_flow_error *error)\n+{\n+\tstruct sub_device *sdev;\n+\tstruct rte_flow *flow;\n+\tvoid *tmp;\n+\tuint8_t i;\n+\tint ret;\n+\n+\tFOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {\n+\t\tDEBUG(\"Calling rte_flow_flush on sub_device %d\", i);\n+\t\tret = rte_flow_flush(PORT_ID(sdev), error);\n+\t\tif (ret) {\n+\t\t\tERROR(\"Operation rte_flow_flush failed for sub_device %d\"\n+\t\t\t      \" with error %d\", i, ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tTAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) {\n+\t\tTAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);\n+\t\tfs_flow_release(&flow);\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+fs_flow_query(struct rte_eth_dev *dev,\n+\t      struct rte_flow *flow,\n+\t      enum rte_flow_action_type type,\n+\t      void *arg,\n+\t      struct rte_flow_error *error)\n+{\n+\tstruct sub_device *sdev;\n+\n+\tsdev = TX_SUBDEV(dev);\n+\tif (sdev != NULL) {\n+\t\treturn rte_flow_query(PORT_ID(sdev),\n+\t\t\t\tflow->flows[SUB_ID(sdev)], type, arg, error);\n+\t}\n+\tWARN(\"No active sub_device to query about its flow\");\n+\treturn -1;\n+}\n+\n+const struct rte_flow_ops fs_flow_ops = {\n+\t.validate = fs_flow_validate,\n+\t.create = fs_flow_create,\n+\t.destroy = fs_flow_destroy,\n+\t.flush = fs_flow_flush,\n+\t.query = fs_flow_query,\n+};\ndiff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c\nindex 4044473..4cb2e90 100644\n--- a/drivers/net/failsafe/failsafe_ops.c\n+++ b/drivers/net/failsafe/failsafe_ops.c\n@@ -35,6 +35,7 @@\n #include <stdint.h>\n #include <rte_ethdev.h>\n #include <rte_malloc.h>\n+#include <rte_flow.h>\n \n #include \"failsafe_private.h\"\n \n@@ -628,6 +629,33 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)\n \t\trte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);\n }\n \n+static int\n+fs_filter_ctrl(struct rte_eth_dev *dev,\n+\t\tenum rte_filter_type type,\n+\t\tenum rte_filter_op op,\n+\t\tvoid *arg)\n+{\n+\tstruct sub_device *sdev;\n+\tuint8_t i;\n+\tint ret;\n+\n+\tif (type == RTE_ETH_FILTER_GENERIC &&\n+\t    op == RTE_ETH_FILTER_GET) {\n+\t\t*(const void **)arg = &fs_flow_ops;\n+\t\treturn 0;\n+\t}\n+\tFOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) {\n+\t\tDEBUG(\"Calling rte_eth_dev_filter_ctrl on sub_device %d\", i);\n+\t\tret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);\n+\t\tif (ret) {\n+\t\t\tERROR(\"Operation rte_eth_dev_filter_ctrl failed for sub_device %d\"\n+\t\t\t      \" with error %d\", i, ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n const struct eth_dev_ops failsafe_ops = {\n \t.dev_configure = fs_dev_configure,\n \t.dev_start = fs_dev_start,\n@@ -655,4 +683,5 @@ const struct eth_dev_ops failsafe_ops = {\n \t.mac_addr_remove = fs_mac_addr_remove,\n \t.mac_addr_add = fs_mac_addr_add,\n \t.mac_addr_set = fs_mac_addr_set,\n+\t.filter_ctrl = fs_filter_ctrl,\n };\ndiff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h\nindex 554d7a3..f40ea2f 100644\n--- a/drivers/net/failsafe/failsafe_private.h\n+++ b/drivers/net/failsafe/failsafe_private.h\n@@ -34,6 +34,8 @@\n #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_\n #define _RTE_ETH_FAILSAFE_PRIVATE_H_\n \n+#include <sys/queue.h>\n+\n #include <rte_dev.h>\n #include <rte_ethdev.h>\n #include <rte_devargs.h>\n@@ -72,6 +74,14 @@ struct txq {\n \tstruct rte_eth_txq_info info;\n };\n \n+struct rte_flow {\n+\tTAILQ_ENTRY(rte_flow) next;\n+\t/* sub_flows */\n+\tstruct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];\n+\t/* flow description for synchronization */\n+\tstruct rte_flow_desc *fd;\n+};\n+\n enum dev_state {\n \tDEV_UNDEFINED = 0,\n \tDEV_PARSED,\n@@ -86,6 +96,7 @@ struct sub_device {\n \tstruct rte_bus *bus;\n \tstruct rte_device *dev;\n \tstruct rte_eth_dev *edev;\n+\tuint8_t sid;\n \t/* Device state machine */\n \tenum dev_state state;\n \t/* Some device are defined as a command line */\n@@ -104,6 +115,8 @@ struct fs_priv {\n \tuint8_t subs_tail; /* first invalid */\n \tuint8_t subs_tx; /* current emitting device */\n \tuint8_t current_probed;\n+\t/* flow mapping */\n+\tTAILQ_HEAD(sub_flows, rte_flow) flow_list;\n \t/* current number of mac_addr slots allocated. */\n \tuint32_t nb_mac_addr;\n \tstruct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR];\n@@ -153,6 +166,7 @@ int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev);\n \n extern const char pmd_failsafe_driver_name[];\n extern const struct eth_dev_ops failsafe_ops;\n+extern const struct rte_flow_ops fs_flow_ops;\n extern uint64_t hotplug_poll;\n extern int mac_from_arg;\n \n@@ -170,6 +184,10 @@ extern int mac_from_arg;\n #define PORT_ID(sdev) \\\n \t(ETH(sdev)->data->port_id)\n \n+/* sdev: (struct sub_device *) */\n+#define SUB_ID(sdev) \\\n+\t((sdev)->sid)\n+\n /**\n  * Stateful iterator construct over fail-safe sub-devices:\n  * s:     (struct sub_device *), iterator\n",
    "prefixes": [
        "dpdk-dev",
        "v6",
        "18/23"
    ]
}