From patchwork Mon Jun 13 16:10:52 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: 1642909 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.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=SVAG55qH; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LMGlR3Ddcz9sFk for ; Tue, 14 Jun 2022 02:11:14 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 8B7C260E56; Mon, 13 Jun 2022 16:11:12 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gImT3Zpdz60x; Mon, 13 Jun 2022 16:11:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 813DC60E50; Mon, 13 Jun 2022 16:11:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5104CC007A; Mon, 13 Jun 2022 16:11:10 +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 D7AE3C0032 for ; Mon, 13 Jun 2022 16:11:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id AC59A415BA for ; Mon, 13 Jun 2022 16:11:08 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com 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 z_l4Y_cSi9do for ; Mon, 13 Jun 2022 16:11:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 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 995AE415D7 for ; Mon, 13 Jun 2022 16:11:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655136664; 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=0PfbhE8ceumuAvQLiQnNx/sD+ziBWzJUyPoHa4om6t0=; b=SVAG55qHw1UlvyJ2fBmW8DhwKZbGlMF2XXIKi31d4ke1hvEiUmL+0Tzu8sVwApK+8IAUky 1MdcmycE4A0wZuAsy4yd0ZYnA89OECZrE5QqmDFOqCBMfARVm2wUGnC8sYH2qgYVmwKwNy wvtnuD/i8mqxAZsfcUIQZD9nFokRaFQ= 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-590-IFQNjM87OVqtYWBvLWVz7w-1; Mon, 13 Jun 2022 12:11:01 -0400 X-MC-Unique: IFQNjM87OVqtYWBvLWVz7w-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 13E80181E066; Mon, 13 Jun 2022 16:11:01 +0000 (UTC) Received: from amorenoz.users.ipa.redhat.com (unknown [10.39.195.66]) by smtp.corp.redhat.com (Postfix) with ESMTP id D059640CFD0A; Mon, 13 Jun 2022 16:10:59 +0000 (UTC) From: Adrian Moreno To: dev@openvswitch.org Date: Mon, 13 Jun 2022 18:10:52 +0200 Message-Id: <20220613161054.2896553-2-amorenoz@redhat.com> In-Reply-To: <20220613161054.2896553-1-amorenoz@redhat.com> References: <20220613161054.2896553-1-amorenoz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=amorenoz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn v1 1/3] actions: add sample action 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" sample ovn action encodes into the OFPACT_SAMPLE ovs action. OVN action allows the following parameters: - obs_domain_id: 8-bit integer that identifies the sampling application. This value will be combined with the datapath's tunnel_id to form the final observation_domain_id that will be used in the OVS action. - obs_point_id: a 32-bit integer or the $cookie macro that will be expanded into the first 32 bits of the lflow's UUID. - probability: a 16-bit integer that specifies the sampling probability. Specifying 0 has no effect and 65535 means sampling all packets. Signed-off-by: Adrian Moreno --- controller/lflow.c | 1 + include/ovn/actions.h | 16 ++++++ lib/actions.c | 119 ++++++++++++++++++++++++++++++++++++++++++ tests/ovn.at | 9 ++++ tests/test-ovn.c | 3 ++ utilities/ovn-trace.c | 2 + 6 files changed, 150 insertions(+) diff --git a/controller/lflow.c b/controller/lflow.c index 934b23698..54312d2df 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -1163,6 +1163,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .group_table = l_ctx_out->group_table, .meter_table = l_ctx_out->meter_table, .lflow_uuid = lflow->header_.uuid, + .tunnel_key = ldp->datapath->tunnel_key, .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS, .ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE, diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 1ae496960..915f9124e 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -118,6 +118,7 @@ struct ovn_extend_table; OVNACT(LOOKUP_FDB, ovnact_lookup_fdb) \ OVNACT(CHECK_IN_PORT_SEC, ovnact_result) \ OVNACT(CHECK_OUT_PORT_SEC, ovnact_result) \ + OVNACT(SAMPLE, ovnact_sample) \ /* enum ovnact_type, with a member OVNACT_ for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -453,6 +454,18 @@ struct ovnact_lookup_fdb { struct expr_field dst; /* 1-bit destination field. */ }; +/* OVNACT_SAMPLE */ +struct ovnact_sample { + struct ovnact ovnact; + uint16_t probability; /* probability over UINT16_MAX. */ + uint8_t obs_domain_id; /* most significant byte of the + observation domain id. The other 24 bits + will come from the datapath's tunnel key. */ + uint32_t collector_set_id; /* colector_set_id. */ + uint32_t obs_point_id; /* observation point id. */ + bool use_cookie; /* use cookie as obs_point_id */ +}; + /* Internal use by the helpers below. */ void ovnact_init(struct ovnact *, enum ovnact_type, size_t len); void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len); @@ -772,6 +785,9 @@ struct ovnact_encode_params { /* The logical flow uuid that drove this action. */ struct uuid lflow_uuid; + /* The tunnel key of the datapath. */ + uint32_t tunnel_key; + /* OVN maps each logical flow table (ltable), one-to-one, onto a physical * OpenFlow flow table (ptable). A number of parameters describe this * mapping and data related to flow tables: diff --git a/lib/actions.c b/lib/actions.c index aab044306..6d1622c66 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -4278,6 +4278,123 @@ encode_CHECK_OUT_PORT_SEC(const struct ovnact_result *dl, MLF_CHECK_PORT_SEC_BIT, ofpacts); } +static void +format_SAMPLE(const struct ovnact_sample *sample, struct ds *s) +{ + ds_put_format(s, "sample(probability=%"PRId16, sample->probability); + + ds_put_format(s, ",collector_set=%"PRId32, sample->collector_set_id); + ds_put_format(s, ",obs_domain=%"PRId8, sample->obs_domain_id); + if (sample->use_cookie) { + ds_put_cstr(s, ",obs_point=$cookie"); + } else { + ds_put_format(s, ",obs_point=%"PRId32, sample->obs_point_id); + } + ds_put_format(s, ");"); +} + +static void +encode_SAMPLE(const struct ovnact_sample *sample, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts); + os->probability = sample->probability; + os->collector_set_id = sample->collector_set_id; + os->obs_domain_id = + (sample->obs_domain_id << 24) | (ep->tunnel_key & 0xFFFFFF); + + if (sample->use_cookie) { + os->obs_point_id = ep->lflow_uuid.parts[0]; + } else { + os->obs_point_id = sample->obs_point_id; + } + os->sampling_port = OFPP_NONE; +} + +static void +parse_sample_arg(struct action_context *ctx, struct ovnact_sample *sample) +{ + if (lexer_match_id(ctx->lexer, "probability")) { + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + if (ctx->lexer->token.type == LEX_T_INTEGER + && ctx->lexer->token.format == LEX_F_DECIMAL) { + if (!action_parse_uint16(ctx, &sample->probability, + "probability")) { + return; + } + } + } else if (lexer_match_id(ctx->lexer, "obs_point")) { + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + if (ctx->lexer->token.type == LEX_T_MACRO && + !strcmp(ctx->lexer->token.s, "cookie")) { + sample->use_cookie = true; + lexer_get(ctx->lexer); + } else if (ctx->lexer->token.type == LEX_T_INTEGER + && ctx->lexer->token.format == LEX_F_DECIMAL) { + sample->obs_point_id = ntohll(ctx->lexer->token.value.integer); + lexer_get(ctx->lexer); + } else { + lexer_syntax_error(ctx->lexer, + "Malformed sample observation_point_id"); + } + } else if (lexer_match_id(ctx->lexer, "obs_domain")) { + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + if (ctx->lexer->token.type == LEX_T_INTEGER + && ctx->lexer->token.format == LEX_F_DECIMAL) { + uint32_t obs_domain = ntohll(ctx->lexer->token.value.integer); + if (obs_domain > UINT8_MAX) { + lexer_syntax_error(ctx->lexer, + "Malformed sample action: obs_domain must be 8-bit long"); + return; + } + sample->obs_domain_id = obs_domain; + } + lexer_get(ctx->lexer); + } else if (lexer_match_id(ctx->lexer, "collector_set")) { + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + if (ctx->lexer->token.type == LEX_T_INTEGER + && ctx->lexer->token.format == LEX_F_DECIMAL) { + sample->collector_set_id = ntohll(ctx->lexer->token.value.integer); + } + lexer_get(ctx->lexer); + } else { + lexer_syntax_error(ctx->lexer, "Malformed sample action"); + } +} +static void +parse_sample(struct action_context *ctx) +{ + struct ovnact_sample * sample = ovnact_put_SAMPLE(ctx->ovnacts); + + if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { + while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { + parse_sample_arg(ctx, sample); + if (ctx->lexer->error) { + return; + } + lexer_match(ctx->lexer, LEX_T_COMMA); + } + } + if (!sample->probability) { + lexer_error(ctx->lexer, "probability must be greater than zero"); + return; + } +} + +static void +ovnact_sample_free(struct ovnact_sample *sample OVS_UNUSED) +{ +} + /* Parses an assignment or exchange or put_dhcp_opts action. */ static void parse_set_action(struct action_context *ctx) @@ -4458,6 +4575,8 @@ parse_action(struct action_context *ctx) ovnact_put_CT_SNAT_TO_VIP(ctx->ovnacts); } else if (lexer_match_id(ctx->lexer, "put_fdb")) { parse_put_fdb(ctx, ovnact_put_PUT_FDB(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "sample")) { + parse_sample(ctx); } else { lexer_syntax_error(ctx->lexer, "expecting action"); } diff --git a/tests/ovn.at b/tests/ovn.at index 59d51f3e0..7afe0040b 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -2080,6 +2080,15 @@ pop(eth.type); push(abc); Syntax error at `abc' expecting field name. +# sample +sample(probability=100,collector_set=200,obs_domain=0,obs_point=1000); + encodes as sample(probability=100,collector_set_id=200,obs_domain_id=11259375,obs_point_id=1000) + +# sample with obs_domain = 10. Final obs_domain is 0xA << 24 | 0xABCDEF. +sample(probability=100,collector_set=200,obs_domain=10,obs_point=$cookie); + encodes as sample(probability=100,collector_set_id=200,obs_domain_id=179031535,obs_point_id=2863311530) + + # Miscellaneous negative tests. ; Syntax error at `;'. diff --git a/tests/test-ovn.c b/tests/test-ovn.c index a241f150d..ea319f81e 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1355,6 +1355,9 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) .common_nat_ct_zone = MFF_LOG_DNAT_ZONE, .in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC, .out_port_sec_ptable = OFTABLE_CHK_OUT_PORT_SEC, + .lflow_uuid.parts = + { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd}, + .tunnel_key = 0xabcdef, }; struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index c4110de0a..d6ccc145f 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -3224,6 +3224,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, execute_check_out_port_sec(ovnact_get_CHECK_OUT_PORT_SEC(a), dp, uflow); break; + case OVNACT_SAMPLE: + break; } } ofpbuf_uninit(&stack); From patchwork Mon Jun 13 16:10:53 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: 1642910 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.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=Lq4KqFIn; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LMGlV6Hlsz9s0r for ; Tue, 14 Jun 2022 02:11:18 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 5C17660D5C; Mon, 13 Jun 2022 16:11:15 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6gXrNILJGEJq; Mon, 13 Jun 2022 16:11:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 462F660D95; Mon, 13 Jun 2022 16:11:12 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1E795C007A; Mon, 13 Jun 2022 16:11:12 +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 1F3D5C0032 for ; Mon, 13 Jun 2022 16:11:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1B10D415F4 for ; Mon, 13 Jun 2022 16:11:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com 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 kyh4vSLqbPdC for ; Mon, 13 Jun 2022 16:11:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id CA282415CB for ; Mon, 13 Jun 2022 16:11:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655136666; 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=af3jKCtLwBMHbFhCib7LWMWyDEF6dXQj2mhmmdlrjDo=; b=Lq4KqFInMbjpsilU2GjGd3M8CALaFlK3npM/rhFtRs/i4tv9CEVoawiO0mUe3yTFWwQ2pF yPkf88bdkV058z1slKhhn9QOkVWdZq3IVKb1+lvS/fXhg64TtLg7v4qV0E2Wz6b+KIeV9l oq4j3+qLQ9ZJ9uL3TYgt3O9PQfCEMwA= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-97-uAtt_VU8N9i6kGnkbQYFNQ-1; Mon, 13 Jun 2022 12:11:03 -0400 X-MC-Unique: uAtt_VU8N9i6kGnkbQYFNQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C134A3C0D84C; Mon, 13 Jun 2022 16:11:02 +0000 (UTC) Received: from amorenoz.users.ipa.redhat.com (unknown [10.39.195.66]) by smtp.corp.redhat.com (Postfix) with ESMTP id 712AB4024BDD; Mon, 13 Jun 2022 16:11:01 +0000 (UTC) From: Adrian Moreno To: dev@openvswitch.org Date: Mon, 13 Jun 2022 18:10:53 +0200 Message-Id: <20220613161054.2896553-3-amorenoz@redhat.com> In-Reply-To: <20220613161054.2896553-1-amorenoz@redhat.com> References: <20220613161054.2896553-1-amorenoz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=amorenoz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn v1 2/3] northd: add drop-debug-mode to add explicit drops 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" Add a new config flag called "drop-debug-mode" that makes northd add an explicit default drop to all tables that currently do not have a default (prio=0, match=1) lflow. In the controller side, also add explicit default drop rules on physical tables that need it. When this mode is enabled the explicit drop actions make it easier to debug when OVN is dropping a packet. Signed-off-by: Adrian Moreno Acked-by: Mark Michelson --- controller/ovn-controller.c | 33 ++++++++ controller/physical.c | 48 +++++++++++ controller/physical.h | 1 + northd/automake.mk | 2 + northd/debug.c | 23 ++++++ northd/debug.h | 31 +++++++ northd/northd.c | 44 +++++++++- ovn-nb.xml | 8 ++ tests/ovn-northd.at | 76 +++++++++++++++++ tests/ovn.at | 158 +++++++++++++++++++++++++++++++++++- 10 files changed, 419 insertions(+), 5 deletions(-) create mode 100644 northd/debug.c create mode 100644 northd/debug.h diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 2793c8687..88e341593 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2941,6 +2941,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. */ + bool debug_drop; }; static void init_physical_ctx(struct engine_node *node, @@ -2985,6 +2987,12 @@ static void init_physical_ctx(struct engine_node *node, chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); } + struct sbrec_sb_global_table *sb_global_table = + (struct sbrec_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 = @@ -3005,6 +3013,8 @@ 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_drop = smap_get_bool(&sb_global->options, + "debug_drop_mode", false); } static void * @@ -3164,6 +3174,27 @@ pflow_output_ct_zones_handler(struct engine_node *node OVS_UNUSED, return !ct_zones_data->recomputed; } +static bool +pflow_output_sb_sb_global_handler(struct engine_node *node, void *data) +{ + struct sbrec_sb_global_table *sb_global_table = + (struct sbrec_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; + + bool debug_drop = smap_get_bool(&sb_global->options, + "debug_drop_mode", false); + + if (pfo->debug_drop != debug_drop) { + engine_set_node_state(node, EN_UPDATED); + pfo->debug_drop = debug_drop; + } + return true; +} + static void * en_flow_output_init(struct engine_node *node OVS_UNUSED, struct engine_arg *arg OVS_UNUSED) @@ -3498,6 +3529,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 24de86f24..49f754af9 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -823,6 +823,20 @@ put_zones_ofpacts(const struct zone_ids *zone_ids, struct ofpbuf *ofpacts_p) } } +static void +add_default_drop_flow(const struct physical_ctx *p_ctx, + uint8_t table_id, + struct ovn_desired_flow_table *flow_table) +{ + if (p_ctx->debug_drop) { + struct match match = MATCH_CATCHALL_INITIALIZER; + struct ofpbuf ofpacts; + ofpbuf_init(&ofpacts, 0); + ofctrl_add_flow(flow_table, table_id, 0, 0, &match, + &ofpacts, hc_uuid); + } +} + static void put_local_common_flows(uint32_t dp_key, const struct sbrec_port_binding *pb, @@ -1930,6 +1944,13 @@ physical_run(struct physical_ctx *p_ctx, } } + /* Table 0, priority 0. + * ====================== + * + * Drop packets tha do not match any tunnel in_port. + */ + add_default_drop_flow(p_ctx, OFTABLE_PHY_TO_LOG, flow_table); + /* Table 37, priority 150. * ======================= * @@ -1975,6 +1996,13 @@ physical_run(struct physical_ctx *p_ctx, ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, &ofpacts, hc_uuid); + /* Table 38, priority 0. + * ====================== + * + * Drop packets that do not match previous flows. + */ + add_default_drop_flow(p_ctx, OFTABLE_LOCAL_OUTPUT, flow_table); + /* Table 39, Priority 0. * ======================= * @@ -2001,5 +2029,25 @@ physical_run(struct physical_ctx *p_ctx, ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, 0, &match, &ofpacts, hc_uuid); + /* Table 65, priority 0. + * ====================== + * + * Drop packets that do not match previous flows. + */ + add_default_drop_flow(p_ctx, OFTABLE_LOG_TO_PHY, flow_table); + + /* Table 68, priority 0. + * ====================== + * + * Drop packets that do not match previous flows. + */ + add_default_drop_flow(p_ctx, OFTABLE_CHK_LB_HAIRPIN, flow_table); + + /* Table 70, priority 0. + * ====================== + * + * Drop packets that do not match previous flows. + */ + add_default_drop_flow(p_ctx, OFTABLE_CT_SNAT_HAIRPIN, flow_table); ofpbuf_uninit(&ofpacts); } diff --git a/controller/physical.h b/controller/physical.h index ee4b1ae1f..b96641a6f 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -58,6 +58,7 @@ struct physical_ctx { struct shash *local_bindings; struct simap *patch_ofports; struct hmap *chassis_tunnels; + bool debug_drop; }; void physical_register_ovs_idl(struct ovsdb_idl *); diff --git a/northd/automake.mk b/northd/automake.mk index 4862ec7b7..7537c00b5 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/northd.c \ northd/northd.h \ northd/ovn-northd.c \ diff --git a/northd/debug.c b/northd/debug.c new file mode 100644 index 000000000..3db0a3c4f --- /dev/null +++ b/northd/debug.c @@ -0,0 +1,23 @@ +#include + +#include + +#include "debug.h" + +#include "smap.h" + +static struct debug_config config; + +void +init_debug_config(const struct nbrec_nb_global *nb) +{ + + const struct smap *options = &nb->options; + config.enabled = smap_get_bool(options, "debug_drop_mode", false); +} + +bool +debug_enabled(void) +{ + return config.enabled; +} diff --git a/northd/debug.h b/northd/debug.h new file mode 100644 index 000000000..69d4da171 --- /dev/null +++ b/northd/debug.h @@ -0,0 +1,31 @@ +/* + * 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" + +struct debug_config { + bool enabled; +}; + +void init_debug_config(const struct nbrec_nb_global *nb); + +bool debug_enabled(void); + +#endif /* NORTHD_DEBUG_H */ diff --git a/northd/northd.c b/northd/northd.c index 0d6ebccde..2fde9fb71 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" @@ -5044,6 +5045,18 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, io_port, ctrl_meter, stage_hint, where, hash); } +static void +__ovn_lflow_add_default_drop(struct hmap *lflow_map, + struct ovn_datapath *od, + enum ovn_stage stage, + const char *where) +{ + if (OVS_UNLIKELY(debug_enabled())) { + ovn_lflow_add_at(lflow_map, od, stage, 0, "1", "drop;", + NULL, NULL, NULL, where ); + } +} + /* Adds a row with the specified contents to the Logical_Flow table. */ #define ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ ACTIONS, IN_OUT_PORT, CTRL_METER, \ @@ -5056,6 +5069,10 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \ NULL, NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) +#define ovn_lflow_add_default_drop(LFLOW_MAP, OD, STAGE) \ + __ovn_lflow_add_default_drop(LFLOW_MAP, OD, STAGE, OVS_SOURCE_LOCATOR) + + /* This macro is similar to ovn_lflow_add_with_hint, except that it requires * the IN_OUT_PORT argument, which tells the lport name that appears in the * MATCH, which helps ovn-controller to bypass lflows parsing when the lport is @@ -7751,6 +7768,9 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, REGBIT_PORT_SEC_DROP" == 1", "drop;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;"); + /* Port security flows have priority 50 + * (see build_lswitch_input_port_sec()) and will continue + * to the next table if packet source is acceptable. */ } } @@ -9607,6 +9627,7 @@ add_route(struct hmap *lflows, struct ovn_datapath *od, priority + 1, ds_cstr(&match), ds_cstr(&common_actions), stage_hint); } + ds_destroy(&match); ds_destroy(&common_actions); ds_destroy(&actions); @@ -10756,6 +10777,9 @@ build_adm_ctrl_flows_for_lrouter( * Broadcast/multicast source address is invalid. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, "vlan.present || eth.src[40]", "drop;"); + + /* Default action for L2 security is to drop. */ + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION); } } @@ -10980,6 +11004,8 @@ build_neigh_learning_flows_for_lrouter( "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;", copp_meter_get(COPP_ND_NS, od->nbr->copp, meter_groups)); + + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR); } } @@ -11256,6 +11282,8 @@ build_static_route_flows_for_lrouter( const struct hmap *bfd_connections) { if (od->nbr) { + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP); + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING); ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150, REG_ECMP_GROUP_ID" == 0", "next;"); @@ -11427,6 +11455,7 @@ build_ingress_policy_flows_for_lrouter( REG_ECMP_GROUP_ID" = 0; next;"); ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150, REG_ECMP_GROUP_ID" == 0", "next;"); + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP); /* Convert routing policies to flows. */ uint16_t ecmp_group_id = 1; @@ -11459,11 +11488,13 @@ build_arp_resolve_flows_for_lrouter( ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500, "ip4.mcast || ip6.mcast", "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 0, "ip4", + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 0, "ip6", + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;"); + + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE); } } @@ -11589,9 +11620,9 @@ build_arp_resolve_flows_for_lrouter_port( * in stage "lr_in_ip_input" but traffic that could have been unSNATed * but didn't match any existing session might still end up here. * - * Priority 1. + * Priority 2. */ - build_lrouter_drop_own_dest(op, S_ROUTER_IN_ARP_RESOLVE, 1, true, + build_lrouter_drop_own_dest(op, S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); } else if (op->od->n_router_ports && !lsp_is_router(op->nbsp) && strcmp(op->nbsp->type, "virtual")) { @@ -12172,6 +12203,8 @@ build_egress_delivery_flows_for_lrouter_port( ds_put_format(match, "outport == %s", op->json_key); ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100, ds_cstr(match), "output;"); + + ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY); } } @@ -15364,6 +15397,9 @@ ovnnb_db_run(struct northd_input *input_data, default_acl_drop = smap_get_bool(&nb->options, "default_acl_drop", 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); build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name, diff --git a/ovn-nb.xml b/ovn-nb.xml index 14a624c16..360fa96df 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -263,6 +263,14 @@

+ +

+ If set to true, ovn-northd will add an explicit 'drop' + logical flow when possible instead of relying on the OVS implicitly + dropping packets that do not match any flow. +

+
+

These options control how routes are advertised between OVN diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index dc95587a6..fb047f151 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -7643,3 +7643,79 @@ AT_CHECK([ovn-sbctl dump-flows ls0 | grep -e 'ls_in_\(put\|lookup\)_fdb' | sort AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([Check drop-debug-mode]) +AT_KEYWORDS([debug drop]) + +check_default_lflow() { + dps=$(ovn-sbctl --bare --columns=_uuid list Datapath_Binding | xargs) + for dp in $dps; do + for pipeline in ingress egress; do + for table in $(ovn-sbctl --bare --columns=table_id find Logical_Flow logical_datapath="$dp" pipeline="$pipeline" | xargs | sort | uniq); do + echo "Checking if datapath $dp pipeline $pipeline table $table has a default action" + AT_CHECK([ovn-sbctl --columns=_uuid find Logical_Flow logical_datapath="$dp" pipeline="$pipeline" table_id=$table match="1" priority">="0 | wc -l | tr -d "\n\r" ], [0], [1], [ignore], + [echo "Datapath $dp pipeline $pipeline table $table does not have a default action"]) + done + done + done +} + +ovn_start + +check ovn-nbctl set NB_Global . options:debug_drop_mode="true" + +# Create LS + LR +check ovn-nbctl --wait=sb \ + -- lr-add R1 \ + -- lrp-add R1 R1-S1 02:ac:10:01:00:01 172.16.1.1/24 \ + -- ls-add S1 \ + -- lsp-add S1 S1-R1 \ + -- lsp-set-type S1-R1 router \ + -- lsp-set-addresses S1-R1 02:ac:10:01:00:01 \ + -- lsp-set-options S1-R1 router-port=R1-S1 \ + -- lsp-add S1 p1 \ + -- lsp-set-addresses p1 "02:ac:10:01:00:0a 172.16.1.100" + +check_default_lflow + +# Add stateless ACL +check ovn-nbctl --wait=sb \ + -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless + +check_default_lflow + +check ovn-nbctl --wait=sb acl-del S1 + + +# Add stateful ACL +check ovn-nbctl --wait=sb \ + -- acl-add S1 from-lport 2 "udp" allow-related + +check_default_lflow + +check ovn-nbctl --wait=sb acl-del S1 + +# Add LB +check ovn-nbctl --wait=sb \ + -- lb-add lb "10.0.0.1" "10.0.0.2" \ + -- ls-lb-add S1 lb + +check_default_lflow + +# Check LB + stateless ACL +check ovn-nbctl --wait=sb \ + -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless +check_default_lflow + +check ovn-nbctl --wait=sb acl-del S1 + +# Check LB + statelful ACL +check ovn-nbctl --wait=sb \ + -- acl-add S1 from-lport 2 "udp" allow-related + +check_default_lflow + +AT_CLEANUP +]) + diff --git a/tests/ovn.at b/tests/ovn.at index 7afe0040b..1466ee492 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -27323,7 +27323,7 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep ]) # The packet should've been dropped in the lr_in_arp_resolve stage. -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=23, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=23, n_packets=1,.* priority=2,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl 1 ]) @@ -32050,3 +32050,159 @@ AT_CHECK([test $(ovn-sbctl list fdb | grep -c "00:00:00:00:10:30") = 0]) OVN_CLEANUP([hv1]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([Check drop-debug-mode openflow flows]) +AT_KEYWORDS([debug drop]) +ovn_start + +check_default_flows() { + ovs-ofctl dump-flows br-int > oflows + AT_CAPTURE_FILE([oflows]) + for table in $(grep -oP "table=\K\d*, " oflows | sort -n | uniq); do + AT_CHECK([grep -qe "table=$table.* priority=0\(,metadata=0x\w*\)\? actions" oflows], [0], [ignore], [ignore], [echo "Table $table does not contain a default action"]) + done +} + +check ovn-nbctl -- set NB_Global . options:debug_drop_mode="true" + +# 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. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="192.168.1.2" +ls2_lp1_ip="172.16.1.2" + +ovn-nbctl lr-add R1 +ovn-nbctl ls-add ls1 +ovn-nbctl ls-add ls2 + +# Connect ls1 to R1 +ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 + +ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R1 +ovn-nbctl lrp-add R1 ls2 $rp_ls2_mac 172.16.1.1/24 + +ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Create logical port ls1-lp1 in ls1 +ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +as hv1 +check_default_flows +as hv2 +check_default_flows + +# Add stateless ACL +check ovn-nbctl --wait=sb \ + -- acl-add ls1 from-lport 100 'ip4' allow-stateless +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 ovn-nbctl --wait=sb acl-del ls1 +check ovn-nbctl --wait=sb acl-del ls2 + +# Add stateful ACL +check ovn-nbctl --wait=sb \ + -- acl-add ls1 from-lport 100 "udp" allow-related +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 ovn-nbctl --wait=sb acl-del ls1 +check ovn-nbctl --wait=sb acl-del ls2 + +# Add LB +check ovn-nbctl --wait=sb \ + -- lb-add lb1 "10.0.0.1" "10.0.0.2" \ + -- ls-lb-add ls1 lb1 + +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 + +# LB + stateless ACL +check ovn-nbctl --wait=sb \ + -- acl-add ls1 from-lport 100 'ip4' allow-stateless +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 ovn-nbctl --wait=sb acl-del ls1 +check ovn-nbctl --wait=sb acl-del ls2 + +# LB + stateful ACL +check ovn-nbctl --wait=sb \ + -- acl-add ls1 from-lport 100 "udp" allow-related +check ovn-nbctl --wait=sb \ + -- acl-add ls2 from-lport 100 "udp" allow-related + +as hv1 +check_default_flows +as hv2 +check_default_flows + +OVN_CLEANUP([hv1],[hv2]) +AT_CLEANUP +]) From patchwork Mon Jun 13 16:10:54 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: 1642911 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.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=Pp5/HMyd; dkim-atps=neutral Authentication-Results: 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=) 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 RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LMGlh1NPBz9s0r for ; Tue, 14 Jun 2022 02:11:27 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 98A70415CB; Mon, 13 Jun 2022 16:11:23 +0000 (UTC) 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 sOh0WXWAiRFZ; Mon, 13 Jun 2022 16:11:19 +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 7A064415FE; Mon, 13 Jun 2022 16:11:17 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 493D2C0032; Mon, 13 Jun 2022 16:11:17 +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 21028C002D for ; Mon, 13 Jun 2022 16:11:16 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 48C21415BA for ; Mon, 13 Jun 2022 16:11:15 +0000 (UTC) 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 FY9gfcNPaqGz for ; Mon, 13 Jun 2022 16:11:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id DDB20415F2 for ; Mon, 13 Jun 2022 16:11:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655136669; 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=x7PyqIPXqa/8w72hFs4OpM7p5w/ugGnTt0J892GZH8s=; b=Pp5/HMydD8s6CpR7bJIN5z/BxjIlWbE4pVVo35367paxVejKKj+4ZlqJqBKl/fZN2ZZ+4Q keZhcStUAig/IGTcnTa+JZDsef0W0byACItyMzHwbMnIm2Dnb6Qd2D8PuECSr2LGCI45GT eNSaYnUPa4OUyhRNCRoOoNLLnEjKDaU= 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-367-yjDCIQfyM9qX3FoOGSdCcQ-1; Mon, 13 Jun 2022 12:11:05 -0400 X-MC-Unique: yjDCIQfyM9qX3FoOGSdCcQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 41ED3181E070; Mon, 13 Jun 2022 16:11:04 +0000 (UTC) Received: from amorenoz.users.ipa.redhat.com (unknown [10.39.195.66]) by smtp.corp.redhat.com (Postfix) with ESMTP id 12E5940CFD0A; Mon, 13 Jun 2022 16:11:02 +0000 (UTC) From: Adrian Moreno To: dev@openvswitch.org Date: Mon, 13 Jun 2022 18:10:54 +0200 Message-Id: <20220613161054.2896553-4-amorenoz@redhat.com> In-Reply-To: <20220613161054.2896553-1-amorenoz@redhat.com> References: <20220613161054.2896553-1-amorenoz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=amorenoz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn v1 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 | tunnel_key - 8 most significant bits: the obs_domain_id specified in the NB_Global options - 24 least significant bits: the tunnel_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 table number Signed-off-by: Adrian Moreno --- controller/ovn-controller.c | 29 +++++++++--- controller/physical.c | 34 ++++++++++++-- controller/physical.h | 8 +++- northd/debug.c | 93 +++++++++++++++++++++++++++++++++++-- northd/debug.h | 10 ++++ northd/northd.c | 73 +++++++++++++++-------------- ovn-nb.xml | 24 ++++++++++ tests/ovn.at | 65 ++++++++++++++++---------- 8 files changed, 261 insertions(+), 75 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 88e341593..0e0da362f 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2942,7 +2942,7 @@ struct ed_type_pflow_output { /* Desired physical flows. */ struct ovn_desired_flow_table flow_table; /* Drop debugging options. */ - bool debug_drop; + struct physical_debug debug; }; static void init_physical_ctx(struct engine_node *node, @@ -3013,8 +3013,15 @@ 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_drop = smap_get_bool(&sb_global->options, + p_ctx->debug.enabled = smap_get_bool(&sb_global->options, "debug_drop_mode", false); + 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 * @@ -3185,12 +3192,22 @@ pflow_output_sb_sb_global_handler(struct engine_node *node, void *data) struct ed_type_pflow_output *pfo = data; - bool debug_drop = smap_get_bool(&sb_global->options, + bool debug_enabled = smap_get_bool(&sb_global->options, "debug_drop_mode", false); - - if (pfo->debug_drop != debug_drop) { + 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.enabled != debug_enabled || + 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_drop = debug_drop; + pfo->debug.enabled = debug_enabled; + pfo->debug.collector_set_id = collector_set_id; + pfo->debug.obs_domain_id = obs_domain_id; } return true; } diff --git a/controller/physical.c b/controller/physical.c index 49f754af9..90b4260fd 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -823,25 +823,44 @@ put_zones_ofpacts(const struct zone_ids *zone_ids, struct ofpbuf *ofpacts_p) } } +static void +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) { - if (p_ctx->debug_drop) { + if (p_ctx->debug.enabled) { 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 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) { @@ -877,6 +896,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); @@ -1009,6 +1029,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) { @@ -1032,7 +1053,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); @@ -1208,7 +1229,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. * ============================== @@ -1337,6 +1358,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); @@ -1731,7 +1753,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); } @@ -1825,7 +1848,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. */ diff --git a/controller/physical.h b/controller/physical.h index b96641a6f..0830743d7 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -43,6 +43,12 @@ struct local_nonvif_data; #define OVN_GENEVE_TYPE 0x80 /* Critical option. */ #define OVN_GENEVE_LEN 4 +struct physical_debug { + bool enabled; + uint32_t collector_set_id; + uint32_t obs_domain_id; +}; + struct physical_ctx { struct ovsdb_idl_index *sbrec_port_binding_by_name; const struct sbrec_port_binding_table *port_binding_table; @@ -58,7 +64,7 @@ struct physical_ctx { struct shash *local_bindings; struct simap *patch_ofports; struct hmap *chassis_tunnels; - bool debug_drop; + struct physical_debug debug; }; void physical_register_ovs_idl(struct ovsdb_idl *); diff --git a/northd/debug.c b/northd/debug.c index 3db0a3c4f..bf47919a9 100644 --- a/northd/debug.c +++ b/northd/debug.c @@ -4,20 +4,105 @@ #include "debug.h" +#include "openvswitch/dynamic-string.h" +#include "openvswitch/vlog.h" #include "smap.h" +VLOG_DEFINE_THIS_MODULE(debug) + static struct debug_config config; +bool +debug_enabled(void) +{ + return config.enabled; +} + +bool debug_sampling_enabled(void) +{ + return config.collector_set_id != 0; +} + void init_debug_config(const struct nbrec_nb_global *nb) { const struct smap *options = &nb->options; - config.enabled = smap_get_bool(options, "debug_drop_mode", false); + bool enabled = smap_get_bool(options, "debug_drop_mode", false); + 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 (enabled != config.enabled || + collector_set_id != config.collector_set_id || + observation_domain_id != config.observation_domain_id || + !config.drop_action.string) { + + if (observation_domain_id >= UINT8_MAX) { + VLOG_ERR("Observation domain id must be an 8-bit number"); + return; + } + + if (!enabled && collector_set_id) { + VLOG_WARN("Debug collection set configured, " + "assuming debug_drop_mode"); + enabled = true; + } + + config.enabled = enabled; + config.collector_set_id = collector_set_id; + config.observation_domain_id = observation_domain_id; + + ds_clear(&config.drop_action); + + VLOG_INFO("Debug drop mode: %s", debug_enabled() ? "enabled" : + "disabled"); + if (debug_sampling_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_format(&config.drop_action, "/* drop */"); + VLOG_INFO("Debug drop sampling: enabled"); + } else { + ds_put_format(&config.drop_action, "drop;"); + VLOG_INFO("Debug drop sampling: disabled"); + } + } } -bool -debug_enabled(void) +void +destroy_debug_config(void) { - return config.enabled; + 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_sampling_enabled())) { + return ds_cstr_ro(&config.drop_action); + } else { + return "drop;"; + } +} + +const char * +debug_implicit_drop_action(void) +{ + if (OVS_UNLIKELY(debug_sampling_enabled())) { + return ds_cstr_ro(&config.drop_action); + } else { + return "/* drop */"; + } } diff --git a/northd/debug.h b/northd/debug.h index 69d4da171..9a1c02986 100644 --- a/northd/debug.h +++ b/northd/debug.h @@ -19,13 +19,23 @@ #include #include "lib/ovn-nb-idl.h" +#include "openvswitch/dynamic-string.h" struct debug_config { bool enabled; + uint32_t collector_set_id; + uint32_t observation_domain_id; + struct ds drop_action; }; void init_debug_config(const struct nbrec_nb_global *nb); +void destroy_debug_config(void); bool debug_enabled(void); +bool debug_sampling_enabled(void); + +const char *debug_drop_action(void); +const char *debug_implicit_drop_action(void); +const char *debug_reject_action(void); #endif /* NORTHD_DEBUG_H */ diff --git a/northd/northd.c b/northd/northd.c index 2fde9fb71..12c9975b9 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -3903,7 +3903,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; @@ -5052,7 +5052,7 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map, const char *where) { if (OVS_UNLIKELY(debug_enabled())) { - 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 ); } } @@ -6315,7 +6315,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), @@ -6343,7 +6343,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), @@ -6360,7 +6360,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), @@ -6596,9 +6596,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). * @@ -7642,7 +7642,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++) { @@ -7658,7 +7658,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_); } @@ -7673,7 +7673,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_); } } @@ -7711,7 +7712,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;"); @@ -7754,18 +7755,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;"); /* Port security flows have priority 50 @@ -8304,7 +8305,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, @@ -8824,7 +8825,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) { @@ -9596,7 +9597,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); @@ -10379,7 +10380,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; " @@ -10435,7 +10436,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 { @@ -10582,7 +10583,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); } @@ -10608,7 +10609,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); } @@ -10776,7 +10777,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); @@ -11352,7 +11353,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; } @@ -11399,13 +11400,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, @@ -11429,7 +11430,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()); } } } @@ -12234,7 +12235,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. @@ -12242,7 +12243,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). @@ -12252,21 +12253,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. */ @@ -12528,7 +12530,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 @@ -13562,8 +13564,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); @@ -15311,6 +15313,7 @@ northd_destroy(struct northd_data *data) destroy_datapaths_and_ports(&data->datapaths, &data->ports, &data->lr_list); + destroy_debug_config(); } static void diff --git a/ovn-nb.xml b/ovn-nb.xml index 360fa96df..80cbc2e3e 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -271,6 +271,30 @@

+ +

+ If set to a 8-bit number and if + debug_drop_collection_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 of the specified in the + debug_drop_domain_id. + The 24 least significant bits of the observation_domain_id field will + be those of the datapath's tunnel key. +

+
+ + +

+ 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 + collection_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/tests/ovn.at b/tests/ovn.at index 1466ee492..67e90b6a8 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -32064,6 +32064,41 @@ check_default_flows() { done } +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_debug() { + as hv1 + check_default_flows + as hv2 + check_default_flows + + as hv1 + check_sample_drops + as hv2 + check_sample_drops +} + check ovn-nbctl -- set NB_Global . options:debug_drop_mode="true" # Logical network: @@ -32131,10 +32166,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 \ @@ -32142,10 +32174,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 @@ -32156,10 +32185,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 @@ -32173,10 +32199,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_debug # LB + stateless ACL check ovn-nbctl --wait=sb \ @@ -32184,10 +32207,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 @@ -32198,10 +32218,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 OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP