Skip to content

bgpd: rt vpn export overwritten with RD on daemon restart (same root cause as #18987) #22579

Description

@alyxhaswon21

Description

rt vpn both <ASN>:<NN> under router bgp <ASN> vrf <NAME> / address-family <ipv4|ipv6> unicast gets silently split into mismatched rt vpn import / rt vpn export lines, with the export half incorrectly set to this router's own rd vpn export value instead of retaining the configured shared RT.

Reproduced on 3 of 4 PEs in a lab, on separate occasions, via one trigger: restarting the daemon/container. The on-disk frr.conf shows rt vpn both 65000:100 before and after the restart, unchanged. Once bgpd reloads it at startup, though, show running-config shows the split/broken form instead. The save itself is fine; the reload is what breaks it.

Effect: the export RT no longer matches what other PEs import on, so the route silently stops being importable anywhere else in the VPN. There are no logs or error messages. A remote PE's show bgp vrf <NAME> <afi> unicast just shows zero routes.

Related issue

This looks like the same underlying bug as #18987 ("Export Route Target Overwritten on Startup"), which was auto-closed by the stale-issue bot in June 2026. The last activity was the reporter sharing a patch in December 2025. That issue evolved across versions: originally the export RT got overwritten with a VRF interface's IP address (10.3.1), then later with the RD itself (10.5, per a comment from the reporter on 2025-11-13). That's exactly what's reproduced here on 10.6.1.

The reporter's diagnosis: "The problem seems to be with the auto derivation code overwriting RT when router-id changes." That matches this report's trigger: router-id gets freshly determined at daemon startup, and something in that path unconditionally re-derives and overwrites the export RT with no check for whether it was explicitly configured via CLI.

The attached patch (https://github.com/user-attachments/files/23884283/bgp_fix.txt) confirms this. It adds a BGP_VPN_POLICY_TOVPN_RT_CLI_SET flag, set when rt vpn export/both is configured via CLI, and gates the auto-derivation in vpn_handle_router_id_update() (bgpd/bgp_mplsvpn.c) on that flag being unset. That single missing check appears to be the entire bug.

Filing this as a new issue rather than commenting on #18987 since it's closed and would likely get skipped in normal triage. Wanted to flag that this looks like the same bug, still present on the current 10.6.1 GA release, with a full reproduction below.

Version

FRRouting 10.6.1_git (pe1) on Linux(7.0.11-orbstack-00360-gc9bc4d96ac70).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
configured with:
    '--prefix=/usr' '--sysconfdir=/etc' '--localstatedir=/var' '--sbindir=/usr/lib/frr' '--libdir=/usr/lib' '--enable-rpki' '--enable-vtysh' '--enable-multipath=64' '--enable-vty-group=frrvty' '--enable-user=frr' '--enable-group=frr' '--enable-pcre2posix' '--enable-scripting' 'CC=cc' 'CXX=c++'

Deployed via quay.io/frrouting/frr:10.6.1 (containerlab / Docker), kernel 7.0.11-orbstack (OrbStack Linux VM on macOS, arm64).

Topology / setup

SRv6 L3VPN lab: 4 PE routers (pe1-pe4) in a full iBGP mesh over loopbacks, 2 P routers as pure IS-IS/SRv6 underlay transit, one shared customer VRF (cust1) across all four PEs tied together with a shared RT (65000:100) and per-PE RDs (65000:6/7/8/9). Probably not SRv6-specific, looks like generic VPN RT handling, but haven't tested it against a plain MPLS L3VPN VRF yet.

How to reproduce

  1. Configure a VRF-scoped BGP instance with a shared RT via both:
    router bgp 65000 vrf cust1
     sid vpn per-vrf export auto
     !
     address-family ipv4 unicast
      redistribute connected
      rd vpn export 65000:6
      nexthop vpn export 5f00:0:6::1
      rt vpn both 65000:100
      export vpn
      import vpn
     exit-address-family
     !
     address-family ipv6 unicast
      redistribute connected
      rd vpn export 65000:6
      nexthop vpn export 5f00:0:6::1
      rt vpn both 65000:100
      export vpn
      import vpn
     exit-address-family
    exit
    
    (Base instance also has ipv4 vpn / ipv6 vpn activated for VPN route exchange, and segment-routing srv6 / locator IGP bound for per-VRF SID allocation. Included for completeness, probably unrelated.)
  2. write memory. Confirm the on-disk file is correct:
    # grep "rt vpn" /etc/frr/frr.conf
      rt vpn both 65000:100
      rt vpn both 65000:100
    
  3. Restart bgpd. Here, via containerlab deploy --reconfigure, which recreates the container and forces bgpd to reload frr.conf from scratch.
  4. Compare show running-config against the (unchanged) on-disk file.

Expected behavior

After restart, show running-config should match the on-disk config: rt vpn both 65000:100 on both address-families, unchanged from what was saved.

Actual behavior

On-disk file (confirmed unchanged, still correct):

router bgp 65000 vrf cust1
 sid vpn per-vrf export auto
 !
 address-family ipv4 unicast
  redistribute connected
  rd vpn export 65000:6
  nexthop vpn export 5f00:X::X
  rt vpn both 65000:100
  export vpn
  import vpn
 exit-address-family
 !
 address-family ipv6 unicast
  redistribute connected
  rd vpn export 65000:6
  nexthop vpn export 5f00:X::X
  rt vpn both 65000:100
  export vpn
  import vpn
 exit-address-family
exit

show running-config after the restart, same section:

router bgp 65000 vrf cust1
 sid vpn per-vrf export auto
 !
 address-family ipv4 unicast
  redistribute connected
  rd vpn export 65000:6
  nexthop vpn export 5f00:X::X
  rt vpn import 65000:100
  rt vpn export 65000:6          <-- wrong: matches "rd vpn export", not the configured "rt vpn both" value
  export vpn
  import vpn
 exit-address-family
 !
 address-family ipv6 unicast
  redistribute connected
  rd vpn export 65000:6
  nexthop vpn export 5f00:X::X
  rt vpn import 65000:100
  rt vpn export 65000:6          <-- same wrong value here
  export vpn
  import vpn
 exit-address-family
exit

Both address-families get hit identically, and the wrong export value (65000:6) exactly matches this router's own rd vpn export 65000:6. Looks like the export RT is getting re-derived from the RD as a fallback during reload, instead of keeping the configured both value.

Workaround

Re-issuing rt vpn both 65000:100 live after the fact fixes it until the next restart:

configure terminal
router bgp 65000 vrf cust1
address-family ipv4 unicast
rt vpn both 65000:100
exit-address-family
address-family ipv6 unicast
rt vpn both 65000:100
exit-address-family
end
write memory

Has to be reapplied after every restart. It doesn't stick, since the on-disk file was never actually wrong; every reload just re-triggers the same split.

Additional context

Reproduced on 3 of 4 PEs across multiple redeploys this session. pe2, otherwise identically configured, hasn't shown it once. Given the router-id-change trigger described in #18987, this is probably just luck: router-id here is auto-derived from an interface IP that Docker reassigns somewhat unpredictably across container recreations, so pe2 may simply not have gotten a genuine router-id change on the redeploys where the others did.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions