[PATCH] EVPN: Fix crash when the tunnel device does not exist yet
The EVPN protocol is prepared to start before its VXLAN tunnel device exists: evpn_start() returns PS_START to wait for the interface and evpn_if_notify() brings the protocol up once it appears. But evpn_start() also attaches the VLAN request topic, which is keyed by the name of the bridge the tunnel device is enslaved to. The configuration parser resolves the tunnel device with if_get_by_name(), which returns a placeholder for an interface that does not exist yet. Such a placeholder has no master, so attaching the topic dereferences a NULL pointer and BIRD crashes during configuration commit. Attach the topic only once the bridge is known, and retry from evpn_started(), which already runs when the interface shows up. While the topic is unattached there is nothing to publish to, so skip publishing VLAN requests and re-issue them when attaching later. This also covers evpn_shutdown(), which withdraws VLANs unconditionally and would otherwise trip the assertion in ps_publish() on the way out. Reproducible on both branches with any evpn protocol whose tunnel device is created after BIRD starts, which happens with a restarted daemon or a rebuilt bridge. --- Rooted in thread-next; cherry-picks onto master without conflicts if you want it in 2.x as well. Reproducer, a bridge and an evpn protocol pointing at a VXLAN device that is never created: ip link add lo0 type dummy ip -6 addr add fd00::1/128 dev lo0 nodad ip link set lo0 up ip link add name br-red type bridge ip link set br-red up bird -f -c bird.conf protocol bridge bridge_red { eth { table etab_red; export all; }; bridge device "br-red"; } protocol evpn evpn_red { eth { table etab_red; }; evpn; encapsulation vxlan { tunnel device "vx-red"; router address fd00::1; }; rd 10.0.0.1:100; route target (rt, 1, 100); vni 100; } Without this commit, at configuration commit: #1 ps_get_topic (name=0x10 <error: Cannot access memory at address 0x10>) at lib/pubsub.c:94 #2 ps_attach_topic (name=0x10 ...) at ./lib/pubsub.h:64 #3 evpn_start (P=...) at proto/evpn/evpn.c:1092 #4 proto_start ... #13 main 0x10 is offsetof(struct iface, name) applied to a NULL master. Built and run at the branch heads of 2026-08-08, each against its own unpatched parent, with the device missing and with it appearing late: 3.3.0 and 2.19.0 segfault before the fix, run after it, and evpn_red reaches up when the device shows up. Tarballs 3.3.1 and 2.19.2 match their heads. Rebasing onto the current thread-next moved hunk offsets only. The path where the device exists at startup is unaffected: a three-leaf two-tenant fabric on patched 3.3.1 still passes its reachability, tenant isolation and MAC learning suite. Nothing added under netlab/ in bird-tools; happy to do so if you want this case covered there. proto/evpn/evpn.c | 41 ++++++++++++++++++++++++++++++++++++++++- proto/evpn/evpn.h | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/proto/evpn/evpn.c b/proto/evpn/evpn.c index 32326ea..c8487d9 100644 --- a/proto/evpn/evpn.c +++ b/proto/evpn/evpn.c @@ -750,6 +750,13 @@ evpn_remove_vlan(struct evpn_proto *p, struct evpn_vlan *v) static void evpn_publish_vlan_request(struct evpn_proto *p, struct vlan_request *req, bool update, int vlan_count) { + /* The topic is attached only once the tunnel device and its bridge are known, + so there may be nothing to publish to yet. Requests skipped here are + re-issued from evpn_started(); the withdraw on shutdown has nothing to + withdraw. */ + if (!p->vlan_pub_attached) + return; + struct evpn_encap *encap = evpn_get_encap(p); /* Fill header */ @@ -1068,6 +1075,28 @@ evpn_init(struct proto_config *CF) return P; } +/* + * Attach the VLAN request topic, which is keyed by the name of the bridge the + * tunnel device is enslaved to. + * + * Neither the tunnel device nor its bridge has to exist when the protocol + * starts: evpn_start() returns PS_START precisely to wait for the interface, + * and evpn_if_notify() picks it up later. So this may be called before the + * bridge is known, and is a no-op until it is. + */ +static void +evpn_attach_vlan_topic(struct evpn_proto *p, struct evpn_encap *encap) +{ + if (p->vlan_pub_attached) + return; + + if (!encap->tunnel_dev || !encap->tunnel_dev->master) + return; + + ps_attach_topic(p->vlan_pub, &vlan_requests, encap->tunnel_dev->master->name); + p->vlan_pub_attached = true; +} + static int evpn_start(struct proto *P) { @@ -1089,7 +1118,8 @@ evpn_start(struct proto *P) struct evpn_encap *encap = evpn_get_encap(p); p->vlan_pub = ps_publisher_new(p->p.pool, evpn_vlan_subscribe_hook, p); - ps_attach_topic(p->vlan_pub, &vlan_requests, encap->tunnel_dev->master->name); + p->vlan_pub_attached = false; + evpn_attach_vlan_topic(p, encap); init_list(&p->vlans); memset(&p->vlan_tag_hash, 0, sizeof(p->vlan_tag_hash)); @@ -1123,6 +1153,15 @@ evpn_started(struct evpn_proto *p, struct iface *i) if (!evpn_validate_iface_attrs(p, i)) return; + /* The bridge may only become known now; VLAN requests made before the topic + was attached went nowhere, so re-issue them once it is. */ + if (!p->vlan_pub_attached) + { + evpn_attach_vlan_topic(p, evpn_get_encap(p)); + if (p->vlan_pub_attached) + evpn_request_vlans(p); + } + proto_notify_state(&p->p, PS_UP); evpn_announce_imet(p, EVPN_ROOT_VLAN(p), 1); diff --git a/proto/evpn/evpn.h b/proto/evpn/evpn.h index 8103dfb..3fe527b 100644 --- a/proto/evpn/evpn.h +++ b/proto/evpn/evpn.h @@ -81,6 +81,7 @@ struct evpn_proto { HASH(struct evpn_vlan) vlan_tag_hash; HASH(struct evpn_vlan) vlan_vid_hash; ps_publisher *vlan_pub; + bool vlan_pub_attached; /* VLAN topic attached (needs the bridge name) */ }; struct evpn_encap { base-commit: 06ca9bf5c588df6c0587eb64bd375eb0ade526ab -- 2.55.0
On Sun, Aug 09, 2026 at 04:18:01PM +0200, Florian Bauer via Bird-users wrote:
The EVPN protocol is prepared to start before its VXLAN tunnel device exists: evpn_start() returns PS_START to wait for the interface and evpn_if_notify() brings the protocol up once it appears. But evpn_start() also attaches the VLAN request topic, which is keyed by the name of the bridge the tunnel device is enslaved to.
Hello Thanks for the bugreport and patch. There are likely some more issues related to bridge or vxlan interface add/remove during run, i plan to review these code paths soon. will include your patch with it. -- Elen sila lumenn' omentielvo Ondrej 'Santiago' Zajicek (email: santiago@crfreenet.org) "To err is human -- to blame it on a computer is even more so."
participants (2)
-
Florian Bauer -
Ondrej Zajicek