Hi Dumitru,
Thanks for your review. I'll look for the test, maybe it could be non-deterministic. Em qua., 15 de out. de 2025 às 09:44, Dumitru Ceara <[email protected]> escreveu: > On 10/15/25 2:19 PM, Dumitru Ceara wrote: > > On 8/26/25 9:43 PM, Lucas Vargas Dias via dev wrote: > >> FIN or FIN-ACK packets from client was dropping because the client > >> side was using conntrack. Connection is in SYN_SENT state because the > >> response from backends bypass the conntrack, when client sends a FIN > >> or FIN-ACK, the conntrack is invalid and packet is dropped. > >> To fix it, remove the client side from conntrack, calculating the hash > >> from packet to choice the backend. > >> REG_CT_TP_DST is reused to store the index from backend > >> because some flows the depends from conntracks use this register. > >> > >> Fixes: 264c8310c399 ("northd: Fix logical router load-balancer nat > rules when using DGP.") > >> Signed-off-by: Lucas Vargas Dias <[email protected]> > >> --- > > > > Hi Lucas, > > > > Thanks for the patch and sorry for the delay in reviewing it. > > > >> northd/northd.c | 131 +++++++++++++++++++------- > >> tests/multinode.at | 99 ++++++++++++-------- > >> tests/ovn-northd.at | 218 +++++++++++++++++++++++++++++++++++++++++--- > >> 3 files changed, 367 insertions(+), 81 deletions(-) > >> > >> diff --git a/northd/northd.c b/northd/northd.c > >> index 2cb69f9aa..f7c8053dd 100644 > >> --- a/northd/northd.c > >> +++ b/northd/northd.c > >> @@ -11955,37 +11955,13 @@ build_distr_lrouter_nat_flows_for_lb(struct > lrouter_nat_lb_flows_ctx *ctx, > >> bool stateless_nat) > >> { > >> struct ds dnat_action = DS_EMPTY_INITIALIZER; > >> + struct ds new_action_stateless_nat = DS_EMPTY_INITIALIZER; > >> + struct ds new_match_stateless_nat = DS_EMPTY_INITIALIZER; > >> > >> /* Store the match lengths, so we can reuse the ds buffer. */ > >> size_t new_match_len = ctx->new_match->length; > >> size_t undnat_match_len = ctx->undnat_match->length; > >> > >> - /* (NOTE) dnat_action: Add the first LB backend IP as a destination > >> - * action of the lr_in_dnat NAT rule. Including the backend IP is > useful > >> - * for accepting packets coming from a chassis that does not have > >> - * previously established conntrack entries. This means that the > actions > >> - * (ip4.dst + ct_lb_mark) are executed in addition and ip4.dst is > not > >> - * useful when traffic passes through the same chassis for > ingress/egress > >> - * packets. However, the actions are complementary in cases where > traffic > >> - * enters from one chassis, the ack response comes from another > chassis, > >> - * and the final ack step of the TCP handshake comes from the first > >> - * chassis used. Without using stateless NAT, the connection will > not be > >> - * established because the return packet followed a path through > another > >> - * chassis and only ct_lb_mark will not be able to receive the ack > and > >> - * forward it to the right backend. With using stateless NAT, the > packet > >> - * will be accepted and forwarded to the same backend that > corresponds to > >> - * the previous conntrack entry that is in the SYN_SENT state > >> - * (created by ct_lb_mark for the first rcv packet in this flow). > >> - */ > >> - if (stateless_nat) { > >> - if (!vector_is_empty(&ctx->lb_vip->backends)) { > >> - const struct ovn_lb_backend *backend = > >> - vector_get_ptr(&ctx->lb_vip->backends, 0); > >> - bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&backend->ip); > >> - ds_put_format(&dnat_action, "%s.dst = %s; ", ipv6 ? "ip6" > : "ip4", > >> - backend->ip_str); > >> - } > >> - } > >> ds_put_format(&dnat_action, "%s", ctx->new_action[type]); > >> > >> const char *meter = NULL; > >> @@ -11996,18 +11972,77 @@ build_distr_lrouter_nat_flows_for_lb(struct > lrouter_nat_lb_flows_ctx *ctx, > >> > >> if (!vector_is_empty(&ctx->lb_vip->backends) || > >> !ctx->lb_vip->empty_backend_rej) { > >> + ds_put_format(&new_match_stateless_nat, > "is_chassis_resident(%s)", > >> + dgp->cr_port->json_key); > >> ds_put_format(ctx->new_match, " && is_chassis_resident(%s)", > >> dgp->cr_port->json_key); > >> } > >> > >> - ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, > ctx->prio, > >> - ds_cstr(ctx->new_match), > ds_cstr(&dnat_action), > >> - NULL, meter, &ctx->lb->nlb->header_, > >> - lflow_ref); > >> + if (stateless_nat) { > > > > This is becoming quite hard to follow. We need at least a comment > > explaining the differences between the "stateless" case and the regular > > case. I think we should also create separate functions for the two > > types of LBs. > > > I agree. > >> + bool ipv4 = ctx->lb_vip->address_family == AF_INET; > >> + const char *ip_match = ipv4 ? "ip4" : "ip6"; > >> + ds_put_format(&new_match_stateless_nat, " && %s && %s.dst == > %s", > >> + ip_match, ip_match, ctx->lb_vip->vip_str); > >> + if (ctx->lb_vip->port_str) { > >> + ds_put_format(&new_match_stateless_nat, > >> + " && %s && %s.dst == %s", > >> + ctx->lb->proto, ctx->lb->proto, > >> + ctx->lb_vip->port_str); > >> + } > >> > >> + const struct ovn_lb_backend *backend; > >> + if (vector_len(&ctx->lb_vip->backends) == 1) { > >> + backend = vector_get_ptr(&ctx->lb_vip->backends, 0); > >> + ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ", > >> + ip_match, backend->ip_str); > > > > Nit: one space too many. > > > >> + if (ctx->lb_vip->port_str) { > >> + ds_put_format(&new_action_stateless_nat, "%s.dst = %s; > ", > >> + ctx->lb->proto, backend->port_str); > > > > Nit: one space too many. > > > >> + } > >> + ds_put_format(&new_action_stateless_nat, "next;"); > >> + ovn_lflow_add_with_hint__(ctx->lflows, od, > S_ROUTER_IN_DNAT, > >> + ctx->prio, > >> + > ds_cstr(&new_match_stateless_nat), > >> + > ds_cstr(&new_action_stateless_nat), > >> + NULL, meter, > &ctx->lb->nlb->header_, > >> + lflow_ref); > >> + } > >> + size_t match_len = new_match_stateless_nat.length; > >> + size_t i = 0; > >> + VECTOR_FOR_EACH_PTR (&ctx->lb_vip->backends, backend) { > >> + if (vector_len(&ctx->lb_vip->backends) <= 1) { > >> + break; > >> + } > >> + ds_put_format(&new_match_stateless_nat, " && > "REG_CT_TP_DST" == " > >> + "%"PRIuSIZE, i++); > > > > This is becoming a bit confusing. REG_CT_TP_DST stands for "register > > for conntrack transport protocol destination". But now it's used to > > store an index. Can we add a new definition for this case? That is, > > another alias for "reg1[0..15]"? > > > I'll add another alias. > > Also nit: one space too many. > > > >> + ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ", > >> + ip_match, backend->ip_str); > > > > Nit: one space too many. > > > >> + if (ctx->lb_vip->port_str) { > >> + ds_put_format(&new_action_stateless_nat, "%s.dst = %s; > ", > >> + ctx->lb->proto, backend->port_str); > > > > Nit: one space too many. > > > >> + } > >> + ds_put_format(&new_action_stateless_nat, "next;"); > >> + ovn_lflow_add_with_hint__(ctx->lflows, od, > S_ROUTER_IN_DNAT, > >> + ctx->prio, > >> + > ds_cstr(&new_match_stateless_nat), > >> + > ds_cstr(&new_action_stateless_nat), > >> + NULL, meter, > &ctx->lb->nlb->header_, > >> + lflow_ref); > >> + ds_clear(&new_action_stateless_nat); > >> + ds_truncate(&new_match_stateless_nat, match_len); > >> + } > >> + } else { > >> + ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, > >> + ctx->prio, ds_cstr(ctx->new_match), > >> + ds_cstr(&dnat_action), NULL, meter, > >> + &ctx->lb->nlb->header_, lflow_ref); > >> + } > >> ds_truncate(ctx->new_match, new_match_len); > >> > >> ds_destroy(&dnat_action); > >> + ds_destroy(&new_match_stateless_nat); > >> + ds_destroy(&new_action_stateless_nat); > >> + > >> if (vector_is_empty(&ctx->lb_vip->backends)) { > >> return; > >> } > >> @@ -12401,21 +12436,51 @@ build_lrouter_defrag_flows_for_lb(struct > ovn_lb_datapaths *lb_dps, > >> if (!lb_dps->n_nb_lr) { > >> return; > >> } > >> + struct ds action = DS_EMPTY_INITIALIZER; > > > > Instead of adding a local 'action' variable you could just pass the > > existing one from the caller of build_lrouter_defrag_flows_for_lb() like > > we do for 'match'. > > > > For some context: that's a (micro) optimization that happened at some > > point in northd to avoid reallocating strings when possible. > > > >> + struct ds values = DS_EMPTY_INITIALIZER; > >> > > > We don't really need this temporary string, do we? Can't we just > > populate 'action' directly? > > > Yes, we can populate directly. > >> + bool use_stateless_nat = smap_get_bool(&lb_dps->lb->nlb->options, > >> + "use_stateless_nat", false); > > > > This should actually happen in ovn_northd_lb_init() and should be stored > > as a field in 'struct ovn_northd_lb'. There's another instance of this > > in build_lrouter_nat_flows_for_lb(). That should be fixed up too. > > > I agree > > > >> for (size_t i = 0; i < lb_dps->lb->n_vips; i++) { > >> struct ovn_lb_vip *lb_vip = &lb_dps->lb->vips[i]; > >> bool ipv6 = lb_vip->address_family == AF_INET6; > >> int prio = 100; > >> - > >> + enum ovn_stage stage = S_ROUTER_IN_DEFRAG; > >> ds_clear(match); > >> ds_put_format(match, "ip && ip%c.dst == %s", ipv6 ? '6' : '4', > >> lb_vip->vip_str); > >> - > >> + if (use_stateless_nat) { > > > > We need at least a comment here explaining the difference between the > > stateless nat and "stateful" nat case. Maybe even separate functions to > > populate the action string? > > > I agree > >> + stage = S_ROUTER_IN_CT_EXTRACT; > >> + prio = 120; > >> + if (vector_len(&lb_vip->backends) > 1) { > >> + ds_put_format(&action, REG_CT_TP_DST" = select("); > > > > Don't we need to set REG_CT_PROTO too? > > > No, because REG_CT_TP_DST is used to select the backend, I'll add a new alias and it'll be more clear. > >> + for (size_t idx_backend = 0; idx_backend < > >> + vector_len(&lb_vip->backends); idx_backend++){ > > > > The correct way to break the line here is (IMO): > > > > for (size_t idx_backend = 0; > > idx_backend < vector_len(&lb_vip->backends); > > idx_backend++) { > > ds_put_format(&values, "%"PRIuSIZE",", idx_backend); > > } > > > >> + ds_put_format(&values, "%"PRIuSIZE",", > idx_backend); > >> + } > >> + ds_truncate(&values, values.length - 1); > > > > Nit: across the code base in most similar cases we'd do something like: > > > > ds_chomp(&values, ','); > > > >> + if (lb_dps->lb->selection_fields) { > >> + ds_put_format(&action, "values=(%s); > hash_fields=\"%s\"", > >> + ds_cstr(&values), > >> + lb_dps->lb->selection_fields); > >> + } else { > >> + ds_put_format(&action, "%s", ds_cstr(&values)); > > > > Just a note: if selection_fields is not set, the select() might return a > > random backend if !ovs_feature_is_supported(OVS_DP_HASH_L4_SYM_SUPPORT) > > (e.g., when TCP retransmits happen). > > > >> + } > >> + ds_put_format(&action,"); "); > >> + } > >> + ds_put_format(&action, "next;"); > >> + } else { > >> + ds_put_format(&action, "ct_dnat;"); > >> + } > >> ovn_lflow_add_with_dp_group( > >> lflows, lb_dps->nb_lr_map, ods_size(lr_datapaths), > >> - S_ROUTER_IN_DEFRAG, prio, ds_cstr(match), "ct_dnat;", > >> + stage, prio, ds_cstr(match), ds_cstr(&action), > >> &lb_dps->lb->nlb->header_, lb_dps->lflow_ref); > >> + ds_clear(&action); > >> + ds_clear(&values); > >> } > >> + ds_destroy(&action); > >> + ds_destroy(&values); > >> } > >> > >> static void > >> diff --git a/tests/multinode.at b/tests/multinode.at > > > > Thanks for adding and updating the multinode e2e tests for the feature! > > > >> index cf748af49..25e3193f7 100644 > >> --- a/tests/multinode.at > >> +++ b/tests/multinode.at > >> @@ -1643,6 +1643,7 @@ check multinode_nbctl ls-lb-add sw0 lb0 > >> > >> # Set use_stateless_nat to true > >> check multinode_nbctl set load_balancer lb0 > options:use_stateless_nat=true > >> +check multinode_nbctl set load_balancer lb0 > selection_fields="ip_src,tp_src,ip_dst,tp_dst" > >> > >> # Start backend http services > >> M_NS_DAEMONIZE([ovn-chassis-1], [sw0p1], [python3 -m http.server > --bind 10.0.1.3 80 >/dev/null 2>&1], [http1.pid]) > >> @@ -1674,14 +1675,12 @@ m_as ovn-gw-2 ovs-appctl dpctl/flush-conntrack > >> M_NS_EXEC([ovn-chassis-3], [publicp1], [sh -c 'curl -v 172.16.0.100:80 > --retry 0 --connect-timeout 1 --max-time 1 --local-port 59001']) > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ovs-appctl dpctl/dump-conntrack | > M_FORMAT_CT(20.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59001,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59001),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59001,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59001),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> M_NS_EXEC([ovn-chassis-4], [publicp2], [sh -c 'curl -v 172.16.0.100:80 > --retry 0 --connect-timeout 1 --max-time 1 --local-port 59000']) > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ovs-appctl dpctl/dump-conntrack | > M_FORMAT_CT(30.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59000,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59000),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59000,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59000),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> @@ -1712,7 +1711,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80 > >> # Check if we have only one backend for the same connection - orig + > dest ports > >> OVS_WAIT_FOR_OUTPUT([echo -e $gw1_ct | M_FORMAT_CT(20.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59004,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59004),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59004,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59004),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> @@ -1778,7 +1776,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80 > >> # Check if we have only one backend for the same connection - orig + > dest ports > >> OVS_WAIT_FOR_OUTPUT([echo -e $gw1_ct | M_FORMAT_CT(20.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59005,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59005),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59005,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59005),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> @@ -1834,7 +1831,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80 > >> # Check if we have only one backend for the same connection - orig + > dest ports > >> OVS_WAIT_FOR_OUTPUT([echo -e $gw2_ct | M_FORMAT_CT(30.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59006,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59006),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59006,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59006),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> @@ -1900,7 +1896,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80 > >> # Check if we have only one backend for the same connection - orig + > dest ports > >> OVS_WAIT_FOR_OUTPUT([echo -e $gw2_ct | M_FORMAT_CT(30.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > -tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59007,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59007),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> > tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59007,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59007),zone=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> @@ -1987,7 +1982,6 @@ M_NS_EXEC([ovn-chassis-3], [publicp1], [sh -c > 'curl -v -O 172.16.0.100:9000/down > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ovs-appctl dpctl/dump-conntrack | > M_FORMAT_CT(20.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59008,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59008),zone=<cleared>,protoinfo=(state=<cleared>) > >> > -tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59008,dport=9000),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59008),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [9000])], [0], [dnl > >> @@ -2003,7 +1997,6 @@ M_NS_EXEC([ovn-chassis-4], [publicp2], [sh -c > 'curl -v -O 172.16.0.100:9000/down > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ovs-appctl dpctl/dump-conntrack | > M_FORMAT_CT(30.0.1.3) | \ > >> grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], > [dnl > >> > tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59008,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59008),zone=<cleared>,protoinfo=(state=<cleared>) > >> > -tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59008,dport=9000),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59008),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>) > >> ]) > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [9000])], [0], [dnl > >> @@ -2036,14 +2029,14 @@ done > >> # | > >> # > +.............................|.............................+ > >> # | > | > >> -# DGP publicp3 (ovn-gw-3) (20.0.2.3/24) DGP > publicp4 (ovn-gw-4) (20.0.2.4/24) > >> +# DGP publicp3 (ovn-gw-3) (20.0.1.2/24) DGP > publicp4 (ovn-gw-4) (20.0.2.4/24) > >> # | > | > >> # > +.............................+.............................+ > >> -# | > >> -# | (overlay) > >> +# | > | > >> +# | (public_right) > (public_left)| > >> # > +.............................+.............................+ > >> # | > | > >> -# DGP public1 (ovn-gw-1) (20.0.2.1/24) DGP > public2 (ovn-gw-2) (20.0.2.2/24) > >> +# DGP public1 (ovn-gw-1) (20.0.1.1/24) DGP > public2 (ovn-gw-2) (20.0.2.2/24) > >> # | > | > >> # > +.............................+.............................+ > >> # | > >> @@ -2100,17 +2093,18 @@ check multinode_nbctl lsp-set-addresses sw0-lr0 > router > >> check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 > >> > >> # create external connection for N/S traffic using multiple DGPs > >> -check multinode_nbctl ls-add public > >> +check multinode_nbctl ls-add public_right > >> +check multinode_nbctl ls-add public_left > >> > >> # create external connection for N/S traffic > >> # DGP public1 > >> -check multinode_nbctl lsp-add public ln-public-1 > >> +check multinode_nbctl lsp-add public_right ln-public-1 > >> check multinode_nbctl lsp-set-type ln-public-1 localnet > >> check multinode_nbctl lsp-set-addresses ln-public-1 unknown > >> check multinode_nbctl lsp-set-options ln-public-1 network_name=public1 > >> > >> # DGP public2 > >> -check multinode_nbctl lsp-add public ln-public-2 > >> +check multinode_nbctl lsp-add public_left ln-public-2 > >> check multinode_nbctl lsp-set-type ln-public-2 localnet > >> check multinode_nbctl lsp-set-addresses ln-public-2 unknown > >> check multinode_nbctl lsp-set-options ln-public-2 network_name=public2 > >> @@ -2121,8 +2115,8 @@ m_as ovn-gw-1 ovs-vsctl set open . > external-ids:ovn-bridge-mappings=public1:br-e > >> # Attach DGP public2 to GW-2 public2 (overlay connectivity) > >> m_as ovn-gw-2 ovs-vsctl set open . > external-ids:ovn-bridge-mappings=public2:br-ex > >> > >> -check multinode_nbctl lrp-add lr0 lr0-public-p1 40:54:00:00:00:01 > 20.0.2.1/24 2000::1/64 > >> -check multinode_nbctl lsp-add public public-lr0-p1 > >> +check multinode_nbctl lrp-add lr0 lr0-public-p1 40:54:00:00:00:01 > 20.0.1.1/24 2000::1/64 > >> +check multinode_nbctl lsp-add public_right public-lr0-p1 > >> check multinode_nbctl lsp-set-type public-lr0-p1 router > >> check multinode_nbctl lsp-set-addresses public-lr0-p1 router > >> check multinode_nbctl lsp-set-options public-lr0-p1 > router-port=lr0-public-p1 > >> @@ -2130,13 +2124,13 @@ check multinode_nbctl lrp-set-gateway-chassis > lr0-public-p1 ovn-gw-1 10 > >> > >> m_wait_for_ports_up > >> > >> -M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.2.1 | FORMAT_PING], \ > >> +M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.1.1 | FORMAT_PING], \ > >> [0], [dnl > >> 3 packets transmitted, 3 received, 0% packet loss, time 0ms > >> ]) > >> > >> check multinode_nbctl lrp-add lr0 lr0-public-p2 40:54:00:00:00:02 > 20.0.2.2/24 2000::2/64 > >> -check multinode_nbctl lsp-add public public-lr0-p2 > >> +check multinode_nbctl lsp-add public_left public-lr0-p2 > >> check multinode_nbctl lsp-set-type public-lr0-p2 router > >> check multinode_nbctl lsp-set-addresses public-lr0-p2 router > >> check multinode_nbctl lsp-set-options public-lr0-p2 > router-port=lr0-public-p2 > >> @@ -2157,7 +2151,7 @@ check multinode_nbctl lsp-set-options sw1-lr1 > router-port=lr1-sw1 > >> > >> # create external connection for N/S traffic > >> # DGP public3 > >> -check multinode_nbctl lsp-add public ln-public-3 > >> +check multinode_nbctl lsp-add public_right ln-public-3 > >> check multinode_nbctl lsp-set-type ln-public-3 localnet > >> check multinode_nbctl lsp-set-addresses ln-public-3 unknown > >> check multinode_nbctl lsp-set-options ln-public-3 network_name=public3 > >> @@ -2165,8 +2159,8 @@ check multinode_nbctl lsp-set-options ln-public-3 > network_name=public3 > >> # Attach DGP public3 to GW-3 public3 (overlay connectivity) > >> m_as ovn-gw-3 ovs-vsctl set open . > external-ids:ovn-bridge-mappings=public3:br-ex > >> > >> -check multinode_nbctl lrp-add lr1 lr1-public-p3 40:54:00:00:00:03 > 20.0.2.3/24 2000::3/64 > >> -check multinode_nbctl lsp-add public public-lr1-p3 > >> +check multinode_nbctl lrp-add lr1 lr1-public-p3 40:54:00:00:00:03 > 20.0.1.2/24 2000::3/64 > >> +check multinode_nbctl lsp-add public_right public-lr1-p3 > >> check multinode_nbctl lsp-set-type public-lr1-p3 router > >> check multinode_nbctl lsp-set-addresses public-lr1-p3 router > >> check multinode_nbctl lsp-set-options public-lr1-p3 > router-port=lr1-public-p3 > >> @@ -2177,21 +2171,16 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping > -q -c 3 -i 0.3 -w 2 40.0.2.1 | F > >> 3 packets transmitted, 3 received, 0% packet loss, time 0ms > >> ]) > >> > >> -M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.2.3 | FORMAT_PING], \ > >> +M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.1.2 | FORMAT_PING], \ > >> [0], [dnl > >> 3 packets transmitted, 3 received, 0% packet loss, time 0ms > >> ]) > >> > >> # Add a default route for multiple DGPs using ECMP - first step > >> -check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.2.3 > >> -check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.2.1 > >> - > >> -# Add SNAT rules using gateway-port > >> -check multinode_nbctl --gateway-port lr0-public-p1 lr-nat-add lr0 snat > 20.0.2.1 10.0.2.0/24 > >> -check multinode_nbctl --gateway-port lr0-public-p2 lr-nat-add lr0 snat > 20.0.2.2 10.0.2.0/24 > >> -check multinode_nbctl --gateway-port lr1-public-p3 lr-nat-add lr1 snat > 20.0.2.3 40.0.2.0/24 > >> +check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.1.2 > >> +check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.1.1 > >> > >> -M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.2.1 | FORMAT_PING], \ > >> +M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 > 20.0.1.1 | FORMAT_PING], \ > >> [0], [dnl > >> 3 packets transmitted, 3 received, 0% packet loss, time 0ms > >> ]) > >> @@ -2203,7 +2192,7 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping > -q -c 3 -i 0.3 -w 2 20.0.2.2 | F > >> > >> # Configure the second DGP for the lr1 > >> # DGP public4 > >> -check multinode_nbctl lsp-add public ln-public-4 > >> +check multinode_nbctl lsp-add public_left ln-public-4 > >> check multinode_nbctl lsp-set-type ln-public-4 localnet > >> check multinode_nbctl lsp-set-addresses ln-public-4 unknown > >> check multinode_nbctl lsp-set-options ln-public-4 network_name=public4 > >> @@ -2212,7 +2201,7 @@ check multinode_nbctl lsp-set-options ln-public-4 > network_name=public4 > >> m_as ovn-gw-4 ovs-vsctl set open . > external-ids:ovn-bridge-mappings=public4:br-ex > >> > >> check multinode_nbctl lrp-add lr1 lr1-public-p4 40:54:00:00:00:04 > 20.0.2.4/24 2000::4/64 > >> -check multinode_nbctl lsp-add public public-lr1-p4 > >> +check multinode_nbctl lsp-add public_left public-lr1-p4 > >> check multinode_nbctl lsp-set-type public-lr1-p4 router > >> check multinode_nbctl lsp-set-addresses public-lr1-p4 router > >> check multinode_nbctl lsp-set-options public-lr1-p4 > router-port=lr1-public-p4 > >> @@ -2223,9 +2212,6 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping > -q -c 3 -i 0.3 -w 2 20.0.2.4 | F > >> 3 packets transmitted, 3 received, 0% packet loss, time 0ms > >> ]) > >> > >> -# Add SNAT rules using gateway-port > >> -check multinode_nbctl --gateway-port lr1-public-p4 lr-nat-add lr1 snat > 20.0.2.4 40.0.2.0/24 > >> - > >> # Add a default route for multiple DGPs using ECMP - second step > (multipath) > >> check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.2.4 > >> check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.2.2 > >> @@ -2359,36 +2345,77 @@ fi > >> # Set use_stateless_nat to true > >> # Now, if the traffic passes through both gateways (GW-1 and GW-2) it > will be forwarded successfully > >> check multinode_nbctl set load_balancer lb0 > options:use_stateless_nat=true > >> +check multinode_nbctl --wait=sb set load_balancer lb0 > selection_fields="ip_src,tp_src,ip_dst,tp_dst" > >> > >> # Check the flows again for the LB VIP - always needs to be successful > regardless of the datapath (one or two gw chassis) > >> M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O > 172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1 > 2>curl.out']) > >> +M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out']) > >> +M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out']) > > > > This overrides the connections.out file from the previous command. Did > > you mean to use >> instead of > ? > > > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl > >> Connected to 172.16.0.100 (172.16.0.100) port 80 > >> 200 OK > >> ]) > >> > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O > 172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1 > 2>curl.out']) > >> +M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out']) > >> +M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out']) > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl > >> Connected to 172.16.0.100 (172.16.0.100) port 80 > >> 200 OK > >> ]) > >> > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O > 172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1 > 2>curl.out']) > > > > This now failed in CI in my fork: > > > > > https://github.com/dceara/ovn/actions/runs/18527590496/job/52802379445#step:19:5473 > > > > multinode.at:2355: waiting for output from m_as ovn-chassis-3 cat -v > > curl.out | sed 's/\(.*\)Connected to 172.16.0.100 (172.16.0.100) port > > 80/Connected to 172.16.0.100 (172.16.0.100) port 80\n/' | sed > > 's/\(.*\)200 OK/200 OK\n/' | grep -i -e connected -e 200... > > multinode.at:2355: wait failed after 30 seconds > > --- wait-expected-stdout 2025-10-15 12:03:20.195100146 +0000 > > +++ wait-stdout 2025-10-15 12:03:53.652853417 +0000 > > @@ -1,2 +1 @@ > > Connected to 172.16.0.100 (172.16.0.100) port 80 > > -200 OK > > > > On re-run this passed though: > > https://github.com/dceara/ovn/actions/runs/18527590496/job/52805216765#step:19:57 > > >> +M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out']) > >> +M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out']) > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl > >> Connected to 172.16.0.100 (172.16.0.100) port 80 > >> 200 OK > >> ]) > >> > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O > 172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1 > 2>curl.out']) > >> +M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out']) > >> +M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out']) > >> > >> OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out | > M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl > >> Connected to 172.16.0.100 (172.16.0.100) port 80 > >> 200 OK > >> ]) > >> > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> +OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep > "FIN-WAIT-2" | wc -l], [0], [dnl > >> +0 > >> +]) > >> + > >> # Direct backend traffic using the same LB ports needs to be dropped > >> M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O > 10.0.2.3:80/download_file --retry 0 --connect-timeout 1 --max-time 1 > 2>curl.out']) > >> > >> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > >> index 05acd6f4d..cebf9d6ba 100644 > >> --- a/tests/ovn-northd.at > >> +++ b/tests/ovn-northd.at > >> @@ -14331,14 +14331,66 @@ ovn-sbctl dump-flows lr1 > lr1flows > >> AT_CAPTURE_FILE([lr1flows]) > >> > >> # Check stateless NAT rules for load balancer with multiple DGP > >> -# 1. Check if the backend IPs are in the ipX.dst action > >> +# 1. Check if the reg1[0..15] will select one of backends > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst > == 30.0.0.1), action=(reg1[[0..15]] = select(0,1,2); next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip4 && ip4.dst == 30.0.0.1 && > is_chassis_resident("cr-lr1-ts1")), action=(ip4.dst = 172.16.0.103; > ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);) > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip4 && ip4.dst == 30.0.0.1 && > is_chassis_resident("cr-lr1-ts2")), action=(ip4.dst = 172.16.0.103; > ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);) > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip4 && ip4.dst == 30.0.0.1 && > is_chassis_resident("cr-lr1_public")), action=(ip4.dst = 172.16.0.103; > ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> +AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") && > is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1-ts2" || outport == "lr1-ts2") && > is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1_public" || outport == "lr1_public") && > is_chassis_resident("cr-lr1_public") && tcp), action=(next;) > >> ]) > >> > >> -# 2. Check if the DGP ports are in the match with action next > >> +# 4. Check if the VIP IP is in the ipX.src action > >> +AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") && > is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip4.src = 30.0.0.1; > next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1-ts2" || outport == "lr1-ts2") && > is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip4.src = 30.0.0.1; > next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1_public" || outport == "lr1_public") && > is_chassis_resident("cr-lr1_public") && tcp), action=(ip4.src = 30.0.0.1; > next;) > >> +]) > >> + > >> +# Set selection fields > >> +check ovn-nbctl --wait=sb set load_balancer lb1 > selection_fields="ip_src,tp_src,ip_dst,tp_dst" > >> + > >> +ovn-sbctl dump-flows lr1 > lr1flows > >> +AT_CAPTURE_FILE([lr1flows]) > >> + > >> +# 1. Check if the reg1[0..15] will select one of backends using > hash_fields > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst > == 30.0.0.1), action=(reg1[[0..15]] = select(values=(0,1,2); > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src"); next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> +AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 && > reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 > && reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") && > is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> @@ -14346,7 +14398,7 @@ AT_CHECK([grep "lr_out_undnat" lr1flows | > ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1_public" || outport == "lr1_public") && > is_chassis_resident("cr-lr1_public") && tcp), action=(next;) > >> ]) > >> > >> -# 3. Check if the VIP IP is in the ipX.src action > >> +# 4. Check if the VIP IP is in the ipX.src action > >> AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> @@ -14355,6 +14407,51 @@ AT_CHECK([grep "lr_out_snat" lr1flows | > ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == > 172.16.0.101)) && (inport == "lr1_public" || outport == "lr1_public") && > is_chassis_resident("cr-lr1_public") && tcp), action=(ip4.src = 30.0.0.1; > next;) > >> ]) > >> > >> +# Delete LB and create with one backend > >> +check ovn-nbctl --wait=sb lb-del lb1 > >> +check ovn-nbctl --wait=sb lb-add lb1 "30.0.0.1" "172.16.0.103" > >> + > >> +# Set use_stateless_nat to true > >> +check ovn-nbctl --wait=sb set load_balancer lb1 > options:use_stateless_nat=true > >> + > >> +# Associate load balancer to s1 > >> +check ovn-nbctl ls-lb-add s1 lb1 > >> +check ovn-nbctl lr-lb-add lr1 lb1 > >> +check ovn-nbctl --wait=sb sync > >> + > >> +ovn-sbctl dump-flows lr1 > lr1flows > >> +AT_CAPTURE_FILE([lr1flows]) > >> + > >> +# 1. Check if the reg1[0..15] will select one of backends using > hash_fields > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst > == 30.0.0.1), action=(next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> +AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "30.0.0.1"], [0], [dnl > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1), > action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1), > action=(ip4.dst = 172.16.0.103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1), > action=(ip4.dst = 172.16.0.103; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> +AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(next;) > >> +]) > >> + > >> +# 4. Check if the VIP IP is in the ipX.src action > >> +AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip4.src = > 30.0.0.1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip4.src = > 30.0.0.1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip4 && > ((ip4.src == 172.16.0.103)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(ip4.src = 30.0.0.1; next;) > >> +]) > >> + > >> + > >> AT_CLEANUP > >> ]) > >> > >> @@ -14445,14 +14542,67 @@ ovn-sbctl dump-flows lr1 > lr1flows > >> AT_CAPTURE_FILE([lr1flows]) > >> > >> # Check stateless NAT rules for load balancer with multiple DGP > >> -# 1. Check if the backend IPs are in the ipX.dst action > >> +# 1. Check if the reg1[0..15] will select one of backends > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst > == 2001:db8:cccc::1), action=(reg1[[0..15]] = select(0,1,2); next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip6 && ip6.dst == 2001:db8:cccc::1 && > is_chassis_resident("cr-lr1-ts1")), action=(ip6.dst = 2001:db8:aaaa:3::103; > ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);) > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip6 && ip6.dst == 2001:db8:cccc::1 && > is_chassis_resident("cr-lr1-ts2")), action=(ip6.dst = 2001:db8:aaaa:3::103; > ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);) > >> - table=??(lr_in_dnat ), priority=110 , match=(ct.new && > !ct.rel && ip6 && ip6.dst == 2001:db8:cccc::1 && > is_chassis_resident("cr-lr1_public")), action=(ip6.dst = > 2001:db8:aaaa:3::103; > ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> +AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(next;) > >> ]) > >> > >> -# 2. Check if the DGP ports are in the match with action next > >> +# 4. Check if the VIP IP is in the ipX.src action > >> +AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip6.src = > 2001:db8:cccc::1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip6.src = > 2001:db8:cccc::1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(ip6.src = 2001:db8:cccc::1; next;) > >> +]) > >> + > >> +# Set selection fields > >> +check ovn-nbctl --wait=sb set load_balancer lb1 > selection_fields="ip_src,tp_src,ip_dst,tp_dst" > >> + > >> +ovn-sbctl dump-flows lr1 > lr1flows > >> +AT_CAPTURE_FILE([lr1flows]) > >> + > >> +# Check stateless NAT rules for load balancer with multiple DGP > >> +# 1. Check if the reg1[0..15] will select one of backends > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst > == 2001:db8:cccc::1), action=(reg1[[0..15]] = select(values=(0,1,2); > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src"); next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> +AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst = > 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst = > 2001:db8:aaaa:3::102; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst = > 2001:db8:aaaa:3::101; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> @@ -14460,7 +14610,7 @@ AT_CHECK([grep "lr_out_undnat" lr1flows | > ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(next;) > >> ]) > >> > >> -# 3. Check if the VIP IP is in the ipX.src action > >> +# 4. Check if the VIP IP is in the ipX.src action > >> AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> @@ -14469,6 +14619,50 @@ AT_CHECK([grep "lr_out_snat" lr1flows | > ovn_strip_lflows], [0], [dnl > >> table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || > (ip6.src == 2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == > "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(ip6.src = 2001:db8:cccc::1; next;) > >> ]) > >> > >> +# Delete LB and create with one backend > >> +check ovn-nbctl --wait=sb lb-del lb1 > >> +check ovn-nbctl --wait=sb lb-add lb1 "2001:db8:cccc::1" > "2001:db8:aaaa:3::103" > >> + > >> +# Set use_stateless_nat to true > >> +check ovn-nbctl --wait=sb set load_balancer lb1 > options:use_stateless_nat=true > >> + > >> +# Associate load balancer to s1 > >> +check ovn-nbctl ls-lb-add s1 lb1 > >> +check ovn-nbctl lr-lb-add lr1 lb1 > >> +check ovn-nbctl --wait=sb sync > >> + > >> +ovn-sbctl dump-flows lr1 > lr1flows > >> +AT_CAPTURE_FILE([lr1flows]) > >> +# Check stateless NAT rules for load balancer with multiple DGP > >> +# 1. Check if the reg1[0..15] will select one of backends > >> +AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> + table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst > == 2001:db8:cccc::1), action=(next;) > >> +]) > >> + > >> +# 2. Check if the backend IPs are in the ipX.dst action > >> +AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep > "2001:db8:cccc::1"], [0], [dnl > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == > 2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == > 2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;) > >> + table=??(lr_in_dnat ), priority=110 , > match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst == > 2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;) > >> +]) > >> + > >> +# 3. Check if the DGP ports are in the match with action next > >> +AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_undnat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;) > >> + table=??(lr_out_undnat ), priority=120 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1_public" || outport > == "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(next;) > >> +]) > >> + > >> +# 4. Check if the VIP IP is in the ipX.src action > >> +AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl > >> + table=??(lr_out_snat ), priority=0 , match=(1), > action=(next;) > >> + table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1-ts1" || outport == > "lr1-ts1") && is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip6.src = > 2001:db8:cccc::1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1-ts2" || outport == > "lr1-ts2") && is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip6.src = > 2001:db8:cccc::1; next;) > >> + table=??(lr_out_snat ), priority=160 , match=(ip6 && > ((ip6.src == 2001:db8:aaaa:3::103)) && (inport == "lr1_public" || outport > == "lr1_public") && is_chassis_resident("cr-lr1_public") && tcp), > action=(ip6.src = 2001:db8:cccc::1; next;) > >> +]) > >> + > >> AT_CLEANUP > >> ]) > >> > > > > Regards, > > Dumitru > > > > > > Regards, Lucas -- _‘Esta mensagem é direcionada apenas para os endereços constantes no cabeçalho inicial. Se você não está listado nos endereços constantes no cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão imediatamente anuladas e proibidas’._ * **‘Apesar do Magazine Luiza tomar todas as precauções razoáveis para assegurar que nenhum vírus esteja presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por quaisquer perdas ou danos causados por esse e-mail ou por seus anexos’.* _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
