From patchwork Thu May 15 11:59:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2086203 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; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=f3yT4wOO; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (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 4ZypfZ0m98z1yYR for ; Thu, 15 May 2025 21:59:33 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8CA3641FA6; Thu, 15 May 2025 11:59:47 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id SmrRm9XTbR7t; Thu, 15 May 2025 11:59:43 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0F92D400F1 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=f3yT4wOO Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 0F92D400F1; Thu, 15 May 2025 11:59:43 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DE6DAC007B; Thu, 15 May 2025 11:59:42 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id D9CA6C0009 for ; Thu, 15 May 2025 11:59:41 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id B972D8188B for ; Thu, 15 May 2025 11:59:41 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id GUqdJrQwv0KU for ; Thu, 15 May 2025 11:59:40 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.252; helo=mail1.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 17F3E80FE8 Authentication-Results: smtp1.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 17F3E80FE8 Authentication-Results: smtp1.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=f3yT4wOO Received: from mail1.k2.cloud (mail1.k2.cloud [109.73.14.252]) by smtp1.osuosl.org (Postfix) with ESMTPS id 17F3E80FE8 for ; Thu, 15 May 2025 11:59:35 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1747310370; bh=l42YZeSuFiH8y9TE2aEZuAbaKYqSQIPF2tS4cPdXhnI=; h=From:To:Cc:Subject:Date; b=f3yT4wOO93hqsL1jx+HkOJV2NcgqeCuU95d7kXsPoJmJDeDFY++gGbi43fWDfVd/N v5nQrIVQssOTwybeo1PUQS6IpxPH04eLktNJBv07uvl1/h1C5xxiiK/0JU28RPAj45 li0V/CPfoL0sYKPuVNiAE5G0hYAMSP3lespWaIH8= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Thu, 15 May 2025 14:59:27 +0300 Message-Id: <20250515115928.35028-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v5] northd: Add option to make work lb with stateless ACL. 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" [0] Removed support for using load balancers in conjunction with stateless ACL. This commit adds an option enable-stateless-acl-with-lb for logical switch to make load balancers work. [0] - https://github.com/ovn-org/ovn/commit/a0f82efdd9dfd3ef2d9606c1890e353df1097a51 Signed-off-by: Alexandra Rukomoinikova --- v4 --> v5: 1) made this functionality optional on the logical switch. 2) moved snat_ip to ovn_northd_lb structure from lb_vip bc it's seems to be more correct. 3) added ls_lb_with_stateless_mode hmapx in ovn_lb_datapaths because the flows for the load balancer are added to the datapath group, and I would like to separately add the flows needed for the balancers to work with stateless acl only for datapath with enabled option. 4) added doc and NEWS. --- NEWS | 3 + northd/lb.c | 18 +++++- northd/lb.h | 5 ++ northd/northd.c | 62 +++++++++++++++++++- northd/northd.h | 4 ++ northd/ovn-northd.8.xml | 8 +++ ovn-nb.xml | 8 +++ tests/ovn-northd.at | 123 ++++++++++++++++++++++++++++++++++++++++ tests/system-ovn.at | 91 +++++++++++++++++++++++++++++ 9 files changed, 318 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index f82f25754..52c829e83 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ Post v25.03.0 - Introduce exclude-router-ips-from-garp in logical_switch_port column so that the router port IPs are not advertised in the GARPs. - Added support for port mirroring in OVN overlay. + - Add a new logical switch option - enable-stateless-acl-lb with default + value of false. This option should be set to true for logical switch + with stateless ACL to work with load balancer. OVN v25.03.0 - 07 Mar 2025 -------------------------- diff --git a/northd/lb.c b/northd/lb.c index ffd21c5bc..b11896cf1 100644 --- a/northd/lb.c +++ b/northd/lb.c @@ -257,6 +257,14 @@ ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, return NULL; } +static bool +validate_snap_ip_address(const char *snat_ip) +{ + ovs_be32 ip; + + return ip_parse(snat_ip, &ip); +} + static void ovn_northd_lb_init(struct ovn_northd_lb *lb, const struct nbrec_load_balancer *nbrec_lb) @@ -297,6 +305,12 @@ ovn_northd_lb_init(struct ovn_northd_lb *lb, } lb->affinity_timeout = affinity_timeout; + const char *snat_ip = smap_get(&nbrec_lb->options, "hairpin_snat_ip"); + + if (snat_ip && validate_snap_ip_address(snat_ip)) { + lb->hairpin_snat_ip = xstrdup(snat_ip); + } + sset_init(&lb->ips_v4); sset_init(&lb->ips_v6); struct smap_node *node; @@ -413,6 +427,7 @@ ovn_northd_lb_cleanup(struct ovn_northd_lb *lb) sset_destroy(&lb->ips_v4); sset_destroy(&lb->ips_v6); free(lb->selection_fields); + free(lb->hairpin_snat_ip); lb->selection_fields = NULL; lb->health_checks = false; } @@ -566,7 +581,7 @@ ovn_lb_datapaths_create(const struct ovn_northd_lb *lb, size_t n_ls_datapaths, lb_dps->nb_ls_map = bitmap_allocate(n_ls_datapaths); lb_dps->nb_lr_map = bitmap_allocate(n_lr_datapaths); lb_dps->lflow_ref = lflow_ref_create(); - + hmapx_init(&lb_dps->ls_lb_with_stateless_mode); return lb_dps; } @@ -576,6 +591,7 @@ ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *lb_dps) bitmap_free(lb_dps->nb_lr_map); bitmap_free(lb_dps->nb_ls_map); lflow_ref_destroy(lb_dps->lflow_ref); + hmapx_destroy(&lb_dps->ls_lb_with_stateless_mode); free(lb_dps); } diff --git a/northd/lb.h b/northd/lb.h index aa6616af4..eb1942bd4 100644 --- a/northd/lb.h +++ b/northd/lb.h @@ -18,6 +18,7 @@ #define OVN_NORTHD_LB_H 1 #include "openvswitch/hmap.h" +#include "hmapx.h" #include "uuid.h" #include "lib/lb.h" @@ -72,6 +73,8 @@ struct ovn_northd_lb { /* Indicates if the load balancer has health checks configured. */ bool health_checks; + + char *hairpin_snat_ip; }; /* ovn-northd specific backend information. */ @@ -139,6 +142,8 @@ struct ovn_lb_datapaths { size_t n_nb_lr; unsigned long *nb_lr_map; + struct hmapx ls_lb_with_stateless_mode; + /* Reference of lflows generated for this load balancer. * * This data is initialized and destroyed by the en_northd node, but diff --git a/northd/northd.c b/northd/northd.c index 7b05147b4..85a1fcc58 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -503,6 +503,7 @@ ovn_datapath_create(struct hmap *datapaths, const struct uuid *key, od->router_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *); od->l3dgw_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *); od->localnet_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *); + od->lb_with_stateless_mode = false; return od; } @@ -942,6 +943,12 @@ join_datapaths(const struct nbrec_logical_switch_table *nbrec_ls_table, if (smap_get_bool(&nbs->other_config, "ic-vxlan_mode", false)) { vxlan_ic_mode = true; } + + if (smap_get_bool(&nbs->other_config, + "enable-stateless-acl-with-lb", false)) { + VLOG_WARN("set option to true"); + od->lb_with_stateless_mode = true; + } } const struct nbrec_logical_router *nbr; @@ -3965,6 +3972,9 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); ovs_assert(lb_dps); ovn_lb_datapaths_add_ls(lb_dps, 1, &od); + if (od->lb_with_stateless_mode) { + hmapx_add(&lb_dps->ls_lb_with_stateless_mode, od); + } } for (size_t i = 0; i < od->nbs->n_load_balancer_group; i++) { @@ -5534,6 +5544,10 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, ovs_assert(lb_dps); ovn_lb_datapaths_add_ls(lb_dps, 1, &od); + if (od->lb_with_stateless_mode) { + hmapx_add(&lb_dps->ls_lb_with_stateless_mode, od); + } + /* Add the lb to the northd tracked data. */ hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); } @@ -6215,7 +6229,7 @@ build_stateless_filter(const struct ovn_datapath *od, action, &acl->header_, lflow_ref); - } else { + } else if (!od->lb_with_stateless_mode) { ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, acl->priority + OVN_ACL_PRI_OFFSET, acl->match, @@ -7780,8 +7794,14 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, * * This is enforced at a higher priority than ACLs can be defined. */ ds_clear(&match); - ds_put_format(&match, "%s(ct.est && ct.rpl && ct_mark.blocked == 1)", - use_ct_inv_match ? "ct.inv || " : ""); + + if (use_ct_inv_match && !od->lb_with_stateless_mode) { + ds_put_cstr(&match, "ct.inv || (ct.est && ct.rpl && " + "ct_mark.blocked == 1)"); + } else { + ds_put_cstr(&match, "(ct.est && ct.rpl && ct_mark.blocked == 1)"); + } + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3, ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;", lflow_ref); @@ -8086,6 +8106,42 @@ build_lb_rules_pre_stateful(struct lflow_table *lflows, lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths), S_SWITCH_IN_PRE_STATEFUL, 120, ds_cstr(match), ds_cstr(action), &lb->nlb->header_, lb_dps->lflow_ref); + + struct lflow_ref *lflow_ref = lb_dps->lflow_ref; + struct hmapx_node *hmapx_node; + struct ovn_datapath *od; + HMAPX_FOR_EACH (hmapx_node, &lb_dps->ls_lb_with_stateless_mode) { + od = hmapx_node->data; + + ds_clear(action); + ds_clear(match); + + ds_put_format(match, "%s.dst == %s", ip_match, lb_vip->vip_str); + + if (lb_vip->port_str) { + ds_put_format(match, " && %s.dst == %s", lb->proto, + lb_vip->port_str); + } + + ds_put_cstr(action, "ct_lb_mark;"); + + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 150, + ds_cstr(match), ds_cstr(action), lflow_ref); + + if (lb->hairpin_snat_ip || lb_vip->port_str) { + ds_clear(action); + ds_clear(match); + + ds_put_format(match, "%s && %s.dst == %s", lb->proto, ip_match, + lb->hairpin_snat_ip ? lb->hairpin_snat_ip + : lb_vip->vip_str); + + ds_put_cstr(action, "ct_lb_mark;"); + + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 105, + ds_cstr(match), ds_cstr(action), lflow_ref); + } + } } } diff --git a/northd/northd.h b/northd/northd.h index 5a698458f..f32ff1e2e 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -379,6 +379,10 @@ struct ovn_datapath { bool has_vtep_lports; bool has_arp_proxy_port; + /* Set to true if the option 'enable-stateless-acl-with-lb' is enabled + * on the logical switch. */ + bool lb_with_stateless_mode; + /* IPAM data. */ struct ipam_info ipam_info; diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 96e102eeb..5d00cff89 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -652,6 +652,12 @@ ct_lb_mark; action. +
  • + A priority-105 added enabled when enable-stateless-acl-with-lb and + send all packet directed to VIP that don't match the above flows to + connection tracker. +
  • +
  • A priority-100 flow sends the packets to connection tracker based on a hint provided by the previous tables @@ -2331,6 +2337,8 @@ output;

    This is similar to ingress table Pre-ACLs except for to-lport traffic. + Except when the option enable-stateless-acl-with-lbis enabled: + REGBIT_ACL_STATELESS ignored.

    diff --git a/ovn-nb.xml b/ovn-nb.xml index 4396023a4..94ee92b9c 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -839,6 +839,14 @@ is not set and the zone limit is derived from OvS default datapath limit. + + + This option must be set to true for stateless ACL to work with load + balancers. When enabled, packets with the ct.inv flag will not be + dropped, even if use_ct_inv_match is set to true. + Default: false. + diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 69b75fe9d..0eca60fdb 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -17290,3 +17290,126 @@ AT_CHECK([cat trace | grep output], [0], [dnl AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([enable-stateless-acl-with-lb usage]) +ovn_start ovn-northd + +AS_BOX([Create logical switches and ports.]) +check ovn-nbctl ls-add sw0 +check ovn-nbctl --wait=sb lsp-add sw0 sw0-p1 -- lsp-set-addresses sw0-p1 \ +"00:00:00:00:00:02 10.0.0.2" + +check ovn-nbctl --wait=sb lsp-add sw0 sw0-p2 -- lsp-set-addresses sw0-p2 \ +"00:00:00:00:00:03 10.0.0.3" + +AS_BOX([Create stateless ACLs.]) +check ovn-nbctl --wait=sb acl-add sw0 from-lport 1001 "ip" allow-stateless +check ovn-nbctl --wait=sb acl-add sw0 to-lport 1001 "ip" allow-stateless + +AS_BOX([Create stateful ACLs.]) +# check if allow-stateless acls have higher priority we skip conntrack. +check ovn-nbctl --wait=sb acl-add sw0 from-lport 1000 "ip" allow-related +check ovn-nbctl --wait=sb acl-add sw0 to-lport 1000 "ip" allow-related + +AS_BOX([Create Load Balancer.]) +check ovn-nbctl lb-add lb1 10.0.0.4:80 10.0.0.2:80,10.0.0.3:80 +check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 + +ovn-sbctl dump-flows sw0 > sw0flows + +AT_CHECK( + [grep -E 'ls_(in|out)_pre_acl' sw0flows | grep reg0 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) + table=??(ls_in_pre_acl ), priority=2001 , match=(ip), action=(reg0[[16]] = 1; next;) + table=??(ls_out_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) + table=??(ls_out_pre_acl ), priority=2001 , match=(ip), action=(reg0[[16]] = 1; next;) +]) + +AT_CHECK( + [grep -E 'ls_out_acl_eval' sw0flows | grep 65532 | ovn_strip_lflows], [0], [dnl + table=??(ls_out_acl_eval ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;) + table=??(ls_out_acl_eval ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(ct.est && ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;) +]) + +AS_BOX([Enable enable-stateless-acl-with-lb option.]) +check ovn-nbctl --wait=sb set logical_switch sw0 other_config:enable-stateless-acl-with-lb=true +ovn-sbctl dump-flows sw0 > sw0flows +AT_CHECK( + [grep -E 'ls_(in|out)_pre_acl' sw0flows | grep reg0 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) + table=??(ls_in_pre_acl ), priority=2001 , match=(ip), action=(reg0[[16]] = 1; next;) + table=??(ls_out_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) +]) + +# We do not match conntrack invalide packets in case of load balancers with stateless ACLs. +AT_CHECK( + [grep -E 'ls_out_acl_eval' sw0flows | grep 65532 | ovn_strip_lflows], [0], [dnl + table=??(ls_out_acl_eval ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;) + table=??(ls_out_acl_eval ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(ct.est && ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;) + table=??(ls_out_acl_eval ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;) +]) + +AT_CHECK([grep -E 'ls_in_pre_stateful' sw0flows | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) + table=??(ls_in_pre_stateful ), priority=105 , match=(tcp && ip4.dst == 10.0.0.4), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 && ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 10.0.0.4 && tcp.dst == 80), action=(reg4 = 10.0.0.4; reg2[[0..15]] = 80; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=150 , match=(ip4.dst == 10.0.0.4 && tcp.dst == 80), action=(ct_lb_mark;) +]) + +AS_BOX([Create Load Balancer without port.]) +check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 +check ovn-nbctl lb-add lb2 10.0.0.5 10.0.0.2,10.0.0.3 +check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 + +ovn-sbctl dump-flows sw0 > sw0flows +AT_CHECK([grep -E 'ls_in_pre_stateful' sw0flows | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) + table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 && ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 10.0.0.5), action=(reg4 = 10.0.0.5; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=150 , match=(ip4.dst == 10.0.0.5), action=(ct_lb_mark;) +]) + +AS_BOX([Set hairpin_snat_ip to Load Balancer without port.]) +check ovn-nbctl --wait=sb set load_balancer lb2 options:hairpin_snat_ip="10.0.0.6" + +ovn-sbctl dump-flows sw0 > sw0flows +AT_CHECK([grep -E 'ls_in_pre_stateful' sw0flows | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) + table=??(ls_in_pre_stateful ), priority=105 , match=(tcp && ip4.dst == 10.0.0.6), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 && ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 10.0.0.5), action=(reg4 = 10.0.0.5; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=150 , match=(ip4.dst == 10.0.0.5), action=(ct_lb_mark;) +]) + +AS_BOX([Create one more logical switch with load balancer.]) +# Check if load balancer is attached to multiple logical switches: +# the lflows for the load balancer will only change on the switch +# where the option is enabled. +check ovn-nbctl ls-add sw1 +check ovn-nbctl ls-lb-add sw1 lb2 + +ovn-sbctl dump-flows sw1 > sw1flows +AT_CHECK([grep -E 'ls_in_pre_stateful' sw1flows | ovn_strip_lflows], [0], [dnl + table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) + table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 && ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;) + table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 10.0.0.5), action=(reg4 = 10.0.0.5; ct_lb_mark;) +]) + +AT_CLEANUP +]) + diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 1dccefb09..dbd129e3b 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -5184,6 +5184,97 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([system enable-stateless-acl-with-lb usage]) + +ovn_start + +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# One logical switch with IPv4 load balancers that hairpin the traffic. +check ovn-nbctl ls-add sw +check ovn-nbctl lsp-add sw lsp1 -- lsp-set-addresses lsp1 00:00:00:00:00:01 +check ovn-nbctl lsp-add sw lsp2 -- lsp-set-addresses lsp2 00:00:00:00:00:02 + +check ovn-nbctl lb-add lb-ipv4-tcp 88.88.88.88:8080 42.42.42.1:4041 tcp +check ovn-nbctl ls-lb-add sw lb-ipv4-tcp + +check ovn-nbctl lr-add rtr +check ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 42.42.42.254/24 +check ovn-nbctl lsp-add sw sw-rtr \ + -- lsp-set-type sw-rtr router \ + -- lsp-set-addresses sw-rtr 00:00:00:00:01:00 \ + -- lsp-set-options sw-rtr router-port=rtr-sw + +ADD_NAMESPACES(lsp1) +ADD_VETH(lsp1, lsp1, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \ + "42.42.42.254") + +ADD_NAMESPACES(lsp2) +ADD_VETH(lsp2, lsp2, br-int, "42.42.42.2/24", "00:00:00:00:00:02", \ + "42.42.42.254") + +# Wait for ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Start IPv4 TCP server on lsp1. +NETNS_DAEMONIZE([lsp1], [nc -l -k 42.42.42.1 4041], [lsp1.pid]) + +# Send the packet to VIP. +NS_CHECK_EXEC([lsp1], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) +NS_CHECK_EXEC([lsp2], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) + +check ovn-nbctl --wait=hv acl-add sw to-lport 2000 'ip' allow-stateless +check ovn-nbctl --wait=hv acl-add sw from-lport 2000 'ip' allow-stateless + +# To provide work of load balancer with stateless ACL this is necessary +# to set enable-stateless-acl-lb to true. +check ovn-nbctl set logical_switch sw other_config:enable-stateless-acl-with-lb=true + +check ovn-nbctl --wait=hv sync + +# Send the packet to VIP after add stateless acl. +NS_CHECK_EXEC([lsp1], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) +NS_CHECK_EXEC([lsp2], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) + +check ovn-nbctl --wait=hv acl-add sw to-lport 2001 'ip' allow-related +check ovn-nbctl --wait=hv acl-add sw from-lport 2001 'ip' allow-related + +# Send the packet to VIP after add related acls. +NS_CHECK_EXEC([lsp1], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) +NS_CHECK_EXEC([lsp2], [nc -z 88.88.88.88 8080], [0], [ignore], [ignore]) + +OVN_CLEANUP_CONTROLLER([hv1]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/connection dropped.*/d"]) +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD([ AT_SETUP([Load Balancer LS hairpin IPv6]) AT_SKIP_IF([test $HAVE_NC = no])