Thank you very much @Mj ponsonby <[email protected]>, I have tested this against both Master and 24.03.09, and it is actually solved my issue!
On Thu, Oct 29, 2026 at 3:37 PM MJ Ponsonby via dev <[email protected]> wrote: > For a neighbor that is not part of any of the LRP's configured prefixes, > e.g. an off-subnet next hop selected with an explicit output_port route, > mac_binding_probe_stats_run() left the source address as in6addr_any and > silently suppressed the ARP/ND refresh probe. Such neighbors are still > reachable through the port (find_static_route_outport() already falls back > to the port's first address for this case), so their MAC bindings were no > longer refreshed when aging is enabled. > > Fall back to the port's first address when no prefix contains the neighbor, > matching the routing decision, while keeping the matching-subnet selection > introduced by the original fix. > > Add a regression test where an LRP only has /32 and /128 addresses and the > off-subnet next hops are reached via explicit output_port routes. > > Ubuntu tracking bug: https://bugs.launchpad.net/bugs/2172542. > > Fixes: 05005d6e78db ("mac-cache: Make sure we re-arp for proper IP for LRP > with multiple IPs.") > Assisted-by: OpenCode (deepseek/deepseek-pro-latest) > Signed-off-by: MJ Ponsonby <[email protected]> > --- > v2: > - Shorten the subject line to fit within 70 characters > (checkpatch warning). > - Use a 12-character abbreviated hash in the Fixes tag > (checkpatch error). > controller/mac-cache.c | 14 ++++++++ > tests/ovn.at | 77 ++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 91 insertions(+) > > diff --git a/controller/mac-cache.c b/controller/mac-cache.c > index b25115f19..4b743adf8 100644 > --- a/controller/mac-cache.c > +++ b/controller/mac-cache.c > @@ -1053,6 +1053,20 @@ mac_binding_probe_stats_run(struct vector > *stats_vec, uint64_t *req_delay, > } > } > > + /* The neighbor is not part of any of the LRP's configured > prefixes. > + * This is the case for off-subnet next hops selected with an > explicit > + * output_port route (e.g. /32 addressing with a reachable default > + * gateway). Fall back to the port's first address, matching > + * find_static_route_outport(). */ > + if (ipv6_addr_equals(&local, &in6addr_any)) { > + if (IN6_IS_ADDR_V4MAPPED(&mb->data.ip) && laddr.n_ipv4_addrs) > { > + local = in6_addr_mapped_ipv4(laddr.ipv4_addrs[0].addr); > + } else if (!IN6_IS_ADDR_V4MAPPED(&mb->data.ip) > + && laddr.n_ipv6_addrs) { > + local = laddr.ipv6_addrs[0].addr; > + } > + } > + > if (!ipv6_addr_equals(&local, &in6addr_any)) { > struct eth_addr eth_dst = > mb->arp_attempts < PROBE_MULICAST_THRESHOLD > diff --git a/tests/ovn.at b/tests/ovn.at > index 780149467..8e48a1556 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -38910,6 +38910,83 @@ OVN_CLEANUP([hv1]) > AT_CLEANUP > ]) > > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([MAC binding aging - probing off-subnet next hop]) > +CHECK_SCAPY > +ovn_start > + > +aging_th=10 > +net_add n1 > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +ovn-appctl -t ovn-controller vlog/set mac_cache:file:dbg pinctrl:file:dbg > + > +check ovn-nbctl > \ > + -- ls-add ls1 > \ > + -- lr-add lr > \ > + -- set logical_router lr options:mac_binding_age_threshold=$aging_th > \ > + -- lrp-add lr lr-ls1 00:00:00:00:10:00 10.10.10.1/32 fd11::1/128 > \ > + -- lsp-add-router-port ls1 ls1-lr lr-ls1 > \ > + -- lsp-add ls1 vif1 > \ > + -- lsp-set-addresses vif1 "unknown" > + > +# Off-subnet next hops reachable through the router port via explicit > +# output_port routes, as documented in ovn-nb.xml. > +check ovn-nbctl lr-route-add lr 10.10.30.0/24 10.10.20.100 lr-ls1 > +check ovn-nbctl lr-route-add lr fd30::/64 fd20::64 lr-ls1 > + > +check ovs-vsctl > \ > + -- add-port br-int vif1 > \ > + -- set interface vif1 external-ids:iface-id=vif1 > \ > + options:tx_pcap=hv1/vif1-tx.pcap options:rxq_pcap=hv1/vif1-rx.pcap > + > +OVN_POPULATE_ARP > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Wait for pinctrl thread to be connected. > +OVS_WAIT_UNTIL([grep pinctrl hv1/ovn-controller.log | grep -q connected]) > + > +# Learn MAC bindings for the off-subnet next hops. > +send_garp hv1 vif1 2 00:00:00:00:10:1a ff:ff:ff:ff:ff:ff 10.10.20.100 > 10.10.20.100 > +wait_row_count mac_binding 1 ip="10.10.20.100" logical_port="lr-ls1" > + > +send_na hv1 vif1 00:00:00:00:10:1a 00:00:00:00:10:00 fd20::64 fd11::1 > +wait_row_count mac_binding 1 ip=\"fd20::64\" logical_port=\"lr-ls1\" > + > +# Send IPv4 and IPv6 UDP traffic so the router resolves and uses the > learned > +# bindings (this refreshes the OFTABLE_MAC_BINDING entries). Use a src > MAC > +# different from the one learned via GARP/NA so OFTABLE_MAC_CACHE_USE is > not > +# reset (that would keep the timestamp fresh and suppress probing). > +send_udp hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a 10.10.30.1 > 172.16.1.1 > +send_udp6 hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a fd30::1 fd55::1 > + > +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | \ > + sed > 's/reg15=0x.,metadata=0x./reg15=<cleared>,metadata=<cleared>/g' | \ > + grep -q > "reg0=0xa0a1464,reg15=<cleared>,metadata=<cleared> > actions=mod_dl_dst:00:00:00:00:10:1a"]) > + > +# Wait until entries in OFTABLE_MAC_CACHE_USE are stale. > +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int > table=OFTABLE_MAC_CACHE_USE | \ > + awk '/nw_src=10.10.20.100/{print > <http://10.10.20.100/%7Bprint> substr($6,10,1)}') -ge $((aging_th/2))]) > +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int > table=OFTABLE_MAC_CACHE_USE | \ > + awk '/ipv6_src=fd20::64/{print substr($6,10,1)}') > -ge $((aging_th/2))]) > + > +# Send traffic to trigger probing for both entries. > +send_udp hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a 10.10.30.1 > 172.16.1.1 > +send_udp6 hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a fd30::1 fd55::1 > + > +# Verify ARP/ND probes use the router port's (only) address as the source. > +dump_arp 1 00:00:00:00:10:00 00:00:00:00:10:1a 10.10.10.1 10.10.20.100 > 00:00:00:00:10:1a > expected > +OVN_CHECK_PACKETS_CONTAIN([hv1/vif1-tx.pcap], [expected]) > + > +dump_ns 00:00:00:00:10:1a 00:00:00:00:10:00 fd20::64 fd11::1 fd20::64 > > expected_v6 > +OVN_CHECK_PACKETS_CONTAIN([hv1/vif1-tx.pcap], [expected_v6]) > + > +OVN_CLEANUP([hv1]) > +AT_CLEANUP > +]) > OVN_FOR_EACH_NORTHD([ > AT_SETUP([MAC binding aging - probing unicast to broadcast transition]) > CHECK_SCAPY > -- > 2.43.0 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
