Hoi,

I've found that issuing a new link-local from Linux will emit a Netlink address remove followed by an address add with the new address. Linux CP will see this removal and disable linklocal processing on the interface in src/plugins/linux-cp/lcp_router.c:686:

          if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
            if (is_del)
              ip6_link_disable (sw_if_index);
            else
              {
                ip6_link_enable (sw_if_index, NULL);
                ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
              }

The subsequent add will re-enable and set the link-local address. There is no ip6_link_remove_local_address() so the code as written makes sense, but there's a lot of book-keeping that occurs on link disable/enable, including address listeners, MLD, VRRP, FIB changes and a few other bits and pieces. I propose that we disable the link iff there are no addresses left, rather than unconditionally on ip6ll changes from netlink.

https://gerrit.fd.io/r/c/vpp/+/46038 has this change, but I'm not sure as the original crash is related to having no ilt_fibs entry for the sw_if_index, which is done by ip6_link_disable(), but should be re-enabled with the subsequent add from ip6_link_enable+set_address. Considering these calls are done under barrier lock, the only explanation I could come up with, is that the address delete comes in on batch #1, leaving ilt_fibs[sw_if_index] = ~0, while the address add come in on batch #2, and the window of time between #1 and #2 is where an incoming NS can cause the crash.

Matt, what do you think?


On 10.06.2026 21:27, Pim van Pelt via lists.fd.io wrote:
Hoi,

I am running VPP on a few aarch64 machines and observed regular crashes with a stacktrace that suggests IPv6 FIB lookup issue -

Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #0  0x0000fc1b8ac808f8
Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from linux-vdso.so.1
Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #1  0x0000fc1b8998ac3c ip6_fib_table_lookup_exact_match + 0x3c Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libvnet.so.26.06 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #2  0x0000fc1b89a21d2c proxy_arp_intfc_walk + 0x4030 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libvnet.so.26.06 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #3  0x0000fc1b89101658 vlib_exit_with_status + 0x808 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libvlib.so.26.06 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #4  0x0000fc1b89103eb0 vlib_exit_with_status + 0x3060 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libvlib.so.26.06 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #5  0x0000fc1b8912d88c vlib_worker_thread_bootstrap_fn + 0x6c Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libvlib.so.26.06 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #6  0x0000fc1b88de595c pthread_condattr_setpshared + 0x5bc Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libc.so.6 Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]: #7  0x0000fc1b88e4bb4c __clone + 0x2cc Jun 04 19:42:29 dpu0-ddln0 vpp[1179016]:      from /lib/aarch64-linux-gnu/libc.so.6

I was lucky enough to get two coredumps out of it, which I fed to Claude and it came back with an analysis that pointed to me having changed the link-local address on an interface:

    The interface did have IPv6/ND enabled — otherwise the
    icmp6_neighbor_solicitation node would never have run. What it
    transiently lacked was its per-interface link-local FIB table
    (ilt_fibs[sw_if_index]), which is a structure distinct from "IPv6
    is enabled." That table is created lazily when a link-local
    address is added (ip6_ll_fib_create) and freed, with the slot
    reset to ~0, when the last FIB_SOURCE_IP6_ND entry is removed
    (ip6_ll_table.c:150-154). Crucially, ip6_link_set_local_address()
    (ip6_link.c:359-362) changes a link-local address by doing
    delete-then-update: it removes the old LL prefix (which frees the
    FIB and sets ilt_fibs = ~0), then re-adds the new one (which
    recreates it). The ND node stays enabled across this whole
    sequence. So the NS did not arrive anywhere unexpected — it hit a
    normally-configured interface during the brief window in which its
    LL FIB had been torn down and not yet rebuilt. A worker thread
    forwarding an ordinary link-local NS in that window read ilt_fibs
    == ~0 and segfaulted; two crashes 31 minutes apart is consistent
    with two separate LL-address-change events, matching your note
    that you'd been changing link-local addresses.

The debugging session made my head spin a little bit as I'm not very good with gdb, but what the cores do prove: an unguarded ~0 from ip6_ll_fib_get() in the link-local NS branch causes an out-of-bounds pool_elt_at_index; the trigger is an NS for a link-local target arriving while ilt_fibs[sw_if_index] == ~0.

The fix is a simple check of ip6_ll_fib_get() before doing the FIB lookup, just as happens a few lines further down in the same vnet/ip6-nd/ip6_nd.c file. A candidate fix is in https://gerrit.fd.io/r/c/vpp/+/46038 and I have not observed crashes after applying it, although I'm not certain if returning FIB_NODE_INDEX_INVALID and dropping the packet is the right call in this case, or if we have to do something more?

I have the coredumps and symbols here if somebody wants to take a closer look.

groet,
Pim
--
Pim van Pelt<[email protected]>
PBVP1-RIPEhttps://ipng.ch/




--
Pim van Pelt
PBVP1-RIPE -https://ipng.ch/

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#27070): https://lists.fd.io/g/vpp-dev/message/27070
Mute This Topic: https://lists.fd.io/mt/119745721/21656
Group Owner: [email protected]
Unsubscribe: https://lists.fd.io/g/vpp-dev/leave/14379924/21656/631435203/xyzzy 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to