From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm0-f48.google.com (mail-wm0-f48.google.com [74.125.82.48]) by dpdk.org (Postfix) with ESMTP id 491933DC for ; Wed, 8 Mar 2017 16:16:11 +0100 (CET) Received: by mail-wm0-f48.google.com with SMTP id v186so117346170wmd.0 for ; Wed, 08 Mar 2017 07:16:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references:in-reply-to :references; bh=EBENDxsUsfdYeKxu045j3huBSCOhs97+Xd7KrRCORzU=; b=Qbv+bK9+WD63reDkXNdIK5XMhmyb9cOBl+pssHbq8PNIXc1HL1ZQaoYg+j+vrHCKnr keKIMPfaNbFhNm8Wm/2WYyZkwNACGQshnmf4z1CpJrGPQH5zFwQ1YzWQeEH/RDas5mZ4 4ws8+aWv4tEESmfD6RMjVA9p7a9Gkk6pGa91mJGzCsiZ/e5J3eoOFvCKNAH53M35L+IC +pJeD+2ee2kDIYGNzl2oeLcxvZ8tXU72/EmgAwh1kQZxUHDXnEcIQ6xv80EMy6mIUOFi /7VJfHlz42mqIjAUSP0Hg49g2aCEAE0HZhhcJ1f/lM6VrVpL7VmcgfpB9esevENXp2/X xhnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=EBENDxsUsfdYeKxu045j3huBSCOhs97+Xd7KrRCORzU=; b=ljWhtmz6xXUiNG7TNEy1JrMp3wvSX1QMOOdTf6IXA8Bn5UUIcRsnNeLUF7Crkusv7h rCDFmhNN7TZbXTYmrkt+hguAHYJDQcbItFK3XnIIr0XNYgECa2Q5ylzFVaHR8HirH24H Ac75qNGaauVPrWVX8FXjUR8ULstyr+x1q8JnWVALIxCyN2cJYKluM0N/jLlSkA1RrQlh wIQcz/S47pcU8I33vRwyJsA0XgJrZXad26j1bfg6pf6vkZYN8tTMLZHsLM6Tx5Y/2tGk WBGjh3uBCMJG80uiwT4CTO/42PbGqyaDjdbsnQWQ7r+hyR8oNS06tHnm8B8iMc7FGh0o TyBA== X-Gm-Message-State: AMke39nSZzgoZCf6swAXEMlyqnCggFYMcaZEFq17O5hZSLY8wwV+W+SBc5omQmrZ9iq+TzW/ X-Received: by 10.28.212.79 with SMTP id l76mr11844638wmg.6.1488986170484; Wed, 08 Mar 2017 07:16:10 -0800 (PST) Received: from bidouze.dev.6wind.com (host.78.145.23.62.rev.coltfrance.com. [62.23.145.78]) by smtp.gmail.com with ESMTPSA id t103sm4553592wrc.43.2017.03.08.07.16.09 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 08 Mar 2017 07:16:10 -0800 (PST) From: Gaetan Rivet To: dev@dpdk.org Date: Wed, 8 Mar 2017 16:15:42 +0100 Message-Id: X-Mailer: git-send-email 2.1.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v2 09/13] net/failsafe: support flow API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Mar 2017 15:16:11 -0000 Signed-off-by: Gaetan Rivet Acked-by: Olga Shern --- doc/guides/nics/features/failsafe.ini | 1 + drivers/net/failsafe/Makefile | 1 + drivers/net/failsafe/failsafe.c | 1 + drivers/net/failsafe/failsafe_eal.c | 2 + drivers/net/failsafe/failsafe_ether.c | 76 +++++++++++ drivers/net/failsafe/failsafe_flow.c | 230 ++++++++++++++++++++++++++++++++ drivers/net/failsafe/failsafe_ops.c | 29 ++++ drivers/net/failsafe/failsafe_private.h | 20 +++ 8 files changed, 360 insertions(+) create mode 100644 drivers/net/failsafe/failsafe_flow.c diff --git a/doc/guides/nics/features/failsafe.ini b/doc/guides/nics/features/failsafe.ini index 3c52823..9167b59 100644 --- a/doc/guides/nics/features/failsafe.ini +++ b/doc/guides/nics/features/failsafe.ini @@ -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 diff --git a/drivers/net/failsafe/Makefile b/drivers/net/failsafe/Makefile index 4567961..a53bb75 100644 --- a/drivers/net/failsafe/Makefile +++ b/drivers/net/failsafe/Makefile @@ -41,6 +41,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 diff --git a/drivers/net/failsafe/failsafe.c b/drivers/net/failsafe/failsafe.c index 2063393..6151736 100644 --- a/drivers/net/failsafe/failsafe.c +++ b/drivers/net/failsafe/failsafe.c @@ -180,6 +180,7 @@ eth_dev_create(const char *name, 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) { diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c index a5e8c3c..9817fc9 100644 --- a/drivers/net/failsafe/failsafe_eal.c +++ b/drivers/net/failsafe/failsafe_eal.c @@ -139,6 +139,7 @@ dev_init(struct rte_eth_dev *dev) continue; } ETH(sdev)->state = RTE_ETH_DEV_DEFERRED; + SUB_ID(sdev) = i; sdev->state = DEV_PROBED; } } @@ -189,6 +190,7 @@ pci_probe(struct rte_eth_dev *dev) continue; } ETH(sdev)->state = RTE_ETH_DEV_DEFERRED; + SUB_ID(sdev) = i; sdev->state = DEV_PROBED; } } diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c index a6ccf8f..8c73b4c 100644 --- a/drivers/net/failsafe/failsafe_ether.c +++ b/drivers/net/failsafe/failsafe_ether.c @@ -33,8 +33,46 @@ #include +#include +#include + #include "failsafe_private.h" +/** Print a message out of a flow error. */ +static int +fs_flow_complain(struct rte_flow_error *error) +{ + static const char *const errstrlist[] = { + [RTE_FLOW_ERROR_TYPE_NONE] = "no error", + [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified", + [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)", + [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field", + [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field", + [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field", + [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field", + [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure", + [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length", + [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item", + [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions", + [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action", + }; + const char *errstr; + char buf[32]; + int err = rte_errno; + + if ((unsigned int)error->type >= RTE_DIM(errstrlist) || + !errstrlist[error->type]) + errstr = "unknown type"; + else + errstr = errstrlist[error->type]; + ERROR("Caught error type %d (%s): %s%s\n", + error->type, errstr, + error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ", + error->cause), buf) : "", + error->message ? error->message : "(no stated reason)"); + return -err; +} + static int eth_dev_conf_apply(struct rte_eth_dev *dev, struct sub_device *sdev) @@ -42,6 +80,8 @@ eth_dev_conf_apply(struct rte_eth_dev *dev, struct rte_eth_dev *edev; struct rte_vlan_filter_conf *vfc1; struct rte_vlan_filter_conf *vfc2; + struct rte_flow *flow; + struct rte_flow_error ferror; uint32_t i; int ret; @@ -177,6 +217,42 @@ eth_dev_conf_apply(struct rte_eth_dev *dev, } else { DEBUG("VLAN filter already set"); } + /* rte_flow */ + if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) { + DEBUG("rte_flow already set"); + } else { + DEBUG("Resetting rte_flow configuration"); +#ifndef NDEBUG + memset(&ferror, 0x11, sizeof(ferror)); +#endif + ret = rte_flow_flush(PORT_ID(sdev), &ferror); + if (ret) { + fs_flow_complain(&ferror); + return ret; + } +#ifndef NDEBUG + memset(&ferror, 0x11, sizeof(ferror)); +#endif + i = 0; + rte_errno = 0; + DEBUG("Configuring rte_flow"); + TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) { + DEBUG("Creating flow #%" PRIu32, i++); + flow->flows[SUB_ID(sdev)] = + rte_flow_create(PORT_ID(sdev), + &flow->fd->attr, + flow->fd->items, + flow->fd->actions, + &ferror); + ret = rte_errno; + if (ret) + break; + } + if (ret) { + fs_flow_complain(&ferror); + return ret; + } + } return 0; } diff --git a/drivers/net/failsafe/failsafe_flow.c b/drivers/net/failsafe/failsafe_flow.c new file mode 100644 index 0000000..3079786 --- /dev/null +++ b/drivers/net/failsafe/failsafe_flow.c @@ -0,0 +1,230 @@ +/*- + * 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 + +#include +#include +#include +#include + +#include "failsafe_private.h" + +static void * +fs_calloc(size_t n, size_t sz) +{ + size_t size; + + size = n * sz; + if (n != 0 && size / n != sz) { + ERROR("size_t overflow"); + return NULL; + } + return rte_zmalloc(NULL, size, + RTE_CACHE_LINE_SIZE); +} + +static struct rte_flow * +fs_flow_allocate(const struct rte_flow_attr *attr, + const struct rte_flow_item *items, + const struct rte_flow_action *actions) +{ + struct rte_flow *flow; + + flow = rte_zmalloc(NULL, sizeof(struct rte_flow), + RTE_CACHE_LINE_SIZE); + if (flow == NULL) { + ERROR("Could not allocate new flow"); + return NULL; + } + flow->fd = rte_flow_copy(attr, items, actions, fs_calloc); + if (flow->fd == NULL) { + ERROR("Could not allocate flow description"); + goto free_flow; + } + return flow; +free_flow: + rte_free(flow); + + return NULL; +} + +static void +fs_flow_release(struct rte_flow **flow) +{ + rte_free((*flow)->fd); + rte_free(*flow); + *flow = NULL; +} + +static int +fs_flow_validate(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item patterns[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + struct sub_device *sdev; + uint8_t i; + int ret; + + FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) { + DEBUG("Calling rte_flow_validate on sub_device %d", i); + ret = rte_flow_validate(PORT_ID(sdev), + attr, patterns, actions, error); + if (ret) { + ERROR("Operation rte_flow_validate failed for sub_device %d" + " with error %d", i, ret); + return ret; + } + } + return 0; +} + +static struct rte_flow * +fs_flow_create(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item patterns[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + struct sub_device *sdev; + struct rte_flow *flow; + uint8_t i; + + 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); + if (flow->flows[i] == NULL) { + ERROR("Failed to create flow on sub_device %d", + i); + goto err; + } + } + TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next); + return flow; +err: + FOREACH_SUBDEV(sdev, i, dev) { + if (flow->flows[i] != NULL) + rte_flow_destroy(PORT_ID(sdev), + flow->flows[i], error); + } + fs_flow_release(&flow); + return NULL; +} + +static int +fs_flow_destroy(struct rte_eth_dev *dev, + struct rte_flow *flow, + struct rte_flow_error *error) +{ + struct sub_device *sdev; + uint8_t i; + int ret; + + if (flow == NULL) { + ERROR("Invalid flow"); + return -EINVAL; + } + ret = 0; + FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) { + int local_ret; + + if (flow->flows[i] == NULL) + continue; + local_ret = rte_flow_destroy(PORT_ID(sdev), + flow->flows[i], error); + if (local_ret) { + ERROR("Failed to destroy flow on sub_device %d: %d", + i, local_ret); + if (ret == 0) + ret = local_ret; + } + } + TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); + rte_free(flow); + return ret; +} + +static int +fs_flow_flush(struct rte_eth_dev *dev, + struct rte_flow_error *error) +{ + struct sub_device *sdev; + struct rte_flow *flow; + void *tmp; + uint8_t i; + int ret; + + FOREACH_SUBDEV_ST(sdev, i, dev, DEV_ACTIVE) { + DEBUG("Calling rte_flow_flush on sub_device %d", i); + ret = rte_flow_flush(PORT_ID(sdev), error); + if (ret) { + ERROR("Operation rte_flow_flush failed for sub_device %d" + " with error %d", i, ret); + return ret; + } + } + TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) { + TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); + fs_flow_release(&flow); + } + return 0; +} + +static int +fs_flow_query(struct rte_eth_dev *dev, + struct rte_flow *flow, + enum rte_flow_action_type type, + void *arg, + struct rte_flow_error *error) +{ + struct sub_device *sdev; + + sdev = TX_SUBDEV(dev); + if (sdev != NULL) { + return rte_flow_query(PORT_ID(sdev), + flow->flows[SUB_ID(sdev)], type, arg, error); + } + WARN("No active sub_device to query about its flow"); + return -1; +} + +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, +}; diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c index b408877..d837280 100644 --- a/drivers/net/failsafe/failsafe_ops.c +++ b/drivers/net/failsafe/failsafe_ops.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "failsafe_private.h" @@ -642,6 +643,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, @@ -669,4 +697,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, }; diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h index fcd5b75..c636199 100644 --- a/drivers/net/failsafe/failsafe_private.h +++ b/drivers/net/failsafe/failsafe_private.h @@ -34,6 +34,8 @@ #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_ #define _RTE_ETH_FAILSAFE_PRIVATE_H_ +#include + #include #include #include @@ -73,6 +75,16 @@ 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, @@ -91,6 +103,7 @@ struct sub_device { struct rte_pci_device pci_device; }; struct rte_eth_dev *eth_dev; + uint8_t sid; /* Device state machine */ enum dev_state state; /* Some device are defined as a command line */ @@ -109,6 +122,8 @@ struct fs_priv { uint8_t subs_tx; struct sub_device *subs; 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]; @@ -158,6 +173,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 plug_in_poll; extern int mac_from_arg; @@ -175,6 +191,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 -- 2.1.4