On 5/7/25 2:13 PM, Rukomoinikova Aleksandra wrote: > Hi Dumitru, thanks for your time and review.
Hi Alexandra, > I think the idea of adding logical flows for each backend is extremely > inefficient with a large number of backends. Regarding the option: this That's my concern too with flows per backend. > was our original approach, but what bothers me about this approach is > that what is the point of having a load balancer if there is a stateless > ACL if they won't work? > They work if the traffic matched by stateless ACLs is different than the traffic processed by load balancers. A rather simple example (I guess it can appear in a more complex form in real deployments too though): VIF2 (42.42.42.2/24) --- LS --- VIF3 (42.42.42.3/24) with: stateless ACLs that allow all udp traffic except traffic for port 4242: ovn-nbctl acl-add ls from-lport 1 'udp' allow-stateless ovn-nbctl acl-add ls to-lport 2 'udp && udp.dst == 4242' drop ovn-nbctl acl-add ls to-lport 1 'udp' allow-stateless and a TCP LB: ovn-nbctl lb-add lb-test 66.66.66.66:666 42.42.42.2:4242 tcp If VIF3 sends UDP packets to 42.42.42.2:3131 these match the allow-stateless ACLs (ingress and egress) and reach VIF2. If VIF3 initiates a TCP connection to LB VIP 66.66.66.66:666, DNAT to 42.42.42.2:4242 happens and replies are properly sent to conntrack (they don't match allow-stateless ACLs). Regards, Dumitru > > On 07.05.2025 13:55, Dumitru Ceara wrote: >> On 4/28/25 8:32 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> >>> --- >>> v3 --> v4: fixed Dumitu's comments. >>> >> Hi Alexandra, >> >> Thanks for the patch and sorry for the slowness in reviews. >> >>> --- >>> lib/lb.c | 1 + >>> lib/lb.h | 2 + >>> northd/en-ls-stateful.c | 4 + >>> northd/en-ls-stateful.h | 1 + >>> northd/lb.c | 17 ++++- >>> northd/northd.c | 71 +++++++++++++++--- >>> northd/ovn-northd.8.xml | 11 ++- >>> tests/ovn-northd.at | 143 +++++++++++++++++++++++++++++++++--- >>> tests/ovn.at | 8 +- >>> tests/system-ovn.at | 157 ++++++++++++++++++++++++++++++++++++---- >>> 10 files changed, 372 insertions(+), 43 deletions(-) >>> >>> diff --git a/lib/lb.c b/lib/lb.c >>> index 6e7a4e296..f12373321 100644 >>> --- a/lib/lb.c >>> +++ b/lib/lb.c >>> @@ -304,6 +304,7 @@ ovn_lb_vip_destroy(struct ovn_lb_vip *vip) >>> { >>> free(vip->vip_str); >>> free(vip->port_str); >>> + free(vip->hairpin_snat_ip); >>> ovn_lb_backends_destroy(vip); >>> } >>> >>> diff --git a/lib/lb.h b/lib/lb.h >>> index b1a89d63c..c629e1efd 100644 >>> --- a/lib/lb.h >>> +++ b/lib/lb.h >>> @@ -42,6 +42,8 @@ struct ovn_lb_vip { >>> >>> bool empty_backend_rej; >>> int address_family; >>> + >>> + char *hairpin_snat_ip; >>> }; >>> >>> struct ovn_lb_backend { >>> 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/lb.c b/northd/lb.c >>> index af0c92954..3279a8fcd 100644 >>> --- a/northd/lb.c >>> +++ b/northd/lb.c >>> @@ -256,6 +256,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) >>> @@ -338,7 +346,14 @@ ovn_northd_lb_init(struct ovn_northd_lb *lb, >>> if (lb_vip_nb->lb_health_check) { >>> ovn_lb_vip_backends_health_check_init(lb, lb_vip, lb_vip_nb); >>> } >>> - } >>> + >>> + const char *snat_ip = smap_get(&lb->nlb->options, >>> + "hairpin_snat_ip"); >>> + >>> + if (snat_ip && validate_snap_ip_address(snat_ip)) { >>> + lb_vip->hairpin_snat_ip = xstrdup(snat_ip); >>> + } >>> + } >>> >>> /* It's possible that parsing VIPs fails. Update the lb->n_vips to >>> the >>> * correct value. >>> diff --git a/northd/northd.c b/northd/northd.c >>> index 74792e38b..b9f733bd8 100644 >>> --- a/northd/northd.c >>> +++ b/northd/northd.c >>> @@ -5926,7 +5926,8 @@ skip_port_from_conntrack(const struct ovn_datapath >>> *od, struct ovn_port *op, >>> } >>> >>> static void >>> -build_stateless_filter(const struct ovn_datapath *od, >>> +build_stateless_filter(const struct ls_stateful_record *ls_stateful_rec, >>> + const struct ovn_datapath *od, >>> const struct nbrec_acl *acl, >>> struct lflow_table *lflows, >>> struct lflow_ref *lflow_ref) >>> @@ -5939,7 +5940,11 @@ build_stateless_filter(const struct ovn_datapath *od, >>> action, >>> &acl->header_, >>> lflow_ref); >>> - } else { >>> + } else if (!ls_stateful_rec->has_lb_vip) { >>> + /* For cases when we have statefull ACLs but no load >> Uhm, I think you mean "For cases when we have stateless ACLs but no load >> balancer". >> >>> + 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, >> However, I've been testing this patch some more and, as I was trying to >> say on earlier versions, I don't think we can accept it as is. Let's >> assume we have an user that has the following configuration: >> >> VIF2 (42.42.42.2/24) --- LS --- VIF3 (42.42.42.3/24) >> >> And a to-lport (egress) stateless ACL: >> >> to-lport, prio 1, if "ip4.dst == 42.42.42.0/24", then allow-stateless >> >> When there's no load balancer configured all traffic from VIF3 >> (42.42.42.3) to VIF2 (42.42.42.2) is forwarded without ever being sent >> to conntrack, in the datapath ct_state=-trk, which is fine. >> >> Now let's assume we also have VIFs 4 and 5: >> >> VIF2 (42.42.42.2/24) --- LS --- VIF3 (42.42.42.3/24) >> | >> VIF4 (42.42.42.4/24) ----+----- VIF5 (42.42.42.5/24) >> >> And a TCP load balancer: >> - VIP: 66.66.66.66:666 >> - backends: 42.42.42.4:4242 (VIF4) >> >> Before your patch: >> >> a. traffic from VIF5 to LB VIP (66.66.66.66:666) is not DNATed, LB >> doesn't work >> >> b. all traffic from VIF3 (42.42.42.3) to VIF2 (42.42.42.2) is forwarded >> without ever being sent to conntrack, in the datapath ct_state=-trk. >> >> According to Han and Venu [0], [1], that's as designed: >> [0] >> https://github.com/ovn-org/ovn/commit/a0f82efdd9dfd3ef2d9606c1890e353df1097a51 >> [1] https://mail.openvswitch.org/pipermail/ovs-dev/2022-November/399224.html >> >> Now with your patch: >> >> a. traffic from VIF5 to LB VIP (66.66.66.66:666) works. >> >> BUT >> >> b. all traffic between VIF3 (42.42.42.3) and VIF2 (42.42.42.2) is >> forwarded either on datapath flows that match on: >> ct_state(+new-est-rel-rpl-inv+trk) >> >> OR on flows that match on: >> ct_state(-new-est-rel-rpl+inv+trk) >> >> That means the to-lport allow-stateless ACL has no stateless semantics >> anymore. It also breaks HW offload for some NVIDIA NICs and it also >> means (useless?) recirculations in the datapath. >> >> I understand that for your use case that's acceptable but other use >> cases as above get broken. >> >> I think we have two options: >> >> A. add flows that match on reply traffic that's destined to load >> balancer backends. This comes with a control plane performance cost >> because we need to add a flow per backend. It also means we'd have to >> add the flows from ovn-controller if we want to support template load >> balancers (for which the backend IPs are potentially not known in >> ovn-northd). >> >> B. add a per switch option to enable the load balancer functionality >> when stateless ACLs are configured on the switch. The documentation for >> this option should clearly note that when the option is set >> allow-stateless ACLs in the egress direction are not stateless anymore >> if LBs are present. The option should be false by default so we don't >> break any existing deployments. >> >> Something like NB.Logical_Switch.other_config:enable-stateless-acl-lb. >> >> Then change the code above to bypass the stateless filter in the egress >> pipeline only if the option is set to True for the given switch. >> >> We'd also need to make sure we change the ct.inv/!ct.inv lflow matches >> only if the option is set to true. >> >> This new option would also need a NEWS file entry. >> >> Knobs are not great but in this situation I'm out of ideas so I vote for >> option B. >> >> Please see some more minor comments below. >> >>> @@ -5950,15 +5955,17 @@ build_stateless_filter(const struct ovn_datapath >>> *od, >>> } >>> >>> static void >>> -build_stateless_filters(const struct ovn_datapath *od, >>> +build_stateless_filters(const struct ls_stateful_record *ls_stateful_rec, >>> const struct ls_port_group_table *ls_port_groups, >>> + const struct ovn_datapath *od, >>> struct lflow_table *lflows, >>> struct lflow_ref *lflow_ref) >>> { >>> 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")) { >>> - build_stateless_filter(od, acl, lflows, lflow_ref); >>> + build_stateless_filter(ls_stateful_rec, od, acl, lflows, >>> + lflow_ref); >>> } >>> } >>> >>> @@ -5974,7 +5981,8 @@ build_stateless_filters(const struct ovn_datapath *od, >>> const struct nbrec_acl *acl = ls_pg_rec->nb_pg->acls[i]; >>> >>> if (!strcmp(acl->action, "allow-stateless")) { >>> - build_stateless_filter(od, acl, lflows, lflow_ref); >>> + build_stateless_filter(ls_stateful_rec, od, acl, lflows, >>> + lflow_ref); >>> } >>> } >>> } >>> @@ -6029,7 +6037,8 @@ build_ls_stateful_rec_pre_acls( >>> } >>> >>> /* stateless filters always take precedence over stateful ACLs. */ >>> - build_stateless_filters(od, ls_port_groups, lflows, lflow_ref); >>> + build_stateless_filters(ls_stateful_rec, ls_port_groups, od, >>> lflows, >>> + lflow_ref); >>> >>> /* Ingress and Egress Pre-ACL Table (Priority 110). >>> * >>> @@ -6074,7 +6083,8 @@ build_ls_stateful_rec_pre_acls( >>> } else if (ls_stateful_rec->has_lb_vip) { >>> /* We'll build stateless filters if there are LB rules so that >>> * the stateless flows are not tracked in pre-lb. */ >>> - build_stateless_filters(od, ls_port_groups, lflows, lflow_ref); >>> + build_stateless_filters(ls_stateful_rec, ls_port_groups, od, >>> lflows, >>> + lflow_ref); >>> } >>> } >>> >>> @@ -7400,6 +7410,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) { >> Nit: these fit on the same line. >> >>> + return false; >>> + } >>> + >>> + return true; >>> +} >>> + >>> static void >>> build_acls(const struct ls_stateful_record *ls_stateful_rec, >>> const struct ovn_datapath *od, >>> @@ -7502,8 +7529,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); >>> @@ -7797,8 +7830,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); >>> @@ -7808,6 +7840,23 @@ 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->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_vip->hairpin_snat_ip ? lb_vip->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 e087b6f59..08803b4c7 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,12 @@ >>> <code>ct_lb_mark;</code> action. >>> </li> >>> >>> + <li> >>> + A priority-105 flow sends all packet directed to VIP that don't >>> + match the above flows to connection tracker. This allows load >>> + balancers to work in case of stateless ACLs. >>> + </li> >>> + >>> <li> >>> A priority-100 flow sends the packets to connection tracker based >>> on a hint provided by the previous tables >>> @@ -770,7 +776,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 82dfe92fd..63e1fe330 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;) >>> ]) >>> @@ -14398,7 +14416,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);) >>> @@ -14512,7 +14530,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);) >>> @@ -14623,7 +14641,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);) >>> @@ -16960,5 +16978,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 88c9cabfe..ea5682e00 100644 >>> --- a/tests/ovn.at >>> +++ b/tests/ovn.at >>> @@ -26388,7 +26388,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");) >>> ]) >>> >>> @@ -26433,7 +26433,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]) >>> @@ -26594,7 +26594,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");) >>> ]) >>> >>> @@ -26638,7 +26638,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 5fa740cfb..59f6fdefa 100644 >>> --- a/tests/system-ovn.at >>> +++ b/tests/system-ovn.at >>> @@ -5184,6 +5184,88 @@ 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 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") >>> + >>> +check ovn-nbctl --wait=hv -t 3 sync >>> + >> >> We shouldn't reduce the default timeout (-t 3), a plain "check ovn-nbctl >> --wait=hv sync" is enough. >> >> We probably want a "wait_for_ports_up" as well here. >> >>> +# 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 acl-add sw to-lport 2000 'ip' allow-stateless >>> +check ovn-nbctl acl-add sw from-lport 2000 'ip' allow-stateless >>> + >> This is racy, we need a "--wait=hv sync" here. >> >>> +# 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 acl-add sw to-lport 2001 'ip' allow-related >>> +check ovn-nbctl acl-add sw from-lport 2001 'ip' allow-related >>> + >> Here too. >> >>> +# 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]) >>> @@ -10071,7 +10153,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 +10170,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 +10201,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 +10308,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 +10320,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 +10360,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 +10369,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