On Sat, Mar 21, 2026 at 5:12 AM Han Zhou <[email protected]> wrote:

> When resolving the output port and LRP address for a static route, use
> the nexthop's address family (not the prefix) for the is_ipv4 parameter
> to find_static_route_outport.  This matters when the "first IP on port"
> fallback is used (nexthop not in any LRP network): we must pick the
> first IPv4 or IPv6 address according to the nexthop family, so that
> ARP/ND can work.  In add_route() the register type (reg5 for IPv4 vs
> xxreg1 for IPv6) is determined by the nexthop's address family, which is
> correct.  Without this fix it can end up with assigning an IPv6 address
> to the 32-bit reg5.
>
> Fixes: 559924291c7f ("northd: Handle routing for other address families.")
> Assisted-by: Cursor, with model: claude-4.6-opus-high
> Signed-off-by: Han Zhou <[email protected]>
> Acked-by: Lorenzo Bianconi <[email protected]>
> ---
>  northd/northd.c     | 3 ++-
>  tests/ovn-northd.at | 5 +++++
>  2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 70cd6a644a84..4b87c2305c20 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -12266,7 +12266,8 @@ parsed_routes_add_static(const struct ovn_datapath
> *od,
>      struct ovn_port *out_port = NULL;
>      if (!is_discard_route &&
>          !find_static_route_outport(od, lr_ports, route,
> -                                   IN6_IS_ADDR_V4MAPPED(&prefix),
> +                                   nexthop ? IN6_IS_ADDR_V4MAPPED(nexthop)
> +                                   : IN6_IS_ADDR_V4MAPPED(&prefix),
>                                     &lrp_addr_s, &out_port)) {
>          free(nexthop);
>          return;
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 1afdbbf2ea9d..587ce94148e4 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -7395,6 +7395,10 @@ check ovn-nbctl --wait=sb lr-route-add lr0
> 11.0.0.0/24 2001:db8::10
>  check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 192.168.0.20
>  check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 2001:db8::20
>
> +# Add a IPv6 route with IPv4 nexthop that is not on any subnet of the
> router port.
> +# It should select the first IPv4 and assign to REG_SRC_IPV4 (reg5).
> +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:3::/64 192.168.1.10
> lr0-public
> +
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
> @@ -7404,6 +7408,7 @@ AT_CHECK([grep -e "lr_in_ip_routing " lr0flows |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing   ), priority=198  , match=(ip4.dst ==
> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst;
> reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public";
> flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=516  , match=(reg7 == 0 &&
> ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=516  , match=(reg7 == 0 &&
> ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 =
> 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport =
> "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
> +  table=??(lr_in_ip_routing   ), priority=516  , match=(reg7 == 0 &&
> ip6.dst == 2001:db8:3::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> 192.168.1.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=518  , match=(inport ==
> "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] =
> 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1214; eth.src =
> 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] =
> 0; next;)
>    table=??(lr_in_ip_routing   ), priority=518  , match=(inport ==
> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0;
> xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src =
> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] =
> 0; next;)
>    table=??(lr_in_ip_routing   ), priority=518  , match=(ip6.dst ==
> 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst;
> xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private";
> flags.loopback = 1; reg9[[9]] = 0; next;)
> --
> 2.38.1
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Looks good to me, thanks.

Acked-by: Ales Musil <[email protected]>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to