Hi Alexandra,

On 4/8/25 10:46 PM, Alexandra Rukomoinikova wrote:
> [0] Removed support for using load balancers in conjunction with stateless 
> ACL.
> This commit removes the ability to use load balancers alongside stateless ACL.
> If a load balancer is created, the datapath is no longer fully stateless.
> Therefore, to avoid traffic being directed to the contract, it is recommended
> to refrain from creating a load balancer entirely.
> 
> Commit [0] ensures the separation of stateful and stateless scenarios
> in the absence of load balancers, without altering the functionality
> of load balancers themselves.
> 
> When a logical switch is configured with stateless ACL and a load balancer,
> the check for the `REGBIT_CONNTRACK_NAT` flag in the `pre_lb` stage of
> the ingress pipeline becomes redundant. Traffic directed to the load balancer
> must be processed through the conntrack.
> 
> To ensure proper load balancer operation, a rule must be added to match
> the load balancer's VIP address and its protocol (if applicable). This rule
> is added to the datapath group and does not negatively impact performance.
> Packets matching this rule would still be directed to the contract via
> lower-priority rules in the absence of stateless ACL. However, with stateless 
> ACL,
> this rule enables load balancing when the client balances traffic to itself.
> 
> In the egress pipeline, the stateless register should only be set if no
> load balancers are present on the datapath. This maintains a clear separation
> between Stateful and Stateless modes when using ACL.
> If a user creates a load balancer on a logical switch, they should be aware
> that the traffic will no longer be fully stateless.
> 
> Also in case of lb configured with stateless ACLs we no longer take into 
> account
> ct.inv packets in egress. They will be dropped further, at the hypervisor 
> level.
> 
> [0] - ovn-org@a0f82ef.
> 
> Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud>
> ---
> v2 --> v3: 
>       fixed Dumitru comments in v2.
>       corrected hairpin case
>       fixed failed tests
> ---
>  northd/en-ls-stateful.c |   4 +
>  northd/en-ls-stateful.h |   1 +
>  northd/northd.c         |  60 ++++++++++++--
>  northd/ovn-northd.8.xml |  13 ++-
>  tests/ovn-northd.at     | 143 +++++++++++++++++++++++++++++---
>  tests/ovn.at            |   8 +-
>  tests/system-ovn.at     | 179 ++++++++++++++++++++++++++++++++++++----
>  7 files changed, 372 insertions(+), 36 deletions(-)
> 
> diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c
> index 69cda5008..6240c1ea8 100644
> --- a/northd/en-ls-stateful.c
> +++ b/northd/en-ls-stateful.c
> @@ -452,6 +452,10 @@ ls_stateful_record_set_acl_flags_(struct 
> ls_stateful_record *ls_stateful_rec,
>                  && !strcmp(acl->action, "allow-related")) {
>              ls_stateful_rec->has_stateful_acl = true;
>          }
> +        if (!ls_stateful_rec->has_stateless_acl
> +                && !strcmp(acl->action, "allow-stateless")) {
> +            ls_stateful_rec->has_stateless_acl = true;
> +        }
>          if (ls_stateful_rec->has_stateful_acl &&
>              ls_acl_tiers_are_maxed_out(
>                  &ls_stateful_rec->max_acl_tier,
> diff --git a/northd/en-ls-stateful.h b/northd/en-ls-stateful.h
> index 18a7398a6..8516996c5 100644
> --- a/northd/en-ls-stateful.h
> +++ b/northd/en-ls-stateful.h
> @@ -50,6 +50,7 @@ struct ls_stateful_record {
>      size_t ls_index;
>  
>      bool has_stateful_acl;
> +    bool has_stateless_acl;
>      bool has_lb_vip;
>      bool has_acls;
>      struct acl_tier max_acl_tier;
> diff --git a/northd/northd.c b/northd/northd.c
> index 762e4e057..29c3229b3 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -5894,7 +5894,11 @@ build_stateless_filter(const struct ovn_datapath *od,
>                                  action,
>                                  &acl->header_,
>                                  lflow_ref);
> -    } else {
> +    } else if (!od->nbs->n_load_balancer){

This is not correct.  A switch can have load balancers applied to it via
load balancer groups.  We need to check the ls_stateful_rec->has_lb_vip
associated to the datapath instead.

> +        /* For cases when we have statefull ACLs but no load
> +           balancer configured on logical switch - we should
> +           completely bypass conntrack on egress, otherwise
> +           it is necessary to check the balanced traffic. */

So what's the point of stateless to-lport ACLs (egress) if you still
commit to conntrack in the egress pipeline whenever there's a load
balancer configured on the switch/

>          ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
>                                  acl->priority + OVN_ACL_PRI_OFFSET,
>                                  acl->match,
> @@ -7355,6 +7359,23 @@ choose_max_acl_tier(const struct ls_stateful_record 
> *ls_stateful_rec,
>      }
>  }
>  
> +/* In the case of stateless ACLs and load balancers, all traffic
> + * is passed to conntrack during egress pipeline. Conntrack will
> + * mark the packets as 'invalid,' but since stateless systems do
> + * not rely on conntrack state, these invalid packets will be
> + * discarded during processing on the hypervisor level.
> + */
> +static bool
> +stateless_inv_match(const struct ls_stateful_record *ls_stateful_rec)
> +{
> +    if (ls_stateful_rec->has_lb_vip
> +            && ls_stateful_rec->has_stateless_acl) {
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
>  static void
>  build_acls(const struct ls_stateful_record *ls_stateful_rec,
>             const struct ovn_datapath *od,
> @@ -7457,8 +7478,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 && stateless_inv_match(ls_stateful_rec)) {
> +            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);
> @@ -7752,8 +7779,7 @@ build_lb_rules_pre_stateful(struct lflow_table *lflows,
>          }
>          ds_put_cstr(action, "ct_lb_mark;");
>  
> -        ds_put_format(match, REGBIT_CONNTRACK_NAT" == 1 && %s.dst == %s",
> -                      ip_match, lb_vip->vip_str);
> +        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);
> @@ -7763,6 +7789,30 @@ 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);
> +
> +        /* Pass all VIP traffic to the conntrack to support load balancers
> +           in the case of stateless acl. */
> +        const char *hairpin_snat_ip = smap_get(&lb->nlb->options,
> +                                               "hairpin_snat_ip");

We shouldn't be parsing LB options here.  We should do that when we're
building the parsed 'lb', in ovn_northd_lb_init().

> +        bool valid_snat_ip = false;
> +        if (hairpin_snat_ip) {
> +            ovs_be32 ip;
> +            valid_snat_ip = ip_parse(hairpin_snat_ip, &ip);
> +        }
> +
> +        if ((!lb_vip->port_str && valid_snat_ip) || lb_vip->port_str) {

I'm not sure I understand the condition here.  Why do we check
valid_snat_ip only if the VIP has no port?

> +            ds_clear(action);
> +            ds_clear(match);
> +
> +            ds_put_format(match, "%s && %s.dst == %s", lb->proto, ip_match,
> +                          valid_snat_ip ? hairpin_snat_ip : lb_vip->vip_str);
> +            ds_put_cstr(action, "ct_lb_mark;");
> +
> +            ovn_lflow_add_with_dp_group(
> +                lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
> +                S_SWITCH_IN_PRE_STATEFUL, 105, ds_cstr(match), 
> ds_cstr(action),
> +                &lb->nlb->header_, lb_dps->lflow_ref);
> +        }
>      }
>  }
>  
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 1a70ba579..600eea824 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -507,7 +507,7 @@
>        <ref table="Logical_Switch_Port" db="OVN_Northbound"/>.  Multicast, 
> IPv6
>        Neighbor Discovery and MLD traffic also skips stateful ACLs. For
>        "allow-stateless" ACLs, a flow is added to bypass setting the hint for
> -      connection tracker processing when there are stateful ACLs or LB rules;
> +      connection tracker processing when there are stateful ACLs without LB;
>        <code>REGBIT_ACL_STATELESS</code> is set for traffic matching stateless
>        ACL flows.
>      </p>
> @@ -624,6 +624,14 @@
>           <code>ct_lb_mark;</code> action.
>        </li>
>  
> +      <li>
> +         A priority-115 flow sends all packet directed to VIP to connection
> +         tracker. Packets that match this rule would still be subject to
> +         connection tracking via lower-priority rules in the absence of
> +         stateless ACLs. However, with stateless ACLs in place, this rule
> +         enables load balancing when the client balances traffic to itself.
> +      </li>
> +
>        <li>
>           A priority-100 flow sends the packets to connection tracker based
>           on a hint provided by the previous tables
> @@ -770,7 +778,8 @@
>        </li>
>        <li>
>          <code>allow-stateless</code> ACLs translate into logical flows that 
> set
> -        the allow bit and advance to the next table.
> +        the allow bit and advance to the next table. In case of load 
> balancers
> +        with stateless ACLs in this table we allow ct.inv packets go further.
>        </li>
>        <li>
>          <code>reject</code> ACLs translate into logical flows with that set 
> the
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 8ee3c977f..ca1d1a8b1 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -3747,10 +3747,18 @@ for direction in from to; do
>  done
>  check ovn-nbctl --wait=sb sync
>  
> -# TCP packets should not go to conntrack for load balancing.
> +# TCP packets should go to conntrack for load balancing.
>  flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --minimal ls "${flow}"], [0], 
> [dnl
> -output("lsp2");
> +ct_lb_mark {
> +    ct_lb_mark {
> +        reg0[[6]] = 0;
> +        reg0[[12]] = 0;
> +        ct_lb_mark /* default (use --ct to customize) */ {
> +            output("lsp2");
> +        };
> +    };
> +};
>  ])
>  
>  # UDP packets still go to conntrack.
> @@ -3883,10 +3891,18 @@ for direction in from to; do
>  done
>  check ovn-nbctl --wait=sb sync
>  
> -# TCP packets should not go to conntrack for load balancing.
> +# TCP packets should go to conntrack for load balancing.
>  flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --minimal ls "${flow}"], [0], 
> [dnl
> -output("lsp2");
> +ct_lb_mark {
> +    ct_lb_mark {
> +        reg0[[6]] = 0;
> +        reg0[[12]] = 0;
> +        ct_lb_mark /* default (use --ct to customize) */ {
> +            output("lsp2");
> +        };
> +    };
> +};
>  ])
>  
>  # UDP packets still go to conntrack.
> @@ -4775,10 +4791,12 @@ check_stateful_flows() {
>      AT_CHECK([grep "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.10), action=(ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=105  , match=(tcp && ip4.dst == 
> 10.0.0.20), 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.10 && tcp.dst == 80), action=(reg4 = 10.0.0.10; 
> reg2[[0..15]] = 80; ct_lb_mark;)
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg4 = 10.0.0.20; 
> reg2[[0..15]] = 80; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 10.0.0.10 
> && tcp.dst == 80), action=(reg4 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 10.0.0.20 
> && tcp.dst == 80), action=(reg4 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb_mark;)
>  ])
>  
>      AT_CHECK([grep "ls_in_lb " sw0flows | ovn_strip_lflows], [0], [dnl
> @@ -5072,16 +5090,16 @@ AT_CAPTURE_FILE([sw0flows])
>  
>  AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | ovn_strip_lflows], 
> [0], [dnl
>    table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && 
> !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; 
> ct_commit_nat;)
> -  table=??(ls_in_acl_eval     ), priority=65532, match=((ct.est && ct.rpl && 
> ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
>    table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && 
> !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] 
> = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && ct.rpl && 
> ct_mark.blocked == 1), action=(reg8[[17]] = 1; next;)
>    table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && 
> ct_mark.allow_established == 1), action=(reg0[[21]] = 1; reg8[[16]] = 1; 
> next;)
>    table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs 
> || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>  ])
>  
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | 
> ovn_strip_lflows], [0], [dnl
>    table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && 
> !ct.new && 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.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  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_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;)
>  ])
> @@ -14348,7 +14366,7 @@ ovn-sbctl dump-flows s1 > s1flows
>  AT_CAPTURE_FILE([s1flows])
>  
>  AT_CHECK([grep "ls_in_pre_stateful" s1flows | ovn_strip_lflows | grep 
> "30.0.0.1"], [0], [dnl
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip4.dst == 30.0.0.1), action=(reg4 = 30.0.0.1; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 
> 30.0.0.1), action=(reg4 = 30.0.0.1; ct_lb_mark;)
>  ])
>  AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep "30.0.0.1"], 
> [0], [dnl
>    table=??(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 
> 30.0.0.1), action=(reg4 = 30.0.0.1; 
> ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> @@ -14462,7 +14480,7 @@ ovn-sbctl dump-flows s1 > s1flows
>  AT_CAPTURE_FILE([s1flows])
>  
>  AT_CHECK([grep "ls_in_pre_stateful" s1flows | ovn_strip_lflows | grep 
> "2001:db8:cccc::1"], [0], [dnl
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip6.dst == 2001:db8:cccc::1), action=(xxreg1 = 2001:db8:cccc::1; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip6.dst == 
> 2001:db8:cccc::1), action=(xxreg1 = 2001:db8:cccc::1; ct_lb_mark;)
>  ])
>  AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep 
> "2001:db8:cccc::1"], [0], [dnl
>    table=??(ls_in_lb           ), priority=110  , match=(ct.new && ip6.dst == 
> 2001:db8:cccc::1), action=(xxreg1 = 2001:db8:cccc::1; 
> ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
> @@ -14573,7 +14591,7 @@ ovn-sbctl dump-flows s1 > s1flows
>  AT_CAPTURE_FILE([s1flows])
>  
>  AT_CHECK([grep "ls_in_pre_stateful" s1flows | ovn_strip_lflows | grep 
> "30.0.0.1"], [0], [dnl
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip4.dst == 30.0.0.1), action=(reg4 = 30.0.0.1; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 
> 30.0.0.1), action=(reg4 = 30.0.0.1; ct_lb_mark;)
>  ])
>  AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep "30.0.0.1"], 
> [0], [dnl
>    table=??(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 
> 30.0.0.1), action=(reg4 = 30.0.0.1; 
> ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> @@ -16909,5 +16927,108 @@ AT_CHECK([ovn_strip_lflows < lrflows | grep 
> priority=105 | grep -c "flags.force_
>  1
>  ])
>  
> +AT_CLEANUP
> +])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([Load Balancers with stateless ACLs])
> +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 acl-add sw0 from-lport 1001 "ip" allow-stateless
> +check ovn-nbctl 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 acl-add sw0 from-lport 1000 "ip" allow-related
> +check ovn-nbctl acl-add sw0 to-lport 1000 "ip" allow-related
> +
> +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([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;)
> +])
> +
> +# 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.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.rpl && 
> ct_mark.blocked == 1), action=(reg8[[17]] = 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=(ip4.dst == 10.0.0.4 
> && tcp.dst == 80), action=(reg4 = 10.0.0.4; reg2[[0..15]] = 80; 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=(ip4.dst == 
> 10.0.0.5), action=(reg4 = 10.0.0.5; 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=(ip4.dst == 
> 10.0.0.5), action=(reg4 = 10.0.0.5; ct_lb_mark;)
> +])
> +
> +
>  AT_CLEANUP
>  ])
> diff --git a/tests/ovn.at b/tests/ovn.at
> index bbaa653a8..da6714a65 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -26366,7 +26366,7 @@ OVS_WAIT_FOR_OUTPUT(
>    [ovn-sbctl dump-flows > sbflows
>     ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed 
> 's/table=..//'], 0,
>    [dnl
> -  (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 
> 10.0.0.10 && tcp.dst == 80), action=(reg4 = 10.0.0.10; reg2[[0..15]] = 80; 
> ct_lb_mark;)
> +  (ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 10.0.0.10 && 
> tcp.dst == 80), action=(reg4 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark;)
>    (ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 
> 10.0.0.10 && tcp.dst == 80), action=(reg4 = 10.0.0.10; reg2[[0..15]] = 80; 
> ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; 
> hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
>  ])
>  
> @@ -26411,7 +26411,7 @@ AT_CHECK(
>    [grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" sbflows3 | grep priority=120 
> |\
>     ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 
> 10.0.0.10 && tcp.dst == 80), action=(drop;)
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg4 = 10.0.0.10; 
> reg2[[0..15]] = 80; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 10.0.0.10 
> && tcp.dst == 80), action=(reg4 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark;)
>  ])
>  
>  AT_CAPTURE_FILE([sbflows4])
> @@ -26572,7 +26572,7 @@ OVS_WAIT_FOR_OUTPUT(
>    [ovn-sbctl dump-flows > sbflows
>     ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed 
> 's/table=..//'], 0,
>    [dnl
> -  (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip6.dst == 
> 2002::a && tcp.dst == 80), action=(xxreg1 = 2002::a; reg2[[0..15]] = 80; 
> ct_lb_mark;)
> +  (ls_in_pre_stateful ), priority=120  , match=(ip6.dst == 2002::a && 
> tcp.dst == 80), action=(xxreg1 = 2002::a; reg2[[0..15]] = 80; ct_lb_mark;)
>    (ls_in_lb           ), priority=120  , match=(ct.new && ip6.dst == 2002::a 
> && tcp.dst == 80), action=(xxreg1 = 2002::a; reg2[[0..15]] = 80; 
> ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; 
> hash_fields="ipv6_dst,ipv6_src,tcp_dst,tcp_src");)
>  ])
>  
> @@ -26616,7 +26616,7 @@ AT_CHECK(
>    [grep "ip6.dst == 2002::a && tcp.dst == 80" sbflows3 | grep priority=120 |\
>     ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip6.dst == 
> 2002::a && tcp.dst == 80), action=(drop;)
> -  table=??(ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && 
> ip6.dst == 2002::a && tcp.dst == 80), action=(xxreg1 = 2002::a; reg2[[0..15]] 
> = 80; ct_lb_mark;)
> +  table=??(ls_in_pre_stateful ), priority=120  , match=(ip6.dst == 2002::a 
> && tcp.dst == 80), action=(xxreg1 = 2002::a; reg2[[0..15]] = 80; ct_lb_mark;)
>  ])
>  
>  AT_CAPTURE_FILE([sbflows4])
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 7097e4155..515967520 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -5184,6 +5184,110 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port 
> patch-.*/d
>  AT_CLEANUP
>  ])
>  
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([Load Balancer LS hairpin IPv4 with stateless ACLs])
> +
> +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 lsp -- lsp-set-addresses lsp 00:00:00:00:00:01
> +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(lsp)
> +ADD_VETH(lsp, lsp, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \
> +         "42.42.42.254")
> +
> +check ovn-nbctl --wait=hv -t 3 sync
> +
> +# Start IPv4 TCP server on lsp.
> +NETNS_DAEMONIZE([lsp], [nc -l -k 42.42.42.1 4041], [lsp0.pid])
> +
> +
> +# Check that IPv4 TCP hairpin connection succeeds on VIP.
> +NS_CHECK_EXEC([lsp], [nc 88.88.88.88 8080 -z], [0], [ignore], [ignore])
> +
> +check ovn-nbctl acl-add sw to-lport 2000 'ip' allow-stateless
> +check ovn-nbctl acl-add sw from-lport 2000 'ip' allow-stateless
> +
> +NS_CHECK_EXEC([lsp], [timeout 10 nc -z 88.88.88.88 8080 || echo "Connection 
> timed out after 10 seconds"], [0], [ignore], [ignore])
> +
> +# send syn
> +# 42.42.42.1:y -> 88.88.88.88:8080
> +# snat to lb vip
> +# 88.88.88.88:x - 42.42.42.1:4041 syn (we pass this packet to conntrack in 
> egress)
> +# so we send syn + ack
> +# 42.42.42.1:4041 -> 88.88.88.88:x (here we need fourth flow to pass this 
> packet to conntrack)
> +# snat to client ip
> +# send syn + ack
> +# 88.88.88.88:8080 -> 42.42.42.1:y (we pass this packet to conntrack in 
> egress)
> +# send ack
> +# 42.42.42.1:y -> 88.88.88.88:8080 (this package matches the fourth flow)
> +# snat to vip
> +# send ack
> +# 88.88.88.88:x - 42.42.42.1:4041 (here we need third flow to pass this 
> packet to conntrack)
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_stateful | 
> 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 == 
> 88.88.88.88), 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=(ip4.dst == 
> 88.88.88.88 && tcp.dst == 8080), action=(reg4 = 88.88.88.88; reg2[[0..15]] = 
> 8080; ct_lb_mark;)
> +])
> +
> +check ovn-nbctl set load_balancer lb-ipv4-tcp 
> options:hairpin_snat_ip="88.88.88.89"
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_stateful | 
> 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 == 
> 88.88.88.89), 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=(ip4.dst == 
> 88.88.88.88 && tcp.dst == 8080), action=(reg4 = 88.88.88.88; reg2[[0..15]] = 
> 8080; ct_lb_mark;)
> +])
> +
> +# Check that IPv4 TCP hairpin connection succeeds on VIP.
> +NS_CHECK_EXEC([lsp], [nc 88.88.88.88 8080 -z], [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])
> @@ -10071,7 +10175,7 @@ 
> tcp,orig=(src=192.168.1.2,dst=30.30.30.30,sport=<cleared>,dport=<cleared>),reply
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>  
> -# remove lb
> +# Remove Load Balancer.
>  check ovn-nbctl ls-lb-del foo lb1
>  
>  # add stateless acl
> @@ -10088,7 +10192,29 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>  
> -# add lb back
> +# Delete ACLs.
> +check ovn-nbctl acl-del foo
> +
> +# Add stateful ACLs.
> +check ovn-nbctl acl-add foo from-lport 1 1 allow-related
> +check ovn-nbctl --wait=hv acl-add foo to-lport 1 1 allow-related
> +
> +# Add stateless ACLs.
> +check ovn-nbctl acl-add foo from-lport 2 1 allow-stateless
> +check ovn-nbctl --wait=hv acl-add foo to-lport 2 1 allow-stateless
> +
> +AT_CHECK([ip netns exec foo1 wget   192.168.2.2 -t 1 -T 1], [0], [ignore], 
> [ignore])
> +
> +# Check conntrack zone has no entry.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=$zone_id | \
> +FORMAT_CT(192.168.2.2) | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> +
> +# When lb configured: pass conntrack for vip traffic.
> +# Add Load Balancer back.
>  check ovn-nbctl ls-lb-add foo lb1
>  
>  # Wait for ovn-controller to catch up.
> @@ -10097,13 +10223,14 @@ check ovn-nbctl --wait=hv sync
>  OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
>  grep 'nat(dst=192.168.2.2:80)'])
>  
> -# should not dnat so will not be able to connect
> -AT_CHECK([ip netns exec foo1 curl 30.30.30.30 --retry 3 --max-time 1], [28], 
> [ignore], [ignore])
> +# Now check with VIP.
> +AT_CHECK([ip netns exec foo1 wget   30.30.30.30  -t 3 -T 1], [0], [ignore], 
> [ignore])
>  
> -# check conntrack zone has no tcp entry
> +# Check conntrack zone has tcp entry.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=$zone_id | \
>  FORMAT_CT(30.30.30.30) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=192.168.1.2,dst=30.30.30.30,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>)
>  ])
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -10203,7 +10330,7 @@ 
> tcp,orig=(src=fd11::2,dst=fd12::2,sport=<cleared>,dport=<cleared>),reply=(src=fd
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>  
> -# now check with VIP
> +# Now check with VIP.
>  AT_CHECK([ip netns exec foo1 wget  http://[[fd30::2]]  -t 3 -T 1], [0], 
> [ignore], [ignore])
>  
>  # check conntrack zone has tcp entry
> @@ -10215,16 +10342,39 @@ 
> tcp,orig=(src=fd11::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>  
> -# remove lb
> +# Remove Load_Balancer.
>  check ovn-nbctl ls-lb-del foo lb1
>  
> -# add stateless acl
> +# Delete ACLs.
> +check ovn-nbctl acl-del foo
> +
> +# Add stateful ACLs.
> +check ovn-nbctl acl-add foo from-lport 1 1 allow-related
> +check ovn-nbctl --wait=hv acl-add foo to-lport 1 1 allow-related
> +
> +# Add stateless ACLs.
> +check ovn-nbctl acl-add foo from-lport 2 1 allow-stateless
> +check ovn-nbctl --wait=hv acl-add foo to-lport 2 1 allow-stateless
> +
> +AT_CHECK([ip netns exec foo1  wget http://[[fd12::2]] -t 1 -T 1], [0], 
> [ignore], [ignore])
> +
> +# Check conntrack zone has no tcp entry.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=$zone_id | \
> +FORMAT_CT(fd12::2) |  grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> +
> +check ovn-nbctl acl-del foo
> +
> +# Add stateless ACLs.
>  check ovn-nbctl acl-add foo from-lport 1 1 allow-stateless
>  check ovn-nbctl --wait=hv acl-add foo to-lport 1 1 allow-stateless
>  
>  AT_CHECK([ip netns exec foo1  wget http://[[fd12::2]] -t 3 -T 1], [0], 
> [ignore], [ignore])
>  
> -# check conntrack zone has no tcp entry
> +# Check conntrack zone has no tcp entry.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=$zone_id | \
>  FORMAT_CT(fd12::2) |  grep -v fe80 | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> @@ -10232,7 +10382,7 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>  
> -# add lb back
> +# Add Load Balancer back.
>  check ovn-nbctl ls-lb-add foo lb1
>  
>  # Wait for ovn-controller to catch up.
> @@ -10241,13 +10391,14 @@ check ovn-nbctl --wait=hv sync
>  OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
>  grep 'nat(dst=\[[fd12::2\]]:80)'])
>  
> -# should not dnat so will not be able to connect
> -AT_CHECK([ip netns exec foo1 curl http://[[fd30::2]] --retry 3 --max-time 
> 1], [28], [ignore], [ignore])
> -#
> -# check conntrack zone has no tcp entry
> +# Now check with VIP.
> +AT_CHECK([ip netns exec foo1 wget  http://[[fd30::2]]  -t 3 -T 1], [0], 
> [ignore], [ignore])
> +
> +# Check conntrack zone has tcp entry.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=$zone_id | \
>  FORMAT_CT(fd30::2) | grep -v fe80 | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd11::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd11::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>)
>  ])
>  
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])

Regards,
Dumitru


_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to