From patchwork Mon Jul 30 06:46:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950720 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=ovn.org 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 41f98w55psz9ryt for ; Mon, 30 Jul 2018 16:46:55 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 58CC37F6; Mon, 30 Jul 2018 06:46:51 +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 D0B353EE for ; Mon, 30 Jul 2018 06:46:49 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id A546F701 for ; Mon, 30 Jul 2018 06:46:48 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 8A7DB1BF20B for ; Mon, 30 Jul 2018 06:46:45 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:32 -0700 Message-Id: <20180730064638.121021-1-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 1/7] ovn: Use C strings instead of ds for extended tables. 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 Dynamic strings are not needed for the most part and are introduing additional conversions back and forth with C strings. Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- ovn/controller/ofctrl.c | 4 ++-- ovn/lib/actions.c | 20 ++++++++------------ ovn/lib/extend-table.c | 22 ++++++++++++---------- ovn/lib/extend-table.h | 5 ++--- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c index 349de3aaa284..c7f41612456d 100644 --- a/ovn/controller/ofctrl.c +++ b/ovn/controller/ofctrl.c @@ -874,7 +874,7 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, enum ofputil_protocol usable_protocols; char *group_string = xasprintf("group_id=%"PRIu32",%s", desired->table_id, - ds_cstr(&desired->info)); + desired->name); char *error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD, group_string, NULL, NULL, &usable_protocols); if (!error) { @@ -897,7 +897,7 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, enum ofputil_protocol usable_protocols; char *meter_string = xasprintf("meter=%"PRIu32",%s", m_desired->table_id, - ds_cstr(&m_desired->info)); + m_desired->name); char *error = parse_ofp_meter_mod_str(&mm, meter_string, OFPMC13_ADD, &usable_protocols); if (!error) { diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 5c559e37a479..430bb677bafb 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -1049,7 +1049,7 @@ encode_CT_LB(const struct ovnact_ct_lb *cl, recirc_table, zone_reg); } - table_id = ovn_extend_table_assign_id(ep->group_table, &ds); + table_id = ovn_extend_table_assign_id(ep->group_table, ds_cstr(&ds)); ds_destroy(&ds); if (table_id == EXT_TABLE_ID_INVALID) { return; @@ -2217,25 +2217,21 @@ encode_SET_METER(const struct ovnact_set_meter *cl, uint32_t table_id; struct ofpact_meter *om; - struct ds ds = DS_EMPTY_INITIALIZER; + char *name; if (cl->burst) { - ds_put_format(&ds, - "kbps burst stats bands=type=drop rate=%"PRId64" " - "burst_size=%"PRId64"", - cl->rate, cl->burst); + name = xasprintf("kbps burst stats bands=type=drop rate=%"PRId64" " + "burst_size=%"PRId64"", cl->rate, cl->burst); } else { - ds_put_format(&ds, "kbps stats bands=type=drop rate=%"PRId64"", - cl->rate); + name = xasprintf("kbps stats bands=type=drop rate=%"PRId64"", + cl->rate); } - table_id = ovn_extend_table_assign_id(ep->meter_table, &ds); + table_id = ovn_extend_table_assign_id(ep->meter_table, name); + free(name); if (table_id == EXT_TABLE_ID_INVALID) { - ds_destroy(&ds); return; } - ds_destroy(&ds); - /* Create an action to set the meter. */ om = ofpact_put_METER(ofpacts); om->meter_id = table_id; diff --git a/ovn/lib/extend-table.c b/ovn/lib/extend-table.c index e18713b9766c..511d1a84b0c0 100644 --- a/ovn/lib/extend-table.c +++ b/ovn/lib/extend-table.c @@ -15,6 +15,8 @@ */ #include +#include + #include "bitmap.h" #include "hash.h" #include "openvswitch/vlog.h" @@ -39,7 +41,7 @@ ovn_extend_table_destroy(struct ovn_extend_table *table) struct ovn_extend_table_info *desired, *d_next; HMAP_FOR_EACH_SAFE (desired, d_next, hmap_node, &table->existing) { hmap_remove(&table->existing, &desired->hmap_node); - ds_destroy(&desired->info); + free(desired->name); free(desired); } hmap_destroy(&table->desired); @@ -47,7 +49,7 @@ ovn_extend_table_destroy(struct ovn_extend_table *table) struct ovn_extend_table_info *existing, *e_next; HMAP_FOR_EACH_SAFE (existing, e_next, hmap_node, &table->existing) { hmap_remove(&table->existing, &existing->hmap_node); - ds_destroy(&existing->info); + free(existing->name); free(existing); } hmap_destroy(&table->existing); @@ -84,7 +86,7 @@ ovn_extend_table_clear(struct ovn_extend_table *table, bool existing) if (existing || g->new_table_id) { bitmap_set0(table->table_ids, g->table_id); } - ds_destroy(&g->info); + free(g->name); free(g); } } @@ -95,7 +97,7 @@ ovn_extend_table_remove(struct ovn_extend_table *table, { /* Remove 'existing' from 'groups->existing' */ hmap_remove(&table->existing, &existing->hmap_node); - ds_destroy(&existing->info); + free(existing->name); /* Dealloc group_id. */ bitmap_set0(table->table_ids, existing->table_id); @@ -115,7 +117,7 @@ ovn_extend_table_move(struct ovn_extend_table *table) hmap_insert(&table->existing, &desired->hmap_node, desired->hmap_node.hash); } else { - ds_destroy(&desired->info); + free(desired->name); free(desired); } } @@ -124,16 +126,16 @@ ovn_extend_table_move(struct ovn_extend_table *table) /* Assign a new table ID for the table information from the bitmap. * If it already exists, return the old ID. */ uint32_t -ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds) +ovn_extend_table_assign_id(struct ovn_extend_table *table, const char *name) { uint32_t table_id = 0, hash; struct ovn_extend_table_info *table_info; - hash = hash_string(ds_cstr(ds), 0); + hash = hash_string(name, 0); /* Check whether we have non installed but allocated group_id. */ HMAP_FOR_EACH_WITH_HASH (table_info, hmap_node, hash, &table->desired) { - if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds))) { + if (!strcmp(table_info->name, name)) { return table_info->table_id; } } @@ -141,7 +143,7 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds) /* Check whether we already have an installed entry for this * combination. */ HMAP_FOR_EACH_WITH_HASH (table_info, hmap_node, hash, &table->existing) { - if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds))) { + if (!strcmp(table_info->name, name)) { table_id = table_info->table_id; } } @@ -161,7 +163,7 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds) bitmap_set1(table->table_ids, table_id); table_info = xmalloc(sizeof *table_info); - ds_clone(&table_info->info, ds); + table_info->name = xstrdup(name); table_info->table_id = table_id; table_info->hmap_node.hash = hash; table_info->new_table_id = new_table_id; diff --git a/ovn/lib/extend-table.h b/ovn/lib/extend-table.h index d9ae549beaf5..e4501f254fb7 100644 --- a/ovn/lib/extend-table.h +++ b/ovn/lib/extend-table.h @@ -20,7 +20,6 @@ #define MAX_EXT_TABLE_ID 65535 #define EXT_TABLE_ID_INVALID 0 -#include "openvswitch/dynamic-string.h" #include "openvswitch/hmap.h" #include "openvswitch/list.h" @@ -36,7 +35,7 @@ struct ovn_extend_table { struct ovn_extend_table_info { struct hmap_node hmap_node; - struct ds info; /* Details string for the table entity. */ + char *name; /* Name for the table entity. */ uint32_t table_id; bool new_table_id; /* 'True' if 'table_id' was reserved from * ovn_extend_table's 'table_ids' bitmap. */ @@ -58,7 +57,7 @@ void ovn_extend_table_remove(struct ovn_extend_table *, void ovn_extend_table_move(struct ovn_extend_table *); uint32_t ovn_extend_table_assign_id(struct ovn_extend_table *, - struct ds *); + const char *name); /* Iterates 'DESIRED' through all of the 'ovn_extend_table_info's in * 'TABLE'->desired that are not in 'TABLE'->existing. (The loop body From patchwork Mon Jul 30 06:46:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950721 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=ovn.org 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 41f99Q306Pz9ryt for ; Mon, 30 Jul 2018 16:47:22 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 383ABBA9; Mon, 30 Jul 2018 06:46:52 +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 980573EE for ; Mon, 30 Jul 2018 06:46:50 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0494F6A2 for ; Mon, 30 Jul 2018 06:46:49 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id B92101BF206 for ; Mon, 30 Jul 2018 06:46:47 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:33 -0700 Message-Id: <20180730064638.121021-2-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 2/7] ovn-controller: Add "meter-table-list" ovs-appctl command. 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 Signed-off-by: Justin Pettit --- ovn/controller/ovn-controller.8.xml | 5 +++++ ovn/controller/ovn-controller.c | 30 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/ovn/controller/ovn-controller.8.xml b/ovn/controller/ovn-controller.8.xml index 0eff2113f52e..7d8fa66d7313 100644 --- a/ovn/controller/ovn-controller.8.xml +++ b/ovn/controller/ovn-controller.8.xml @@ -369,6 +369,11 @@ Lists each local logical port and its connection tracking zone. +
meter-table-list
+
+ Lists each meter table entry and its local meter id. +
+
inject-pkt microflow

diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 6ee72a9fafb4..62caace247a8 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -65,6 +65,7 @@ VLOG_DEFINE_THIS_MODULE(main); static unixctl_cb_func ovn_controller_exit; static unixctl_cb_func ct_zone_list; +static unixctl_cb_func meter_table_list; static unixctl_cb_func inject_pkt; #define DEFAULT_BRIDGE_NAME "br-int" @@ -569,6 +570,8 @@ main(int argc, char *argv[]) /* Initialize meter ids for QoS. */ struct ovn_extend_table meter_table; ovn_extend_table_init(&meter_table); + unixctl_command_register("meter-table-list", "", 0, 0, + meter_table_list, &meter_table); daemonize_complete(); @@ -1024,6 +1027,33 @@ ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_destroy(&ds); } +static void +meter_table_list(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *meter_table_) +{ + struct ovn_extend_table *meter_table = meter_table_; + struct ds ds = DS_EMPTY_INITIALIZER; + struct simap meters = SIMAP_INITIALIZER(&meters); + + struct ovn_extend_table_info *m_installed, *next_meter; + EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_meter, meter_table) { + simap_put(&meters, m_installed->name, m_installed->table_id); + } + + const struct simap_node **nodes = simap_sort(&meters); + size_t n_nodes = simap_count(&meters); + for (size_t i = 0; i < n_nodes; i++) { + const struct simap_node *node = nodes[i]; + ds_put_format(&ds, "%s: %d\n", node->name, node->data); + } + + free(nodes); + simap_destroy(&meters); + + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); +} + static void inject_pkt(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *pending_pkt_) From patchwork Mon Jul 30 06:46:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950722 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=ovn.org 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 41f99z6SS4z9s0R for ; Mon, 30 Jul 2018 16:47:51 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 0FB9DBD8; Mon, 30 Jul 2018 06:46:55 +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 C2EDE927 for ; Mon, 30 Jul 2018 06:46:51 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 27F886A2 for ; Mon, 30 Jul 2018 06:46:50 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 40DDE1BF20C for ; Mon, 30 Jul 2018 06:46:49 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:34 -0700 Message-Id: <20180730064638.121021-3-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 3/7] ovn-controller: Add "group-table-list" ovs-appctl command. 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 Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- ovn/controller/ovn-controller.8.xml | 5 +++++ ovn/controller/ovn-controller.c | 30 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/ovn/controller/ovn-controller.8.xml b/ovn/controller/ovn-controller.8.xml index 7d8fa66d7313..2e4e53d6b1b1 100644 --- a/ovn/controller/ovn-controller.8.xml +++ b/ovn/controller/ovn-controller.8.xml @@ -374,6 +374,11 @@ Lists each meter table entry and its local meter id.

+
group-table-list
+
+ Lists each group table entry and its local group id. +
+
inject-pkt microflow

diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 62caace247a8..008f81d70eeb 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -66,6 +66,7 @@ VLOG_DEFINE_THIS_MODULE(main); static unixctl_cb_func ovn_controller_exit; static unixctl_cb_func ct_zone_list; static unixctl_cb_func meter_table_list; +static unixctl_cb_func group_table_list; static unixctl_cb_func inject_pkt; #define DEFAULT_BRIDGE_NAME "br-int" @@ -566,6 +567,8 @@ main(int argc, char *argv[]) /* Initialize group ids for loadbalancing. */ struct ovn_extend_table group_table; ovn_extend_table_init(&group_table); + unixctl_command_register("group-table-list", "", 0, 0, + group_table_list, &group_table); /* Initialize meter ids for QoS. */ struct ovn_extend_table meter_table; @@ -1054,6 +1057,33 @@ meter_table_list(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_destroy(&ds); } +static void +group_table_list(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *group_table_) +{ + struct ovn_extend_table *group_table = group_table_; + struct ds ds = DS_EMPTY_INITIALIZER; + struct simap groups = SIMAP_INITIALIZER(&groups); + + struct ovn_extend_table_info *m_installed, *next_group; + EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_group, group_table) { + simap_put(&groups, m_installed->name, m_installed->table_id); + } + + const struct simap_node **nodes = simap_sort(&groups); + size_t n_nodes = simap_count(&groups); + for (size_t i = 0; i < n_nodes; i++) { + const struct simap_node *node = nodes[i]; + ds_put_format(&ds, "%s: %d\n", node->name, node->data); + } + + free(nodes); + simap_destroy(&groups); + + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); +} + static void inject_pkt(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *pending_pkt_) From patchwork Mon Jul 30 06:46:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950723 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=ovn.org 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 41f9BX3dHcz9ryt for ; Mon, 30 Jul 2018 16:48:20 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C07CCBBF; Mon, 30 Jul 2018 06:46:55 +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 527ED720 for ; Mon, 30 Jul 2018 06:46:54 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 53C256A2 for ; Mon, 30 Jul 2018 06:46:52 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 1DDC61BF20B for ; Mon, 30 Jul 2018 06:46:49 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:35 -0700 Message-Id: <20180730064638.121021-4-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 4/7] ovn: Add Meter and Meter_Band tables to the NB and SB databases. 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 Add support for configuring meters through the Meter and Meter_Band tables in the Northbound database. This commit also has ovn-northd sync those tables between the Northbound and Southbound databases. Add support for configuring meters with ovn-nbctl. Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- ovn/northd/ovn-northd.c | 145 ++++++++++++++++++++++++++++++++++ ovn/ovn-nb.ovsschema | 33 +++++++- ovn/ovn-nb.xml | 80 +++++++++++++++++++ ovn/ovn-sb.ovsschema | 27 ++++++- ovn/ovn-sb.xml | 72 +++++++++++++++++ ovn/utilities/ovn-nbctl.8.xml | 50 ++++++++++++ ovn/utilities/ovn-nbctl.c | 143 +++++++++++++++++++++++++++++++++ tests/ovn-nbctl.at | 58 ++++++++++++++ 8 files changed, 604 insertions(+), 4 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 04a072ba8de7..45557170edc8 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -6606,6 +6606,140 @@ sync_port_groups(struct northd_context *ctx) shash_destroy(&sb_port_groups); } +struct band_entry { + int64_t rate; + int64_t burst_size; + const char *action; +}; + +static int +band_cmp(const void *band1_, const void *band2_) +{ + const struct band_entry *band1p = band1_; + const struct band_entry *band2p = band2_; + + if (band1p->rate != band2p->rate) { + return band1p->rate > band2p->rate ? -1 : 1; + } else if (band1p->burst_size != band2p->burst_size) { + return band1p->burst_size > band2p->burst_size ? -1 : 1; + } else { + return strcmp(band1p->action, band2p->action); + } +} + +static bool +bands_need_update(const struct nbrec_meter *nb_meter, + const struct sbrec_meter *sb_meter) +{ + if (nb_meter->n_bands != sb_meter->n_bands) { + return true; + } + + /* A single band is the most common scenario, so speed up that + * check. */ + if (nb_meter->n_bands == 1) { + struct nbrec_meter_band *nb_band = nb_meter->bands[0]; + struct sbrec_meter_band *sb_band = sb_meter->bands[0]; + + return !(nb_band->rate == sb_band->rate + && nb_band->burst_size == sb_band->burst_size + && !strcmp(sb_band->action, nb_band->action)); + } + + /* Place the Northbound entries in sorted order. */ + struct band_entry *nb_bands; + nb_bands = xmalloc(sizeof *nb_bands * nb_meter->n_bands); + for (size_t i = 0; i < nb_meter->n_bands; i++) { + struct nbrec_meter_band *nb_band = nb_meter->bands[i]; + + nb_bands[i].rate = nb_band->rate; + nb_bands[i].burst_size = nb_band->burst_size; + nb_bands[i].action = nb_band->action; + } + qsort(nb_bands, nb_meter->n_bands, sizeof *nb_bands, band_cmp); + + /* Place the Southbound entries in sorted order. */ + struct band_entry *sb_bands; + sb_bands = xmalloc(sizeof *sb_bands * sb_meter->n_bands); + for (size_t i = 0; i < sb_meter->n_bands; i++) { + struct sbrec_meter_band *sb_band = sb_meter->bands[i]; + + sb_bands[i].rate = sb_band->rate; + sb_bands[i].burst_size = sb_band->burst_size; + sb_bands[i].action = sb_band->action; + } + qsort(sb_bands, sb_meter->n_bands, sizeof *sb_bands, band_cmp); + + bool need_update = false; + for (size_t i = 0; i < nb_meter->n_bands; i++) { + if (nb_bands[i].rate != sb_bands[i].rate + || nb_bands[i].burst_size != sb_bands[i].burst_size + || strcmp(nb_bands[i].action, nb_bands[i].action)) { + need_update = true; + goto done; + } + } + +done: + free(nb_bands); + free(sb_bands); + + return need_update; +} + +/* Each entry in the Meter and Meter_Band tables in OVN_Northbound have + * a corresponding entries in the Meter and Meter_Band tables in + * OVN_Southbound. + */ +static void +sync_meters(struct northd_context *ctx) +{ + struct shash sb_meters = SHASH_INITIALIZER(&sb_meters); + + const struct sbrec_meter *sb_meter; + SBREC_METER_FOR_EACH (sb_meter, ctx->ovnsb_idl) { + shash_add(&sb_meters, sb_meter->name, sb_meter); + } + + const struct nbrec_meter *nb_meter; + NBREC_METER_FOR_EACH (nb_meter, ctx->ovnnb_idl) { + bool new_sb_meter = false; + + sb_meter = shash_find_and_delete(&sb_meters, nb_meter->name); + if (!sb_meter) { + sb_meter = sbrec_meter_insert(ctx->ovnsb_txn); + sbrec_meter_set_name(sb_meter, nb_meter->name); + new_sb_meter = true; + } + + if (new_sb_meter || bands_need_update(nb_meter, sb_meter)) { + struct sbrec_meter_band **sb_bands; + sb_bands = xcalloc(nb_meter->n_bands, sizeof *sb_bands); + for (size_t i = 0; i < nb_meter->n_bands; i++) { + const struct nbrec_meter_band *nb_band = nb_meter->bands[i]; + + sb_bands[i] = sbrec_meter_band_insert(ctx->ovnsb_txn); + + sbrec_meter_band_set_action(sb_bands[i], nb_band->action); + sbrec_meter_band_set_rate(sb_bands[i], nb_band->rate); + sbrec_meter_band_set_burst_size(sb_bands[i], + nb_band->burst_size); + } + sbrec_meter_set_bands(sb_meter, sb_bands, nb_meter->n_bands); + free(sb_bands); + } + + sbrec_meter_set_unit(sb_meter, nb_meter->unit); + } + + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, &sb_meters) { + sbrec_meter_delete(node->data); + shash_delete(&sb_meters, node); + } + shash_destroy(&sb_meters); +} + /* * struct 'dns_info' is used to sync the DNS records between OVN Northbound db * and Southbound db. @@ -6726,6 +6860,7 @@ ovnnb_db_run(struct northd_context *ctx, sync_address_sets(ctx); sync_port_groups(ctx); + sync_meters(ctx); sync_dns_entries(ctx, &datapaths); struct ovn_port_group *pg, *next_pg; @@ -7351,6 +7486,16 @@ main(int argc, char *argv[]) &sbrec_rbac_permission_col_insert_delete); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 8e6ddec4662f..9a0d8ec70514 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.11.0", - "cksum": "1149260021 18713", + "version": "5.12.0", + "cksum": "2812995200 20238", "tables": { "NB_Global": { "columns": { @@ -195,6 +195,35 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "isRoot": false}, + "Meter": { + "columns": { + "name": {"type": "string"}, + "unit": {"type": {"key": {"type": "string", + "enum": ["set", ["kbps", "pktps"]]}}}, + "bands": {"type": {"key": {"type": "uuid", + "refTable": "Meter_Band", + "refType": "strong"}, + "min": 1, + "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, + "Meter_Band": { + "columns": { + "action": {"type": {"key": {"type": "string", + "enum": ["set", ["drop"]]}}}, + "rate": {"type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 4294967295}}}, + "burst_size": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 4294967295}}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "isRoot": false}, "Logical_Router": { "columns": { "name": {"type": "string"}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index e4e72b27cf36..1feb2af52027 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -1356,6 +1356,86 @@ + +

+ Each row in this table represents a meter that can be used for QoS or + rate-limiting. +

+ + +

+ A name for this meter. +

+ +

+ Names that begin with "__" are reserved for OVN internal use and should + not be added manually. +

+
+ + +

+ The unit for and + parameters in + the entry. kbps specifies + kilobits per second, and pktps specifies packets + per second. +

+
+ + +

+ The bands associated with this meter. Each band specifies a + rate above which the band is to take the action + action. If multiple bands' rates are exceeded, + then the band with the highest rate among the exceeded bands is + selected. +

+
+ + + See External IDs at the beginning of this document. + +
+ + +

+ Each row in this table represents a meter band which specifies the + rate above which the configured action should be applied. These bands + are referenced by the column in + the table. +

+ + +

+ The action to execute when this band matches. The only supported + action is drop. +

+
+ + +

+ The relative rate limit for this band, in kilobits per second or + bits per second, depending on whether the parent + entry's column specified + kbps or pktps. +

+
+ + +

+ The maximum burst allowed for the band in kilobits or packets, + depending on whether kbps or pktps was + selected in the parent entry's + column. +

+
+ + + See External IDs at the beginning of this document. + +
+

A port within an L3 logical router. diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema index 9e271d433246..ad6ad3b71da0 100644 --- a/ovn/ovn-sb.ovsschema +++ b/ovn/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "1.15.0", - "cksum": "1839738004 13639", + "version": "1.16.0", + "cksum": "3046632234 14844", "tables": { "SB_Global": { "columns": { @@ -98,6 +98,29 @@ "indexes": [["datapath", "tunnel_key"], ["datapath", "name"]], "isRoot": true}, + "Meter": { + "columns": { + "name": {"type": "string"}, + "unit": {"type": {"key": {"type": "string", + "enum": ["set", ["kbps", "pktps"]]}}}, + "bands": {"type": {"key": {"type": "uuid", + "refTable": "Meter_Band", + "refType": "strong"}, + "min": 1, + "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, + "Meter_Band": { + "columns": { + "action": {"type": {"key": {"type": "string", + "enum": ["set", ["drop"]]}}}, + "rate": {"type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 4294967295}}}, + "burst_size": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 4294967295}}}}, + "isRoot": false}, "Datapath_Binding": { "columns": { "tunnel_key": { diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index f9724d398ce6..57d8a9e042a5 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1923,6 +1923,78 @@ tcp.flags = RST;

+ +

+ Each row in this table represents a meter that can be used for QoS or + rate-limiting. +

+ + +

+ A name for this meter. +

+ +

+ Names that begin with "__" are reserved for OVN internal use and should + not be added manually. +

+
+ + +

+ The unit for and + parameters in + the entry. kbps specifies + kilobits per second, and pktps specifies packets + per second. +

+
+ + +

+ The bands associated with this meter. Each band specifies a + rate above which the band is to take the action + action. If multiple bands' rates are exceeded, + then the band with the highest rate among the exceeded bands is + selected. +

+
+
+ + +

+ Each row in this table represents a meter band which specifies the + rate above which the configured action should be applied. These bands + are referenced by the column in + the table. +

+ + +

+ The action to execute when this band matches. The only supported + action is drop. +

+
+ + +

+ The relative rate limit for this band, in kilobits per second or + bits per second, depending on whether the parent + entry's column specified + kbps or pktps. +

+
+ + +

+ The maximum burst allowed for the band in kilobits or packets, + depending on whether kbps or pktps was + selected in the parent entry's + column. +

+
+
+

Each row in this table represents a logical datapath, which implements a diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index 2cd2fab304cd..a8ea7d8cb1e1 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -172,6 +172,56 @@ +

Meter Commands

+
+
meter-add name unit action rate [burst_size]
+
+

+ Adds the specified meter. name must be a unique + name to identify this meter. The action argument + specifies what should happen when this meter is exceeded. + The only supported action is drop. +

+ +

+ The unit specifies the unit for the rate + argument; valid values are kbps and + pktps for kilobits per second and packets per + second, respectively. The burst_rate option + configures the maximum burst allowed for the band in kilobits + or packets depending on whether the unit chosen was + kbps or pktps, respectively. +

+ +

+ ovn-nbctl only supports adding a meter with a + single band, but the other commands support meters with + multiple bands. +

+ +

+ Names that start with "__" are reserved for internal use by OVN, + so ovn-nbctl does not allow adding them. +

+
+ +
meter-del [name]
+
+

+ Deletes meters. By default, all meters are deleted. If + name is supplied, only the meter with that name + will be deleted. +

+
+ +
meter-list
+
+

+ Lists all meters. +

+
+
+

Logical Switch Port Commands

[--may-exist] lsp-add switch port
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index 3c3e582cb906..9f0e6347c104 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -496,6 +496,12 @@ QoS commands:\n\ remove QoS rules from SWITCH\n\ qos-list SWITCH print QoS rules for SWITCH\n\ \n\ +Meter commands:\n\ + meter-add NAME UNIT ACTION RATE [BURST_SIZE]\n\ + add a meter\n\ + meter-del [NAME] remove meters\n\ + meter-list print meters\n\ +\n\ Logical switch port commands:\n\ lsp-add SWITCH PORT add logical port PORT on SWITCH\n\ lsp-add SWITCH PORT PARENT TAG\n\ @@ -2290,6 +2296,137 @@ nbctl_qos_del(struct ctl_context *ctx) } } +static int +meter_cmp(const void *meter1_, const void *meter2_) +{ + struct nbrec_meter *const *meter1p = meter1_; + struct nbrec_meter *const *meter2p = meter2_; + const struct nbrec_meter *meter1 = *meter1p; + const struct nbrec_meter *meter2 = *meter2p; + + return strcmp(meter1->name, meter2->name); +} + +static void +nbctl_meter_list(struct ctl_context *ctx) +{ + const struct nbrec_meter **meters = NULL; + const struct nbrec_meter *meter; + size_t n_capacity = 0; + size_t n_meters = 0; + + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (n_meters == n_capacity) { + meters = x2nrealloc(meters, &n_capacity, sizeof *meters); + } + + meters[n_meters] = meter; + n_meters++; + } + + if (n_meters) { + qsort(meters, n_meters, sizeof *meters, meter_cmp); + } + + for (size_t i = 0; i < n_meters; i++) { + meter = meters[i]; + ds_put_format(&ctx->output, "%s: unit=%s bands:\n", meter->name, + meter->unit); + + for (size_t j = 0; j < meter->n_bands; j++) { + const struct nbrec_meter_band *band = meter->bands[j]; + + ds_put_format(&ctx->output, " %s: rate=%"PRId64"", + band->action, band->rate); + if (band->burst_size) { + ds_put_format(&ctx->output, ", burst_size=%"PRId64"", + band->burst_size); + } + } + + ds_put_cstr(&ctx->output, "\n"); + } + + free(meters); +} + +static void +nbctl_meter_add(struct ctl_context *ctx) +{ + const struct nbrec_meter *meter; + + const char *name = ctx->argv[1]; + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (!strcmp(meter->name, name)) { + ctl_fatal("meter with name \"%s\" already exists", name); + } + } + + if (!strncmp(name, "__", 2)) { + ctl_fatal("meter names that begin with \"__\" are reserved"); + } + + const char *unit = ctx->argv[2]; + if (strcmp(unit, "kbps") && strcmp(unit, "pktps")) { + ctl_fatal("unit must be \"kbps\" or \"pktps\""); + } + + const char *action = ctx->argv[3]; + if (strcmp(action, "drop")) { + ctl_fatal("action must be \"drop\""); + } + + int64_t rate; + if (!ovs_scan(ctx->argv[4], "%"SCNd64, &rate) + || rate < 1 || rate > UINT32_MAX) { + ctl_fatal("rate must be in the range 1...4294967295"); + } + + int64_t burst_size = 0; + if (ctx->argc > 5) { + if (!ovs_scan(ctx->argv[5], "%"SCNd64, &burst_size) + || burst_size < 0 || burst_size > UINT32_MAX) { + ctl_fatal("burst_size must be in the range 0...4294967295"); + } + } + + /* Create the band. We only support adding a single band. */ + struct nbrec_meter_band *band = nbrec_meter_band_insert(ctx->txn); + nbrec_meter_band_set_action(band, action); + nbrec_meter_band_set_rate(band, rate); + nbrec_meter_band_set_burst_size(band, burst_size); + + /* Create the meter. */ + meter = nbrec_meter_insert(ctx->txn); + nbrec_meter_set_name(meter, name); + nbrec_meter_set_unit(meter, unit); + nbrec_meter_set_bands(meter, &band, 1); +} + +static void +nbctl_meter_del(struct ctl_context *ctx) +{ + const struct nbrec_meter *meter, *next; + + /* If a name is not specified, delete all meters. */ + if (ctx->argc == 1) { + NBREC_METER_FOR_EACH_SAFE (meter, next, ctx->idl) { + nbrec_meter_delete(meter); + } + return; + } + + /* Remove the matching meter. */ + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (strcmp(ctx->argv[1], meter->name)) { + continue; + } + + nbrec_meter_delete(meter); + return; + } +} + static void nbctl_lb_add(struct ctl_context *ctx) { @@ -4678,6 +4815,12 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_qos_del, NULL, "", RW }, { "qos-list", 1, 1, "SWITCH", NULL, nbctl_qos_list, NULL, "", RO }, + /* meter commands. */ + { "meter-add", 4, 5, "NAME UNIT ACTION RATE [BURST_SIZE]", NULL, + nbctl_meter_add, NULL, "", RW }, + { "meter-del", 0, 1, "[NAME]", NULL, nbctl_meter_del, NULL, "", RW }, + { "meter-list", 0, 0, "", NULL, nbctl_meter_list, NULL, "", RO }, + /* logical switch port commands. */ { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add, NULL, "--may-exist", RW }, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 64e217654c2f..7a1445e312ff 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -323,6 +323,64 @@ OVN_NBCTL_TEST_STOP AT_CLEANUP dnl --------------------------------------------------------------------- + +AT_SETUP([ovn-nbctl - Meters]) +OVN_NBCTL_TEST_START + +AT_CHECK([ovn-nbctl meter-add meter1 kbps drop 10]) +AT_CHECK([ovn-nbctl meter-add meter2 kbps drop 3 2]) +AT_CHECK([ovn-nbctl meter-add meter3 kbps drop 100 200]) + +dnl Add duplicate meter name +AT_CHECK([ovn-nbctl meter-add meter1 kbps drop 10], [1], [], [stderr]) +AT_CHECK([grep 'already exists' stderr], [0], [ignore]) + +dnl Add reserved meter name +AT_CHECK([ovn-nbctl meter-add __meter1 kbps drop 10], [1], [], [stderr]) +AT_CHECK([grep 'reserved' stderr], [0], [ignore]) + +dnl Add meter with invalid rates +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 100010111111], [1], [], +[ovn-nbctl: rate must be in the range 1...4294967295 +]) + +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 0], [1], [], +[ovn-nbctl: rate must be in the range 1...4294967295 +]) + +dnl Add meter with invalid burst_size +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 10 100010111111], [1], [], +[ovn-nbctl: burst_size must be in the range 0...4294967295 +]) + +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +meter1: unit=kbps bands: + drop: rate=10 +meter2: unit=kbps bands: + drop: rate=3, burst_size=2 +meter3: unit=kbps bands: + drop: rate=100, burst_size=200 +]) + +dnl Delete a single meter. +AT_CHECK([ovn-nbctl meter-del meter2]) +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +meter1: unit=kbps bands: + drop: rate=10 +meter3: unit=kbps bands: + drop: rate=100, burst_size=200 +]) + +dnl Delete all meters. +AT_CHECK([ovn-nbctl meter-del]) +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +]) + +OVN_NBCTL_TEST_STOP +AT_CLEANUP + +dnl --------------------------------------------------------------------- + AT_SETUP([ovn-nbctl - NATs]) OVN_NBCTL_TEST_START AT_CHECK([ovn-nbctl lr-add lr0]) From patchwork Mon Jul 30 06:46:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950724 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=ovn.org 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 41f9CF5MnTz9s1R for ; Mon, 30 Jul 2018 16:48:57 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id D34F9BB6; Mon, 30 Jul 2018 06:46:57 +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 4EAD3C0A for ; Mon, 30 Jul 2018 06:46:55 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 34A9F75C for ; Mon, 30 Jul 2018 06:46:54 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id ACC0C1BF210 for ; Mon, 30 Jul 2018 06:46:51 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:36 -0700 Message-Id: <20180730064638.121021-5-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 5/7] ovn: Support configuring meters through SB Meter table. 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 Add the ability to configure meters through the newly introduced Meter table in the Southbound database. Previously, meters were configured by providing strings to describe the meter in the extended meter table. This patch changes the behavior so that the extended meter table's strings are references to names in the Meter table. The old behavior is still supported if the extended meter table entry begins with "__string: " Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- ovn/controller/ofctrl.c | 124 +++++++++++++++++++++++--------- ovn/controller/ofctrl.h | 3 +- ovn/controller/ovn-controller.c | 1 + ovn/lib/actions.c | 11 +-- 4 files changed, 100 insertions(+), 39 deletions(-) diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c index c7f41612456d..01981a79480b 100644 --- a/ovn/controller/ofctrl.c +++ b/ovn/controller/ofctrl.c @@ -812,6 +812,81 @@ add_ct_flush_zone(uint16_t zone_id, struct ovs_list *msgs) ovs_list_push_back(msgs, &msg->list_node); } +static void +add_meter_string(struct ovn_extend_table_info *m_desired, + struct ovs_list *msgs) +{ + /* Create and install new meter. */ + struct ofputil_meter_mod mm; + enum ofputil_protocol usable_protocols; + char *meter_string = xasprintf("meter=%"PRIu32",%s", + m_desired->table_id, + &m_desired->name[9]); + char *error = parse_ofp_meter_mod_str(&mm, meter_string, OFPMC13_ADD, + &usable_protocols); + if (!error) { + add_meter_mod(&mm, msgs); + } else { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_ERR_RL(&rl, "new meter %s %s", error, meter_string); + free(error); + } + free(meter_string); +} + +static void +add_meter(struct ovn_extend_table_info *m_desired, + const struct sbrec_meter_table *meter_table, + struct ovs_list *msgs) +{ + const struct sbrec_meter *sb_meter; + SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) { + if (!strcmp(m_desired->name, sb_meter->name)) { + break; + } + } + + if (!sb_meter) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name); + return; + } + + struct ofputil_meter_mod mm; + mm.command = OFPMC13_ADD; + mm.meter.meter_id = m_desired->table_id; + mm.meter.flags = OFPMF13_STATS; + + if (!strcmp(sb_meter->unit, "pktps")) { + mm.meter.flags |= OFPMF13_PKTPS; + } else { + mm.meter.flags |= OFPMF13_KBPS; + } + + mm.meter.n_bands = sb_meter->n_bands; + mm.meter.bands = xcalloc(mm.meter.n_bands, sizeof *mm.meter.bands); + + for (size_t i = 0; i < sb_meter->n_bands; i++) { + struct sbrec_meter_band *sb_band = sb_meter->bands[i]; + struct ofputil_meter_band *mm_band = &mm.meter.bands[i]; + + if (!strcmp(sb_band->action, "drop")) { + mm_band->type = OFPMBT13_DROP; + } + + mm_band->prec_level = 0; + mm_band->rate = sb_band->rate; + mm_band->burst_size = sb_band->burst_size; + + if (mm_band->burst_size) { + mm.meter.flags |= OFPMF13_BURST; + } + } + + add_meter_mod(&mm, msgs); + free(mm.meter.bands); +} + /* The flow table can be updated if the connection to the switch is up and * in the correct state and not backlogged with existing flow_mods. (Our * criteria for being backlogged appear very conservative, but the socket @@ -830,10 +905,10 @@ ofctrl_can_put(void) /* Replaces the flow table on the switch, if possible, by the flows added * with ofctrl_add_flow(). * - * Replaces the group table and meter table on the switch, if possible, by the - * contents of 'groups->desired'. Regardless of whether the group table - * is updated, this deletes all the groups from the 'groups->desired' and frees - * them. (The hmap itself isn't destroyed.) + * Replaces the group table and meter table on the switch, if possible, + * by the contents of '->desired'. Regardless of whether the table is + * updated, this deletes all the groups ore metersjfrom the '->desired' + * and frees them. (The hmap itself isn't destroyed.) * * Sends conntrack flush messages to each zone in 'pending_ct_zones' that * is in the CT_ZONE_OF_QUEUED state and then moves the zone into the @@ -842,7 +917,7 @@ ofctrl_can_put(void) * This should be called after ofctrl_run() within the main loop. */ void ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, - int64_t nb_cfg) + const struct sbrec_meter_table *meter_table, int64_t nb_cfg) { if (!ofctrl_can_put()) { ovn_flow_table_clear(flow_table); @@ -892,22 +967,13 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, * add them to the switch. */ struct ovn_extend_table_info *m_desired; EXTEND_TABLE_FOR_EACH_UNINSTALLED (m_desired, meters) { - /* Create and install new meter. */ - struct ofputil_meter_mod mm; - enum ofputil_protocol usable_protocols; - char *meter_string = xasprintf("meter=%"PRIu32",%s", - m_desired->table_id, - m_desired->name); - char *error = parse_ofp_meter_mod_str(&mm, meter_string, OFPMC13_ADD, - &usable_protocols); - if (!error) { - add_meter_mod(&mm, &msgs); + if (!strncmp(m_desired->name, "__string: ", 10)) { + /* The "set-meter" action creates a meter entry name that + * describes the meter itself. */ + add_meter_string(m_desired, &msgs); } else { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_ERR_RL(&rl, "new meter %s %s", error, meter_string); - free(error); + add_meter(m_desired, meter_table, &msgs); } - free(meter_string); } /* Iterate through all of the installed flows. If any of them are no @@ -1015,21 +1081,11 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_meter, meters) { /* Delete the meter. */ struct ofputil_meter_mod mm; - enum ofputil_protocol usable_protocols; - char *meter_string = xasprintf("meter=%"PRIu32"", - m_installed->table_id); - char *error = parse_ofp_meter_mod_str(&mm, meter_string, - OFPMC13_DELETE, - &usable_protocols); - if (!error) { - add_meter_mod(&mm, &msgs); - } else { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_ERR_RL(&rl, "Error deleting meter %"PRIu32": %s", - m_installed->table_id, error); - free(error); - } - free(meter_string); + memset(&mm, 0, sizeof mm); + mm.command = OFPMC13_DELETE; + mm.meter.meter_id = m_installed->table_id; + add_meter_mod(&mm, &msgs); + ovn_extend_table_remove(meters, m_installed); } diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h index 886b9bd21e9a..e3fc95b05cd3 100644 --- a/ovn/controller/ofctrl.h +++ b/ovn/controller/ofctrl.h @@ -27,6 +27,7 @@ struct hmap; struct match; struct ofpbuf; struct ovsrec_bridge; +struct sbrec_meter_table; struct shash; /* Interface for OVN main loop. */ @@ -36,7 +37,7 @@ enum mf_field_id ofctrl_run(const struct ovsrec_bridge *br_int, struct shash *pending_ct_zones); bool ofctrl_can_put(void); void ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones, - int64_t nb_cfg); + const struct sbrec_meter_table *meter_table, int64_t nb_cfg); void ofctrl_wait(void); void ofctrl_destroy(void); int64_t ofctrl_get_cur_cfg(void); diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 008f81d70eeb..470e02ae862e 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -768,6 +768,7 @@ main(int argc, char *argv[]) time_msec()); ofctrl_put(&flow_table, &pending_ct_zones, + sbrec_meter_table_get(ovnsb_idl_loop.idl), get_nb_cfg(sbrec_sb_global_table_get( ovnsb_idl_loop.idl))); diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 430bb677bafb..26cdb4fdd482 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -2217,13 +2217,16 @@ encode_SET_METER(const struct ovnact_set_meter *cl, uint32_t table_id; struct ofpact_meter *om; + /* Use the special "__string:" prefix to indicate that the name + * describes the meter itself. */ char *name; if (cl->burst) { - name = xasprintf("kbps burst stats bands=type=drop rate=%"PRId64" " - "burst_size=%"PRId64"", cl->rate, cl->burst); + name = xasprintf("__string: kbps burst stats bands=type=drop " + "rate=%"PRId64" burst_size=%"PRId64"", cl->rate, + cl->burst); } else { - name = xasprintf("kbps stats bands=type=drop rate=%"PRId64"", - cl->rate); + name = xasprintf("__string: kbps stats bands=type=drop " + "rate=%"PRId64"", cl->rate); } table_id = ovn_extend_table_assign_id(ep->meter_table, name); From patchwork Mon Jul 30 06:46:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950725 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=ovn.org 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 41f9Cs4tNTz9ryt for ; Mon, 30 Jul 2018 16:49:29 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C174CC87; Mon, 30 Jul 2018 06:46:59 +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 9B160C87 for ; Mon, 30 Jul 2018 06:46:58 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5A633701 for ; Mon, 30 Jul 2018 06:46:57 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 9002A1BF20C for ; Mon, 30 Jul 2018 06:46:53 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:37 -0700 Message-Id: <20180730064638.121021-6-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 6/7] ofproto: Add support for specifying a meter in controller actions. 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 Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- include/openvswitch/ofp-actions.h | 8 ++++++ lib/ofp-actions.c | 27 +++++++++++++++++-- ofproto/ofproto-dpif-xlate.c | 24 +++++++++++++---- ofproto/ofproto-dpif.c | 1 + ofproto/ofproto.c | 44 +++++++++++++++++++++++++++++++ utilities/ovs-ofctl.8.in | 4 +++ 6 files changed, 101 insertions(+), 7 deletions(-) diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index b3dd0959d53e..3b0350496294 100644 --- a/include/openvswitch/ofp-actions.h +++ b/include/openvswitch/ofp-actions.h @@ -287,6 +287,8 @@ struct ofpact_output { uint16_t max_len; /* Max send len, for port OFPP_CONTROLLER. */ }; +#define NX_CTLR_NO_METER 0 + /* OFPACT_CONTROLLER. * * Used for NXAST_CONTROLLER. */ @@ -305,6 +307,12 @@ struct ofpact_controller { /* Arbitrary data to include in the packet-in message (currently, * only in NXT_PACKET_IN2). */ uint16_t userdata_len; + + /* Meter to which this controller action should be associated. + * If requested, this will override a "controller" virtual meter. + * A value of NX_CTLR_NO_METER means no meter is requested. */ + uint32_t meter_id; + uint32_t provider_meter_id; ); uint8_t userdata[0]; }; diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index fa94cbbd9436..5aacff62a34a 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -754,6 +754,7 @@ enum nx_action_controller2_prop_type { NXAC2PT_REASON, /* uint8_t reason (OFPR_*), default 0. */ NXAC2PT_USERDATA, /* Data to copy into NXPINT_USERDATA. */ NXAC2PT_PAUSE, /* Flag to pause pipeline to resume later. */ + NXAC2PT_METER_ID, /* ovs_b32 meter (default NX_CTLR_NO_METER). */ }; /* The action structure for NXAST_CONTROLLER2 is "struct ext_action_header", @@ -771,6 +772,7 @@ decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac, oc->max_len = ntohs(nac->max_len); oc->controller_id = ntohs(nac->controller_id); oc->reason = nac->reason; + oc->meter_id = NX_CTLR_NO_METER; ofpact_finish_CONTROLLER(out, &oc); return 0; @@ -790,6 +792,7 @@ decode_NXAST_RAW_CONTROLLER2(const struct ext_action_header *eah, oc->ofpact.raw = NXAST_RAW_CONTROLLER2; oc->max_len = UINT16_MAX; oc->reason = OFPR_ACTION; + oc->meter_id = NX_CTLR_NO_METER; struct ofpbuf properties; ofpbuf_use_const(&properties, eah, ntohs(eah->len)); @@ -831,6 +834,10 @@ decode_NXAST_RAW_CONTROLLER2(const struct ext_action_header *eah, oc->pause = true; break; + case NXAC2PT_METER_ID: + error = ofpprop_parse_u32(&payload, &oc->meter_id); + break; + default: error = OFPPROP_UNKNOWN(false, "NXAST_RAW_CONTROLLER2", type); break; @@ -852,6 +859,7 @@ encode_CONTROLLER(const struct ofpact_controller *controller, { if (controller->userdata_len || controller->pause + || controller->meter_id != NX_CTLR_NO_METER || controller->ofpact.raw == NXAST_RAW_CONTROLLER2) { size_t start_ofs = out->size; put_NXAST_CONTROLLER2(out); @@ -872,6 +880,9 @@ encode_CONTROLLER(const struct ofpact_controller *controller, if (controller->pause) { ofpprop_put_flag(out, NXAC2PT_PAUSE); } + if (controller->meter_id != NX_CTLR_NO_METER) { + ofpprop_put_u32(out, NXAC2PT_METER_ID, controller->meter_id); + } pad_ofpat(out, start_ofs); } else { struct nx_action_controller *nac; @@ -889,6 +900,7 @@ parse_CONTROLLER(char *arg, const struct ofpact_parse_params *pp) enum ofp_packet_in_reason reason = OFPR_ACTION; uint16_t controller_id = 0; uint16_t max_len = UINT16_MAX; + uint32_t meter_id = NX_CTLR_NO_METER; const char *userdata = NULL; bool pause = false; @@ -921,6 +933,11 @@ parse_CONTROLLER(char *arg, const struct ofpact_parse_params *pp) userdata = value; } else if (!strcmp(name, "pause")) { pause = true; + } else if (!strcmp(name, "meter_id")) { + char *error = str_to_u32(value, &meter_id); + if (error) { + return error; + } } else { return xasprintf("unknown key \"%s\" parsing controller " "action", name); @@ -928,7 +945,8 @@ parse_CONTROLLER(char *arg, const struct ofpact_parse_params *pp) } } - if (reason == OFPR_ACTION && controller_id == 0 && !userdata && !pause) { + if (reason == OFPR_ACTION && controller_id == 0 && !userdata && !pause + && meter_id == NX_CTLR_NO_METER) { struct ofpact_output *output; output = ofpact_put_OUTPUT(pp->ofpacts); @@ -942,6 +960,7 @@ parse_CONTROLLER(char *arg, const struct ofpact_parse_params *pp) controller->reason = reason; controller->controller_id = controller_id; controller->pause = pause; + controller->meter_id = meter_id; if (userdata) { size_t start_ofs = pp->ofpacts->size; @@ -976,7 +995,7 @@ format_CONTROLLER(const struct ofpact_controller *a, const struct ofpact_format_params *fp) { if (a->reason == OFPR_ACTION && !a->controller_id && !a->userdata_len - && !a->pause) { + && !a->pause && a->meter_id == NX_CTLR_NO_METER) { ds_put_format(fp->s, "%sCONTROLLER:%s%"PRIu16, colors.special, colors.end, a->max_len); } else { @@ -1006,6 +1025,10 @@ format_CONTROLLER(const struct ofpact_controller *a, if (a->pause) { ds_put_format(fp->s, "%spause%s,", colors.value, colors.end); } + if (a->meter_id != NX_CTLR_NO_METER) { + ds_put_format(fp->s, "%smeter_id=%s%"PRIu32",", + colors.param, colors.end, a->meter_id); + } ds_chomp(fp->s, ','); ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); } diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index dc63afa35a6b..01f1fafeb356 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4619,6 +4619,7 @@ static void xlate_controller_action(struct xlate_ctx *ctx, int len, enum ofp_packet_in_reason reason, uint16_t controller_id, + uint32_t provider_meter_id, const uint8_t *userdata, size_t userdata_len) { xlate_commit_actions(ctx); @@ -4655,9 +4656,21 @@ xlate_controller_action(struct xlate_ctx *ctx, int len, } recirc_refs_add(&ctx->xout->recircs, recirc_id); + /* If the controller action didn't request a meter (indicated by a + * 'meter_id' argument other than NX_CTLR_NO_METER), see if one was + * configured through the "controller" virtual meter. + * + * Internally, ovs-vswitchd uses UINT32_MAX to indicate no meter is + * configured. */ + uint32_t meter_id; + if (provider_meter_id == UINT32_MAX) { + meter_id = ctx->xbridge->ofproto->up.controller_meter_id; + } else { + meter_id = provider_meter_id; + } + size_t offset; size_t ac_offset; - uint32_t meter_id = ctx->xbridge->ofproto->up.controller_meter_id; if (meter_id != UINT32_MAX) { /* If controller meter is configured, generate clone(meter, userspace) * action. */ @@ -4852,7 +4865,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) for (i = 0; i < ids->n_controllers; i++) { xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, - ids->cnt_ids[i], NULL, 0); + ids->cnt_ids[i], UINT32_MAX, NULL, 0); } /* Stop processing for current table. */ @@ -4893,7 +4906,7 @@ compose_dec_nsh_ttl_action(struct xlate_ctx *ctx) return false; } else { xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, - 0, NULL, 0); + 0, UINT32_MAX, NULL, 0); } } @@ -4926,7 +4939,7 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) return false; } else { xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0, - NULL, 0); + UINT32_MAX, NULL, 0); } } @@ -4985,7 +4998,7 @@ xlate_output_action(struct xlate_ctx *ctx, ofp_port_t port, : group_bucket_action ? OFPR_GROUP : ctx->in_action_set ? OFPR_ACTION_SET : OFPR_ACTION), - 0, NULL, 0); + 0, UINT32_MAX, NULL, 0); break; case OFPP_NONE: break; @@ -6392,6 +6405,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, xlate_controller_action(ctx, controller->max_len, controller->reason, controller->controller_id, + controller->provider_meter_id, controller->userdata, controller->userdata_len); } diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index ad1e8af43f6e..afe333e35166 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1520,6 +1520,7 @@ add_internal_flows(struct ofproto_dpif *ofproto) controller->max_len = UINT16_MAX; controller->controller_id = 0; controller->reason = OFPR_IMPLICIT_MISS; + controller->meter_id = NX_CTLR_NO_METER; ofpact_finish_CONTROLLER(&ofpacts, &controller); error = add_internal_miss_flow(ofproto, id++, &ofpacts, diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index f946e27b77a9..e71431129af9 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3017,6 +3017,9 @@ remove_groups_rcu(struct ofgroup **groups) static bool ofproto_fix_meter_action(const struct ofproto *, struct ofpact_meter *); +static bool ofproto_fix_controller_action(const struct ofproto *, + struct ofpact_controller *); + /* Creates and returns a new 'struct rule_actions', whose actions are a copy * of from the 'ofpacts_len' bytes of 'ofpacts'. */ const struct rule_actions * @@ -3429,6 +3432,17 @@ ofproto_check_ofpacts(struct ofproto *ofproto, return OFPERR_OFPMMFC_INVALID_METER; } + if (a->type == OFPACT_CONTROLLER) { + struct ofpact_controller *ca = ofpact_get_CONTROLLER(a); + + if (!ofproto_fix_controller_action(ofproto, ca)) { + static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_INFO_RL(&rl2, "%s: controller action specified an " + "unknown meter id: %d", + ofproto->name, ca->meter_id); + } + } + if (a->type == OFPACT_GROUP && !ofproto_group_exists(ofproto, ofpact_get_GROUP(a)->group_id)) { return OFPERR_OFPBAC_BAD_OUT_GROUP; @@ -6292,6 +6306,36 @@ ofproto_fix_meter_action(const struct ofproto *ofproto, return false; } +/* This is used in instruction validation at flow set-up time, to map + * the OpenFlow meter ID in a controller action to the corresponding + * datapath provider meter ID. If either does not exist, sets the + * provider meter id to a value to prevent the provider from using it + * and returns false. Otherwise, updates the meter action and returns + * true. */ +static bool +ofproto_fix_controller_action(const struct ofproto *ofproto, + struct ofpact_controller *ca) +{ + if (ca->meter_id == NX_CTLR_NO_METER) { + ca->provider_meter_id = UINT32_MAX; + return true; + } + + const struct meter *meter = ofproto_get_meter(ofproto, ca->meter_id); + + if (meter && meter->provider_meter_id.uint32 != UINT32_MAX) { + /* Update the action with the provider's meter ID, so that we + * do not need any synchronization between ofproto_dpif_xlate + * and ofproto for meter table access. */ + ca->provider_meter_id = meter->provider_meter_id.uint32; + return true; + } + + /* Prevent the meter from being set by the ofproto provider. */ + ca->provider_meter_id = UINT32_MAX; + return false; +} + /* Finds the meter invoked by 'rule''s actions and adds 'rule' to the meter's * list of rules. */ static void diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 5f26c4cca34a..f7dbd250ef37 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -859,6 +859,10 @@ switch in an \fBNXT_RESUME\fR message, which will restart the packet's traversal from the point where it was interrupted. This permits an OpenFlow controller to interpose on a packet midway through processing in Open vSwitch. +.IP "\fBmeter_id=\fIid\fR" +Associate packets sent to the controller with meter \fIid\fR. By +default, packets sent to the controller are associated with the +"controller" virtual meter, if one was configured. . .RE .IP From patchwork Mon Jul 30 06:46:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Pettit X-Patchwork-Id: 950726 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=ovn.org 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 41f9DM3WzGz9ryt for ; Mon, 30 Jul 2018 16:49:55 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7803AC97; Mon, 30 Jul 2018 06:47:01 +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 24E3EC96 for ; Mon, 30 Jul 2018 06:47:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 80EF96A2 for ; Mon, 30 Jul 2018 06:46:58 +0000 (UTC) X-Originating-IP: 76.21.1.228 Received: from localhost.localdomain (unknown [76.21.1.228]) (Authenticated sender: jpettit@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 7ADBB1BF207 for ; Mon, 30 Jul 2018 06:46:56 +0000 (UTC) From: Justin Pettit To: dev@openvswitch.org Date: Sun, 29 Jul 2018 23:46:38 -0700 Message-Id: <20180730064638.121021-7-jpettit@ovn.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730064638.121021-1-jpettit@ovn.org> References: <20180730064638.121021-1-jpettit@ovn.org> X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW 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] [ACL Meters 7/7] ovn: Add rate-limiting for ACL logs. 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 Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- include/ovn/actions.h | 1 + ovn/lib/actions.c | 56 +++++++++++++++++++++------ ovn/northd/ovn-northd.c | 4 ++ ovn/ovn-nb.ovsschema | 5 ++- ovn/ovn-nb.xml | 9 +++++ ovn/utilities/ovn-nbctl.8.xml | 6 ++- ovn/utilities/ovn-nbctl.c | 13 +++++-- tests/ovn.at | 73 +++++++++++++++++++++++++++++++++++ 8 files changed, 149 insertions(+), 18 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 6384651938f1..1c0c67ce6ffa 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -284,6 +284,7 @@ struct ovnact_log { uint8_t verdict; /* One of LOG_VERDICT_*. */ uint8_t severity; /* One of LOG_SEVERITY_*. */ char *name; + char *meter; }; /* OVNACT_SET_METER. */ diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 26cdb4fdd482..6d4ed1e2c4ed 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -78,7 +78,7 @@ ovnact_init(struct ovnact *ovnact, enum ovnact_type type, size_t len) static size_t encode_start_controller_op(enum action_opcode opcode, bool pause, - struct ofpbuf *ofpacts) + uint32_t meter_id, struct ofpbuf *ofpacts) { size_t ofs = ofpacts->size; @@ -86,6 +86,7 @@ encode_start_controller_op(enum action_opcode opcode, bool pause, oc->max_len = UINT16_MAX; oc->reason = OFPR_ACTION; oc->pause = pause; + oc->meter_id = meter_id; struct action_header ah = { .opcode = htonl(opcode) }; ofpbuf_put(ofpacts, &ah, sizeof ah); @@ -105,7 +106,8 @@ encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts) static void encode_controller_op(enum action_opcode opcode, struct ofpbuf *ofpacts) { - size_t ofs = encode_start_controller_op(opcode, false, ofpacts); + size_t ofs = encode_start_controller_op(opcode, false, NX_CTLR_NO_METER, + ofpacts); encode_finish_controller_op(ofs, ofpacts); } @@ -1245,7 +1247,8 @@ encode_nested_actions(const struct ovnact_nest *on, * converted to OpenFlow, as its userdata. ovn-controller will convert the * packet to ARP or NA and then send the packet and actions back to the * switch inside an OFPT_PACKET_OUT message. */ - size_t oc_offset = encode_start_controller_op(opcode, false, ofpacts); + size_t oc_offset = encode_start_controller_op(opcode, false, + NX_CTLR_NO_METER, ofpacts); ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, ofpacts, OFP13_VERSION); encode_finish_controller_op(oc_offset, ofpacts); @@ -1738,7 +1741,8 @@ encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS, - true, ofpacts); + true, NX_CTLR_NO_METER, + ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -1769,7 +1773,7 @@ encode_PUT_DHCPV6_OPTS(const struct ovnact_put_opts *pdo, struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_DHCPV6_OPTS, true, ofpacts); + ACTION_OPCODE_PUT_DHCPV6_OPTS, true, NX_CTLR_NO_METER, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -1864,7 +1868,8 @@ encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl, struct mf_subfield dst = expr_resolve_field(&dl->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_DNS_LOOKUP, - true, ofpacts); + true, NX_CTLR_NO_METER, + ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2027,7 +2032,7 @@ encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, struct mf_subfield dst = expr_resolve_field(&po->dst); size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_ND_RA_OPTS, true, ofpacts); + ACTION_OPCODE_PUT_ND_RA_OPTS, true, NX_CTLR_NO_METER, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2101,6 +2106,19 @@ parse_log_arg(struct action_context *ctx, struct ovnact_log *log) } } lexer_syntax_error(ctx->lexer, "expecting severity"); + } else if (lexer_match_id(ctx->lexer, "meter")) { + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + /* If multiple meters are given, use the most recent. */ + if (ctx->lexer->token.type == LEX_T_STRING) { + free(log->meter); + log->meter = xstrdup(ctx->lexer->token.s); + } else { + lexer_syntax_error(ctx->lexer, "expecting string"); + return; + } + lexer_get(ctx->lexer); } else { lexer_syntax_error(ctx->lexer, NULL); } @@ -2136,16 +2154,31 @@ format_LOG(const struct ovnact_log *log, struct ds *s) } ds_put_format(s, "verdict=%s, ", log_verdict_to_string(log->verdict)); - ds_put_format(s, "severity=%s);", log_severity_to_string(log->severity)); + ds_put_format(s, "severity=%s", log_severity_to_string(log->severity)); + + if (log->meter) { + ds_put_format(s, ",meter=%s", log->meter); + } + + ds_put_cstr(s, ");"); } static void encode_LOG(const struct ovnact_log *log, - const struct ovnact_encode_params *ep OVS_UNUSED, - struct ofpbuf *ofpacts) + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { + uint32_t meter_id = NX_CTLR_NO_METER; + + if (log->meter) { + meter_id = ovn_extend_table_assign_id(ep->meter_table, log->meter); + if (meter_id == EXT_TABLE_ID_INVALID) { + VLOG_WARN("log specified unknown meter: %"PRIu32, meter_id); + return; + } + } + size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_LOG, false, - ofpacts); + meter_id, ofpacts); struct log_pin_header *lph = ofpbuf_put_uninit(ofpacts, sizeof *lph); lph->verdict = log->verdict; @@ -2163,6 +2196,7 @@ static void ovnact_log_free(struct ovnact_log *log) { free(log->name); + free(log->meter); } static void diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 45557170edc8..ccf74f7c5299 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -3140,6 +3140,10 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl) ds_put_cstr(actions, "verdict=allow, "); } + if (acl->meter) { + ds_put_format(actions, "meter=\"%s\", ", acl->meter); + } + ds_chomp(actions, ' '); ds_chomp(actions, ','); ds_put_cstr(actions, "); "); diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 9a0d8ec70514..3e7164baafaa 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.12.0", - "cksum": "2812995200 20238", + "version": "5.13.0", + "cksum": "1278623084 20312", "tables": { "NB_Global": { "columns": { @@ -166,6 +166,7 @@ "notice", "info", "debug"]]}, "min": 0, "max": 1}}, + "meter": {"type": {"key": "string", "min": 0, "max": 1}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index 1feb2af52027..e124d9489e7c 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -1159,6 +1159,15 @@ info.

+ + +

+ The name of a meter to rate-limit log messages for the ACL. + The string must match the + column of a row in the table. By + default, log messages are not rate-limited. +

+
diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index a8ea7d8cb1e1..269e0fb37e8b 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -85,7 +85,7 @@ must be either switch or port-group.

-
[--type={switch | port-group}] [--log] [--severity=severity] [--name=name] [--may-exist] acl-add entity direction priority match verdict
+
[--type={switch | port-group}] [--log] [--meter=meter] [--severity=severity] [--name=name] [--may-exist] acl-add entity direction priority match verdict

Adds the specified ACL to entity. direction @@ -105,7 +105,9 @@ logging). The severity must be one of alert, warning, notice, info, or debug. If a severity is not specified, the default is - info. + info. The --meter=meter option + is used to rate-limit packet logging. The meter argument + names a meter configured by meter-add.

diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index 9f0e6347c104..a82e9c96f446 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -1822,7 +1822,10 @@ nbctl_acl_list(struct ctl_context *ctx) ds_put_format(&ctx->output, "name=%s,", acl->name); } if (acl->severity) { - ds_put_format(&ctx->output, "severity=%s", acl->severity); + ds_put_format(&ctx->output, "severity=%s,", acl->severity); + } + if (acl->meter) { + ds_put_format(&ctx->output, "meter=\"%s\",", acl->meter); } ds_chomp(&ctx->output, ','); ds_put_cstr(&ctx->output, ")"); @@ -1927,7 +1930,8 @@ nbctl_acl_add(struct ctl_context *ctx) bool log = shash_find(&ctx->options, "--log") != NULL; const char *severity = shash_find_data(&ctx->options, "--severity"); const char *name = shash_find_data(&ctx->options, "--name"); - if (log || severity || name) { + const char *meter = shash_find_data(&ctx->options, "--meter"); + if (log || severity || name || meter) { nbrec_acl_set_log(acl, true); } if (severity) { @@ -1940,6 +1944,9 @@ nbctl_acl_add(struct ctl_context *ctx) if (name) { nbrec_acl_set_name(acl, name); } + if (meter) { + nbrec_acl_set_meter(acl, meter); + } /* Check if same acl already exists for the ls/portgroup */ size_t n_acls = pg ? pg->n_acls : ls->n_acls; @@ -4801,7 +4808,7 @@ static const struct ctl_command_syntax nbctl_commands[] = { /* acl commands. */ { "acl-add", 5, 6, "{SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION", NULL, nbctl_acl_add, NULL, - "--log,--may-exist,--type=,--name=,--severity=", RW }, + "--log,--may-exist,--type=,--name=,--severity=,--meter=", RW }, { "acl-del", 1, 4, "{SWITCH | PORTGROUP} [DIRECTION [PRIORITY MATCH]]", NULL, nbctl_acl_del, NULL, "--type=", RW }, { "acl-list", 1, 1, "{SWITCH | PORTGROUP}", diff --git a/tests/ovn.at b/tests/ovn.at index d1a8967dd300..81edeafc0848 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -6153,6 +6153,79 @@ OVN_CLEANUP([hv]) AT_CLEANUP +AT_SETUP([ovn -- ACL rate-limited logging]) +AT_KEYWORDS([ovn]) +ovn_start + +net_add n1 + +sim_add hv +as hv +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +for i in lp1 lp2; do + ovs-vsctl -- add-port br-int $i -- \ + set interface $i external-ids:iface-id=$i \ + options:tx_pcap=hv/$i-tx.pcap \ + options:rxq_pcap=hv/$i-rx.pcap +done + +lp1_mac="f0:00:00:00:00:01" +lp1_ip="192.168.1.2" + +lp2_mac="f0:00:00:00:00:02" +lp2_ip="192.168.1.3" + +ovn-nbctl ls-add lsw0 +ovn-nbctl --wait=sb lsp-add lsw0 lp1 +ovn-nbctl --wait=sb lsp-add lsw0 lp2 +ovn-nbctl lsp-set-addresses lp1 $lp1_mac +ovn-nbctl lsp-set-addresses lp2 $lp2_mac +ovn-nbctl --wait=sb sync + + +# Add an ACL that rate-limits logs at 10 per second. +ovn-nbctl meter-add http-rl1 pktps drop 10 +ovn-nbctl --log --severity=alert --meter=http-rl1 --name=http-acl1 acl-add lsw0 to-lport 1000 'tcp.dst==80' drop + +# Add an ACL that rate-limits logs at 5 per second. +ovn-nbctl meter-add http-rl2 pktps drop 5 +ovn-nbctl --log --severity=alert --meter=http-rl2 --name=http-acl2 acl-add lsw0 to-lport 1000 'tcp.dst==81' allow + +# Add an ACL that doesn't rate-limit logs. +ovn-nbctl --log --severity=alert --name=http-acl3 acl-add lsw0 to-lport 1000 'tcp.dst==82' drop + + +# For each ACL, send 100 packets. +for i in `seq 1 100`; do + ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=80)' + + ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=81)' + + ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=82)' +done + +# Print some information that may help debugging. +as hv ovs-appctl -t ovn-controller meter-table-list +as hv ovs-ofctl -O OpenFlow13 meter-stats br-int + +# The userspace meter implementation doesn't precisely enforce counts, +# so we just check that exactly 100 "http-acl3" actions were logged and +# that there were more "http-acl1" actions than "http-acl2" ones. +OVS_WAIT_UNTIL([ test 100 = $(grep -c 'http-acl3' hv/ovn-controller.log) ]) + +n_acl1=$(grep -c 'http-acl1' hv/ovn-controller.log) +n_acl2=$(grep -c 'http-acl2' hv/ovn-controller.log) +n_acl3=$(grep -c 'http-acl3' hv/ovn-controller.log) + +AT_CHECK([ test $n_acl3 -gt $n_acl1 ], [0], []) +AT_CHECK([ test $n_acl1 -gt $n_acl2 ], [0], []) + + +OVN_CLEANUP([hv]) +AT_CLEANUP + + AT_SETUP([ovn -- DSCP marking and meter check]) AT_KEYWORDS([ovn]) ovn_start