From patchwork Sun Jul 12 19:26:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sriharsha Basavapatna X-Patchwork-Id: 1327591 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=none (p=none dis=none) header.from=openvswitch.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=broadcom.com header.i=@broadcom.com header.a=rsa-sha256 header.s=google header.b=HCauatr0; dkim-atps=neutral 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 4B4cP91Jxrz9sR4 for ; Mon, 13 Jul 2020 05:32:29 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 5F1D788775; Sun, 12 Jul 2020 19:32:27 +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 aXKM06k9sTY4; Sun, 12 Jul 2020 19:32:26 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id 3224F8876F; Sun, 12 Jul 2020 19:32:26 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id F1A65C088E; Sun, 12 Jul 2020 19:32:25 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id B5716C0733 for ; Sun, 12 Jul 2020 19:32:24 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 9D19F88775 for ; Sun, 12 Jul 2020 19:32:24 +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 8W25vPmyStDJ for ; Sun, 12 Jul 2020 19:32:23 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mail-oi1-f195.google.com (mail-oi1-f195.google.com [209.85.167.195]) by whitealder.osuosl.org (Postfix) with ESMTPS id 5969B8876F for ; Sun, 12 Jul 2020 19:32:23 +0000 (UTC) Received: by mail-oi1-f195.google.com with SMTP id 12so9274701oir.4 for ; Sun, 12 Jul 2020 12:32:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=awnBGREzWaAlkieDI4wkqSg5/PDpcstrdyqJe+eLhRQ=; b=HCauatr0u6mSApzdtUQtKk55MyDxCgTu77GJnh/T579Bk5gUqWK/aS1S9L0Uml3oFk 6XUfGIgi4m8N9SgmROGjODE1gJX9eDhFatzagPVUCMnakztPhtUmiJD6D1sadFCVl6AE joxpvSbME3C+DdSVDS4un9ea+ROtxhfEd28JM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=awnBGREzWaAlkieDI4wkqSg5/PDpcstrdyqJe+eLhRQ=; b=DL5TkkO5eN1saKj0QUdjBpTIXphJ+hq5zrcHxacvKz9Hslmp1BABPbfQrsMEmg9So4 Nz22UU0v/3ONeDo51e4e850090o0n+OUtXRqwAaQSxsnotEuAbSRmu8X/ABYpiXJED8O TXtyPAYL48N/fgLwDwmaAP7tyxRUgJptCCaI7vOCiiwGdWDKj0PT+L5q55N85dLVbBdC vUm+wYy1PZt0Rqb28YyqXqOXMKpZ1DSt5ekEYi6R6b+lwkvt3qtAIZawF5HOopto3jrC 3XRP65mbrhf+erteoa5LO23s3DRlcsz7OnQ3srnNXCqbHMlcMD29IUod/nSb3RUnf8eW ihdQ== X-Gm-Message-State: AOAM530vcSwbp5QD2q4/bFTBE2LwogtxiaIysegtvoVT1ixiUQyWDy0d JOMCSfVYYqpQ1LADGO4/HvEyHqNX7l8CCQ01UuaV6p7KDAEm6XXF32GudMY8zb1IVlOBD0kYjY8 0nqOlo9cIXGclb/hmQyT8xb1kR/GEkKug8m0Mnsgt0FRWV1mqTO4uoCm8m6owTVN5rdHDDi/owU 1Qq5AA X-Google-Smtp-Source: ABdhPJzpts2WlFU9UaanyApuGfe0vF0eB82uc+pcjQ52TZwna9B2POuDhuDQR3FWMPZtxo1zkoWRbw== X-Received: by 2002:a17:90a:1b2c:: with SMTP id q41mr16507021pjq.195.1594582017826; Sun, 12 Jul 2020 12:26:57 -0700 (PDT) Received: from dhcp-10-123-153-36.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id 17sm9124023pjl.30.2020.07.12.12.26.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 12 Jul 2020 12:26:56 -0700 (PDT) To: dev@openvswitch.org Date: Sun, 12 Jul 2020 15:26:24 -0400 Message-Id: <20200712192625.7359-8-sriharsha.basavapatna@broadcom.com> X-Mailer: git-send-email 2.25.0.rc2 In-Reply-To: <20200712192625.7359-1-sriharsha.basavapatna@broadcom.com> References: <20200712192625.7359-1-sriharsha.basavapatna@broadcom.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH v6 7/8] dpif-netdev: Support partial offload of POP_VLAN action 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: , X-Patchwork-Original-From: Sriharsha Basavapatna via dev From: Sriharsha Basavapatna Reply-To: Sriharsha Basavapatna Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" If the output-port is a vhost-user port and the action is POP_VLAN, offload the action on the ingress device if it is offload capable. Note: - With ingress partial action offload, the flow must be added to the mark-to-flow table. Otherwise, since the action (e.g, POP_VLAN) is already performed in the HW, the flow can't be located in the datapath flow tables and caches. - The mark action is offloaded implicitly to facilitate this mark-to-flow lookup. - Add a new member 'partial_actions_offloaded' to the info structure passed to the offload layer. When the offload layer successfully offloads the partial action, it indicates this to the dpif-netdev layer through this flag. This is needed by the dpif-netdev layer to distinguish partial offload (i.e, classification offload or mark,rss actions) from partial actions offload (classification + some actions, e.g vlan-pop,mark actions) in ingress direction. Signed-off-by: Sriharsha Basavapatna --- lib/dpif-netdev.c | 61 ++++++++++++++++++---- lib/netdev-offload-dpdk.c | 97 ++++++++++++++++++++++++++++++++--- lib/netdev-offload-provider.h | 6 +++ lib/netdev-offload.c | 35 +++++++++++++ lib/netdev-offload.h | 4 ++ 5 files changed, 186 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 53f07fc44..60de686bd 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -115,6 +115,7 @@ COVERAGE_DEFINE(datapath_drop_invalid_tnl_port); COVERAGE_DEFINE(datapath_drop_rx_invalid_packet); COVERAGE_DEFINE(datapath_skip_tunnel_push); COVERAGE_DEFINE(datapath_skip_vlan_push); +COVERAGE_DEFINE(datapath_skip_vlan_pop); /* Protects against changes to 'dp_netdevs'. */ static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER; @@ -2551,6 +2552,28 @@ dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) } } +/* This function determines if the given flow actions can be partially + * offloaded. Partial action offload is attempted when either the in-port + * or the out-port for the flow is a vhost-user port. + */ +static bool +should_partial_offload(struct netdev *in_netdev, const char *dpif_type, + struct match *match, struct nlattr *actions, + size_t act_len, struct netdev **egress_netdev, + odp_port_t *egress_port) +{ + if (netdev_partial_offload_ingress(in_netdev, dpif_type, match, actions, + act_len)) { + return true; + } else if (netdev_partial_offload_egress(in_netdev, dpif_type, match, + actions, act_len, egress_netdev, + egress_port)) { + return true; + } else { + return false; + } +} + static int dp_netdev_alloc_flow_mark(struct dp_netdev_flow *flow, bool modification, uint32_t *markp) @@ -2626,14 +2649,14 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) info.attr_egress = 0; info.partial_actions = 0; - - if (unlikely(netdev_partial_offload_egress(netdev, dpif_type_str, - &offload->match, - CONST_CAST(struct nlattr *, - offload->actions), - offload->actions_len, - &egress_netdev, - &egress_port))) { + info.partial_actions_offloaded = 0; + + if (unlikely(should_partial_offload(netdev, dpif_type_str, &offload->match, + CONST_CAST(struct nlattr *, + offload->actions), + offload->actions_len, + &egress_netdev, + &egress_port))) { if (egress_netdev) { netdev_close(netdev); netdev = egress_netdev; @@ -2666,12 +2689,14 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) goto err_free; } - if (unlikely(info.partial_actions && egress_netdev)) { + if (unlikely(info.partial_actions && info.partial_actions_offloaded)) { VLOG_DBG_RL("%s: flow: %p mega_ufid: "UUID_FMT" pmd_id: %d\n", __func__, flow, UUID_ARGS((struct uuid *)&flow->mega_ufid), flow->pmd_id); flow->partial_actions_offloaded = true; - } else if (!modification) { + } + + if (!modification && alloc_mark) { megaflow_to_mark_associate(&flow->mega_ufid, mark); mark_to_flow_associate(mark, flow); } @@ -7529,6 +7554,7 @@ dp_netdev_assist_cb(void *dp OVS_UNUSED, const struct nlattr *a) switch (type) { case OVS_ACTION_ATTR_PUSH_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: return true; default: return false; @@ -7903,7 +7929,20 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, break; } - case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: { + struct dp_packet *packet; + + if (!dp_flow || !dp_flow->partial_actions_offloaded) { + DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) { + eth_pop_vlan(packet); + } + } else { + packet_count = dp_packet_batch_size(packets_); + COVERAGE_ADD(datapath_skip_vlan_pop, packet_count); + } + break; + } + case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_SET: diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 449333248..a4da03e62 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -1347,8 +1347,11 @@ parse_flow_actions(struct netdev *netdev, } NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { - if (add_output_action(netdev, actions, nla)) { - return -1; + /* add output action only if full-offload */ + if (!info->partial_actions) { + if (add_output_action(netdev, actions, nla)) { + return -1; + } } } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL); @@ -1390,6 +1393,13 @@ parse_flow_actions(struct netdev *netdev, return -1; } + if (info->partial_actions && !info->attr_egress) { + struct rte_flow_action_mark *mark = xzalloc(sizeof *mark); + + mark->id = info->flow_mark; + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_MARK, mark); + } + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL); return 0; } @@ -1407,9 +1417,11 @@ netdev_offload_dpdk_actions(struct netdev *netdev, struct rte_flow_error error; int ret; - if (info->attr_egress) { - flow_attr.ingress = 0; - flow_attr.egress = 1; + if (info->partial_actions) { + if (info->attr_egress) { + flow_attr.ingress = 0; + flow_attr.egress = 1; + } flow_attr.transfer = 0; } @@ -1447,11 +1459,12 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, flow = netdev_offload_dpdk_actions(netdev, &patterns, nl_actions, actions_len, info); if (flow) { - if (info->partial_actions && info->attr_egress) { + if (info->partial_actions) { /* actions_offloaded should be set to false with partial actions, * since it is still considered as partial-offload and not * full-offload. */ actions_offloaded = false; + info->partial_actions_offloaded = 1; } } else if (!(info->partial_actions && info->attr_egress)) { /* If we failed to offload the rule actions fallback to MARK+RSS @@ -1518,6 +1531,7 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, VLOG_DBG_RL("%s: mega_ufid: "UUID_FMT" refcnt: %d\n", __func__, UUID_ARGS((struct uuid *)ufid), rte_flow_data->refcnt); rte_flow_data->refcnt++; + info->partial_actions_offloaded = 1; return ret; } else { /* @@ -1635,6 +1649,18 @@ enum num_action_attr_egress { MAX_ACTION_ATTRS_EGRESS = TUNNEL_PUSH_ATTRS }; +/* + * Maxium number of actions to be parsed while selecting a flow for ingress + * partial action offload. This number is currently based on the minimum + * number of attributes seen with the vlan pop action (vlan_pop, output). + * This number includes output action to a single vhost device (uplink) and + * does not support multiple output actions. + */ +enum num_action_attr_ingress { + VLAN_POP_ATTRS = 2, /* vlan_pop, output */ + MAX_ACTION_ATTRS_INGRESS = VLAN_POP_ATTRS +}; + /* * This function parses the list of OVS "actions" of length "actions_len", * and returns them in an array of action "attrs", of size "max_attrs". @@ -1682,6 +1708,64 @@ parse_nlattr_actions(struct nlattr *actions, size_t actions_len, return 0; } +/* This function determines if the given flow should be partially offloaded + * on the ingress device, when the out-port is not offload-capable like a + * vhost-user port. The function currently supports offloading of only + * vlan-pop action. + */ +static bool +netdev_offload_dpdk_ingress_partial(struct netdev *netdev, + struct match *match, + struct nlattr *actions, + size_t actions_len) +{ + struct action_attr attrs[MAX_ACTION_ATTRS_INGRESS]; + odp_port_t out_port = ODPP_NONE; + struct netdev *out_netdev; + int num_attrs = 0; + int type; + int rc; + + /* Support ingress partial-offload only + * when the in-port supports offloads. + */ + if (!netdev_dpdk_flow_api_supported(netdev)) { + return false; + } + + rc = parse_nlattr_actions(actions, actions_len, attrs, + MAX_ACTION_ATTRS_INGRESS, &num_attrs); + if (rc == E2BIG) { + /* Action list too big; decline partial offload */ + return false; + } + + /* Minimum number of attrs expected (pop_vlan) */ + if (num_attrs < VLAN_POP_ATTRS) { + return false; + } + + if (num_attrs == VLAN_POP_ATTRS && + (attrs[0].type != OVS_ACTION_ATTR_POP_VLAN || + attrs[1].type != OVS_ACTION_ATTR_OUTPUT)) { + return false; + } + + /* Ingress partial-offload needs an output action at the end. */ + out_port = nl_attr_get_odp_port(attrs[num_attrs - 1].action); + if (out_port == ODPP_NONE) { + return false; + } + + /* Support ingress partial-offload only if out-port is vhost-user. */ + out_netdev = netdev_ports_get(out_port, netdev->dpif_type); + if (out_netdev && is_dpdk_vhost_netdev(out_netdev)) { + return true; + } + + return false; +} + /* This function determines if the given flow should be partially offloaded * on the egress device, when the in-port is not offload-capable like a * vhost-user port. The function currently supports offloading of only @@ -1754,4 +1838,5 @@ const struct netdev_flow_api netdev_offload_dpdk = { .init_flow_api = netdev_offload_dpdk_init_flow_api, .flow_get = netdev_offload_dpdk_flow_get, .flow_offload_egress_partial = netdev_offload_dpdk_egress_partial, + .flow_offload_ingress_partial = netdev_offload_dpdk_ingress_partial, }; diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h index 94973b24d..f0e944281 100644 --- a/lib/netdev-offload-provider.h +++ b/lib/netdev-offload-provider.h @@ -93,6 +93,12 @@ struct netdev_flow_api { bool (*flow_offload_egress_partial)(struct netdev *, struct match *, struct nlattr *, size_t, struct netdev **, odp_port_t *); + + /* Determine if the flow should be partial offloaded to the ingress + * device and if yes return true; otherwise return false. + */ + bool (*flow_offload_ingress_partial)(struct netdev *, struct match *, + struct nlattr *, size_t); }; int netdev_register_flow_api_provider(const struct netdev_flow_api *); diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c index 4fee717d9..9ce9bfb8b 100644 --- a/lib/netdev-offload.c +++ b/lib/netdev-offload.c @@ -733,3 +733,38 @@ netdev_partial_offload_egress(struct netdev *netdev, const char *dpif_type, netdev_close(flow_api_netdev); return true; } + +bool +netdev_partial_offload_ingress(struct netdev *netdev, const char *dpif_type, + struct match *match, struct nlattr *actions, + size_t act_len) +{ + struct netdev *flow_api_netdev; + struct port_to_netdev_data *data; + struct netdev_flow_api *flow_api = + ovsrcu_get(const struct netdev_flow_api *, &netdev->flow_api); + + /* Ingress netdev is not offload capable */ + if (!flow_api) { + return false; + } + + /* Ingress netdev must belong to the datapath specified */ + if (netdev_get_dpif_type(netdev) != dpif_type) { + return false; + } + + /* flow_api does not support ingress partial offload */ + if (!flow_api->flow_offload_ingress_partial) { + return false; + } + + /* Can the flow be partial offloaded to the ingress dev ? */ + if (!flow_api->flow_offload_ingress_partial(netdev, match, actions, + act_len)) { + return false; + } + + /* Success */ + return true; +} diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index 66b31af59..bf782fa29 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -69,6 +69,7 @@ struct offload_info { * sync with datapath recirc ids. */ uint8_t attr_egress; /* Egress direction offload */ uint8_t partial_actions; /* Partial action offload; no forward action */ + uint8_t partial_actions_offloaded; /* Success flag */ /* * The flow mark id assigened to the flow. If any pkts hit the flow, @@ -131,6 +132,9 @@ bool netdev_partial_offload_egress(struct netdev *netdev, struct nlattr *actions, size_t act_len, struct netdev **egress_netdev, odp_port_t *egress_port); +bool netdev_partial_offload_ingress(struct netdev *netdev, + const char *dpif_type, struct match *match, + struct nlattr *actions, size_t act_len); #ifdef __cplusplus } #endif