On 3/13/25 4:53 PM, Lorenzo Bianconi wrote: > Do not drop traffic destinated to the template load-balancer vip if the > vip var is set to one of the router interface IPs. > > Reported-at: https://issues.redhat.com/browse/FDP-988 > Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> > ---
Hi Lorenzo, Thanks for the patch! This triggered a failure in ovsrobot CI: https://github.com/ovsrobot/ovn/actions/runs/13839126891/job/38722035267 75: system-ovn.at:6106 load-balancer and firewall tuple conflict IPv6 -- parallelization=yes -- ovn_monitor_all=yes ./system-ovn.at:6106: ovs-appctl dpctl/dump-conntrack | grep 2001 | \ grep "orig=.src=4242::3" | \ sed -e 's/port=2001/port=<clnt_s_port>/g' \ -e 's/sport=4242,dport=[0-9]\+/sport=4242,dport=<rnd_port>/g' \ -e 's/state=[0-9_A-Z]*/state=<cleared>/g' \ -e 's/zone=[0-9]*/zone=<cleared>/' | sort --- - 2025-03-13 16:21:18.297453704 +0000 +++ /workspace/ovn-tmp/tests/system-kmod-testsuite.dir/at-groups/75/stdout 2025-03-13 16:21:18.294824729 +0000 @@ -1,4 +1,5 @@ tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,protoinfo=(state=<cleared>) -tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<rnd_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>6),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>6,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>6),zone=<cleared>,protoinfo=(state=<cleared>) tcp,orig=(src=4242::3,dst=6666::1,sport=<clnt_s_port>,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) > lib/lb.c | 1 + > lib/lb.h | 1 + > northd/northd.c | 30 +++++++++ > northd/ovn-northd.8.xml | 9 +++ > tests/system-ovn.at | 145 ++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 186 insertions(+) > > diff --git a/lib/lb.c b/lib/lb.c > index e67a5fcfd..2fb4dad51 100644 > --- a/lib/lb.c > +++ b/lib/lb.c > @@ -217,6 +217,7 @@ ovn_lb_vip_init_template(struct ovn_lb_vip *lb_vip, const > char *lb_key_, > success = true; > if (!lb_vip->vip_str) { > lb_vip->vip_str = xstrdup(atom); > + lb_vip->template_vips = !!strchr(atom, LEX_TEMPLATE_PREFIX); > } else { > lb_vip->port_str = xstrdup(atom); > } > diff --git a/lib/lb.h b/lib/lb.h > index bcc677f82..71689b333 100644 > --- a/lib/lb.h > +++ b/lib/lb.h > @@ -36,6 +36,7 @@ struct ovn_lb_vip { > char *port_str; /* Actual port string representation. To be used > * in ovn-northd. > */ > + bool template_vips; /* True if the vips are templates. */ > struct ovn_lb_backend *backends; > size_t n_backends; > bool template_backends; /* True if the backends are templates. False if > diff --git a/northd/northd.c b/northd/northd.c > index 1d3e132d4..42b5f5058 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -12335,6 +12335,33 @@ build_lrouter_defrag_flows_for_lb(struct > ovn_lb_datapaths *lb_dps, > } > } > > +static void > +build_lrouter_allow_vip_traffic_template(struct lflow_table *lflows, > + struct ovn_lb_datapaths *lb_dps, > + struct ovn_lb_vip *lb_vip, > + const struct ovn_northd_lb *lb, > + const struct ovn_datapaths *lr_dps) > +{ > + if (!lb_vip->template_vips) { > + return; > + } > + > + size_t index; > + BITMAP_FOR_EACH_1 (index, ods_size(lr_dps), lb_dps->nb_lr_map) { > + struct ovn_datapath *od = lr_dps->array[index]; > + /* Do not drop ip traffic with destination the template VIP. */ > + if (lb_vip->address_family == AF_INET) { > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, 100, > + "ip4.dst == ^vip", "next;", Template variables are defined as: "Chassis_Template_Var": { "columns": { "chassis": {"type": "string"}, "variables": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "indexes": [["chassis"]], "isRoot": true}, According to the documentation: <p> One record per chassis, each containing a map, <code>variables</code>, between template variable names and their value for that specific chassis. A template variable has a name and potentially different values on different hypervisors in the OVN cluster. For example, two rows, <code>R1 = (.chassis=C1, variables={(N: V1)}</code> and <code>R2 = (.chassis=C2, variables={(N: V2)}</code> will make <code>ovn-controller</code> running on chassis <code>C1</code> and <code>C2</code> interpret the token <code>N</code> either as <code>V1</code> (on <code>C1</code>) or as <code>V2</code> (on <code>C2</code>). Users can refer to template variables from within other logical components, e.g., within ACL, QoS or Logical_Router_Policy matches or from Load_Balancer VIP and backend definitions. </p> So each variable has a name and that expands to a chassis-specific value according to the Chassis_Template_Var map. Here you're adding a flow that matches unconditionally on "ip4.dst == ^vip". "vip" is just a template variable name, it can be anything, we can't assume anything about it. Instead, we need to match on the actual template, in this case you probably need something like: ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, 100, "ip4.dst == %s", "next;", lb_vip->vip_str ... I didn't test it though. > + &lb->nlb->header_, lb_dps->lflow_ref); > + } else { > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, 100, > + "ip6.dst == ^vip", "next;", > + &lb->nlb->header_, lb_dps->lflow_ref); Same here. > + } > + } > +} > + > static void > build_lrouter_flows_for_lb(struct ovn_lb_datapaths *lb_dps, > struct lflow_table *lflows, > @@ -12359,6 +12386,9 @@ build_lrouter_flows_for_lb(struct ovn_lb_datapaths > *lb_dps, > match, action, meter_groups, > svc_monitor_map); > > + build_lrouter_allow_vip_traffic_template(lflows, lb_dps, lb_vip, lb, > + lr_datapaths); > + > if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) { > continue; > } > diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml > index 155ba8a49..5916b4739 100644 > --- a/northd/ovn-northd.8.xml > +++ b/northd/ovn-northd.8.xml > @@ -3100,6 +3100,15 @@ icmp6_error { > router. > </li> > > + <li> > + For each load balancer applied to this logical router configured > + with <code>vip</code> template, a priority-100 flow with match > + <code>ip4.dst == ^vip</code> or <code>ip6.dst == ^vip</code> for This will need to be updated too. > + IPv4 and IPv6 respectively and action <code>next;</code>. > + These flows avoid dropping the packet if the <code>vip</code> is > + set to one of the router IPs. > + </li> > + > <li> > <p> > ICMP echo reply. These flows reply to ICMP echo requests received > diff --git a/tests/system-ovn.at b/tests/system-ovn.at > index fb8184cd9..626cd7011 100644 > --- a/tests/system-ovn.at > +++ b/tests/system-ovn.at > @@ -17411,3 +17411,148 @@ OVS_TRAFFIC_VSWITCHD_STOP() > > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([load balancing lb_force_snat_ip with template]) > +AT_KEYWORDS([ovnlb]) > + > +CHECK_CONNTRACK() > +CHECK_CONNTRACK_NAT() > +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: > +# Two LRs - R1 and R2 that are connected to each other via LS "join" > +# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and > +# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) > connected > +# to it. R2 is a gateway router on which we add load-balancing rules. > +# > +# foo -- R1 -- join - R2 -- alice > +# | > +# bar ---- > + > +check_uuid ovn-nbctl create Logical_Router name=R1 > +check_uuid ovn-nbctl create Logical_Router name=R2 options:chassis=hv1 > + > +check ovn-nbctl ls-add foo > +check ovn-nbctl ls-add bar > +check ovn-nbctl ls-add alice > +check ovn-nbctl ls-add join > + > +# Connect foo to R1 > +check ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 > +check ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ > + type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" > + > +# Connect bar to R1 > +check ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 > +check ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ > + type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" > + > +# Connect alice to R2 > +check ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24 > +check ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ > + type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" > + > +# Connect R1 to join > +check ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24 > +check ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ > + type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' > + > +# Connect R2 to join > +check ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24 > +check ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ > + type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' > + > +# Static routes. > +check ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2 > +check ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1 > + > +# Logical port 'foo1' in switch 'foo'. > +ADD_NAMESPACES(foo1) > +ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ > + "192.168.1.1") > +check ovn-nbctl lsp-add foo foo1 \ > +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2" > + > +# Logical port 'alice1' in switch 'alice'. > +ADD_NAMESPACES(alice1) > +ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \ > + "172.16.1.1") > +check ovn-nbctl lsp-add alice alice1 \ > +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2" > + > +# Logical port 'bar1' in switch 'bar'. > +ADD_NAMESPACES(bar1) > +ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \ > +"192.168.2.1") > +check ovn-nbctl lsp-add bar bar1 \ > +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2" > + > +check ovn-nbctl set logical_router R2 options:lb_force_snat_ip="20.0.0.5" > + > +AT_CHECK([ovn-nbctl -- create chassis_template_var chassis="hv1" \ > + > variables="{vip=172.16.1.1,vport1=8000,backends1=\"192.168.1.2:80,192.168.2.2:80\"}"], > + [0], [ignore]) > + > +# Config OVN load-balancer with a VIP. > +check ovn-nbctl --template lb-add lb1 "^vip:^vport1" "^backends1" tcp > +check ovn-nbctl lr-lb-add R2 lb1 > +# Wait for ovn-controller to catch up. > +check ovn-nbctl --wait=hv sync > + > +# Start webservers in 'foo1', 'bar1'. > +OVS_START_L7([foo1], [http]) > +OVS_START_L7([bar1], [http]) > + > +NETNS_START_TCPDUMP([foo1], [-neei foo1 src 20.0.0.5 and tcp], [foo1]) > +NETNS_START_TCPDUMP([bar1], [-neei bar1 src 20.0.0.5 and tcp], [bar1]) > + > +check ovs-appctl dpctl/flush-conntrack > +for i in $(seq 10); do > + NS_EXEC([alice1], [wget 172.16.1.1:8000 -t 5 -T 1 --retry-connrefused -v > -o wget$i.log]) > +done > + > +OVS_WAIT_UNTIL([ > + n_pkt=$(cat foo1.tcpdump | wc -l) > + test "${n_pkt}" -ge 1 > +]) > +OVS_WAIT_UNTIL([ > + n_pkt=$(cat bar1.tcpdump | wc -l) > + test "${n_pkt}" -ge 1 > +]) > + > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.5) | \ > +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > +tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.5,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.5,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +]) > + > +OVS_APP_EXIT_AND_WAIT([ovn-controller]) > + > +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 > +]) Regards, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev