Hello Dumitru,

On 04.04.2025 13:55, Dumitru Ceara wrote:
> On 4/3/25 6:57 PM, Aleksandra Rukomoinikova wrote:
>> On 03.04.2025 11:58, Dumitru Ceara wrote:
>> /Hi, Dumitru/
>> Thank you for your time, I will respond to your comments below.
> Hi Alexandra,
>
>>> On 3/23/25 3:07 PM, Vladislav Odintsov wrote:
>>>> Hi Dumitru, Venu,
>>>>
>>> Hi Vladislav,
>>>
>>>> thanks for your time spent digging into this!
>>>>
>>>> The code within current patch sends reply traffic to conntrack only if it 
>>>> sees that it needs to do that (LB is created within the datapath). If 
>>>> there is no LB, so traffic will not be sent to conntrack and HW-offload 
>>>> will probably work.
>>>> I’m worried why load balancer is created even if it doesn’t work in such 
>>>> scenario? Shouldn’t that be fixed from the orchestrator side (not to 
>>>> create LB)?
>>>>
>>> I guess I'm a bit confused by the statement above.  I don't see all
>>> reply traffic being sent to conntrack.  Instead the patch only sends
>>> traffic destined to the LB VIP to conntrack.
>>>
>>> @@ -7752,8 +7806,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 +7816,22 @@ 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. */
>>> +        if (lb_vip->port_str && lb->proto) {
>>> +            ds_clear(action);
>>> +            ds_clear(match);
>>> +
>>> +            ds_put_cstr(action, "ct_lb_mark;");
>>> +            ds_put_format(match, "%s && %s.dst == %s",
>>> +                          lb->proto, ip_match, lb_vip->vip_str);
>>> +
>>> +            ovn_lflow_add_with_dp_group(
>>> +                lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>>> +                S_SWITCH_IN_PRE_STATEFUL, 115, ds_cstr(match), 
>>> ds_cstr(action),
>>> +                &lb->nlb->header_, lb_dps->lflow_ref);
>>> +        }
>>>        }
>>>    }
>>>
>>> Also, the code above generates logical flows in in_pre_stateful, at priority
>>> 115, that can never be matched.
>>>
>>> E.g., "make sandbox" and then:
>>> $ ovn-nbctl ls-add sw1
>>> $ ovn-nbctl lb-add lb 1.1.1.1:80 2.2.2.2:80 tcp
>>> $ ovn-nbctl ls-lb-add sw1 lb
>>> $ ovn-nbctl acl-add sw1 from-lport 1002 'ip4 || ip6'  allow-stateless
>>>
>>> Dump the in_pre_stateful relevant logical flows:
>>>
>>>     table=6 (ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 
>>> 1.1.1.1 && tcp.dst == 80), action=(reg4 = 1.1.1.1; reg2[0..15] = 80; 
>>> ct_lb_mark;)
>>>     table=6 (ls_in_pre_stateful ), priority=115  , match=(reg0[2] == 1 && 
>>> ip.is_frag), action=(reg0[19] = 1; ct_lb_mark;)
>>>     table=6 (ls_in_pre_stateful ), priority=115  , match=(tcp && ip4.dst == 
>>> 1.1.1.1), action=(ct_lb_mark;)
>>>
>>> The first flow match (prio 120) is a super set of the match of the third
> I had missed the tcp.dst == 80 match here, it's not a super set.  But
> still, please see my comment on LB hairpin below.
>
>>> flow match (prio 115).  That means the third flow will never be hit.
>>>
>>> This seems a bit weird.
>>>
>>> Regards,
>>> Dumitru
>>>
>>>> regards,
>>>> Vladislav Odintsov
>>>>
>>>>> On 23 Mar 2025, at 11:56, Dumitru Ceara via dev <ovs-dev@openvswitch.org> 
>>>>> wrote:
>>>>>
>>>>> On 3/22/25 2:01 AM, Venu Iyer wrote:
>>>>>> Sorry for the much delayed response Dumitru; I am just catching up on 
>>>>>> this and will look at the patch and follow-ups.
>>>>>> Just a quick response below.
>>>>>>
>>>>> Hi Venu,
>>>>>
>>>>>> ________________________________
>>>>>> From: Dumitru Ceara <dce...@redhat.com>
>>>>>> Sent: Wednesday, March 19, 2025 6:00 AM
>>>>>> To: Aleksandra Rukomoinikova <ARukomoinikova@k2.cloud>; 
>>>>>> d...@openvswitch.org <d...@openvswitch.org>
>>>>>> Cc: Venu Iyer <venugop...@nvidia.com>; Han Zhou <hz...@ovn.org>; Numan 
>>>>>> Siddique <num...@ovn.org>
>>>>>> Subject: Re: [PATCH ovn v2] northd: Make work load balancer with 
>>>>>> stateless ACL.
>>>>>>
>>>>>> External email: Use caution opening links or attachments
>>>>>>
>>>>>>
>>>>>>> On 3/18/25 5:08 PM, Aleksandra Rukomoinikova wrote:
>>>>>>> Hi Dumitru,
>>>>>>>
>>>>>> Hi Alexandra,
>>>>>>
>>>>>>> I want to clarify a little my question that I asked yesterday at the 
>>>>>>> meeting,
>>>>>>> it was formulated incorrectly by me
>>>>>>>
>>>>>>> in a situation when we have stateless acl and related one (or lb 
>>>>>>> configured)
>>>>>>>
>>>>>>> before patch [0] (that is, before version v23.03.0 judging by the log) 
>>>>>>> there was a lookup in ingress
>>>>>>> and in the egress of all packages in the conntrack
>>>>>>>
>>>>>>> because the packages fell under:
>>>>>>>
>>>>>>> table=4 (ls_in_pre_acl), priority=100, match=(ip), action=(reg0[0] = 1; 
>>>>>>> next;)
>>>>>>> table=0 (ls_out_pre_lb), priority=100, match=(ip), action=(reg0[2] = 1; 
>>>>>>> next;)
>>>>>>>
>>>>>>> and then the packages were not committed because:
>>>>>>> table=8 (ls_in_acl), priority=2002, match=(stateless acl match), 
>>>>>>> action=(next;)
>>>>>>>
>>>>>>> That is, we were cheating traffic to the contract, but did not commit, 
>>>>>>> an invalid state was returned.
>>>>>>>
>>>>>>> That is, such a situation arose when using stateless acls, which are 
>>>>>>> higher priority than statefull ones
>>>>>>> or also when using lb.
>>>>>>>
>>>>>>> A similar situation is now occurring in my patch, I bypass it this way:
>>>>>>>
>>>>>>> Despite the enabled ct_match_inv option, we add it only if there is no 
>>>>>>> stateless acl + lb bundle
>>>>>>>
>>>>>>> What do you think?
>>>>>>>
>>>>>>> [0] - 
>>>>>>> https://github.com/ovn-org/ovn/commit/a0f82efdd9dfd3ef2d9606c1890e353df1097a51.
>>>>>>>
>>>>>> Thanks for the additional details!
>>>>>>
>>>>>> I'm CC-ing Venu, Han and Numan for more input on this.  Venu, you added
>>>>>> this restriction that doesn't allow traffic matched by stateless ACLs to
>>>>>> be load balanced, what is your opinion with respect to Alexandra's
>>>>>> suggested change below?
>>>>>>
>>>>>>> [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.
>>>>>> This was an issue with ovn-k8s where the logical switch has LB for the 
>>>>>> service IPs  ..
>>>>>> and this made configuring any stateless rules impossible - e.g if there  
>>>>>> is a application
>>>>>> with unidirection UDP flows such flows will not be offloaded without 
>>>>>> stateless.
>>>>>>
>>>>>>
>>>>>>
>>>>>>> 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.
>>>>>> I think statelesss and LB should not overlap and, hence, should be able 
>>>>>> to
>>>>>> coexist. Maybe Han can provide some input as well.
>>>>>>
>>>>> Ah, I see, so the problem was for unidirectional traffic that needs to
>>>>> be offloaded (which doesn't happen if it's forwarded on
>>>>> ct_state=+trk+new).
>>>>>
>>>>> I guess Alexandra's change here doesn't suffice though:
>>>>>
>>>>> @@ -7763,6 +7816,22 @@  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. */
>>>>> +        if (lb_vip->port_str && lb->proto) {
>>>>> +            ds_clear(action);
>>>>> +            ds_clear(match);
>>>>> +
>>>>> +            ds_put_cstr(action, "ct_lb_mark;");
>>>>> +            ds_put_format(match, "%s && %s.dst == %s",
>>>>> +                          lb->proto, ip_match, lb_vip->vip_str);
>>>>> +
>>>>> +            ovn_lflow_add_with_dp_group(
>>>>> +                lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>>>>> +                S_SWITCH_IN_PRE_STATEFUL, 115, ds_cstr(match), 
>>>>> ds_cstr(action),
>>>>> +                &lb->nlb->header_, lb_dps->lflow_ref);
>>>>> +        }
>>>>>       }
>>>>>
>>>>> This will send to conntrack in the original direction only traffic that is
>>>>> destined to the LB VIP.
>>>>>
>>>>> But for replies we'll send everything to conntrack:
>>>>>
>>>>> @@ -5894,7 +5894,11 @@  build_stateless_filter(const struct ovn_datapath 
>>>>> *od,
>> you said that you don't see how all the replay traffic ends up in the 
>> conntrack:
>>
>> this flow will be added to the egress pipeline only if there are no lb,
>> and it is responsible for sending packets to the conntrack.
>>
> I still don't understand, sorry.  Let's assume we have a TCP LB with
> VIP=42.42.42.42:80 and backends=10.10.10.3:8080 configured on a switch;
> and a client LSP (10.10.10.2) and a server LSP (10.10.10.3).
>
> The client tries to connect to the LB VIP:
>
> 1. TCP SYN:
>     ip_src=10.10.10.2, tcp_src=x, ip_dst=42.42.42.42, tcp_dst=80
>
> 2. TCP SYN is DNATed by the OVN LB:
>     ip_src=10.10.10.2, tcp_src=x, ip_dst=10.10.10.3, tcp_dst=8080
>
> 3. The SYN reaches the server and the server replies with SYN+ACK:
>     ip_src=10.10.10.3, tcp_src=8080, ip_dst=10.10.10.2, tcp_dst=x
>
> This packet should be unDNATed.  How is this packet matched by the flow
> you mentioned above?  That flow matches on ip.dst == lb.vip.

I meant using this flow for the hairpin case (the client is the server), 
but i missed the ability to configure ip for snat option. i will fix it 
like that?

table=6 (ls_in_pre_stateful ), priority=115  , match=(tcp && ip4.dst == lb 
vip/snai_hairpin if configured), action=(ct_lb_mark;)

>
>>>>>                                   action,
>>>>>                                   &acl->header_,
>>>>>                                   lflow_ref);
>>>>> -    } else {
>>>>> +    } else if (!od->nbs->n_load_balancer){
>>>>> +        /* 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. */
>>>>>           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
>>>>>                                   acl->priority + OVN_ACL_PRI_OFFSET,
>>>>>                                   acl->match,
>>>>>
>>>>> So, I'm afraid we are also going to need something that restricts traffic
>>>>> that is sent to conntrack in the reply direction.  E.g., logical flows
>>>>> that match on traffic originated by load balancer backends.
>>>>>
>>>>> We need to be careful when we do that though.  We don't want to create
>>>>> a logical flow explosion (there can be quite a few backends so a logical
>>>>> flow per backend might be very costly for both ovn-northd and the SB DB).
>>>>>
>> regarding the added flows in ingress:
>>
>>     table=6 (ls_in_pre_stateful ), priority=120  , match=(ip4.dst == 1.1.1.1 
>> && tcp.dst == 80), action=(reg4 = 1.1.1.1; reg2[0..15] = 80; ct_lb_mark;)
>>     table=6 (ls_in_pre_stateful ), priority=115  , match=(reg0[2] == 1 && 
>> ip.is_frag), action=(reg0[19] = 1; ct_lb_mark;)
>>     table=6 (ls_in_pre_stateful ), priority=115  , match=(tcp && ip4.dst == 
>> 1.1.1.1), action=(ct_lb_mark;)
>>
>> priorities overlapped, i think, i should fix it like this ?
>>
>>     table=6 (ls_in_pre_stateful ), priority=125  , match=(ip4.dst == 1.1.1.1 
>> && tcp.dst == 80), action=(reg4 = 1.1.1.1; reg2[0..15] = 80; ct_lb_mark;)
>>     table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[2] == 1 && 
>> ip.is_frag), action=(reg0[19] = 1; ct_lb_mark;)
>>     table=6 (ls_in_pre_stateful ), priority=115  , match=(tcp && ip4.dst == 
>> 1.1.1.1), action=(ct_lb_mark;)
>>
>> the first rule will work for lb in general, the third rule is important
>> in balancing from the client to itself to establish a connection before
>> dnat occurs.
> I'm not sure I follow.  For hairpin traffic, client -> LB -> client,
> there's an additional SNAT happening after DNAT in the original
> direction.  The SNAT IP is not necessarily the LB VIP, it's configurable
> through LB.options.hairpin_snat_ip.  And we already support this kind of
> connection so I'm not sure why we need that third flow.  We already have
> LB hairpin system tests for the regular case.  Would it be possible to
> add new ones for the case when we have (stateless) ACLs too?
>
>>>>>> Sorry again for not being on top of this.
>>>>>>
>>>>> No worries, thanks for the reply!
>>>>>
>>>>> Regards,
>>>>> Dumitru
>>>>>
>>>>>> -venu
>>>>>>
>>>>>>> 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><mailto:arukomoinikova@k2.cloud>
>>>>>>> ---
>>>>>>> northd/northd.c         |  79 ++++++++++++++++++++++++++++--
>>>>>>> northd/ovn-northd.8.xml |  13 ++++-
>>>>>>> tests/ovn-northd.at     | 106 +++++++++++++++++++++++++++++++++++-----
>>>>>>> tests/ovn.at            |   8 +--
>>>>>>> tests/system-ovn.at     |  61 ++++++++++++++++++++---
>>>>>>> 5 files changed, 238 insertions(+), 29 deletions(-)
>>>>>> The "237: system-ovn-kmod.at:1031 Load Balancer LS hairpin IPv4 UDP -
>>>>>> larger than MTU" test is failing with this patch applied, see CI run 
>>>>>> here:
>>>>>> https://github.com/ovsrobot/ovn/actions/runs/13928303850/job/38978852134#step:9:4712
>>>>>>
>>>>>> Something is weird because the test in question doesn't use stateless
>>>>>> ACLs at all.  So there must be a bug that's introduced by your patch.
>>>>>>
>>>>>> I did a cursory review of the rest of the patch and shared some more
>>>>>> comments below.
>>>>>>
>>>>>> However, I'd like to hear from Venu/Han/Numan first, if possible, before
>>>>>> moving towards a v3.
>>>>>>
>>>>>>> diff --git a/northd/northd.c b/northd/northd.c
>>>>>>> index 1d3e132d4..fab420784 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){
>>>>>>> +        /* 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. */
>>>>>>>           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
>>>>>>>                                   acl->priority + OVN_ACL_PRI_OFFSET,
>>>>>>>                                   acl->match,
>>>>>>> @@ -7355,6 +7359,49 @@ 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,
>>>>>>> +                    const struct ovn_datapath *od,
>>>>>>> +                    const struct ls_port_group_table *ls_port_groups)
>>>>>>> +{
>>>>>>> +    bool inv_match = true;
>>>>>> There's no need for this variable, we always return after setting its 
>>>>>> value.
>>>>>>
>>>>>>> +
>>>>>>> +    if (ls_stateful_rec->has_lb_vip) {
>>>>>>> +        for (size_t i = 0; i < od->nbs->n_acls; i++) {
>>>>>>> +            const struct nbrec_acl *acl = od->nbs->acls[i];
>>>>>>> +            if (!strcmp(acl->action, "allow-stateless")) {
>>>>>>> +                inv_match = false;
>>>>>>> +                return inv_match;
>>>>>> Just return false here.
>>>>>>
>>>>>> However, a cleaner and slightly more efficient way of doing this would
>>>>>> be to add a "has_stateless_acl" field to "struct ls_stateful_record" and
>>>>>> populate it in ls_stateful_record_set_acl_flags().
>>>>>>
>>>>>>> +            }
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        const struct ls_port_group *ls_pg =
>>>>>>> +            ls_port_group_table_find(ls_port_groups, od->nbs);
>>>>>>> +        if (!ls_pg) {
>>>>>>> +            return inv_match;
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        const struct ls_port_group_record *ls_pg_rec;
>>>>>>> +            HMAP_FOR_EACH (ls_pg_rec, key_node, &ls_pg->nb_pgs) {
>>>>>>> +            for (size_t i = 0; i < ls_pg_rec->nb_pg->n_acls; i++) {
>>>>>>> +                const struct nbrec_acl *acl = 
>>>>>>> ls_pg_rec->nb_pg->acls[i];
>>>>>>> +                if (!strcmp(acl->action, "allow-stateless")) {
>>>>>>> +                    inv_match = false;
>>>>>>> +                    return inv_match;
>>>>>>> +                }
>>>>>>> +            }
>>>>>>> +        }
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    return inv_match;
>>>>>>> +}
>>>>>>> +
>>>>>>> static void
>>>>>>> build_acls(const struct ls_stateful_record *ls_stateful_rec,
>>>>>>>              const struct ovn_datapath *od,
>>>>>>> @@ -7457,8 +7504,15 @@ 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,
>>>>>>> +                                                    od, 
>>>>>>> ls_port_groups)) {
>>>>>>> +            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");
>>>>>>> +        }
>>>>>> If we go this way we should probably also update the "use_ct_inv_match"
>>>>>> documentation in ovn-nb.xml.
>>>>>>
>>>>>> This is also a very noticeable behavior change, we should at least
>>>>>> mention it in NEWS if we accept this patch.
>>>>>>
>>>>>>> +
>>>>>>>           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 +7806,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 +7816,22 @@ 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. */
>>>>>>> +        if (lb_vip->port_str && lb->proto) {
>>>>>> lb->proto is always non-NULL, it can be omitted from the condition.
>>>>>>
>>>>>> What about load balancers that have a port specified?
>>>>>>
>>>>>>> +            ds_clear(action);
>>>>>>> +            ds_clear(match);
>>>>>>> +
>>>>>>> +            ds_put_cstr(action, "ct_lb_mark;");
>>>>>>> +            ds_put_format(match, "%s && %s.dst == %s",
>>>>>>> +                          lb->proto, ip_match, lb_vip->vip_str);
>>>>>> Why not restrict this flow to only match traffic destined to the LB
>>>>>> port, if the LB has a port configured?
>>>>>>
>>>>>>> +
>>>>>>> +            ovn_lflow_add_with_dp_group(
>>>>>>> +                lflows, lb_dps->nb_ls_map, ods_size(ls_datapaths),
>>>>>>> +                S_SWITCH_IN_PRE_STATEFUL, 115, 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 155ba8a49..2719ac77b 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 419130aa8..c6540f90d 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.
>>>>>>> @@ -4770,8 +4786,10 @@ check_stateful_flows() {
>>>>>>>     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.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=115  , match=(tcp && ip4.dst 
>>>>>>> == 10.0.0.10), action=(ct_lb_mark;)
>>>>>>> +  table=??(ls_in_pre_stateful ), priority=115  , match=(tcp && ip4.dst 
>>>>>>> == 10.0.0.20), action=(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
>>>>>>> @@ -5065,16 +5083,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;)
>>>>>>> ])
>>>>>>> @@ -14333,7 +14351,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);)
>>>>>>> @@ -14447,7 +14465,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);)
>>>>>>> @@ -14558,7 +14576,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);)
>>>>>>> @@ -16753,3 +16771,69 @@ check grep -q "Bad configuration: The peer of 
>>>>>>> the switch port 'ls-lrp1' (LRP pee
>>>>>>>
>>>>>>> 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 statefull 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_CLEANUP
>>>>>>> +])
>>>>>>> +
>>>>>>> diff --git a/tests/ovn.at b/tests/ovn.at
>>>>>>> index afde2576f..3e299711b 100644
>>>>>>> --- a/tests/ovn.at
>>>>>>> +++ b/tests/ovn.at
>>>>>>> @@ -26345,7 +26345,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");)
>>>>>>> ])
>>>>>>>
>>>>>>> @@ -26390,7 +26390,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])
>>>>>>> @@ -26551,7 +26551,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");)
>>>>>>> ])
>>>>>>>
>>>>>>> @@ -26595,7 +26595,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 dd13575e4..658e3eb26 100644
>>>>>>> --- a/tests/system-ovn.at
>>>>>>> +++ b/tests/system-ovn.at
>>>>>>> @@ -10087,6 +10087,28 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], 
>>>>>>> [0], [dnl
>>>>>>>
>>>>>>> AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>>>>>>>
>>>>>>> +# del acls
>>>>>>> +check ovn-nbctl acl-del foo
>>>>>>> +
>>>>>>> +# add statefull acl
>>>>>> Comments should be sentences: start with a capital letter and end with a
>>>>>> period.  This applies to most comments added by this patch.
>>>>>>
>>>>>> Also, I might be wrong but I think the correct version is "stateful"
>>>>>> instead of "statefull".  This remark also applies to multiple places in
>>>>>> this patch.
>>>>>>
>>>>>>> +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 acl
>>>>>>> +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 configued: pass conntrack for vip traffic.
>>>>>> Typo: configued
>>>>>>
>>>>>>> # add lb back
>>>>>>> check ovn-nbctl ls-lb-add foo lb1
>>>>>>>
>>>>>>> @@ -10096,13 +10118,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])
>>>>>>> @@ -10217,6 +10240,29 @@ AT_CHECK([ovs-appctl dpctl/flush-conntrack])
>>>>>>> # remove lb
>>>>>>> check ovn-nbctl ls-lb-del foo lb1
>>>>>>>
>>>>>>> +# del acls
>>>>>>> +check ovn-nbctl acl-del foo
>>>>>>> +
>>>>>>> +# add statefull acl
>>>>>>> +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 acl
>>>>>>> +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 acl
>>>>>>> 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
>>>>>>> @@ -10240,13 +10286,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,
>>>>>>> Alexandra.
> Regards,
> Dumitru
>

-- 
regards,
Alexandra.

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

Reply via email to