From patchwork Mon Nov 21 16:12:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Adri=C3=A1n_Moreno?= X-Patchwork-Id: 1707469 X-Patchwork-Delegate: dceara@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Zy/JBcRT; dkim-atps=neutral Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NGC931LKQz23nZ for ; Tue, 22 Nov 2022 03:12:54 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id EE8204167A; Mon, 21 Nov 2022 16:12:52 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org EE8204167A Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Zy/JBcRT X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id RjTK45zM3at6; Mon, 21 Nov 2022 16:12:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 79272416A5; Mon, 21 Nov 2022 16:12:49 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 79272416A5 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 568F0C0033; Mon, 21 Nov 2022 16:12:49 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 19769C0033 for ; Mon, 21 Nov 2022 16:12:48 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DD4FC416D1 for ; Mon, 21 Nov 2022 16:12:44 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org DD4FC416D1 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id P_96PvOUw3NH for ; Mon, 21 Nov 2022 16:12:41 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 78F704167E Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id 78F704167E for ; Mon, 21 Nov 2022 16:12:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669047160; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JQcLRexzJzA+X3YIG0w2Ph/E2F9vYMZuIEzBfOAj9zQ=; b=Zy/JBcRTTX8NLsgYitTK3Uee5Xv2fUf7gycIRG4ebZGZmEYBarONVzeNlntl+UYvF7Y7ed W8f8WeUtACD6x66P1yIpIPl24fAlMBUYx16cnwKeB2J7JEMhjvsc7cOHzHkB3XzFpiEap4 KAA8QuUoZnLgJE3rJHTADzTn2Grh01Q= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-204-qmrmSvUpNl6Ik7VFfHQgYA-1; Mon, 21 Nov 2022 11:12:36 -0500 X-MC-Unique: qmrmSvUpNl6Ik7VFfHQgYA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9A13B858F17; Mon, 21 Nov 2022 16:12:36 +0000 (UTC) Received: from antares.redhat.com (unknown [10.39.193.41]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1232F2027062; Mon, 21 Nov 2022 16:12:34 +0000 (UTC) From: Adrian Moreno To: dev@openvswitch.org Date: Mon, 21 Nov 2022 17:12:17 +0100 Message-Id: <20221121161217.304094-4-amorenoz@redhat.com> In-Reply-To: <20221121161217.304094-1-amorenoz@redhat.com> References: <20221121161217.304094-1-amorenoz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn v6 3/3] northd: add drop sampling 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Two new options are added to NB_Global table that enable drop sampling by specifying the collector_set_id and the obs_domain_id of the sample actions added to all drop flows. For drops coming from an lflow, the sample has the following fields: - obs_domain_id (32-bit): obs_domain_id << 8 | datapath_key - 8 most significant bits: the obs_domain_id specified in the NB_Global options. - 24 least significant bits: the datapath key. - obs_point_id: the cookie (first 32-bits of the lflow's UUID). For drops that are inserted by ovn-controller without any associated lflow, the sample will have the follwing fields: - obs_domain_id (32-bit): obs_domain_id << 8 - 8 most significant bits: the obs_domain_id specified in the NB_Global options. - 24 least significant bits: 0. - obs_point_id: The openflow table number. Adding this configuration is not enough to make OVS sample drops. The apropriate configuration IPFIX needs to be added to those chassis that you wish to sample from. See man(5) ovs-vswitchd.conf for more details. Signed-off-by: Adrian Moreno Acked-by: Numan Siddique --- NEWS | 2 + controller/ovn-controller.c | 42 ++++++++++++++++ controller/physical.c | 40 ++++++++++++--- controller/physical.h | 6 +++ northd/automake.mk | 2 + northd/debug.c | 98 +++++++++++++++++++++++++++++++++++++ northd/debug.h | 30 ++++++++++++ northd/northd.c | 77 ++++++++++++++++------------- northd/ovn-northd.8.xml | 26 ++++++++++ ovn-nb.xml | 28 +++++++++++ ovn-sb.xml | 29 +++++++++++ tests/ovn.at | 67 ++++++++++++++++--------- 12 files changed, 380 insertions(+), 67 deletions(-) create mode 100644 northd/debug.c create mode 100644 northd/debug.h diff --git a/NEWS b/NEWS index 224a7b83e..6c4573b50 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ Post v22.09.0 ------------- + - ovn-northd: Add configuration knobs to enable drop sampling using OVS's + per-flow IPFIX sampling. OVN v22.09.0 - 16 Sep 2022 -------------------------- diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 7dd83e7f4..0752a71ad 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -3172,6 +3172,8 @@ lflow_output_sb_meter_handler(struct engine_node *node, void *data) struct ed_type_pflow_output { /* Desired physical flows. */ struct ovn_desired_flow_table flow_table; + /* Drop debugging options. */ + struct physical_debug debug; }; static void init_physical_ctx(struct engine_node *node, @@ -3216,6 +3218,11 @@ static void init_physical_ctx(struct engine_node *node, chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); } + const struct sbrec_sb_global_table *sb_global_table = + EN_OVSDB_GET(engine_get_input("SB_sb_global", node)); + const struct sbrec_sb_global *sb_global = + sbrec_sb_global_table_first(sb_global_table); + ovs_assert(br_int && chassis); struct ed_type_ct_zones *ct_zones_data = @@ -3237,6 +3244,13 @@ static void init_physical_ctx(struct engine_node *node, p_ctx->local_bindings = &rt_data->lbinding_data.bindings; p_ctx->patch_ofports = &non_vif_data->patch_ofports; p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels; + p_ctx->debug.collector_set_id = smap_get_uint(&sb_global->options, + "debug_drop_collector_set", + 0); + + p_ctx->debug.obs_domain_id = smap_get_uint(&sb_global->options, + "debug_drop_domain_id", + 0); } static void * @@ -3439,6 +3453,32 @@ pflow_output_activated_ports_handler(struct engine_node *node, void *data) return true; } +static bool +pflow_output_sb_sb_global_handler(struct engine_node *node, void *data) +{ + const struct sbrec_sb_global_table *sb_global_table = + EN_OVSDB_GET(engine_get_input("SB_sb_global", node)); + const struct sbrec_sb_global *sb_global = + sbrec_sb_global_table_first(sb_global_table); + + struct ed_type_pflow_output *pfo = data; + + uint32_t collector_set_id = smap_get_uint(&sb_global->options, + "debug_drop_collector_set", + 0); + uint32_t obs_domain_id = smap_get_uint(&sb_global->options, + "debug_drop_domain_id", + 0); + + if (pfo->debug.collector_set_id != collector_set_id || + pfo->debug.obs_domain_id != obs_domain_id) { + engine_set_node_state(node, EN_UPDATED); + pfo->debug.collector_set_id = collector_set_id; + pfo->debug.obs_domain_id = obs_domain_id; + } + return true; +} + static void * en_flow_output_init(struct engine_node *node OVS_UNUSED, struct engine_arg *arg OVS_UNUSED) @@ -3781,6 +3821,8 @@ main(int argc, char *argv[]) engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL); + engine_add_input(&en_pflow_output, &en_sb_sb_global, + pflow_output_sb_sb_global_handler); engine_add_input(&en_northd_options, &en_sb_sb_global, en_northd_options_sb_sb_global_handler); diff --git a/controller/physical.c b/controller/physical.c index 58c4e1f05..bda64741e 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -834,14 +834,32 @@ put_zones_ofpacts(const struct zone_ids *zone_ids, struct ofpbuf *ofpacts_p) } static void -add_default_drop_flow(uint8_t table_id, +put_drop(const struct physical_debug *debug, uint8_t table_id, + struct ofpbuf *ofpacts) +{ + if (debug->collector_set_id) { + struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts); + os->probability = UINT16_MAX; + os->collector_set_id = debug->collector_set_id; + os->obs_domain_id = (debug->obs_domain_id << 24); + os->obs_point_id = table_id; + } +} + +static void +add_default_drop_flow(const struct physical_ctx *p_ctx, + uint8_t table_id, struct ovn_desired_flow_table *flow_table) { struct match match = MATCH_CATCHALL_INITIALIZER; struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); + + put_drop(&p_ctx->debug, table_id, &ofpacts); ofctrl_add_flow(flow_table, table_id, 0, 0, &match, &ofpacts, hc_uuid); + + ofpbuf_uninit(&ofpacts); } static void @@ -849,6 +867,7 @@ put_local_common_flows(uint32_t dp_key, const struct sbrec_port_binding *pb, const struct sbrec_port_binding *parent_pb, const struct zone_ids *zone_ids, + const struct physical_debug *debug, struct ofpbuf *ofpacts_p, struct ovn_desired_flow_table *flow_table) { @@ -884,6 +903,7 @@ put_local_common_flows(uint32_t dp_key, * and the MLF_ALLOW_LOOPBACK flag is not set. */ match_init_catchall(&match); ofpbuf_clear(ofpacts_p); + put_drop(debug, OFTABLE_CHECK_LOOPBACK, ofpacts_p); match_set_metadata(&match, htonll(dp_key)); match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, 0, MLF_ALLOW_LOOPBACK); @@ -1155,6 +1175,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct hmap *chassis_tunnels, const struct sbrec_port_binding *binding, const struct sbrec_chassis *chassis, + const struct physical_debug *debug, struct ovn_desired_flow_table *flow_table, struct ofpbuf *ofpacts_p) { @@ -1178,7 +1199,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, struct zone_ids binding_zones = get_zone_ids(binding, ct_zones); put_local_common_flows(dp_key, binding, NULL, &binding_zones, - ofpacts_p, flow_table); + debug, ofpacts_p, flow_table); ofpbuf_clear(ofpacts_p); match_outport_dp_and_port_keys(&match, dp_key, port_key); @@ -1354,7 +1375,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, /* Pass the parent port binding if the port is a nested * container. */ put_local_common_flows(dp_key, binding, parent_port, &zone_ids, - ofpacts_p, flow_table); + debug, ofpacts_p, flow_table); /* Table 0, Priority 150 and 100. * ============================== @@ -1486,6 +1507,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, /* Drop LOCAL_ONLY traffic leaking through localnet ports. */ ofpbuf_clear(ofpacts_p); + put_drop(debug, OFTABLE_CHECK_LOOPBACK, ofpacts_p); match_outport_dp_and_port_keys(&match, dp_key, port_key); match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, MLF_LOCAL_ONLY, MLF_LOCAL_ONLY); @@ -1883,7 +1905,8 @@ physical_eval_port_binding(struct physical_ctx *p_ctx, p_ctx->local_bindings, p_ctx->patch_ofports, p_ctx->chassis_tunnels, - pb, p_ctx->chassis, flow_table, &ofpacts); + pb, p_ctx->chassis, &p_ctx->debug, + flow_table, &ofpacts); ofpbuf_uninit(&ofpacts); } @@ -2006,7 +2029,8 @@ physical_run(struct physical_ctx *p_ctx, p_ctx->local_bindings, p_ctx->patch_ofports, p_ctx->chassis_tunnels, binding, - p_ctx->chassis, flow_table, &ofpacts); + p_ctx->chassis, &p_ctx->debug, + flow_table, &ofpacts); } /* Handle output to multicast groups, in tables 37 and 38. */ @@ -2130,7 +2154,7 @@ physical_run(struct physical_ctx *p_ctx, * * Drop packets tha do not match any tunnel in_port. */ - add_default_drop_flow(OFTABLE_PHY_TO_LOG, flow_table); + add_default_drop_flow(p_ctx, OFTABLE_PHY_TO_LOG, flow_table); /* Table 37, priority 150. * ======================= @@ -2182,7 +2206,7 @@ physical_run(struct physical_ctx *p_ctx, * * Drop packets that do not match previous flows. */ - add_default_drop_flow(OFTABLE_LOCAL_OUTPUT, flow_table); + add_default_drop_flow(p_ctx, OFTABLE_LOCAL_OUTPUT, flow_table); /* Table 39, Priority 0. * ======================= @@ -2215,7 +2239,7 @@ physical_run(struct physical_ctx *p_ctx, * * Drop packets that do not match previous flows. */ - add_default_drop_flow(OFTABLE_LOG_TO_PHY, flow_table); + add_default_drop_flow(p_ctx, OFTABLE_LOG_TO_PHY, flow_table); ofpbuf_uninit(&ofpacts); } diff --git a/controller/physical.h b/controller/physical.h index 1b8f1ea55..f450dca94 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -43,6 +43,11 @@ struct local_nonvif_data; #define OVN_GENEVE_TYPE 0x80 /* Critical option. */ #define OVN_GENEVE_LEN 4 +struct physical_debug { + uint32_t collector_set_id; + uint32_t obs_domain_id; +}; + struct physical_ctx { struct ovsdb_idl_index *sbrec_port_binding_by_name; struct ovsdb_idl_index *sbrec_port_binding_by_datapath; @@ -59,6 +64,7 @@ struct physical_ctx { struct shash *local_bindings; struct simap *patch_ofports; struct hmap *chassis_tunnels; + struct physical_debug debug; }; void physical_register_ovs_idl(struct ovsdb_idl *); diff --git a/northd/automake.mk b/northd/automake.mk index 81582867d..14cf525d8 100644 --- a/northd/automake.mk +++ b/northd/automake.mk @@ -1,6 +1,8 @@ # ovn-northd bin_PROGRAMS += northd/ovn-northd northd_ovn_northd_SOURCES = \ + northd/debug.c \ + northd/debug.h \ northd/mac-binding-aging.c \ northd/mac-binding-aging.h \ northd/northd.c \ diff --git a/northd/debug.c b/northd/debug.c new file mode 100644 index 000000000..59da5d4f6 --- /dev/null +++ b/northd/debug.c @@ -0,0 +1,98 @@ +#include + +#include + +#include "debug.h" + +#include "openvswitch/dynamic-string.h" +#include "openvswitch/vlog.h" +#include "smap.h" + +VLOG_DEFINE_THIS_MODULE(debug) + +struct debug_config { + bool enabled; + uint32_t collector_set_id; + uint32_t observation_domain_id; + struct ds drop_action; +}; + +static struct debug_config config; + +static bool +debug_enabled(void) +{ + return config.collector_set_id != 0; +} + +void +init_debug_config(const struct nbrec_nb_global *nb) +{ + + const struct smap *options = &nb->options; + uint32_t collector_set_id = smap_get_uint(options, + "debug_drop_collector_set", + 0); + uint32_t observation_domain_id = smap_get_uint(options, + "debug_drop_domain_id", + 0); + + if (collector_set_id != config.collector_set_id || + observation_domain_id != config.observation_domain_id || + !config.drop_action.length) { + + if (observation_domain_id >= UINT8_MAX) { + VLOG_ERR("Observation domain id must be an 8-bit number"); + return; + } + + config.collector_set_id = collector_set_id; + config.observation_domain_id = observation_domain_id; + + ds_clear(&config.drop_action); + + if (debug_enabled()) { + ds_put_format(&config.drop_action, + "sample(probability=65535," + "collector_set=%d," + "obs_domain=%d," + "obs_point=$cookie); ", + config.collector_set_id, + config.observation_domain_id); + + ds_put_cstr(&config.drop_action, "/* drop */"); + VLOG_DBG("Debug drop sampling: enabled"); + } else { + ds_put_cstr(&config.drop_action, "drop;"); + VLOG_DBG("Debug drop sampling: disabled"); + } + } +} + +void +destroy_debug_config(void) +{ + if (config.drop_action.string) { + ds_destroy(&config.drop_action); + ds_init(&config.drop_action); + } +} + +const char * +debug_drop_action(void) { + if (OVS_UNLIKELY(debug_enabled())) { + return ds_cstr_ro(&config.drop_action); + } else { + return "drop;"; + } +} + +const char * +debug_implicit_drop_action(void) +{ + if (OVS_UNLIKELY(debug_enabled())) { + return ds_cstr_ro(&config.drop_action); + } else { + return "/* drop */"; + } +} diff --git a/northd/debug.h b/northd/debug.h new file mode 100644 index 000000000..c1a5e5aad --- /dev/null +++ b/northd/debug.h @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NORTHD_DEBUG_H +#define NORTHD_DEBUG_H 1 + +#include +#include + +#include "lib/ovn-nb-idl.h" +#include "openvswitch/dynamic-string.h" + +void init_debug_config(const struct nbrec_nb_global *nb); +void destroy_debug_config(void); + +const char *debug_drop_action(void); +const char *debug_implicit_drop_action(void); + +#endif /* NORTHD_DEBUG_H */ diff --git a/northd/northd.c b/northd/northd.c index 1cccc33df..1911746b8 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -17,6 +17,7 @@ #include #include +#include "debug.h" #include "bitmap.h" #include "dirs.h" #include "ipam.h" @@ -3827,7 +3828,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip, if (!n_active_backends) { if (!lb_vip->empty_backend_rej) { ds_clear(action); - ds_put_cstr(action, "drop;"); + ds_put_cstr(action, debug_drop_action()); skip_hash_fields = true; } else { reject = true; @@ -5161,7 +5162,7 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map, enum ovn_stage stage, const char *where) { - ovn_lflow_add_at(lflow_map, od, stage, 0, "1", "drop;", + ovn_lflow_add_at(lflow_map, od, stage, 0, "1", debug_drop_action(), NULL, NULL, NULL, where ); } @@ -6392,7 +6393,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, } else { ds_put_format(match, " && (%s)", acl->match); build_acl_log(actions, acl, meter_groups); - ds_put_cstr(actions, "/* drop */"); + ds_put_cstr(actions, debug_implicit_drop_action()); ovn_lflow_add_with_hint(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, ds_cstr(match), ds_cstr(actions), @@ -6420,7 +6421,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, } else { ds_put_format(match, " && (%s)", acl->match); build_acl_log(actions, acl, meter_groups); - ds_put_cstr(actions, "/* drop */"); + ds_put_cstr(actions, debug_implicit_drop_action()); ovn_lflow_add_with_hint(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, ds_cstr(match), ds_cstr(actions), @@ -6437,7 +6438,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, actions, &acl->header_, meter_groups); } else { build_acl_log(actions, acl, meter_groups); - ds_put_cstr(actions, "/* drop */"); + ds_put_cstr(actions, debug_implicit_drop_action()); ovn_lflow_add_with_hint(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, acl->match, ds_cstr(actions), @@ -6673,9 +6674,9 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, use_ct_inv_match ? "ct.inv || " : "", ct_blocked_match); ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, - ds_cstr(&match), "drop;"); + ds_cstr(&match), debug_drop_action()); ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, - ds_cstr(&match), "drop;"); + ds_cstr(&match), debug_drop_action()); /* Ingress and Egress ACL Table (Priority 65535 - 3). * @@ -7775,7 +7776,7 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, rp->lsp_addrs[k].ipv4_addrs[l].addr_s); ovn_lflow_add_with_lport_and_hint( lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100, - ds_cstr(&match), "drop;", port->key, + ds_cstr(&match), debug_drop_action(), port->key, &op->nbsp->header_); } for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs; l++) { @@ -7791,7 +7792,7 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, rp->lsp_addrs[k].ipv6_addrs[l].addr_s); ovn_lflow_add_with_lport_and_hint( lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100, - ds_cstr(&match), "drop;", port->key, + ds_cstr(&match), debug_drop_action(), port->key, &op->nbsp->header_); } @@ -7806,7 +7807,8 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, ovn_lflow_add_with_lport_and_hint(lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100, ds_cstr(&match), - "drop;", port->key, + debug_drop_action(), + port->key, &op->nbsp->header_); } } @@ -7844,7 +7846,7 @@ build_lswitch_flows(const struct hmap *datapaths, "outport = \""MC_UNKNOWN "\"; output;"); } else { ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50, - "outport == \"none\"", "drop;"); + "outport == \"none\"", debug_drop_action()); } ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1", "output;"); @@ -7887,18 +7889,18 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, if (!is_vlan_transparent(od)) { /* Block logical VLANs. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100, - "vlan.present", "drop;"); + "vlan.present", debug_drop_action()); } /* Broadcast/multicast source address is invalid. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100, - "eth.src[40]", "drop;"); + "eth.src[40]", debug_drop_action()); ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1", REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50, - REGBIT_PORT_SEC_DROP" == 1", "drop;"); + REGBIT_PORT_SEC_DROP" == 1", debug_drop_action()); ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;"); } @@ -8427,7 +8429,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, */ if (!mcast_sw_info->flood_relay && !mcast_sw_info->flood_static) { - ds_put_cstr(actions, "drop;"); + ds_put_cstr(actions, debug_drop_action()); } ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, @@ -8952,7 +8954,7 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, out_port->json_key); } else if (!strcmp(rule->action, "drop")) { - ds_put_cstr(&actions, "drop;"); + ds_put_cstr(&actions, debug_drop_action()); } else if (!strcmp(rule->action, "allow")) { uint32_t pkt_mark = ovn_smap_get_uint(&rule->options, "pkt_mark", 0); if (pkt_mark) { @@ -9802,7 +9804,7 @@ add_route(struct hmap *lflows, struct ovn_datapath *od, struct ds common_actions = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; if (is_discard_route) { - ds_put_format(&actions, "drop;"); + ds_put_cstr(&actions, debug_drop_action()); } else { ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); @@ -10585,7 +10587,7 @@ build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op, ds_put_format(&match, " && %s", ds_cstr(extra_match)); } if (drop) { - ds_put_format(&actions, "drop;"); + ds_put_cstr(&actions, debug_drop_action()); } else { ds_put_format(&actions, "eth.dst = eth.src; " @@ -10641,7 +10643,7 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, } if (drop) { - ds_put_format(&actions, "drop;"); + ds_put_cstr(&actions, debug_drop_action()); ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority, ds_cstr(&match), ds_cstr(&actions), hint); } else { @@ -10791,7 +10793,7 @@ build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage, char *match = xasprintf("ip4.dst == {%s}", ds_cstr(&match_ips)); ovn_lflow_add_with_hint(lflows, op->od, stage, priority, - match, "drop;", + match, debug_drop_action(), &op->nbrp->header_); free(match); } @@ -10820,7 +10822,7 @@ build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage, char *match = xasprintf("ip6.dst == {%s}", ds_cstr(&match_ips)); ovn_lflow_add_with_hint(lflows, op->od, stage, priority, - match, "drop;", + match, debug_drop_action(), &op->nbrp->header_); free(match); } @@ -10988,7 +10990,7 @@ build_adm_ctrl_flows_for_lrouter( /* Logical VLANs not supported. * Broadcast/multicast source address is invalid. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, - "vlan.present || eth.src[40]", "drop;"); + "vlan.present || eth.src[40]", debug_drop_action()); /* Default action for L2 security is to drop. */ ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION); @@ -11581,7 +11583,7 @@ build_mcast_lookup_flows_for_lrouter( * i.e., router solicitation and router advertisement. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - "nd_rs || nd_ra", "drop;"); + "nd_rs || nd_ra", debug_drop_action()); if (!od->mcast_info.rtr.relay) { return; } @@ -11628,13 +11630,13 @@ build_mcast_lookup_flows_for_lrouter( ds_put_format(match, "eth.src == %s && igmp", op->lrp_networks.ea_s); ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - ds_cstr(match), "drop;"); + ds_cstr(match), debug_drop_action()); ds_clear(match); ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)", op->lrp_networks.ea_s); ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - ds_cstr(match), "drop;"); + ds_cstr(match), debug_drop_action()); } ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460, @@ -11658,7 +11660,7 @@ build_mcast_lookup_flows_for_lrouter( "};"); } else { ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450, - "ip4.mcast || ip6.mcast", "drop;"); + "ip4.mcast || ip6.mcast", debug_drop_action()); } } } @@ -12484,7 +12486,7 @@ build_misc_local_traffic_drop_flows_for_lrouter( "ip4.dst == 127.0.0.0/8 || " "ip4.src == 0.0.0.0/8 || " "ip4.dst == 0.0.0.0/8", - "drop;"); + debug_drop_action()); /* Drop ARP packets (priority 85). ARP request packets for router's own * IPs are handled with priority-90 flows. @@ -12492,7 +12494,7 @@ build_misc_local_traffic_drop_flows_for_lrouter( * IPs are handled with priority-90 flows. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85, - "arp || nd", "drop;"); + "arp || nd", debug_drop_action()); /* Allow IPv6 multicast traffic that's supposed to reach the * router pipeline (e.g., router solicitations). @@ -12502,21 +12504,22 @@ build_misc_local_traffic_drop_flows_for_lrouter( /* Drop other reserved multicast. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83, - "ip6.mcast_rsvd", "drop;"); + "ip6.mcast_rsvd", debug_drop_action()); /* Allow other multicast if relay enabled (priority 82). */ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82, "ip4.mcast || ip6.mcast", - od->mcast_info.rtr.relay ? "next;" : "drop;"); + (od->mcast_info.rtr.relay ? "next;" : + debug_drop_action())); /* Drop Ethernet local broadcast. By definition this traffic should * not be forwarded.*/ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50, - "eth.bcast", "drop;"); + "eth.bcast", debug_drop_action()); /* TTL discard */ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, - "ip4 && ip.ttl == {0, 1}", "drop;"); + "ip4 && ip.ttl == {0, 1}", debug_drop_action()); /* Pass other traffic not already handled to the next table for * routing. */ @@ -12778,7 +12781,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, op_put_v4_networks(match, op, true); ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, - ds_cstr(match), "drop;", + ds_cstr(match), debug_drop_action(), &op->nbrp->header_); /* ICMP echo reply. These flows reply to ICMP echo requests @@ -13835,8 +13838,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, struct ovn_port *op = ovn_port_find(ports, nat->logical_port); if (op && op->nbsp && !strcmp(op->nbsp->type, "virtual")) { ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, - 80, ds_cstr(match), "drop;", - &nat->header_); + 80, ds_cstr(match), + debug_drop_action(), &nat->header_); } ds_put_format(match, " && is_chassis_resident(\"%s\")", nat->logical_port); @@ -15566,6 +15569,7 @@ northd_destroy(struct northd_data *data) destroy_datapaths_and_ports(&data->datapaths, &data->ports, &data->lr_list); + destroy_debug_config(); } static void @@ -15649,6 +15653,9 @@ ovnnb_db_run(struct northd_input *input_data, false); build_chassis_features(input_data, &data->features); + + init_debug_config(nb); + build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list); build_lbs(input_data, &data->datapaths, &data->lbs, &data->lb_groups); build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name, diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index ab01add2f..eb38b51f7 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -4847,4 +4847,30 @@ clone {

+

Drop sampling

+ +

+ As described in the previous section, there are several places where + ovn-northd might decided to drop a packet by explicitly creating a + Logical_Flow with the drop; action. +

+ +

+ When debug drop-sampling has been cofigured in the OVN Northbound + database, the ovn-northd will replace all the drop; + actions with a sample(priority=65535, collector_set=id, + obs_domain=obs_id, obs_point=@cookie) action, where: +

    +
  • + id is the value the debug_drop_collector_set + option configured in the OVN Northbound. +
  • +
  • + obs_id has it's 8 most significant bits equal to the value + of the debug_drop_domain_id option in the OVN Northbound + and it's 24 least significant bits equal to the datapath's tunnel key. +
  • +
+

+ diff --git a/ovn-nb.xml b/ovn-nb.xml index f41e9d7c0..548e2ddb0 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -264,6 +264,34 @@

+ +

+ If set to a 8-bit number and if + debug_drop_collector_set is also configured, + ovn-northd will add a sample action to + every logical flow that contains a 'drop' action. + The 8 most significant bits of the observation_domain_id field will + be those specified in the + debug_drop_domain_id. + The 24 least significant bits of the observation_domain_id field will + be the datapath's key. +

+

+ The observation_point_id will be set to the first 32 bits of the + logical flow's UUID. +

+
+ + +

+ If set to a 32-bit number ovn-northd will add a + sample action to every logical flow that contains a + 'drop' action. The sample action will have the specified + collector_set_id. The value must match that of the local OVS + configuration as described in ovs-actions(7). +

+
+

These options control how routes are advertised between OVN diff --git a/ovn-sb.xml b/ovn-sb.xml index 75ead78fa..2893c45f9 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -198,6 +198,35 @@ BFD option mult value to use when configuring BFD on tunnel interfaces. + + +

+ If set to a 8-bit number and if + debug_drop_collector_set is also configured, + ovn-controller will add a sample action + to every flow that does not come from a logical flow that contains + a 'drop' action. + The 8 most significant bits of the observation_domain_id field will + be those specified in the + debug_drop_domain_id. + The 24 least significant bits of the observation_domain_id field + will be zero. +

+

+ The observation_point_id will be set to the OpenFlow table number. +

+ + + +

+ If set to a 32-bit number ovn-controller will add a + sample action to every flow that does not come from + a logical flow that contains a 'drop' action. + The sample action will have the specified collector_set_id. + The value must match that of the local OVS configuration as + described in ovs-actions(7). +

+
diff --git a/tests/ovn.at b/tests/ovn.at index 792655f99..b65c31078 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -33102,6 +33102,43 @@ check_default_flows() { done } +# Check that every drop flow gets sampled. +check_sample_drops() { + + check ovn-nbctl -- remove NB_Global . options debug_drop_collector_set \ + -- remove NB_Global . options debug_drop_domain_id + check ovn-nbctl --wait=hv sync + + ovs-ofctl dump-flows --no-stats br-int > oflows_nosample + AT_CAPTURE_FILE([oflows_nosample]) + # Take match part of flows that contain "drop". + drop_matches="$(grep 'drop' oflows_nosample | grep -oP 'table=\d*, priority=.* ')" + + check ovn-nbctl -- set NB_Global . options:debug_drop_collector_set="123" \ + -- set NB_Global . options:debug_drop_domain_id="1" + check ovn-nbctl --wait=hv sync + + ovs-ofctl dump-flows --no-stats br-int > oflows_sample + AT_CAPTURE_FILE([oflows_sample]) + + # Check that every drop has now contains a "sample" action. + for flow in "$drop_matches"; do + AT_CHECK([grep -q "$flow actions=.*sample.*" oflows_sample], [0], [ignore], [ignore], [echo "Flow $flow has a drop and did not get sampled"]) + done +} + +check_drops() { + as hv1 + check_default_flows + as hv2 + check_default_flows + + as hv1 + check_sample_drops + as hv2 + check_sample_drops +} + # Logical network: # Two LRs - R1 and R2 that are connected to each other as peers in 20.0.0.0/24 # network. R1 has a switchs ls1 (191.168.1.0/24) connected to it. @@ -33167,10 +33204,7 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- \ wait_for_ports_up check ovn-nbctl --wait=hv sync -as hv1 -check_default_flows -as hv2 -check_default_flows +check_debug # Add stateless ACL check ovn-nbctl --wait=sb \ @@ -33178,10 +33212,7 @@ check ovn-nbctl --wait=sb \ check ovn-nbctl --wait=sb \ -- acl-add ls2 from-lport 100 'ip4' allow-stateless -as hv1 -check_default_flows -as hv2 -check_default_flows +check_debug check ovn-nbctl --wait=sb acl-del ls1 check ovn-nbctl --wait=sb acl-del ls2 @@ -33192,10 +33223,7 @@ check ovn-nbctl --wait=sb \ check ovn-nbctl --wait=sb \ -- acl-add ls2 from-lport 100 "udp" allow-related -as hv1 -check_default_flows -as hv2 -check_default_flows +check_debug check ovn-nbctl --wait=sb acl-del ls1 check ovn-nbctl --wait=sb acl-del ls2 @@ -33209,10 +33237,7 @@ check ovn-nbctl --wait=sb \ -- lb-add lb2 "10.0.1.1" "10.0.1.2" \ -- ls-lb-add ls2 lb2 -as hv1 -check_default_flows -as hv2 -check_default_flows +check_drops # LB + stateless ACL check ovn-nbctl --wait=sb \ @@ -33220,10 +33245,7 @@ check ovn-nbctl --wait=sb \ check ovn-nbctl --wait=sb \ -- acl-add ls2 from-lport 100 'ip4' allow-stateless -as hv1 -check_default_flows -as hv2 -check_default_flows +check_drops check ovn-nbctl --wait=sb acl-del ls1 check ovn-nbctl --wait=sb acl-del ls2 @@ -33234,10 +33256,7 @@ check ovn-nbctl --wait=sb \ check ovn-nbctl --wait=sb \ -- acl-add ls2 from-lport 100 "udp" allow-related -as hv1 -check_default_flows -as hv2 -check_default_flows +check_drops OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP