From patchwork Thu Jun 21 13:35:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Hurley X-Patchwork-Id: 932740 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="NgwYoOyB"; 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 41BN5h139Zz9s2R for ; Thu, 21 Jun 2018 23:36:40 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 3458FCE0; Thu, 21 Jun 2018 13:36:14 +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 AECD3CBA for ; Thu, 21 Jun 2018 13:36:12 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5849E1A0 for ; Thu, 21 Jun 2018 13:36:11 +0000 (UTC) Received: by mail-wm0-f68.google.com with SMTP id z6-v6so3254937wma.0 for ; Thu, 21 Jun 2018 06:36:11 -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=x51nGT4WjSyL4Lk0KU4JPiNqntFDwCfU0/GPNmhxTtQ=; b=NgwYoOyBO8QvWfjjI4tNXigTVnh11aoU9HkAyNRv2/XpbzDJiGHoGyPTI3C7zdEz58 P5XZKwTY51wdjIOhWVUME4VpxED4S2HwdoWq6wGqNbv7eH0qWw6HPi58cqTZAZ66Pb0a 8L42F2Ca65Nv7cDhXrVCbZWmPS5ZRAExKtOz3KmDNPvyLYo4D7zxZGsjhyJP26VslU4D L8K13hjMVE/UF/jAa/fmRaaTKWmuPk3Yzkc/n5dzNWLL+dplz7PTx8/kiQdvNyVPvZbc HnMxJuIvW7N5QQPBCZsorjwcPrykl96xvHzK7AqgCFxOHaMBPzdTECWsXOMTvGBUM0JF y5RQ== 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=x51nGT4WjSyL4Lk0KU4JPiNqntFDwCfU0/GPNmhxTtQ=; b=tkkcas3+CpCCaf3GzDCNX32/9VLdWzJYPDmUhvdAzdzG3KN7w3ebcVCjjjVuJizLwR WNnJ4USXtlUwP5atlHPUyUgcv/N0LMOopNcNUTgTUmFRuChzhH8majhcvkBKJ/02XXfy tk96vvOsFXRDt79wn1IHkzuftE+IUW1vF6QmIsBsViR4XmW2+D/U2+TmS/a3Ddj/x8WE mkmeLudCTG1JW0QAZJ0youwlG0/VW0hI5bK9KPg87nkUfblvCnru59fxJzKDbdAoUizQ qhXu6cNpKeXHnNe+as3rxEEEJq5ssYheRRFBo4oa/ddPriBoIeZbD8q5r2EkOzPHyD2J 7+vA== X-Gm-Message-State: APt69E3umdQ+EwpF/i1Wi4Fm87KA23rLLG331DixIDLeL3R5iFp6lVbB OHTsCUhpP/3jJEwbuzDx71zGswUA X-Google-Smtp-Source: ADUXVKJ0zCvPfWoIFvkLFkDay+a2VGlILHfV/5GIeSthHlJu5rJ8AJ/Qf99Pdsl2hHDiAxGljMRXLw== X-Received: by 2002:a1c:5c82:: with SMTP id q124-v6mr5544234wmb.24.1529588169541; Thu, 21 Jun 2018 06:36:09 -0700 (PDT) Received: from jhurley-Precision-Tower-3420.netronome.com ([80.76.204.157]) by smtp.gmail.com with ESMTPSA id e63-v6sm8406382wma.46.2018.06.21.06.36.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 21 Jun 2018 06:36:08 -0700 (PDT) From: John Hurley To: dev@openvswitch.org, roid@mellanox.com, gavi@mellanox.com, paulb@mellanox.com, fbl@sysclose.org, simon.horman@netronome.com Date: Thu, 21 Jun 2018 14:35:56 +0100 Message-Id: <1529588161-15934-2-git-send-email-john.hurley@netronome.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1529588161-15934-1-git-send-email-john.hurley@netronome.com> References: <1529588161-15934-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] [PATCH 1/6] tc: allow offloading of block ids 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 Blocks, in tc classifiers, allow the grouping of multiple qdiscs with an associated block id. Whenever a filter is added to/removed from this block, the filter is added to/removed from all associated qdiscs. Extend TC offload functions to take a block id as a parameter. If the id is zero then the dqisc is not considered part of a block. Signed-off-by: John Hurley Reviewed-by: Simon Horman Reviewed-by: Dirk van der Merwe --- lib/netdev-linux.c | 4 +-- lib/netdev-tc-offloads.c | 64 +++++++++++++++++++++++++++++++++++------------- lib/tc.c | 60 ++++++++++++++++++++++++++++++++------------- lib/tc.h | 12 ++++----- 4 files changed, 98 insertions(+), 42 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 054a9b6..d89a0fb 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2275,7 +2275,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); + error = tc_add_del_ingress_qdisc(ifindex, false, 0); if (error) { VLOG_WARN_RL(&rl, "%s: removing policing failed: %s", netdev_name, ovs_strerror(error)); @@ -2283,7 +2283,7 @@ netdev_linux_set_policing(struct netdev *netdev_, } if (kbits_rate) { - error = tc_add_del_ingress_qdisc(ifindex, true); + error = tc_add_del_ingress_qdisc(ifindex, true, 0); 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 0d8cc2c..14558ad 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -44,6 +44,7 @@ static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5); static struct hmap ufid_tc = HMAP_INITIALIZER(&ufid_tc); static bool multi_mask_per_prio = false; +static bool block_support = false; struct netlink_field { int offset; @@ -307,6 +308,7 @@ int netdev_tc_flow_flush(struct netdev *netdev) { int ifindex = netdev_get_ifindex(netdev); + uint32_t block_id = 0; if (ifindex < 0) { VLOG_ERR_RL(&error_rl, "flow_flush: failed to get ifindex for %s: %s", @@ -314,7 +316,7 @@ netdev_tc_flow_flush(struct netdev *netdev) return -ifindex; } - return tc_flush(ifindex); + return tc_flush(ifindex, block_id); } int @@ -322,6 +324,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump_out) { struct netdev_flow_dump *dump; + uint32_t block_id = 0; int ifindex; ifindex = netdev_get_ifindex(netdev); @@ -334,7 +337,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); + tc_dump_flower_start(ifindex, dump->nl_dump, block_id); *dump_out = dump; @@ -890,6 +893,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct flow *mask = &match->wc.masks; const struct flow_tnl *tnl = &match->flow.tunnel; struct tc_action *action; + uint32_t block_id = 0; struct nlattr *nla; size_t left; int prio = 0; @@ -1097,7 +1101,7 @@ 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); - tc_del_filter(ifindex, prio, handle); + tc_del_filter(ifindex, prio, handle, block_id); } if (!prio) { @@ -1111,7 +1115,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); + err = tc_replace_flower(ifindex, prio, handle, &flower, block_id); if (!err) { add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex); } @@ -1131,6 +1135,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); struct netdev *dev; struct tc_flower flower; + uint32_t block_id = 0; odp_port_t in_port; int prio = 0; int ifindex; @@ -1152,7 +1157,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); - err = tc_get_flower(ifindex, prio, handle, &flower); + err = tc_get_flower(ifindex, prio, handle, &flower, block_id); netdev_close(dev); if (err) { VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s", @@ -1175,6 +1180,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, struct dpif_flow_stats *stats) { struct tc_flower flower; + uint32_t block_id = 0; struct netdev *dev; int prio = 0; int ifindex; @@ -1196,14 +1202,14 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, if (stats) { memset(stats, 0, sizeof *stats); - if (!tc_get_flower(ifindex, prio, handle, &flower)) { + if (!tc_get_flower(ifindex, prio, handle, &flower, block_id)) { 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 = tc_del_filter(ifindex, prio, handle); + error = tc_del_filter(ifindex, prio, handle, block_id); del_ufid_tc_mapping(ufid); netdev_close(dev); @@ -1212,7 +1218,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, } static void -probe_multi_mask_per_prio(int ifindex) +probe_multi_mask_per_prio(int ifindex, uint32_t block_id) { struct tc_flower flower; int error; @@ -1224,7 +1230,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); + error = tc_replace_flower(ifindex, 1, 1, &flower, block_id); if (error) { return; } @@ -1232,23 +1238,42 @@ 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); - tc_del_filter(ifindex, 1, 1); + error = tc_replace_flower(ifindex, 1, 2, &flower, block_id); + tc_del_filter(ifindex, 1, 1, block_id); if (error) { return; } - tc_del_filter(ifindex, 1, 2); + tc_del_filter(ifindex, 1, 2, block_id); multi_mask_per_prio = true; VLOG_INFO("probe tc: multiple masks on single tc prio is supported."); } +static void +probe_tc_block_support(int ifindex) +{ + uint32_t block_id = 1; + int error; + + error = tc_add_del_ingress_qdisc(ifindex, true, block_id); + if (error) { + return; + } + + tc_add_del_ingress_qdisc(ifindex, false, block_id); + + block_support = true; + VLOG_INFO("probe tc: block offload is supported."); +} + int netdev_tc_init_flow_api(struct netdev *netdev) { - static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static struct ovsthread_once multi_mask_once = OVSTHREAD_ONCE_INITIALIZER; + static struct ovsthread_once block_once = OVSTHREAD_ONCE_INITIALIZER; + uint32_t block_id = 0; int ifindex; int error; @@ -1259,7 +1284,12 @@ netdev_tc_init_flow_api(struct netdev *netdev) return -ifindex; } - error = tc_add_del_ingress_qdisc(ifindex, true); + if (ovsthread_once_start(&block_once)) { + probe_tc_block_support(ifindex); + ovsthread_once_done(&block_once); + } + + error = tc_add_del_ingress_qdisc(ifindex, true, block_id); if (error && error != EEXIST) { VLOG_ERR("failed adding ingress qdisc required for offloading: %s", @@ -1269,9 +1299,9 @@ netdev_tc_init_flow_api(struct netdev *netdev) VLOG_INFO("added ingress qdisc to %s", netdev_get_name(netdev)); - if (ovsthread_once_start(&once)) { - probe_multi_mask_per_prio(ifindex); - ovsthread_once_done(&once); + if (ovsthread_once_start(&multi_mask_once)) { + probe_multi_mask_per_prio(ifindex, block_id); + ovsthread_once_done(&multi_mask_once); } return 0; diff --git a/lib/tc.c b/lib/tc.c index 7133486..7a71036 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -43,6 +43,14 @@ #define MAX_PEDIT_OFFSETS 32 +#ifndef TCM_IFINDEX_MAGIC_BLOCK +#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) +#endif + +#if TCA_MAX < 14 +#define TCA_INGRESS_BLOCK 13 +#endif + VLOG_DEFINE_THIS_MODULE(tc); static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5); @@ -173,10 +181,14 @@ tc_transact(struct ofpbuf *request, struct ofpbuf **replyp) * The configuration and stats may be seen with the following command: * /sbin/tc -s qdisc show dev * + * If block_id is greater than 0, then the ingress qdisc is added to a block. + * In this case, it is equivalent to running (when 'add' is true): + * /sbin/tc qdisc add dev ingress_block ingress + * * Returns 0 if successful, otherwise a positive errno value. */ int -tc_add_del_ingress_qdisc(int ifindex, bool add) +tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -189,6 +201,9 @@ tc_add_del_ingress_qdisc(int ifindex, bool add) 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) { + nl_msg_put_u32(&request, TCA_INGRESS_BLOCK, block_id); + } error = tc_transact(&request, NULL); if (error) { @@ -1007,13 +1022,15 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower) } int -tc_dump_flower_start(int ifindex, struct nl_dump *dump) +tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; + int index; - tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_DUMP, &request); - tcmsg->tcm_parent = TC_INGRESS_PARENT; + 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_info = TC_H_UNSPEC; tcmsg->tcm_handle = 0; @@ -1024,28 +1041,32 @@ tc_dump_flower_start(int ifindex, struct nl_dump *dump) } int -tc_flush(int ifindex) +tc_flush(int ifindex, uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; + int index; - tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ACK, &request); - tcmsg->tcm_parent = TC_INGRESS_PARENT; + 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_info = TC_H_UNSPEC; return tc_transact(&request, NULL); } int -tc_del_filter(int ifindex, int prio, int handle) +tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; struct ofpbuf *reply; int error; + int index; - tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = TC_INGRESS_PARENT; + 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_info = tc_make_handle(prio, 0); tcmsg->tcm_handle = handle; @@ -1057,15 +1078,18 @@ tc_del_filter(int ifindex, int prio, int handle) } int -tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower) +tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower, + uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; struct ofpbuf *reply; int error; + int index; - tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = TC_INGRESS_PARENT; + 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_info = tc_make_handle(prio, 0); tcmsg->tcm_handle = handle; @@ -1625,7 +1649,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) + struct tc_flower *flower, uint32_t block_id) { struct ofpbuf request; struct tcmsg *tcmsg; @@ -1633,10 +1657,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, int error = 0; size_t basic_offset; uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type; + int index; - tcmsg = tc_make_request(ifindex, RTM_NEWTFILTER, - NLM_F_CREATE | NLM_F_ECHO, &request); - tcmsg->tcm_parent = TC_INGRESS_PARENT; + 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_info = tc_make_handle(prio, eth_type); tcmsg->tcm_handle = handle; diff --git a/lib/tc.h b/lib/tc.h index cc19374..80505f0 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -63,7 +63,7 @@ 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); +int tc_add_del_ingress_qdisc(int ifindex, bool add, uint32_t block_id); struct tc_cookie { const void *data; @@ -198,12 +198,12 @@ 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); -int tc_del_filter(int ifindex, int prio, int handle); + struct tc_flower *flower, uint32_t block_id); +int 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); -int tc_flush(int ifindex); -int tc_dump_flower_start(int ifindex, struct nl_dump *dump); + 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); int parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower); void tc_set_policy(const char *policy);