From patchwork Mon Jan 20 15:08:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eli Britstein X-Patchwork-Id: 1226035 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 481Zq70H4dz9sS9 for ; Tue, 21 Jan 2020 02:10:26 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 48DD98627E; Mon, 20 Jan 2020 15:10:25 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PYAyzdf1pOt5; Mon, 20 Jan 2020 15:10:16 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id BA83B86651; Mon, 20 Jan 2020 15:09:16 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A5556C1D8E; Mon, 20 Jan 2020 15:09:16 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 49DA7C0176 for ; Mon, 20 Jan 2020 15:09:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 366CC87884 for ; Mon, 20 Jan 2020 15:09:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jC0k5+vi62vV for ; Mon, 20 Jan 2020 15:08:57 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 2046D875B3 for ; Mon, 20 Jan 2020 15:08:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from elibr@mellanox.com) with ESMTPS (AES256-SHA encrypted); 20 Jan 2020 17:08:45 +0200 Received: from dev-r-vrt-215.mtr.labs.mlnx. (dev-r-vrt-215.mtr.labs.mlnx [10.212.215.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 00KF8hVC013116; Mon, 20 Jan 2020 17:08:45 +0200 From: Eli Britstein To: dev@openvswitch.org, Ilya Maximets Date: Mon, 20 Jan 2020 15:08:27 +0000 Message-Id: <20200120150830.16262-23-elibr@mellanox.com> X-Mailer: git-send-email 2.14.5 In-Reply-To: <20200120150830.16262-1-elibr@mellanox.com> References: <20200120150830.16262-1-elibr@mellanox.com> Cc: Simon Horman , Eli Britstein , Ameer Mahagneh Subject: [ovs-dev] [PATCH 22/25] netdev-dpdk-offload: Infrastructure for multiple rte_flows per UFID X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Ophir Munk When offloading a "dpdk" port, a single rte_flow is created and associated with the OVS flow UFID. For a vport (for example "vxlan"), multiple rte_flows (per uplink port) are created and should be associated. Introduce an infrastructure for that. Co-authored-by: Eli Britstein Signed-off-by: Ophir Munk Reviewed-by: Roni Bar Yanai Signed-off-by: Eli Britstein --- lib/netdev-offload-dpdk.c | 226 +++++++++++++++++++++++++++++++++------------- 1 file changed, 163 insertions(+), 63 deletions(-) diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 669110e4a..0bea84b39 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -62,16 +62,62 @@ struct act_resources { uint32_t flow_miss_ctx_id; }; +struct flow_item { + const char *devargs; + struct rte_flow *rte_flow; +}; + +struct flows_handle { + struct flow_item *items; + int cnt; + int current_max; +}; + struct ufid_to_rte_flow_data { struct cmap_node node; ovs_u128 ufid; - struct rte_flow *rte_flow; + struct flows_handle flows; bool actions_offloaded; struct dpif_flow_stats stats; struct act_resources act_resources; }; -/* Find rte_flow with @ufid. */ +static void +free_flow_handle(struct flows_handle *flows) +{ + int i; + + for (i = 0; i < flows->cnt; i++) { + if (flows->items[i].devargs) { + free(CONST_CAST(void *, flows->items[i].devargs)); + } + } + free(flows->items); + flows->items = NULL; + flows->cnt = 0; +} + +static void +add_flow_item(struct flows_handle *flows, + struct flow_item *item) +{ + int cnt = flows->cnt; + + if (cnt == 0) { + flows->current_max = 1; + flows->items = xcalloc(flows->current_max, sizeof *flows->items); + } else if (cnt == flows->current_max) { + flows->current_max *= 2; + flows->items = xrealloc(flows->items, flows->current_max * + sizeof *flows->items); + } + + flows->items[cnt].devargs = nullable_xstrdup(item->devargs); + flows->items[cnt].rte_flow = item->rte_flow; + flows->cnt++; +} + +/* Find rte_flow_data with @ufid. */ static struct ufid_to_rte_flow_data * ufid_to_rte_flow_data_find(const ovs_u128 *ufid) { @@ -89,7 +135,7 @@ ufid_to_rte_flow_data_find(const ovs_u128 *ufid) static inline void ufid_to_rte_flow_associate(const ovs_u128 *ufid, - struct rte_flow *rte_flow, bool actions_offloaded, + struct flows_handle *flows, bool actions_offloaded, struct act_resources *act_resources) { size_t hash = hash_bytes(ufid, sizeof *ufid, 0); @@ -104,12 +150,12 @@ ufid_to_rte_flow_associate(const ovs_u128 *ufid, */ data_prev = ufid_to_rte_flow_data_find(ufid); if (data_prev) { - ovs_assert(data_prev->rte_flow == NULL); + ovs_assert(data_prev->flows.cnt == 0); } data->ufid = *ufid; - data->rte_flow = rte_flow; data->actions_offloaded = actions_offloaded; + memcpy(&data->flows, flows, sizeof data->flows); memcpy(&data->act_resources, act_resources, sizeof data->act_resources); cmap_insert(&ufid_to_rte_flow, @@ -796,23 +842,25 @@ dump_flow(struct ds *s, return s; } -static struct rte_flow * +static int netdev_offload_dpdk_flow_create(struct netdev *netdev, const struct rte_flow_attr *attr, const struct rte_flow_item *items, const struct rte_flow_action *actions, - struct rte_flow_error *error) + struct rte_flow_error *error, + struct flow_item *fi) { - struct rte_flow *flow; struct ds s; - flow = netdev_dpdk_rte_flow_create(netdev, attr, items, actions, error); - if (flow) { + fi->rte_flow = netdev_dpdk_rte_flow_create(netdev, attr, items, actions, + error); + if (fi->rte_flow) { if (!VLOG_DROP_DBG(&rl)) { ds_init(&s); dump_flow(&s, attr, items, actions); VLOG_DBG_RL(&rl, "%s: rte_flow 0x%"PRIxPTR" created:\n%s", - netdev_get_name(netdev), (intptr_t) flow, ds_cstr(&s)); + netdev_get_name(netdev), (intptr_t) fi->rte_flow, + ds_cstr(&s)); ds_destroy(&s); } } else { @@ -830,7 +878,7 @@ netdev_offload_dpdk_flow_create(struct netdev *netdev, ds_destroy(&s); } } - return flow; + return fi->rte_flow ? 0 : -1; } static void @@ -1217,6 +1265,7 @@ netdev_offload_dpdk_mark_rss(struct flow_patterns *patterns, uint32_t flow_mark) { struct flow_actions actions = { .actions = NULL, .cnt = 0 }; + struct flow_item flow_item = { .devargs = NULL }; const struct rte_flow_attr flow_attr = { .group = 0, .priority = 0, @@ -1224,15 +1273,14 @@ netdev_offload_dpdk_mark_rss(struct flow_patterns *patterns, .egress = 0 }; struct rte_flow_error error; - struct rte_flow *flow; add_flow_mark_rss_actions(&actions, flow_mark, netdev); - flow = netdev_offload_dpdk_flow_create(netdev, &flow_attr, patterns->items, - actions.actions, &error); + netdev_offload_dpdk_flow_create(netdev, &flow_attr, patterns->items, + actions.actions, &error, &flow_item); free_flow_actions(&actions); - return flow; + return flow_item.rte_flow; } static void @@ -1632,16 +1680,16 @@ parse_flow_actions(struct netdev *netdev, return 0; } -static struct rte_flow * +static int netdev_offload_dpdk_actions(struct netdev *netdev, struct flow_patterns *patterns, struct nlattr *nl_actions, size_t actions_len, - struct act_resources *act_resources) + struct act_resources *act_resources, + struct flow_item *fi) { const struct rte_flow_attr flow_attr = { .ingress = 1, .transfer = 1 }; struct flow_actions actions = { .actions = NULL, .cnt = 0 }; - struct rte_flow *flow = NULL; struct rte_flow_error error; int ret; @@ -1650,11 +1698,11 @@ netdev_offload_dpdk_actions(struct netdev *netdev, if (ret) { goto out; } - flow = netdev_offload_dpdk_flow_create(netdev, &flow_attr, patterns->items, - actions.actions, &error); + ret = netdev_offload_dpdk_flow_create(netdev, &flow_attr, patterns->items, + actions.actions, &error, fi); out: free_flow_actions(&actions); - return flow; + return ret; } static int @@ -1666,9 +1714,10 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, struct offload_info *info) { struct flow_patterns patterns = { .items = NULL, .cnt = 0 }; + struct flows_handle flows = { .items = NULL, .cnt = 0 }; + struct flow_item flow_item = { .devargs = NULL }; struct act_resources act_resources; bool actions_offloaded = true; - struct rte_flow *flow; int ret = 0; memset(&act_resources, 0, sizeof act_resources); @@ -1678,24 +1727,27 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, goto out; } - flow = netdev_offload_dpdk_actions(netdev, &patterns, nl_actions, - actions_len, &act_resources); - if (!flow) { + ret = netdev_offload_dpdk_actions(netdev, &patterns, nl_actions, + actions_len, &act_resources, &flow_item); + if (ret) { /* If we failed to offload the rule actions fallback to MARK+RSS * actions. */ - flow = netdev_offload_dpdk_mark_rss(&patterns, netdev, - info->flow_mark); + flow_item.rte_flow = netdev_offload_dpdk_mark_rss(&patterns, netdev, + info->flow_mark); + ret = flow_item.rte_flow ? 0 : -1; actions_offloaded = false; } - if (!flow) { - ret = -1; + if (ret) { goto out; } - ufid_to_rte_flow_associate(ufid, flow, actions_offloaded, &act_resources); + add_flow_item(&flows, &flow_item); + ufid_to_rte_flow_associate(ufid, &flows, actions_offloaded, + &act_resources); VLOG_DBG("%s: installed flow %p by ufid "UUID_FMT"\n", - netdev_get_name(netdev), flow, UUID_ARGS((struct uuid *)ufid)); + netdev_get_name(netdev), flow_item.rte_flow, + UUID_ARGS((struct uuid *)ufid)); out: if (ret) { @@ -1708,29 +1760,57 @@ out: static int netdev_offload_dpdk_destroy_flow(struct netdev *netdev, const ovs_u128 *ufid, - struct rte_flow *rte_flow) + struct flows_handle *flows) { struct ufid_to_rte_flow_data *data; struct rte_flow_error error; - int ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, &error); + struct netdev *flow_netdev; + int ret; + int i; - if (ret == 0) { - data = ufid_to_rte_flow_data_find(ufid); - if (!data) { - VLOG_WARN("ufid "UUID_FMT" is not associated with an rte flow\n", - UUID_ARGS((struct uuid *) ufid)); - return -1; + for (i = 0; i < flows->cnt; i++) { + struct flow_item *fi = &flows->items[i]; + + if (fi->devargs) { + flow_netdev = netdev_dpdk_get_netdev_by_devargs(fi->devargs); + if (!flow_netdev) { + VLOG_DBG_RL(&rl, "%s: ufid "UUID_FMT": " + "could not find a netdev for devargs='%s'\n", + netdev_get_name(netdev), + UUID_ARGS((struct uuid *)ufid), fi->devargs); + continue; + } + } else { + flow_netdev = netdev; + netdev_ref(flow_netdev); } + ret = netdev_dpdk_rte_flow_destroy(flow_netdev, fi->rte_flow, &error); + if (!ret) { + VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT + "\n", netdev_get_name(flow_netdev), fi->rte_flow, + UUID_ARGS((struct uuid *)ufid)); + netdev_close(flow_netdev); + } else { + VLOG_ERR("%s: Failed to destroy flow: %s (%u)\n", + netdev_get_name(flow_netdev), error.message, error.type); + netdev_close(flow_netdev); + goto out; + } + } + + data = ufid_to_rte_flow_data_find(ufid); + if (data) { put_action_resources(&data->act_resources); ufid_to_rte_flow_disassociate(data); - VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT "\n", - netdev_get_name(netdev), rte_flow, - UUID_ARGS((struct uuid *)ufid)); + ret = 0; } else { - VLOG_ERR("%s: Failed to destroy flow: %s (%u)\n", - netdev_get_name(netdev), error.message, error.type); + VLOG_WARN("ufid "UUID_FMT" is not associated with rte flow(s)\n", + UUID_ARGS((struct uuid *) ufid)); + ret = -1; } +out: + free_flow_handle(flows); return ret; } @@ -1748,9 +1828,9 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, * Here destroy the old rte flow first before adding a new one. */ rte_flow_data = ufid_to_rte_flow_data_find(ufid); - if (rte_flow_data && rte_flow_data->rte_flow) { + if (rte_flow_data) { ret = netdev_offload_dpdk_destroy_flow(netdev, ufid, - rte_flow_data->rte_flow); + &rte_flow_data->flows); if (ret < 0) { return ret; } @@ -1770,7 +1850,7 @@ netdev_offload_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid, struct ufid_to_rte_flow_data *rte_flow_data; rte_flow_data = ufid_to_rte_flow_data_find(ufid); - if (!rte_flow_data || !rte_flow_data->rte_flow) { + if (!rte_flow_data) { return -1; } @@ -1778,7 +1858,7 @@ netdev_offload_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid, memset(stats, 0, sizeof *stats); } return netdev_offload_dpdk_destroy_flow(netdev, ufid, - rte_flow_data->rte_flow); + &rte_flow_data->flows); } static int @@ -1803,13 +1883,15 @@ netdev_offload_dpdk_flow_get(struct netdev *netdev, struct dpif_flow_attrs *attrs, struct ofpbuf *buf OVS_UNUSED) { - struct rte_flow_query_count query = { .reset = 1 }; struct ufid_to_rte_flow_data *rte_flow_data; + struct rte_flow_query_count query; struct rte_flow_error error; + struct netdev *flow_netdev; int ret = 0; + int i; rte_flow_data = ufid_to_rte_flow_data_find(ufid); - if (!rte_flow_data || !rte_flow_data->rte_flow) { + if (!rte_flow_data || rte_flow_data->flows.cnt == 0) { ret = -1; goto out; } @@ -1820,19 +1902,37 @@ netdev_offload_dpdk_flow_get(struct netdev *netdev, memset(stats, 0, sizeof *stats); goto out; } + attrs->dp_layer = "dpdk"; - ret = netdev_dpdk_rte_flow_query_count(netdev, rte_flow_data->rte_flow, - &query, &error); - if (ret) { - VLOG_DBG_RL(&rl, "%s: Failed to query ufid "UUID_FMT" flow: %p\n", - netdev_get_name(netdev), UUID_ARGS((struct uuid *) ufid), - rte_flow_data->rte_flow); - goto out; - } - rte_flow_data->stats.n_packets += (query.hits_set) ? query.hits : 0; - rte_flow_data->stats.n_bytes += (query.bytes_set) ? query.bytes : 0; - if (query.hits_set && query.hits) { - rte_flow_data->stats.used = time_msec(); + for (i = 0; i < rte_flow_data->flows.cnt; i++) { + struct flow_item *fi = &rte_flow_data->flows.items[i]; + + memset(&query, 0, sizeof query); + query.reset = 1; + if (rte_flow_data->flows.items[i].devargs) { + flow_netdev = netdev_dpdk_get_netdev_by_devargs(fi->devargs); + if (!flow_netdev) { + ret = -1; + goto out; + } + } else { + flow_netdev = netdev; + netdev_ref(flow_netdev); + } + ret = netdev_dpdk_rte_flow_query_count(flow_netdev, fi->rte_flow, + &query, &error); + if (ret) { + VLOG_DBG_RL(&rl, "%s: Failed to query ufid "UUID_FMT" flow: %p\n", + netdev_get_name(netdev), + UUID_ARGS((struct uuid *) ufid), fi->rte_flow); + goto out; + } + netdev_close(flow_netdev); + rte_flow_data->stats.n_packets += (query.hits_set) ? query.hits : 0; + rte_flow_data->stats.n_bytes += (query.bytes_set) ? query.bytes : 0; + if (query.hits_set && query.hits) { + rte_flow_data->stats.used = time_msec(); + } } memcpy(stats, &rte_flow_data->stats, sizeof *stats); out: