From patchwork Wed Feb 27 18:28:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Hurley X-Patchwork-Id: 1049096 X-Patchwork-Delegate: horms@verge.net.au Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="TNu/Xj/H"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 448kwv4JQDz9s21 for ; Thu, 28 Feb 2019 05:39:11 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9C4C995EB; Wed, 27 Feb 2019 18:38:18 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 8BD789558 for ; Wed, 27 Feb 2019 18:29:32 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-ed1-f66.google.com (mail-ed1-f66.google.com [209.85.208.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 22F4A806 for ; Wed, 27 Feb 2019 18:29:31 +0000 (UTC) Received: by mail-ed1-f66.google.com with SMTP id m35so14728821ede.10 for ; Wed, 27 Feb 2019 10:29:30 -0800 (PST) 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=XNahzZJWtrjevNQwpTPUrOZKC2gy7Wd2FQgSyM9f8sY=; b=TNu/Xj/H+RhxiWA3CrLmhaBChNY/fcAa3WND/nahrSRvq7WNAVFynzKGmI8ST8Xvvx ahxhStNySp8rQbluMVRqryz9fO5QbUFIyeuahK5ZGhpRocilnsR1C7QgYqz4nebsYa0j MLNU+vsBKPjEvLiopJ3nWQuGq8+SyCFp2ywtIGQM6g2VojWeBmX3xlG5H2en60JT9kcS bk0SwhEczX9e34kyFuv2Ek/PoyrjcxRZFu0v0jvInqXa7G7dchm6g8z4wcEH0fqnO1CJ ShsXVaGMvPXNF4SDRD2nEqp4aZqa64YVAnxVNWeVSzfnqCieAIXogwqqNQ6dim05bAhA VCxQ== 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=XNahzZJWtrjevNQwpTPUrOZKC2gy7Wd2FQgSyM9f8sY=; b=WkpdFn6YGzPcjOiDOVIcIIH0pC1Pg6NTfy1L+6RLRyvK35E1yRIzkBoJ+LxfTXkza/ keaXTiquuSR+DrRQo0k54VSOtAa2nyf0iNjeVeF/0LgbjGM7Y7Q+ycNn6qogjK/Mk726 LBH1XWmXLYPWfGHiQ/sayyxsttJIiN+jVTlRGExR3m2KJg8KNV/bxk/M5/hyjqwYWWrL aZYaii4VICGnD6tPIWkA340BzUc7KGuX5aN4FQtBm+eXDQrZERHzu7nQkEZTYBDFI9eW CqWrWa6TCDhldDZF+Z9IsVEcQSWBtrC0I8jjmBhIBIyws8peSisfxHjhmjEWYU4sn+ak vLVw== X-Gm-Message-State: AHQUAuYz+EAOS8O77ztAgoq6x+3g9qS0HQJ3/SdrvqNPmeAR5tcZ7pJg 4r+p2qNCD6FCz7Agm/ctB1QSqq353yM= X-Google-Smtp-Source: AHgI3IaHNX7WkY+l2OIUPc9q/nT3NPX8Y2vUYkMsQih73+rXDY5KRm2A1UU0m0kTZfYCqR2MLi6Wkg== X-Received: by 2002:a17:906:6992:: with SMTP id i18mr2545640ejr.224.1551292169059; Wed, 27 Feb 2019 10:29:29 -0800 (PST) Received: from jhurley-Precision-Tower-3420.netronome.com ([80.76.204.157]) by smtp.gmail.com with ESMTPSA id e53sm4387615ede.26.2019.02.27.10.29.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 Feb 2019 10:29:28 -0800 (PST) From: John Hurley To: dev@openvswitch.org, roid@mellanox.com, fbl@sysclose.org, simon.horman@netronome.com Date: Wed, 27 Feb 2019 18:28:47 +0000 Message-Id: <1551292128-4632-2-git-send-email-john.hurley@netronome.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1551292128-4632-1-git-send-email-john.hurley@netronome.com> References: <1551292128-4632-1-git-send-email-john.hurley@netronome.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC OVS 1/2] ovs-tc: allow offloading TC rules to egress qdiscs X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Offloading rules to a TC datapath only allows the creating of ingress hook qdiscs and the application of filters to these. However, there may be certain situations where an egress qdisc is more applicable (e.g. when offloading to TC rules applied to OvS internal ports). Extend the TC API in OvS to allow the creation of egress qdisc and to add or interact with flower filters applied to these. Signed-off-by: John Hurley Reviewed-by: Simon Horman --- lib/netdev-linux.c | 8 ++++---- lib/netdev-tc-offloads.c | 30 +++++++++++++++--------------- lib/tc.c | 45 ++++++++++++++++++++++++++++++--------------- lib/tc.h | 20 ++++++++++++++------ 4 files changed, 63 insertions(+), 40 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 25d037c..8d37eb6 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -740,7 +740,7 @@ netdev_linux_update_lag(struct rtnetlink_change *change) /* LAG master is linux netdev so add slave to same block. */ error = tc_add_del_ingress_qdisc(change->if_index, true, - block_id); + block_id, false); if (error) { VLOG_WARN("failed to bind LAG slave to master's block"); shash_delete(&lag_shash, lag->node); @@ -756,7 +756,7 @@ netdev_linux_update_lag(struct rtnetlink_change *change) if (lag) { tc_add_del_ingress_qdisc(change->if_index, false, - lag->block_id); + lag->block_id, false); shash_delete(&lag_shash, lag->node); free(lag); } @@ -2370,7 +2370,7 @@ netdev_linux_set_policing(struct netdev *netdev_, COVERAGE_INC(netdev_set_policing); /* Remove any existing ingress qdisc. */ - error = tc_add_del_ingress_qdisc(ifindex, false, 0); + error = tc_add_del_ingress_qdisc(ifindex, false, 0, false); if (error) { VLOG_WARN_RL(&rl, "%s: removing policing failed: %s", netdev_name, ovs_strerror(error)); @@ -2378,7 +2378,7 @@ netdev_linux_set_policing(struct netdev *netdev_, } if (kbits_rate) { - error = tc_add_del_ingress_qdisc(ifindex, true, 0); + error = tc_add_del_ingress_qdisc(ifindex, true, 0, false); if (error) { VLOG_WARN_RL(&rl, "%s: adding policing qdisc failed: %s", netdev_name, ovs_strerror(error)); diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 36bce15..31ad9f4 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -182,7 +182,7 @@ del_filter_and_ufid_mapping(int ifindex, int prio, int handle, { int err; - err = tc_del_filter(ifindex, prio, handle, block_id); + err = tc_del_filter(ifindex, prio, handle, block_id, false); del_ufid_tc_mapping(ufid); return err; @@ -350,7 +350,7 @@ netdev_tc_flow_flush(struct netdev *netdev) block_id = get_block_id_from_netdev(netdev); - return tc_flush(ifindex, block_id); + return tc_flush(ifindex, block_id, false); } int @@ -372,7 +372,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev, dump = xzalloc(sizeof *dump); dump->nl_dump = xzalloc(sizeof *dump->nl_dump); dump->netdev = netdev_ref(netdev); - tc_dump_flower_start(ifindex, dump->nl_dump, block_id); + tc_dump_flower_start(ifindex, dump->nl_dump, block_id, false); *dump_out = dump; @@ -1347,7 +1347,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.act_cookie.data = ufid; flower.act_cookie.len = sizeof *ufid; - err = tc_replace_flower(ifindex, prio, handle, &flower, block_id); + err = tc_replace_flower(ifindex, prio, handle, &flower, block_id, false); if (!err) { add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex); } @@ -1390,7 +1390,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d)", netdev_get_name(dev), prio, handle); block_id = get_block_id_from_netdev(netdev); - err = tc_get_flower(ifindex, prio, handle, &flower, block_id); + err = tc_get_flower(ifindex, prio, handle, &flower, block_id, false); netdev_close(dev); if (err) { VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s", @@ -1437,7 +1437,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, if (stats) { memset(stats, 0, sizeof *stats); - if (!tc_get_flower(ifindex, prio, handle, &flower, block_id)) { + if (!tc_get_flower(ifindex, prio, handle, &flower, block_id, false)) { stats->n_packets = get_32aligned_u64(&flower.stats.n_packets); stats->n_bytes = get_32aligned_u64(&flower.stats.n_bytes); stats->used = flower.lastused; @@ -1458,7 +1458,7 @@ probe_multi_mask_per_prio(int ifindex) int block_id = 0; int error; - error = tc_add_del_ingress_qdisc(ifindex, true, block_id); + error = tc_add_del_ingress_qdisc(ifindex, true, block_id, false); if (error) { return; } @@ -1470,7 +1470,7 @@ probe_multi_mask_per_prio(int ifindex) memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac); memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac); - error = tc_replace_flower(ifindex, 1, 1, &flower, block_id); + error = tc_replace_flower(ifindex, 1, 1, &flower, block_id, false); if (error) { goto out; } @@ -1478,20 +1478,20 @@ probe_multi_mask_per_prio(int ifindex) memset(&flower.key.src_mac, 0x11, sizeof flower.key.src_mac); memset(&flower.mask.src_mac, 0xff, sizeof flower.mask.src_mac); - error = tc_replace_flower(ifindex, 1, 2, &flower, block_id); - tc_del_filter(ifindex, 1, 1, block_id); + error = tc_replace_flower(ifindex, 1, 2, &flower, block_id, false); + tc_del_filter(ifindex, 1, 1, block_id, false); if (error) { goto out; } - tc_del_filter(ifindex, 1, 2, block_id); + tc_del_filter(ifindex, 1, 2, block_id, false); multi_mask_per_prio = true; VLOG_INFO("probe tc: multiple masks on single tc prio is supported."); out: - tc_add_del_ingress_qdisc(ifindex, false, block_id); + tc_add_del_ingress_qdisc(ifindex, false, block_id, false); } static void @@ -1500,12 +1500,12 @@ probe_tc_block_support(int ifindex) uint32_t block_id = 1; int error; - error = tc_add_del_ingress_qdisc(ifindex, true, block_id); + error = tc_add_del_ingress_qdisc(ifindex, true, block_id, false); if (error) { return; } - tc_add_del_ingress_qdisc(ifindex, false, block_id); + tc_add_del_ingress_qdisc(ifindex, false, block_id, false); block_support = true; VLOG_INFO("probe tc: block offload is supported."); @@ -1538,7 +1538,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) } block_id = get_block_id_from_netdev(netdev); - error = tc_add_del_ingress_qdisc(ifindex, true, block_id); + error = tc_add_del_ingress_qdisc(ifindex, true, block_id, false); if (error && error != EEXIST) { VLOG_ERR("failed adding ingress qdisc required for offloading: %s", diff --git a/lib/tc.c b/lib/tc.c index 2d42003..441115a 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -219,7 +219,7 @@ tc_transact(struct ofpbuf *request, struct ofpbuf **replyp) * Returns 0 if successful, otherwise a positive errno value. */ int -tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id) +tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id, bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -228,11 +228,19 @@ tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id) int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0; tcmsg = tc_make_request(ifindex, type, flags, &request); - tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0); - tcmsg->tcm_parent = TC_H_INGRESS; - nl_msg_put_string(&request, TCA_KIND, "ingress"); + + if (egress) { + tcmsg->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0); + tcmsg->tcm_parent = TC_H_CLSACT; + nl_msg_put_string(&request, TCA_KIND, "clsact"); + } else { + tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0); + tcmsg->tcm_parent = TC_H_INGRESS; + nl_msg_put_string(&request, TCA_KIND, "ingress"); + } + nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0); - if (block_id) { + if (!egress && block_id) { nl_msg_put_u32(&request, TCA_INGRESS_BLOCK, block_id); } @@ -1441,7 +1449,8 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower) } int -tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id) +tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id, + bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -1449,7 +1458,8 @@ tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id) index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_DUMP, &request); - tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT; + tcmsg->tcm_parent = + egress ? TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); tcmsg->tcm_info = TC_H_UNSPEC; tcmsg->tcm_handle = 0; @@ -1460,7 +1470,7 @@ tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id) } int -tc_flush(int ifindex, uint32_t block_id) +tc_flush(int ifindex, uint32_t block_id, bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -1468,14 +1478,16 @@ tc_flush(int ifindex, uint32_t block_id) index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ACK, &request); - tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT; + tcmsg->tcm_parent = + egress ? TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); tcmsg->tcm_info = TC_H_UNSPEC; return tc_transact(&request, NULL); } int -tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id) +tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id, + bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -1485,7 +1497,8 @@ tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id) index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT; + tcmsg->tcm_parent = + egress ? TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); tcmsg->tcm_info = tc_make_handle(prio, 0); tcmsg->tcm_handle = handle; @@ -1498,7 +1511,7 @@ tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id) int tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower, - uint32_t block_id) + uint32_t block_id, bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -1508,7 +1521,8 @@ tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower, index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT; + tcmsg->tcm_parent = + egress ? TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); tcmsg->tcm_info = tc_make_handle(prio, 0); tcmsg->tcm_handle = handle; @@ -2228,7 +2242,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, - struct tc_flower *flower, uint32_t block_id) + struct tc_flower *flower, uint32_t block_id, bool egress) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -2241,7 +2255,8 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; tcmsg = tc_make_request(index, RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_ECHO, &request); - tcmsg->tcm_parent = block_id ? : TC_INGRESS_PARENT; + tcmsg->tcm_parent = + egress ? TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); tcmsg->tcm_info = tc_make_handle(prio, eth_type); tcmsg->tcm_handle = handle; diff --git a/lib/tc.h b/lib/tc.h index 3113206..adc79cf 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -36,8 +36,12 @@ #ifndef TC_H_MIN_INGRESS #define TC_H_MIN_INGRESS 0xFFF2U #endif +#ifndef TC_H_MIN_EGRESS +#define TC_H_MIN_EGRESS 0xFFF3U +#endif #define TC_INGRESS_PARENT TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS) +#define TC_EGRESS_PARENT TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS) #define TC_POLICY_DEFAULT "none" @@ -65,7 +69,8 @@ tc_get_minor(unsigned int handle) struct tcmsg *tc_make_request(int ifindex, int type, unsigned int flags, struct ofpbuf *); int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp); -int tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id); +int tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id, + bool egress); struct tc_cookie { const void *data; @@ -215,12 +220,15 @@ BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite) + sizeof(uint32_t) - 2 < sizeof(struct tc_flower)); int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, - struct tc_flower *flower, uint32_t block_id); -int tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id); + struct tc_flower *flower, uint32_t block_id, + bool egress); +int tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id, + bool egress); int tc_get_flower(int ifindex, int prio, int handle, - struct tc_flower *flower, uint32_t block_id); -int tc_flush(int ifindex, uint32_t block_id); -int tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id); + struct tc_flower *flower, uint32_t block_id, bool egress); +int tc_flush(int ifindex, uint32_t block_id, bool egress); +int tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id, + bool egress); int parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower); void tc_set_policy(const char *policy); From patchwork Wed Feb 27 18:28:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Hurley X-Patchwork-Id: 1049097 X-Patchwork-Delegate: horms@verge.net.au Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="eyFGNHl3"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 448kxW2TyRz9s21 for ; Thu, 28 Feb 2019 05:39:43 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 6F6F695FA; Wed, 27 Feb 2019 18:38:19 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id B3794845E for ; Wed, 27 Feb 2019 18:29:33 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-ed1-f67.google.com (mail-ed1-f67.google.com [209.85.208.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 9416A806 for ; Wed, 27 Feb 2019 18:29:32 +0000 (UTC) Received: by mail-ed1-f67.google.com with SMTP id g9so14772923eds.3 for ; Wed, 27 Feb 2019 10:29:32 -0800 (PST) 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=xP8YeX/l9t7QtppFhBXazwLywiM4YlXRmjtveK3oehU=; b=eyFGNHl3pg4EdOkAzVDxdeZYjWWxAmFYFHauz6XcdjWAsJ57/bKJ/XGmbPuse+T82/ B7t6kKuPKTxQ29brN9xpAPRgPBVoStHPiwy/YQ9wTntBXM3vCPVwjK5osIWet+7Vt/d2 8AJ2yYtVBXvCLk40NR1590ypz/xh6CiioweiVIAHMXgNHXtb1zh9aHhMZDIp2KCMbS0a GtHyAw84Zywh9Fdj3hToFtZGX/donRLxGpiDyBEEnLkqmrF+dYIoaDTQXZbgT6EhMx2Y 8EgAi57klCUsVL3eJ7Y78vvCd6lm1QmE/64TzveSOoPEUsPCIjJhqH1IS5/zUZPTqoHK cgSg== 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=xP8YeX/l9t7QtppFhBXazwLywiM4YlXRmjtveK3oehU=; b=SVAvLociGcceMDjMI6Qx/jmNOifIK01pGGcBElTuSyu0OO3EJPkyS3TvkM5VapBnRT kw3ySqFgDKKTas0tRSDQg23eSkQxPCYJ21EtDdNgU3mAwhB6pcYyb5Zpx73qdV1Sky+e vmRJTr+mO47ev4GisAuKCv4+aITxvLLwwBgqaW15AQWwpKvTWpzcofBWKp31aK5ECim/ YX7cmkIoaK7AEsgh9Uk+LFOEEAdsMq2zMlTdLwAROh1vqdl9c81EvTkuGIEkCCNZg4Jy Y1rw77JeSBDdctsO9QhYdKXddw0/O9FqQHs1D+2bfp85oJILFizgxQaSAtG2tICt9WZ8 AVBA== X-Gm-Message-State: AHQUAuZmcP9tsE6hJTMwG/ZgjLMqBQG5x1rxxfcyZnhmEmvguBV0+AD2 LMpFJd8/FhDitzD9mb4jNxSd9WGfspY= X-Google-Smtp-Source: AHgI3IYuE7wy5jaWnXBkbCFdHMgNxyYqg0I0Vr0png2DXsD6AsFuMC/OpgA9+w2yF8MTwa3auebprA== X-Received: by 2002:a17:906:e2cf:: with SMTP id gr15mr2561845ejb.195.1551292170695; Wed, 27 Feb 2019 10:29:30 -0800 (PST) Received: from jhurley-Precision-Tower-3420.netronome.com ([80.76.204.157]) by smtp.gmail.com with ESMTPSA id e53sm4387615ede.26.2019.02.27.10.29.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 Feb 2019 10:29:29 -0800 (PST) From: John Hurley To: dev@openvswitch.org, roid@mellanox.com, fbl@sysclose.org, simon.horman@netronome.com Date: Wed, 27 Feb 2019 18:28:48 +0000 Message-Id: <1551292128-4632-3-git-send-email-john.hurley@netronome.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1551292128-4632-1-git-send-email-john.hurley@netronome.com> References: <1551292128-4632-1-git-send-email-john.hurley@netronome.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC OVS 2/2] ovs-tc: offload datapath rules matching on internal ports X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Rules applied to OvS internal ports are not represented in TC datapaths. However, it is possible to support rules matching on internal ports in TC. The start_xmit ndo of OvS internal ports directs packets back into the OvS kernel datapath where they are rematched with the ingress port now being that of the internal port. Due to this, rules matching on an internal port can be added as TC rules to an egress qdisc for these ports. Allow rules applied to internal ports to be offloaded to TC as egress filters. However, prevent the offload of rules that are redirecting to an internal port. Packets matching these should pass through the network stack for processing and so there is, currently, no benefit in adding them to TC. Signed-off-by: John Hurley Reviewed-by: Simon Horman --- lib/dpif.c | 31 ++++++------------------------- lib/netdev-linux.c | 1 + lib/netdev-tc-offloads.c | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/lib/dpif.c b/lib/dpif.c index 457c9bf..ce413d1 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -100,15 +100,6 @@ static bool should_log_flow_message(const struct vlog_module *module, /* Incremented whenever tnl route, arp, etc changes. */ struct seq *tnl_conf_seq; -static bool -dpif_is_internal_port(const char *type) -{ - /* For userspace datapath, tap devices are the equivalent - * of internal devices in the kernel datapath, so both - * these types are 'internal' devices. */ - return !strcmp(type, "internal") || !strcmp(type, "tap"); -} - static void dp_initialize(void) { @@ -359,10 +350,6 @@ do_open(const char *name, const char *type, bool create, struct dpif **dpifp) struct netdev *netdev; int err; - if (dpif_is_internal_port(dpif_port.type)) { - continue; - } - err = netdev_open(dpif_port.name, dpif_port.type, &netdev); if (!err) { @@ -434,9 +421,7 @@ dpif_remove_netdev_ports(struct dpif *dpif) { struct dpif_port dpif_port; DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) { - if (!dpif_is_internal_port(dpif_port.type)) { - netdev_ports_remove(dpif_port.port_no, dpif->dpif_class); - } + netdev_ports_remove(dpif_port.port_no, dpif->dpif_class); } } @@ -581,16 +566,12 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop) if (!error) { VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu32, dpif_name(dpif), netdev_name, port_no); + struct dpif_port dpif_port; - if (!dpif_is_internal_port(netdev_get_type(netdev))) { - - struct dpif_port dpif_port; - - dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev)); - dpif_port.name = CONST_CAST(char *, netdev_name); - dpif_port.port_no = port_no; - netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port); - } + dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev)); + dpif_port.name = CONST_CAST(char *, netdev_name); + dpif_port.port_no = port_no; + netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port); } else { VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", dpif_name(dpif), netdev_name, ovs_strerror(error)); diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 8d37eb6..18445bd 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -3223,6 +3223,7 @@ const struct netdev_class netdev_tap_class = { const struct netdev_class netdev_internal_class = { NETDEV_LINUX_CLASS_COMMON, + LINUX_FLOW_OFFLOAD_API, .type = "internal", .construct = netdev_linux_construct, .get_stats = netdev_internal_get_stats, diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 31ad9f4..3b2ca56 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -52,6 +52,12 @@ struct netlink_field { int size; }; +static bool +is_internal_port(const char *type) +{ + return !strcmp(type, "internal"); +} + static struct netlink_field set_flower_map[][4] = { [OVS_KEY_ATTR_IPV4] = { { offsetof(struct ovs_key_ipv4, ipv4_src), @@ -178,11 +184,12 @@ del_ufid_tc_mapping(const ovs_u128 *ufid) /* Wrapper function to delete filter and ufid tc mapping */ static int del_filter_and_ufid_mapping(int ifindex, int prio, int handle, - uint32_t block_id, const ovs_u128 *ufid) + uint32_t block_id, const ovs_u128 *ufid, + bool egress) { int err; - err = tc_del_filter(ifindex, prio, handle, block_id, false); + err = tc_del_filter(ifindex, prio, handle, block_id, egress); del_ufid_tc_mapping(ufid); return err; @@ -339,6 +346,7 @@ get_block_id_from_netdev(struct netdev *netdev) int netdev_tc_flow_flush(struct netdev *netdev) { + bool egress = is_internal_port(netdev_get_type(netdev)); int ifindex = netdev_get_ifindex(netdev); uint32_t block_id = 0; @@ -350,13 +358,14 @@ netdev_tc_flow_flush(struct netdev *netdev) block_id = get_block_id_from_netdev(netdev); - return tc_flush(ifindex, block_id, false); + return tc_flush(ifindex, block_id, egress); } int netdev_tc_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump_out) { + bool egress = is_internal_port(netdev_get_type(netdev)); struct netdev_flow_dump *dump; uint32_t block_id = 0; int ifindex; @@ -372,7 +381,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev, dump = xzalloc(sizeof *dump); dump->nl_dump = xzalloc(sizeof *dump->nl_dump); dump->netdev = netdev_ref(netdev); - tc_dump_flower_start(ifindex, dump->nl_dump, block_id, false); + tc_dump_flower_start(ifindex, dump->nl_dump, block_id, egress); *dump_out = dump; @@ -1072,6 +1081,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct dpif_flow_stats *stats OVS_UNUSED) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + bool egress = is_internal_port(netdev_get_type(netdev)); struct tc_flower flower; const struct flow *key = &match->flow; struct flow *mask = &match->wc.masks; @@ -1286,6 +1296,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, odp_port_t port = nl_attr_get_odp_port(nla); struct netdev *outdev = netdev_ports_get(port, info->dpif_class); + if (is_internal_port(netdev_get_type(outdev))) { + return EOPNOTSUPP; + } action->ifindex_out = netdev_get_ifindex(outdev); action->type = TC_ACT_OUTPUT; flower.action_count++; @@ -1333,7 +1346,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, handle = get_ufid_tc_mapping(ufid, &prio, NULL); if (handle && prio) { VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", handle, prio); - del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid); + del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid, + egress); } if (!prio) { @@ -1347,7 +1361,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.act_cookie.data = ufid; flower.act_cookie.len = sizeof *ufid; - err = tc_replace_flower(ifindex, prio, handle, &flower, block_id, false); + err = tc_replace_flower(ifindex, prio, handle, &flower, block_id, egress); if (!err) { add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex); } @@ -1371,6 +1385,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, odp_port_t in_port; int prio = 0; int ifindex; + bool egress; int handle; int err; @@ -1379,6 +1394,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, return ENOENT; } + egress = is_internal_port(netdev_get_type(netdev)); ifindex = netdev_get_ifindex(dev); if (ifindex < 0) { VLOG_ERR_RL(&error_rl, "flow_get: failed to get ifindex for %s: %s", @@ -1390,7 +1406,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d)", netdev_get_name(dev), prio, handle); block_id = get_block_id_from_netdev(netdev); - err = tc_get_flower(ifindex, prio, handle, &flower, block_id, false); + err = tc_get_flower(ifindex, prio, handle, &flower, block_id, egress); netdev_close(dev); if (err) { VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s", @@ -1417,6 +1433,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, struct netdev *dev; int prio = 0; int ifindex; + bool egress; int handle; int error; @@ -1425,6 +1442,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, return ENOENT; } + egress = is_internal_port(netdev_get_type(netdev)); ifindex = netdev_get_ifindex(dev); if (ifindex < 0) { VLOG_ERR_RL(&error_rl, "flow_del: failed to get ifindex for %s: %s", @@ -1437,14 +1455,15 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, if (stats) { memset(stats, 0, sizeof *stats); - if (!tc_get_flower(ifindex, prio, handle, &flower, block_id, false)) { + if (!tc_get_flower(ifindex, prio, handle, &flower, block_id, egress)) { stats->n_packets = get_32aligned_u64(&flower.stats.n_packets); stats->n_bytes = get_32aligned_u64(&flower.stats.n_bytes); stats->used = flower.lastused; } } - error = del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid); + error = del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid, + egress); netdev_close(dev); @@ -1516,6 +1535,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) { static struct ovsthread_once multi_mask_once = OVSTHREAD_ONCE_INITIALIZER; static struct ovsthread_once block_once = OVSTHREAD_ONCE_INITIALIZER; + bool egress = is_internal_port(netdev_get_type(netdev)); uint32_t block_id = 0; int ifindex; int error; @@ -1538,7 +1558,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) } block_id = get_block_id_from_netdev(netdev); - error = tc_add_del_ingress_qdisc(ifindex, true, block_id, false); + error = tc_add_del_ingress_qdisc(ifindex, true, block_id, egress); if (error && error != EEXIST) { VLOG_ERR("failed adding ingress qdisc required for offloading: %s",