From patchwork Mon Apr 15 14:56:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Horman X-Patchwork-Id: 1085682 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="gVkPtAaa"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44jWmL14k3z9s8m for ; Tue, 16 Apr 2019 00:56:34 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727860AbfDOO4c (ORCPT ); Mon, 15 Apr 2019 10:56:32 -0400 Received: from mail-ed1-f66.google.com ([209.85.208.66]:36983 "EHLO mail-ed1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727838AbfDOO4b (ORCPT ); Mon, 15 Apr 2019 10:56:31 -0400 Received: by mail-ed1-f66.google.com with SMTP id f53so13392771ede.4 for ; Mon, 15 Apr 2019 07:56:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wiISF+6XC3SDzhv/q7mJfr+85GCnFqV+G+AHvzsf9Jo=; b=gVkPtAaaHMszjr6UD0IS1d70xOJl1//cEq94/17hkWqV6wOL4BzlhZlmu4MejjDXhZ z5R3hQTaxEvk5zxr7HI4fZ2k9Q5CmaBImfMgqHXW7qK5Pear0isCCgGV8oJ/U5zohjEr sZjTShNMPpoalQ/BpuKUrnZ3hh2AmD8rxkuO70d7rNPSrDIxw0oPlyI5Q1ODDtSU+uCa DJXki7pGygA8FT1X5CK1B27DPnj517Z6w0SlmkjjpV7MS1w2IVpStUgSAzxkxNpsEx4l HaBWKgtqUlvt5ROlhlb8+ZLXQ+O4Uy4ZmzG2wnevboBGvnfU3QHlBcLSkCtV3g7zhcY5 8AJw== 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; bh=wiISF+6XC3SDzhv/q7mJfr+85GCnFqV+G+AHvzsf9Jo=; b=EY1XVf84ZUZzhIUB5AZ6qBtz4q+lxY8BxHGLEBzZHRpwcOYadnobdk9ALz6EAybBEO QW+TNRN3H0eE2B7mchmMI8M0K/ZmF4ECllOAmfC0z6IcWTRIhRhQwl33YrO5en8bgZ72 Ny0inyqL7oEXf8jkYVrUjfDYFiwIu3UhMWB53UKEI8b3PlAeJ0P0bI0aO/UKSCfwmRo1 Vdw7n2/n0tW0FFJrHQgU1dmj9OknUnALNNAJPOkwCAhW3A/qRdHBGrfq38I1SLbFgPLd axxQaATreXgFUkPFqpl82HW5nth9yp9tHp2yhB6BL4Zqp1XgdzpMpDqOQcpRLN67BlPF u2xg== X-Gm-Message-State: APjAAAVuPwRj2bFvnEkCEqmXi+D1A5zKWG0MsPgTUODLkGTIhMEvxW+H 9p6hb0giMBXswRy6zVHD/amWr5r6Txdy3+iy X-Google-Smtp-Source: APXvYqwMBVfBCBJfezqvzCVHxdo2ipWblKZY3eTJIRUGhrXHSHYvhqHKg1AnlDVndT5e/0XW4gg7Cw== X-Received: by 2002:a50:a725:: with SMTP id h34mr47706118edc.201.1555340188035; Mon, 15 Apr 2019 07:56:28 -0700 (PDT) Received: from reginn.horms.nl ([2001:982:756:703:d63d:7eff:fe99:ac9d]) by smtp.gmail.com with ESMTPSA id c38sm2540023ede.61.2019.04.15.07.56.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 15 Apr 2019 07:56:27 -0700 (PDT) From: Simon Horman To: David Miller , Jakub Kicinski Cc: netdev@vger.kernel.org, oss-drivers@netronome.com, John Hurley , Simon Horman Subject: [PATCH net-next 09/11] nfp: flower: generate merge flow rule Date: Mon, 15 Apr 2019 16:56:01 +0200 Message-Id: <20190415145603.32491-10-simon.horman@netronome.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190415145603.32491-1-simon.horman@netronome.com> References: <20190415145603.32491-1-simon.horman@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: John Hurley When combining 2 sub_flows to a single 'merge flow' (assuming the merge is valid), the merge flow should contain the same match fields as sub_flow 1 with actions derived from a combination of sub_flows 1 and 2. This action list should have all actions from sub_flow 1 with the exception of the output action that triggered the 'implicit recirculation' by sending to an internal port, followed by all actions of sub_flow 2. Any pre-actions in either sub_flow should feature at the start of the action list. Add code to generate a new merge flow and populate the match and actions fields based on the sub_flows. The offloading of the flow is left to future patches. Signed-off-by: John Hurley Signed-off-by: Simon Horman --- drivers/net/ethernet/netronome/nfp/flower/main.h | 9 ++ .../net/ethernet/netronome/nfp/flower/offload.c | 142 ++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 311daffb897d..df49cf9d73b3 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -279,6 +279,15 @@ nfp_flower_internal_port_can_offload(struct nfp_app *app, return false; } +/* The address of the merged flow acts as its cookie. + * Cookies supplied to us by TC flower are also addresses to allocated + * memory and thus this scheme should not generate any collisions. + */ +static inline bool nfp_flower_is_merge_flow(struct nfp_fl_payload *flow_pay) +{ + return flow_pay->tc_flower_cookie == (unsigned long)flow_pay; +} + int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, unsigned int host_ctx_split); void nfp_flower_metadata_cleanup(struct nfp_app *app); diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 24e23cba0985..1e329667249d 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -610,6 +610,112 @@ nfp_flower_can_merge(struct nfp_fl_payload *sub_flow1, return 0; } +static unsigned int +nfp_flower_copy_pre_actions(char *act_dst, char *act_src, int len, + bool *tunnel_act) +{ + unsigned int act_off = 0, act_len; + struct nfp_fl_act_head *a; + u8 act_id = 0; + + while (act_off < len) { + a = (struct nfp_fl_act_head *)&act_src[act_off]; + act_len = a->len_lw << NFP_FL_LW_SIZ; + act_id = a->jump_id; + + switch (act_id) { + case NFP_FL_ACTION_OPCODE_PRE_TUNNEL: + if (tunnel_act) + *tunnel_act = true; + case NFP_FL_ACTION_OPCODE_PRE_LAG: + memcpy(act_dst + act_off, act_src + act_off, act_len); + break; + default: + return act_off; + } + + act_off += act_len; + } + + return act_off; +} + +static int nfp_fl_verify_post_tun_acts(char *acts, int len) +{ + struct nfp_fl_act_head *a; + unsigned int act_off = 0; + + while (act_off < len) { + a = (struct nfp_fl_act_head *)&acts[act_off]; + if (a->jump_id != NFP_FL_ACTION_OPCODE_OUTPUT) + return -EOPNOTSUPP; + + act_off += a->len_lw << NFP_FL_LW_SIZ; + } + + return 0; +} + +static int +nfp_flower_merge_action(struct nfp_fl_payload *sub_flow1, + struct nfp_fl_payload *sub_flow2, + struct nfp_fl_payload *merge_flow) +{ + unsigned int sub1_act_len, sub2_act_len, pre_off1, pre_off2; + bool tunnel_act = false; + char *merge_act; + int err; + + /* The last action of sub_flow1 must be output - do not merge this. */ + sub1_act_len = sub_flow1->meta.act_len - sizeof(struct nfp_fl_output); + sub2_act_len = sub_flow2->meta.act_len; + + if (!sub2_act_len) + return -EINVAL; + + if (sub1_act_len + sub2_act_len > NFP_FL_MAX_A_SIZ) + return -EINVAL; + + /* A shortcut can only be applied if there is a single action. */ + if (sub1_act_len) + merge_flow->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); + else + merge_flow->meta.shortcut = sub_flow2->meta.shortcut; + + merge_flow->meta.act_len = sub1_act_len + sub2_act_len; + merge_act = merge_flow->action_data; + + /* Copy any pre-actions to the start of merge flow action list. */ + pre_off1 = nfp_flower_copy_pre_actions(merge_act, + sub_flow1->action_data, + sub1_act_len, &tunnel_act); + merge_act += pre_off1; + sub1_act_len -= pre_off1; + pre_off2 = nfp_flower_copy_pre_actions(merge_act, + sub_flow2->action_data, + sub2_act_len, NULL); + merge_act += pre_off2; + sub2_act_len -= pre_off2; + + /* FW does a tunnel push when egressing, therefore, if sub_flow 1 pushes + * a tunnel, sub_flow 2 can only have output actions for a valid merge. + */ + if (tunnel_act) { + char *post_tun_acts = &sub_flow2->action_data[pre_off2]; + + err = nfp_fl_verify_post_tun_acts(post_tun_acts, sub2_act_len); + if (err) + return err; + } + + /* Copy remaining actions from sub_flows 1 and 2. */ + memcpy(merge_act, sub_flow1->action_data + pre_off1, sub1_act_len); + merge_act += sub1_act_len; + memcpy(merge_act, sub_flow2->action_data + pre_off2, sub2_act_len); + + return 0; +} + /** * nfp_flower_merge_offloaded_flows() - Merge 2 existing flows to single flow. * @app: Pointer to the APP handle @@ -625,13 +731,47 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app, struct nfp_fl_payload *sub_flow1, struct nfp_fl_payload *sub_flow2) { + struct nfp_fl_payload *merge_flow; + struct nfp_fl_key_ls merge_key_ls; int err; + ASSERT_RTNL(); + + if (sub_flow1 == sub_flow2 || + nfp_flower_is_merge_flow(sub_flow1) || + nfp_flower_is_merge_flow(sub_flow2)) + return -EINVAL; + err = nfp_flower_can_merge(sub_flow1, sub_flow2); if (err) return err; - return -EOPNOTSUPP; + merge_key_ls.key_size = sub_flow1->meta.key_len; + + merge_flow = nfp_flower_allocate_new(&merge_key_ls); + if (!merge_flow) + return -ENOMEM; + + merge_flow->tc_flower_cookie = (unsigned long)merge_flow; + merge_flow->ingress_dev = sub_flow1->ingress_dev; + + memcpy(merge_flow->unmasked_data, sub_flow1->unmasked_data, + sub_flow1->meta.key_len); + memcpy(merge_flow->mask_data, sub_flow1->mask_data, + sub_flow1->meta.mask_len); + + err = nfp_flower_merge_action(sub_flow1, sub_flow2, merge_flow); + if (err) + goto err_destroy_merge_flow; + + err = -EOPNOTSUPP; + +err_destroy_merge_flow: + kfree(merge_flow->action_data); + kfree(merge_flow->mask_data); + kfree(merge_flow->unmasked_data); + kfree(merge_flow); + return err; } /**