Hi Jacob

Thanks for the review.

On Fri, Aug 21, 2026 at 7:54 PM Jacob Tanenbaum <[email protected]> wrote:

>
>
> On Fri, Aug 21, 2026 at 3:30 AM Xavier Simonart via dev <
> [email protected]> wrote:
>
>> Since [1] we do not learn routes with auto-generated link-local next-hops.
>> However, routes with auto-generated lla next hops were still created and
>> deleted from ovn-ic-sb, causing high cpu usage on ovn-ic and ovn-ic-sb,
>> as well as high traffic between AZs and ovn-ic-sb.
>>
>> Fix this by skipping route advertisement when the derived next-hop is
>> an EUI-64 LLA (i.e. fe80::/64).
>> Non-EUI-64 link-local addresses (e.g. fe80:10::1/64), are intentionally
>> left unfiltered and continue to be advertised and learned normally.
>>
>> [1] cb0e2b3f44da ("ovn-ic: do not learn routes with link-local next-hops")
>>
>> Reported-at: https://issues.redhat.com/browse/FDP-2000
>> Assisted-by: Claude Sonnet 4.6, OpenCode
>> Signed-off-by: Xavier Simonart <[email protected]>
>>
>> ---
>> v2: - Update test based on comment from Roberto in v1, adding non-EUI-64
>>       addresses.
>>     - Check for NULL lrp in VLOG.
>>     - Change IPv6 addresses used (per Claude's review).
>> ---
>>  ic/ovn-ic.c     | 14 +++++++++
>>  tests/ovn-ic.at | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 98 insertions(+)
>>
>> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
>> index f7cc41748..7eac87259 100644
>> --- a/ic/ovn-ic.c
>> +++ b/ic/ovn-ic.c
>> @@ -2142,6 +2142,20 @@ add_network_to_routes_ad(struct hmap *routes_ad,
>> const char *network,
>>          return;
>>      }
>>
>> +    if (in6_is_lla(&nexthop)) {
>>
>
> The filter is only added here but add_static_to_routes_ad() and
> add_lb_vip_to_routes_ad() also call get_nexthop_from_lport_addresses()
> should the same filter be applied to them as well?
>
You are right; great catch! I'll fix it v3.

>
> If so it might be it cleaner to add the check once, in either
> get_nexthop_from_lport_addresses(), returning false when the result is an
> LLA, or in add_to_routes_ad()?
>
>
>> +        if (VLOG_IS_DBG_ENABLED()) {
>> +            struct ds msg = DS_EMPTY_INITIALIZER;
>> +            ds_put_format(&msg, "Route ad: skip lla nexthop");
>> +            if (nb_lrp) {
>> +                ds_put_format(&msg, " of lrp %s", nb_lrp->name);
>> +            }
>> +            ds_put_format(&msg, ".");
>> +            VLOG_DBG("%s", ds_cstr(&msg));
>> +            ds_destroy(&msg);
>> +        }
>> +        return;
>> +    }
>> +
>>      if (VLOG_IS_DBG_ENABLED()) {
>>          struct ds msg = DS_EMPTY_INITIALIZER;
>>
>> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
>> index 1435a19a3..d7d9ad676 100644
>> --- a/tests/ovn-ic.at
>> +++ b/tests/ovn-ic.at
>> @@ -5628,7 +5628,91 @@ OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl
>> lr-route-list lr11 | grep 192.168 |
>>  ])
>>
>>  OVN_CLEANUP_IC([az1], [az2])
>> +AT_CLEANUP
>> +])
>> +
>> +OVN_FOR_EACH_NORTHD([
>> +AT_SETUP([interconnection - LLA])
>> +AT_KEYWORDS([LLA])
>> +# Logical network:
>>
>> +#┌──────────────────────────────────────────────────┬────────────────────────────────────────────────────┐
>> +#│                       AZ1                        │
>>      AZ2                        │
>>
>> +#├──────────────────────────────────────────────────┼────────────────────────────────────────────────────┤
>> +#│ LS11-LR11 (fd11::254) - LR11 - (2001:db8::1) ── TS1 ── (2001:db8::2)
>> - LR12 - (fd12::254) - LR12-LS12 │
>> +#│ LS21-LR21 (fd21::254) - LR21 - (fe80:10::1) ─────┼──── (fe80:10::2)
>> - LR22 - (fd22::254) - LR22-LS22 │
>>
>> +#└──────────────────────────────────────────────────┴────────────────────────────────────────────────────┘
>> +# LR11/LR12: trigger EUI-64 LLA filtering: they have a global IPv6
>> address on the TS port that gets removed,
>> +#            causing their stub subnet (fd1x::/64) to fall back to an
>> EUI-64 LLA nexthop that should be suppressed.
>> +# LR21/LR22: verify non-EUI-64 LLA nexthops (fe80:10::x) work correctly;
>> their subnets (fd2x::/64) are advertised and learned.
>>
>> +ovn_init_ic_db
>> +net_add n1
>> +
>> +for i in 1 2; do
>> +    ovn_start az$i
>> +    sim_add hv$i
>> +    as hv$i
>> +    check ovs-vsctl add-br br-phys
>> +    ovn_az_attach az$i n1 br-phys 192.168.$i.1 16
>> +    ovn_as az$i
>> +    check ovs-vsctl set open . external-ids:ovn-is-interconn=true
>> +    check ovn-nbctl set nb_global . options:ic-route-learn=true
>> +    check ovn-nbctl set nb_global . options:ic-route-adv=true
>> +done
>> +
>> +check ovn-ic-nbctl ts-add ts1
>> +check ovn_as az1 ovn-nbctl wait-until logical_switch ts1
>> +check ovn_as az2 ovn-nbctl wait-until logical_switch ts1
>> +
>> +for i in 1 2; do
>> +    ovn_as az$i
>> +    check ovn-nbctl lr-add lr1$i \
>> +                 -- lrp-add lr1$i lr1$i-ts1 00:aa:aa:aa:aa:1$i
>> 2001:db8::$i/64 \
>> +                 -- lrp-add lr1$i lr1$i-ls1$i 00:00:00:00:0$i:fe
>> fd1$i::254/64 \
>> +                 -- lsp-add-router-port ts1 ts1-lr1$i lr1$i-ts1
>> +    check ovn-nbctl lr-add lr2$i \
>> +                 -- lrp-add lr2$i lr2$i-ts1 aa:aa:aa:aa:aa:2$i
>> fe80:10::$i/64 \
>> +                 -- lsp-add-router-port ts1 ts1-lr2$i lr2$i-ts1
>> +
>> +    check ovn-nbctl --wait=sb lrp-add lr2$i lr2$i-ls2$i
>> 00:00:00:00:0$i:0$i fd2$i::254/64
>> +
>> +done
>> +
>> +wait_for_ports_up
>> +check ovn-ic-nbctl --wait=sb sync
>> +check ovn_as az1 ovn-nbctl --wait=hv sync
>> +check ovn_as az2 ovn-nbctl --wait=hv sync
>> +
>> +# Non-EUI-64 LLA nexthops must be advertised to IC-SB and learned
>> normally.
>> +OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep learned |
>> \
>> +                grep fd22::])
>> +AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr21 | awk '/learned/{print
>> $1, $2}'], [0], [dnl
>> +fd22::/64 fe80:10::2
>> +])
>> +OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl lr-route-list lr22 | grep learned |
>> \
>> +                grep fd21::])
>> +AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr22 | awk '/learned/{print
>> $1, $2}'], [0], [dnl
>> +fd21::/64 fe80:10::1
>> +])
>>
>
>
> I am pretty sure the following code with static routes will expose the
> issue. Unless I am misunderstanding.
>
> +# Add a static route on lr11. After removing the global IPv6 address,
> +# add_static_to_routes_ad() will use the EUI-64 LLA as nexthop because
> +# it lacks the in6_is_lla() filter that add_network_to_routes_ad() has.
> +ovn_as az1 check ovn-nbctl lr-route-add lr11 fd99::/64 2001:db8::2
> +check ovn-ic-nbctl --wait=sb sync
> +OVS_WAIT_UNTIL([ovn-ic-sbctl list route | grep fd99])
>
You're right, and this (as well as a similar lb test) fails.

>
>
>
>
>
>> +
>> +ovn_as az1 check ovn-nbctl remove logical_router_port lr11-ts1 networks
>> "2001\:db8\:\:1/64"
>> +check ovn-ic-nbctl --wait=sb sync
>> +
>> +# ic-sb route should not contain lla next hops.
>> +# Such routes used to be created and deleted in ic-sb.
>> +# Do not use OVS_WAIT_WHILE or WAIT_UNTIL as the wrong (lla) route
>> appears and disappears.
>> +for i in $(seq 1 50); do
>> +    AT_CHECK([ovn-ic-sbctl list route | grep "fe80:" | sort], [0], [dnl
>> +nexthop             : "fe80:10::1"
>> +nexthop             : "fe80:10::2"
>> +])
>> +done
>> +
>> +OVN_CLEANUP_SBOX([hv1])
>> +
>> +OVN_CLEANUP_SBOX([hv2])
>> +
>> +OVN_CLEANUP_IC([az1], [az2])
>>
>
> Nit: The blank lines are not necessary.
>
Will fix in v3.

>
>
>>  AT_CLEANUP
>>  ])
>>
>> --
>> 2.47.1
>>
>> _______________________________________________
>> dev mailing list
>> [email protected]
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>> Thanks
Xavier
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to