From patchwork Fri Sep 27 17:08:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Michelson X-Patchwork-Id: 1990350 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org 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=MklTjXlC; dkim-atps=neutral Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XFcXz4CX6z1xtG for ; Sat, 28 Sep 2024 03:15:14 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 4B1B6614F3; Fri, 27 Sep 2024 17:15:11 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id OeFde85Lsl2b; Fri, 27 Sep 2024 17:15:09 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 9009060A82 Authentication-Results: smtp3.osuosl.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=MklTjXlC Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 9009060A82; Fri, 27 Sep 2024 17:15:09 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6CA99C002B; Fri, 27 Sep 2024 17:15:09 +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 EF3BEC002A for ; Fri, 27 Sep 2024 17:15:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DE79B4253A for ; Fri, 27 Sep 2024 17:15:08 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 3Q8JQR2RsjjH for ; Fri, 27 Sep 2024 17:15:07 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=mmichels@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 0C86D42480 Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 0C86D42480 Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MklTjXlC 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 0C86D42480 for ; Fri, 27 Sep 2024 17:15:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1727457305; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=WfLkpvWqtpM52sKngfs/24rHeFAI8vk7DrS9SEaxGI0=; b=MklTjXlCh2X6xGyEAZiyIxo+30pHvGg10oIuZ+yazOBy9yRfIk9NM9gfGtjXOGBOxqLGMM WnvTqeH9+BisUpaqzTUW9QZH2u6Nq/LX+Z6WQkaENpG15v+DpHhLl8CutuqgtVDAVI12Sm kI9us6h5lOjQ5Xa+6TbaPkTDyRRO1ko= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-282-FTaP_Mj6NfuULLC0rnltBw-1; Fri, 27 Sep 2024 13:15:04 -0400 X-MC-Unique: FTaP_Mj6NfuULLC0rnltBw-1 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (unknown [10.30.177.17]) (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 mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7F49E18F7762 for ; Fri, 27 Sep 2024 17:15:03 +0000 (UTC) Received: from localhost.redhat.com (unknown [10.22.0.9]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EB5351955D54 for ; Fri, 27 Sep 2024 17:08:26 +0000 (UTC) From: Mark Michelson To: dev@openvswitch.org Date: Fri, 27 Sep 2024 13:08:20 -0400 Message-ID: <20240927170825.1889455-1-mmichels@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn] northd: Track max ACL tiers more accurately. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When ACL tiers were introduced, the code kept track of the highest ACL tier so that when iterating through ACL tiers, we would not attempt to advance the current tier past the highest configured tier. Unfortunately, keeping track of a single max ACL tier doesn't work when ACLs are evaluated in three separate places. ACLs can be evaluated on ingress before load balancing, on ingress after load balancing, and on egress. By only keeping track of a single max ACL tier, it means that we could perform superfluous checks if one stage of ACLs has a higher max tier than other stages. As an example, if ingress pre-load balancing ACLs have a maximum tier of 1, and egress ACLs have a maximum tier of 2, then it means that for all stages of ACLs, we will evaluate tiers 0, 1, and 2 of ACLs, even though only one stage of ACLs uses tier 2. From a pure functionality standpoint, this doesn't cause any issues. Even if we advance the tier past the highest configured value, it results in a no-op and the same net result happens. However, the addition of sampling into ACLs has caused an unwanted side effect. In the example scenario above, let's say the tier 1 ACL in the ingress pre-load balancing stage evaluates to "pass". After the evaluation, we send a sample for the "pass" result. We then advance the tier to 2, then move back to ACL evaluation. There are no tier 2 ACLs, so we move on to the sampling stage again. We then send a second sample for the previous "pass" result from tier 1. The result is confusing since we've sent two samples for the same ACL evaluation. To remedy this, we now track the max ACL tier in each of the stages where ACLs are evaluated. Now there are no superfluous ACL evaluations and no superfluous samples sent either. Reported-at: https://issues.redhat.com/browse/FDP-760 Signed-off-by: Mark Michelson --- northd/en-ls-stateful.c | 48 ++++++++++++++++++++++++++++++++++------- northd/en-ls-stateful.h | 8 ++++++- northd/northd.c | 47 ++++++++++++++++++++++++++++++---------- tests/ovn-northd.at | 34 +++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c index 44f74ea08..eb751d8dd 100644 --- a/northd/en-ls-stateful.c +++ b/northd/en-ls-stateful.c @@ -204,16 +204,18 @@ ls_stateful_port_group_handler(struct engine_node *node, void *data_) ovn_datapaths_find_by_index(input_data.ls_datapaths, ls_stateful_rec->ls_index); bool had_stateful_acl = ls_stateful_rec->has_stateful_acl; - uint64_t max_acl_tier = ls_stateful_rec->max_acl_tier; + struct acl_tier old_max = ls_stateful_rec->max_acl_tier; bool had_acls = ls_stateful_rec->has_acls; bool modified = false; ls_stateful_record_reinit(ls_stateful_rec, od, ls_pg, input_data.ls_port_groups); + struct acl_tier new_max = ls_stateful_rec->max_acl_tier; + if ((had_stateful_acl != ls_stateful_rec->has_stateful_acl) || (had_acls != ls_stateful_rec->has_acls) - || max_acl_tier != ls_stateful_rec->max_acl_tier) { + || memcmp(&old_max, &new_max, sizeof(old_max))) { modified = true; } @@ -365,7 +367,8 @@ ls_stateful_record_set_acl_flags(struct ls_stateful_record *ls_stateful_rec, const struct ls_port_group_table *ls_pgs) { ls_stateful_rec->has_stateful_acl = false; - ls_stateful_rec->max_acl_tier = 0; + memset(&ls_stateful_rec->max_acl_tier, 0, + sizeof ls_stateful_rec->max_acl_tier); ls_stateful_rec->has_acls = false; if (ls_stateful_record_set_acl_flags_(ls_stateful_rec, od->nbs->acls, @@ -391,6 +394,36 @@ ls_stateful_record_set_acl_flags(struct ls_stateful_record *ls_stateful_rec, } } +static void +update_ls_max_acl_tier(struct ls_stateful_record *ls_stateful_rec, + const struct nbrec_acl *acl) +{ + if (!acl->tier) { + return; + } + + if (!strcmp(acl->direction, "from-lport")) { + if (smap_get_bool(&acl->options, "apply-after-lb", false)) { + if (acl->tier > ls_stateful_rec->max_acl_tier.ingress_post_lb) { + ls_stateful_rec->max_acl_tier.ingress_post_lb = acl->tier; + } + } else if (acl->tier > ls_stateful_rec->max_acl_tier.ingress_pre_lb) { + ls_stateful_rec->max_acl_tier.ingress_pre_lb = acl->tier; + } + } else if (acl->tier > ls_stateful_rec->max_acl_tier.egress) { + ls_stateful_rec->max_acl_tier.egress = acl->tier; + } +} + +static bool +ls_acl_tiers_are_maxed_out(struct acl_tier *acl_tier, + uint64_t max_allowed_acl_tier) +{ + return acl_tier->ingress_post_lb == max_allowed_acl_tier && + acl_tier->ingress_pre_lb == max_allowed_acl_tier && + acl_tier->egress == max_allowed_acl_tier; +} + static bool ls_stateful_record_set_acl_flags_(struct ls_stateful_record *ls_stateful_rec, struct nbrec_acl **acls, @@ -408,16 +441,15 @@ ls_stateful_record_set_acl_flags_(struct ls_stateful_record *ls_stateful_rec, ls_stateful_rec->has_acls = true; for (size_t i = 0; i < n_acls; i++) { const struct nbrec_acl *acl = acls[i]; - if (acl->tier > ls_stateful_rec->max_acl_tier) { - ls_stateful_rec->max_acl_tier = acl->tier; - } + update_ls_max_acl_tier(ls_stateful_rec, acl); if (!ls_stateful_rec->has_stateful_acl && !strcmp(acl->action, "allow-related")) { ls_stateful_rec->has_stateful_acl = true; } if (ls_stateful_rec->has_stateful_acl && - ls_stateful_rec->max_acl_tier == - nbrec_acl_col_tier.type.value.integer.max) { + ls_acl_tiers_are_maxed_out( + &ls_stateful_rec->max_acl_tier, + nbrec_acl_col_tier.type.value.integer.max)) { return true; } } diff --git a/northd/en-ls-stateful.h b/northd/en-ls-stateful.h index eae4b08e2..18a7398a6 100644 --- a/northd/en-ls-stateful.h +++ b/northd/en-ls-stateful.h @@ -33,6 +33,12 @@ struct lflow_ref; +struct acl_tier { + uint64_t ingress_pre_lb; + uint64_t ingress_post_lb; + uint64_t egress; +}; + struct ls_stateful_record { struct hmap_node key_node; @@ -46,7 +52,7 @@ struct ls_stateful_record { bool has_stateful_acl; bool has_lb_vip; bool has_acls; - uint64_t max_acl_tier; + struct acl_tier max_acl_tier; /* 'lflow_ref' is used to reference logical flows generated for * this ls_stateful record. diff --git a/northd/northd.c b/northd/northd.c index a267cd5f8..9d3edee32 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -7321,28 +7321,34 @@ build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec, S_SWITCH_OUT_ACL_EVAL, }; + uint64_t max_acl_tiers[] = { + ls_stateful_rec->max_acl_tier.ingress_pre_lb, + ls_stateful_rec->max_acl_tier.ingress_post_lb, + ls_stateful_rec->max_acl_tier.egress, + }; + ds_clear(actions); ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " REGBIT_ACL_VERDICT_DROP " = 0; " REGBIT_ACL_VERDICT_REJECT " = 0; "); - if (ls_stateful_rec->max_acl_tier) { - ds_put_cstr(actions, REG_ACL_TIER " = 0; "); - } size_t verdict_len = actions->length; - for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { enum ovn_stage stage = stages[i]; + if (max_acl_tiers[i]) { + ds_put_cstr(actions, REG_ACL_TIER " = 0; "); + } + size_t verdict_tier_len = actions->length; if (!ls_stateful_rec->has_acls) { ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref); continue; } - ds_truncate(actions, verdict_len); + ds_truncate(actions, verdict_tier_len); ds_put_cstr(actions, "next;"); ovn_lflow_add(lflows, od, stage, 1000, REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions), lflow_ref); - ds_truncate(actions, verdict_len); + ds_truncate(actions, verdict_tier_len); ds_put_cstr(actions, debug_implicit_drop_action()); ovn_lflow_add(lflows, od, stage, 1000, REGBIT_ACL_VERDICT_DROP " == 1", @@ -7350,7 +7356,7 @@ build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec, lflow_ref); bool ingress = ovn_stage_get_pipeline(stage) == P_IN; - ds_truncate(actions, verdict_len); + ds_truncate(actions, verdict_tier_len); build_acl_reject_action(actions, ingress); ovn_lflow_metered(lflows, od, stage, 1000, @@ -7358,12 +7364,12 @@ build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec, copp_meter_get(COPP_REJECT, od->nbs->copp, meter_groups), lflow_ref); - ds_truncate(actions, verdict_len); + ds_truncate(actions, verdict_tier_len); ds_put_cstr(actions, default_acl_action); ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions), lflow_ref); struct ds tier_actions = DS_EMPTY_INITIALIZER; - for (size_t j = 0; j < ls_stateful_rec->max_acl_tier; j++) { + for (size_t j = 0; j < max_acl_tiers[i]; j++) { ds_clear(match); ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); ds_clear(&tier_actions); @@ -7375,6 +7381,7 @@ build_acl_action_lflows(const struct ls_stateful_record *ls_stateful_rec, ds_cstr(&tier_actions), lflow_ref); } ds_destroy(&tier_actions); + ds_truncate(actions, verdict_len); } } @@ -7443,6 +7450,21 @@ build_acl_log_related_flows(const struct ovn_datapath *od, &acl->header_, lflow_ref); } +static uint64_t +choose_max_acl_tier(const struct ls_stateful_record *ls_stateful_rec, + const struct nbrec_acl *acl) +{ + if (!strcmp(acl->direction, "from-lport")) { + if (smap_get_bool(&acl->options, "apply-after-lb", false)) { + return ls_stateful_rec->max_acl_tier.ingress_post_lb; + } else { + return ls_stateful_rec->max_acl_tier.ingress_pre_lb; + } + } else { + return ls_stateful_rec->max_acl_tier.egress; + } +} + static void build_acls(const struct ls_stateful_record *ls_stateful_rec, const struct ovn_datapath *od, @@ -7639,8 +7661,9 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, build_acl_log_related_flows(od, lflows, acl, has_stateful, meter_groups, &match, &actions, lflow_ref); + uint64_t max_acl_tier = choose_max_acl_tier(ls_stateful_rec, acl); consider_acl(lflows, od, acl, has_stateful, - meter_groups, ls_stateful_rec->max_acl_tier, + meter_groups, max_acl_tier, &match, &actions, lflow_ref); build_acl_sample_flows(ls_stateful_rec, od, lflows, acl, &match, &actions, sampling_apps, @@ -7658,8 +7681,10 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, build_acl_log_related_flows(od, lflows, acl, has_stateful, meter_groups, &match, &actions, lflow_ref); + uint64_t max_acl_tier = choose_max_acl_tier(ls_stateful_rec, + acl); consider_acl(lflows, od, acl, has_stateful, - meter_groups, ls_stateful_rec->max_acl_tier, + meter_groups, max_acl_tier, &match, &actions, lflow_ref); build_acl_sample_flows(ls_stateful_rec, od, lflows, acl, &match, &actions, sampling_apps, diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index dcc3dbbc3..dd2ad2330 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -13864,3 +13864,37 @@ check_no_redirect AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL mismatched tiers]) +ovn_start + +check ovn-nbctl ls-add S1 + +# Ingress pre-lb ACLs have only a tier 1 ACL configured. +# Ingress post-lb ACLs have tier up to 3 configured. +# Egress ACLs have up to tier 2 configured. +check ovn-nbctl --tier=1 acl-add S1 from-lport 1001 "tcp" allow +check ovn-nbctl --tier=3 --apply-after-lb acl-add S1 from-lport 1001 "tcp" allow +check ovn-nbctl --tier=2 acl-add S1 to-lport 1001 "tcp" allow + +# Ingress pre-lb ACLs should only ever increment the tier to 1. +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_in_acl_action | grep priority=500 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_acl_action ), priority=500 , match=(reg8[[30..31]] == 0), action=(reg8[[30..31]] = 1; next(pipeline=ingress,table=??);) +]) + +# Ingress post-lb ACLs should increment the tier to 3. +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_in_acl_after_lb_action | grep priority=500 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_acl_after_lb_action), priority=500 , match=(reg8[[30..31]] == 0), action=(reg8[[30..31]] = 1; next(pipeline=ingress,table=??);) + table=??(ls_in_acl_after_lb_action), priority=500 , match=(reg8[[30..31]] == 1), action=(reg8[[30..31]] = 2; next(pipeline=ingress,table=??);) + table=??(ls_in_acl_after_lb_action), priority=500 , match=(reg8[[30..31]] == 2), action=(reg8[[30..31]] = 3; next(pipeline=ingress,table=??);) +]) + +# Egress ACLs should increment the tier to 2. +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_out_acl_action | grep priority=500 | ovn_strip_lflows], [0], [dnl + table=??(ls_out_acl_action ), priority=500 , match=(reg8[[30..31]] == 0), action=(reg8[[30..31]] = 1; next(pipeline=egress,table=??);) + table=??(ls_out_acl_action ), priority=500 , match=(reg8[[30..31]] == 1), action=(reg8[[30..31]] = 2; next(pipeline=egress,table=??);) +]) + +AT_CLEANUP +])