From patchwork Thu Jun 4 10:47:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1303443 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.133; helo=hemlock.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 hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49d2Yt5F82z9sSf for ; Thu, 4 Jun 2020 20:48:18 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 0CA338888C; Thu, 4 Jun 2020 10:48:17 +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 7-AM4Gf7FXnl; Thu, 4 Jun 2020 10:48:12 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 8221888856; Thu, 4 Jun 2020 10:48:12 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5CF52C0888; Thu, 4 Jun 2020 10:48:12 +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 28BFEC016E for ; Thu, 4 Jun 2020 10:48:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 1663A8884C for ; Thu, 4 Jun 2020 10:48:11 +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 6pHtuy36Jlvu for ; Thu, 4 Jun 2020 10:48:06 +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 3FF8088833 for ; Thu, 4 Jun 2020 10:48:06 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE2 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 4 Jun 2020 13:48:01 +0300 Received: from mtr-vdi-191.wap.labs.mlnx. (mtr-vdi-191.wap.labs.mlnx [10.209.100.28]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 054Am1TD031629; Thu, 4 Jun 2020 13:48:01 +0300 From: Roi Dayan To: dev@openvswitch.org, Simon Horman Date: Thu, 4 Jun 2020 13:47:00 +0300 Message-Id: <20200604104701.183504-2-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20200604104701.183504-1-roid@mellanox.com> References: <20200604104701.183504-1-roid@mellanox.com> Cc: Vlad Buslov Subject: [ovs-dev] [PATCH v2 1/2] netdev-offload: Implement terse dump support 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: Vlad Buslov In order to improve revalidator performance by minimizing unnecessary copying of data, extend netdev-offloads to support terse dump mode. Extend netdev_flow_api->flow_dump_create() with 'terse' bool argument. Implement support for terse dump in functions that convert netlink to flower and flower to match. Set flow stats "used" value based on difference in number of flow packets because lastuse timestamp is not included in TC terse dump. Kernel API support is implemented in following patch. Signed-off-by: Vlad Buslov Reviewed-by: Roi Dayan --- lib/dpif-netlink.c | 70 ++++++++++++++++++++++--------------------- lib/netdev-offload-provider.h | 3 +- lib/netdev-offload-tc.c | 67 +++++++++++++++++++++++++++++++---------- lib/netdev-offload.c | 10 ++++--- lib/netdev-offload.h | 6 ++-- ofproto/ofproto-dpif-upcall.c | 24 +++++++++++++-- 6 files changed, 122 insertions(+), 58 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index dc642100fc58..01485c7dc4fa 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1445,7 +1445,8 @@ start_netdev_dump(const struct dpif *dpif_, dump->netdev_current_dump = 0; dump->netdev_dumps = netdev_ports_flow_dump_create(dpif_->dpif_class, - &dump->netdev_dumps_num); + &dump->netdev_dumps_num, + dump->up.terse); ovs_mutex_unlock(&dump->netdev_lock); } @@ -1640,41 +1641,42 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, struct dpif_flow_attrs *attrs, ovs_u128 *ufid, struct dpif_flow *flow, - bool terse OVS_UNUSED) -{ - - struct odp_flow_key_parms odp_parms = { - .flow = &match->flow, - .mask = &match->wc.masks, - .support = { - .max_vlan_headers = 2, - .recirc = true, - .ct_state = true, - .ct_zone = true, - .ct_mark = true, - .ct_label = true, - }, - }; - size_t offset; - + bool terse) +{ memset(flow, 0, sizeof *flow); - /* Key */ - offset = key_buf->size; - flow->key = ofpbuf_tail(key_buf); - odp_flow_key_from_flow(&odp_parms, key_buf); - flow->key_len = key_buf->size - offset; - - /* Mask */ - offset = mask_buf->size; - flow->mask = ofpbuf_tail(mask_buf); - odp_parms.key_buf = key_buf; - odp_flow_key_from_mask(&odp_parms, mask_buf); - flow->mask_len = mask_buf->size - offset; - - /* Actions */ - flow->actions = nl_attr_get(actions); - flow->actions_len = nl_attr_get_size(actions); + if (!terse) { + struct odp_flow_key_parms odp_parms = { + .flow = &match->flow, + .mask = &match->wc.masks, + .support = { + .max_vlan_headers = 2, + .recirc = true, + .ct_state = true, + .ct_zone = true, + .ct_mark = true, + .ct_label = true, + }, + }; + size_t offset; + + /* Key */ + offset = key_buf->size; + flow->key = ofpbuf_tail(key_buf); + odp_flow_key_from_flow(&odp_parms, key_buf); + flow->key_len = key_buf->size - offset; + + /* Mask */ + offset = mask_buf->size; + flow->mask = ofpbuf_tail(mask_buf); + odp_parms.key_buf = key_buf; + odp_flow_key_from_mask(&odp_parms, mask_buf); + flow->mask_len = mask_buf->size - offset; + + /* Actions */ + flow->actions = nl_attr_get(actions); + flow->actions_len = nl_attr_get_size(actions); + } /* Stats */ memcpy(&flow->stats, stats, sizeof *stats); diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h index 5a809c0cdf1f..0bed7bf61edb 100644 --- a/lib/netdev-offload-provider.h +++ b/lib/netdev-offload-provider.h @@ -42,7 +42,8 @@ struct netdev_flow_api { * * On success returns 0 and allocates data, on failure returns * positive errno. */ - int (*flow_dump_create)(struct netdev *, struct netdev_flow_dump **dump); + int (*flow_dump_create)(struct netdev *, struct netdev_flow_dump **dump, + bool terse); int (*flow_dump_destroy)(struct netdev_flow_dump *); /* Returns true if there are more flows to dump. diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index e188e63e560e..3ba70db4690b 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -366,7 +366,8 @@ netdev_tc_flow_flush(struct netdev *netdev) static int netdev_tc_flow_dump_create(struct netdev *netdev, - struct netdev_flow_dump **dump_out) + struct netdev_flow_dump **dump_out, + bool terse) { enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); struct netdev_flow_dump *dump; @@ -386,6 +387,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); + dump->terse = terse; id = tc_make_tcf_id(ifindex, block_id, prio, hook); tc_dump_flower_start(&id, dump->nl_dump); @@ -502,13 +504,53 @@ flower_tun_opt_to_match(struct match *match, struct tc_flower *flower) match->wc.masks.tunnel.flags |= FLOW_TNL_F_UDPIF; } +static void +parse_tc_flower_to_stats(struct tc_flower *flower, + struct dpif_flow_stats *stats) +{ + if (!stats) { + return; + } + + memset(stats, 0, sizeof *stats); + stats->n_packets = get_32aligned_u64(&flower->stats.n_packets); + stats->n_bytes = get_32aligned_u64(&flower->stats.n_bytes); + stats->used = flower->lastused; +} + +static void +parse_tc_flower_to_attrs(struct tc_flower *flower, + struct dpif_flow_attrs *attrs) +{ + attrs->offloaded = (flower->offloaded_state == TC_OFFLOADED_STATE_IN_HW || + flower->offloaded_state == + TC_OFFLOADED_STATE_UNDEFINED); + attrs->dp_layer = "tc"; + attrs->dp_extra_info = NULL; +} + +static int +parse_tc_flower_terse_to_match(struct tc_flower *flower, + struct match *match, + struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs) +{ + match_init_catchall(match); + + parse_tc_flower_to_stats(flower, stats); + parse_tc_flower_to_attrs(flower, attrs); + + return 0; +} + static int parse_tc_flower_to_match(struct tc_flower *flower, struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, struct dpif_flow_attrs *attrs, - struct ofpbuf *buf) + struct ofpbuf *buf, + bool terse) { size_t act_off; struct tc_flower_key *key = &flower->key; @@ -517,6 +559,10 @@ parse_tc_flower_to_match(struct tc_flower *flower, struct tc_action *action; int i; + if (terse) { + return parse_tc_flower_terse_to_match(flower, match, stats, attrs); + } + ofpbuf_clear(buf); match_init_catchall(match); @@ -863,17 +909,8 @@ parse_tc_flower_to_match(struct tc_flower *flower, *actions = ofpbuf_at_assert(buf, act_off, sizeof(struct nlattr)); - if (stats) { - memset(stats, 0, sizeof *stats); - stats->n_packets = get_32aligned_u64(&flower->stats.n_packets); - stats->n_bytes = get_32aligned_u64(&flower->stats.n_bytes); - stats->used = flower->lastused; - } - - attrs->offloaded = (flower->offloaded_state == TC_OFFLOADED_STATE_IN_HW) - || (flower->offloaded_state == TC_OFFLOADED_STATE_UNDEFINED); - attrs->dp_layer = "tc"; - attrs->dp_extra_info = NULL; + parse_tc_flower_to_stats(flower, stats); + parse_tc_flower_to_attrs(flower, attrs); return 0; } @@ -905,7 +942,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, } if (parse_tc_flower_to_match(&flower, match, actions, stats, attrs, - wbuffer)) { + wbuffer, dump->terse)) { continue; } @@ -1784,7 +1821,7 @@ netdev_tc_flow_get(struct netdev *netdev, } in_port = netdev_ifindex_to_odp_port(id.ifindex); - parse_tc_flower_to_match(&flower, match, actions, stats, attrs, buf); + parse_tc_flower_to_match(&flower, match, actions, stats, attrs, buf, false); match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = in_port; diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c index 32eab5910760..ab97a292ebac 100644 --- a/lib/netdev-offload.c +++ b/lib/netdev-offload.c @@ -201,13 +201,14 @@ netdev_flow_flush(struct netdev *netdev) } int -netdev_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump) +netdev_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump, + bool terse) { const struct netdev_flow_api *flow_api = ovsrcu_get(const struct netdev_flow_api *, &netdev->flow_api); return (flow_api && flow_api->flow_dump_create) - ? flow_api->flow_dump_create(netdev, dump) + ? flow_api->flow_dump_create(netdev, dump, terse) : EOPNOTSUPP; } @@ -436,7 +437,8 @@ netdev_ports_flow_flush(const struct dpif_class *dpif_class) } struct netdev_flow_dump ** -netdev_ports_flow_dump_create(const struct dpif_class *dpif_class, int *ports) +netdev_ports_flow_dump_create(const struct dpif_class *dpif_class, int *ports, + bool terse) { struct port_to_netdev_data *data; struct netdev_flow_dump **dumps; @@ -454,7 +456,7 @@ netdev_ports_flow_dump_create(const struct dpif_class *dpif_class, int *ports) HMAP_FOR_EACH (data, portno_node, &port_to_netdev) { if (data->dpif_class == dpif_class) { - if (netdev_flow_dump_create(data->netdev, &dumps[i])) { + if (netdev_flow_dump_create(data->netdev, &dumps[i], terse)) { continue; } diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index b4b882a56aac..87f5852c8d60 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -80,7 +80,8 @@ struct offload_info { }; int netdev_flow_flush(struct netdev *); -int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump); +int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump, + bool terse); int netdev_flow_dump_destroy(struct netdev_flow_dump *); bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *, struct nlattr **actions, struct dpif_flow_stats *, @@ -114,7 +115,8 @@ odp_port_t netdev_ifindex_to_odp_port(int ifindex); struct netdev_flow_dump **netdev_ports_flow_dump_create( const struct dpif_class *, - int *ports); + int *ports, + bool terse); void netdev_ports_flow_flush(const struct dpif_class *); int netdev_ports_flow_del(const struct dpif_class *, const ovs_u128 *ufid, struct dpif_flow_stats *stats); diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 5e08ef10dad6..920f29a6f36a 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -2576,6 +2576,25 @@ udpif_update_flow_pps(struct udpif *udpif, struct udpif_key *ukey, ukey->flow_time = udpif->dpif->current_ms; } +static long long int +udpif_update_used(struct udpif *udpif, struct udpif_key *ukey, + struct dpif_flow_stats *stats) + OVS_REQUIRES(ukey->mutex) +{ + if (!udpif->dump->terse) { + return ukey->created; + } + + if (stats->n_packets > ukey->stats.n_packets) { + stats->used = udpif->dpif->current_ms; + } else if (ukey->stats.used) { + stats->used = ukey->stats.used; + } else { + stats->used = ukey->created; + } + return stats->used; +} + static void revalidate(struct revalidator *revalidator) { @@ -2631,6 +2650,7 @@ revalidate(struct revalidator *revalidator) for (f = flows; f < &flows[n_dumped]; f++) { long long int used = f->stats.used; struct recirc_refs recircs = RECIRC_REFS_EMPTY_INITIALIZER; + struct dpif_flow_stats stats = f->stats; enum reval_result result; struct udpif_key *ukey; bool already_dumped; @@ -2675,12 +2695,12 @@ revalidate(struct revalidator *revalidator) } if (!used) { - used = ukey->created; + used = udpif_update_used(udpif, ukey, &stats); } if (kill_them_all || (used && used < now - max_idle)) { result = UKEY_DELETE; } else { - result = revalidate_ukey(udpif, ukey, &f->stats, &odp_actions, + result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, reval_seq, &recircs, f->attrs.offloaded); } From patchwork Thu Jun 4 10:47:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1303442 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.133; helo=hemlock.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 hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49d2Ys43zgz9sSc for ; Thu, 4 Jun 2020 20:48:17 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 0A6E688833; Thu, 4 Jun 2020 10:48:16 +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 reK7xNrO7-L3; Thu, 4 Jun 2020 10:48:14 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 71A458885F; Thu, 4 Jun 2020 10:48:14 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 39D1BC0892; Thu, 4 Jun 2020 10:48:14 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 35C80C08A6 for ; Thu, 4 Jun 2020 10:48:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 0DC1C86F3B for ; Thu, 4 Jun 2020 10:48:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jYEzxbbdH57Q for ; Thu, 4 Jun 2020 10:48:08 +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 fraxinus.osuosl.org (Postfix) with ESMTP id 167B085AD6 for ; Thu, 4 Jun 2020 10:48:07 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 4 Jun 2020 13:48:01 +0300 Received: from mtr-vdi-191.wap.labs.mlnx. (mtr-vdi-191.wap.labs.mlnx [10.209.100.28]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 054Am1TE031629; Thu, 4 Jun 2020 13:48:01 +0300 From: Roi Dayan To: dev@openvswitch.org, Simon Horman Date: Thu, 4 Jun 2020 13:47:01 +0300 Message-Id: <20200604104701.183504-3-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20200604104701.183504-1-roid@mellanox.com> References: <20200604104701.183504-1-roid@mellanox.com> Cc: Vlad Buslov Subject: [ovs-dev] [PATCH v2 2/2] tc: Support new terse dump kernel API 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: Vlad Buslov When dumping flows in terse mode set TCA_DUMP_FLAGS attribute to TCA_DUMP_FLAGS_TERSE flag to prevent unnecessary copying of data between kernel and user spaces. Only expect kernel to provide cookie, stats and flags when dumping filters in terse mode. Signed-off-by: Vlad Buslov Reviewed-by: Roi Dayan --- lib/netdev-offload-tc.c | 4 ++-- lib/tc.c | 59 ++++++++++++++++++++++++++++++++++++++----------- lib/tc.h | 5 +++-- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 3ba70db4690b..0ad86c448bdf 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -390,7 +390,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev, dump->terse = terse; id = tc_make_tcf_id(ifindex, block_id, prio, hook); - tc_dump_flower_start(&id, dump->nl_dump); + tc_dump_flower_start(&id, dump->nl_dump, terse); *dump_out = dump; @@ -937,7 +937,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) { struct tc_flower flower; - if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower)) { + if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower, dump->terse)) { continue; } diff --git a/lib/tc.c b/lib/tc.c index 12af0192b614..d0d9d0b047f7 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -51,9 +51,14 @@ #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) #endif -#if TCA_MAX < 14 +#ifndef TCA_DUMP_FLAGS_TERSE +#define TCA_DUMP_FLAGS_TERSE (1 << 0) +#endif + +#if TCA_MAX < 15 #define TCA_CHAIN 11 #define TCA_INGRESS_BLOCK 13 +#define TCA_DUMP_FLAGS 15 #endif VLOG_DEFINE_THIS_MODULE(tc); @@ -411,6 +416,11 @@ static const struct nl_policy tca_flower_policy[] = { .optional = true, }, }; +static const struct nl_policy tca_flower_terse_policy[] = { + [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, }, + [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, }, +}; + static void nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower) { @@ -1573,7 +1583,7 @@ nl_parse_act_csum(struct nlattr *options, struct tc_flower *flower) static const struct nl_policy act_policy[] = { [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, }, [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, }, - [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = false, }, + [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, }, [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, }, }; @@ -1584,7 +1594,8 @@ static const struct nl_policy stats_policy[] = { }; static int -nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) +nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, + bool terse) { struct nlattr *act_options; struct nlattr *act_stats; @@ -1597,7 +1608,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) int err = 0; if (!nl_parse_nested(action, act_policy, action_attrs, - ARRAY_SIZE(act_policy))) { + ARRAY_SIZE(act_policy)) || + (!terse && !action_attrs[TCA_ACT_OPTIONS])) { VLOG_ERR_RL(&error_rl, "failed to parse single action options"); return EPROTO; } @@ -1606,7 +1618,9 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) act_options = action_attrs[TCA_ACT_OPTIONS]; act_cookie = action_attrs[TCA_ACT_COOKIE]; - if (!strcmp(act_kind, "gact")) { + if (terse) { + /* Terse dump doesn't provide act options attribute. */ + } else if (!strcmp(act_kind, "gact")) { err = nl_parse_act_gact(act_options, flower); } else if (!strcmp(act_kind, "mirred")) { err = nl_parse_act_mirred(act_options, flower); @@ -1656,7 +1670,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) #define TCA_ACT_MIN_PRIO 1 static int -nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) +nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower, + bool terse) { const struct nlattr *actions = attrs[TCA_FLOWER_ACT]; static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {}; @@ -1682,7 +1697,7 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM); return EOPNOTSUPP; } - err = nl_parse_single_action(actions_orders[i], flower); + err = nl_parse_single_action(actions_orders[i], flower, terse); if (err) { return err; @@ -1701,11 +1716,21 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) } static int -nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) +nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower, + bool terse) { struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)]; int err; + if (terse) { + if (!nl_parse_nested(nl_options, tca_flower_terse_policy, + attrs, ARRAY_SIZE(tca_flower_terse_policy))) { + VLOG_ERR_RL(&error_rl, "failed to parse flower classifier terse options"); + return EPROTO; + } + goto skip_flower_opts; + } + if (!nl_parse_nested(nl_options, tca_flower_policy, attrs, ARRAY_SIZE(tca_flower_policy))) { VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options"); @@ -1721,13 +1746,14 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) return err; } +skip_flower_opts: nl_parse_flower_flags(attrs, flower); - return nl_parse_flower_actions(attrs, flower); + return nl_parse_flower_actions(attrs, flower, terse); } int parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id, - struct tc_flower *flower) + struct tc_flower *flower, bool terse) { struct tcmsg *tc; struct nlattr *ta[ARRAY_SIZE(tca_policy)]; @@ -1770,15 +1796,22 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id, return EPROTO; } - return nl_parse_flower_options(ta[TCA_OPTIONS], flower); + return nl_parse_flower_options(ta[TCA_OPTIONS], flower, terse); } int -tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump) +tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse) { struct ofpbuf request; request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request); + if (terse) { + struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE, + TCA_DUMP_FLAGS_TERSE }; + + nl_msg_put_unspec(&request, TCA_DUMP_FLAGS, &dump_flags, + sizeof dump_flags); + } nl_dump_start(dump, NETLINK_ROUTE, &request); ofpbuf_uninit(&request); @@ -1807,7 +1840,7 @@ tc_get_flower(struct tcf_id *id, struct tc_flower *flower) return error; } - error = parse_netlink_to_tc_flower(reply, id, flower); + error = parse_netlink_to_tc_flower(reply, id, flower, false); ofpbuf_delete(reply); return error; } diff --git a/lib/tc.h b/lib/tc.h index 24a4994fd17e..11f3231f9dfe 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -341,10 +341,11 @@ BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite) int tc_replace_flower(struct tcf_id *id, struct tc_flower *flower); int tc_del_filter(struct tcf_id *id); int tc_get_flower(struct tcf_id *id, struct tc_flower *flower); -int tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump); +int tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse); int parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id, - struct tc_flower *flower); + struct tc_flower *flower, + bool terse); void tc_set_policy(const char *policy); #endif /* tc.h */