You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since the table-ownership enforcement (953be8a, refined in #2339), generate_sonic_config() drops the content of every owned table up front and rebuilds it from NetBox data and hardcoded policy. BGP_GLOBALS, BGP_GLOBALS_AF, and BGP_GLOBALS_ROUTE_ADVERTISE are owned tables (part of SCAFFOLDED_OWNED_TABLE_KEYS), but the generator only repopulates them for VRFs with an EVPN VNI (_add_vrf_configuration). The default-VRF entries that the base config_db.json deliberately ships — introduced in #1937 with the split "default entries in base config_db.json for the default VRF, VRF-specific entries from the generator" — no longer survive regeneration.
Impact
On leaves without VNI VRFs, the regenerated config contains an emptyBGP_GLOBALS_AF and an emptyBGP_GLOBALS_ROUTE_ADVERTISE. In our production pod, the data leaves consequently stopped advertising default-VRF IPv4 unicast routes into EVPN. All traffic that has to transit the fabric to subnets attached to a different leaf (NetApp NVMe over TCP storage) was silently dropped. Because of per-flow ECMP, roughly half of all new storage connections failed. The result was recurring platform-wide incidents since 2026-06-19 — shortly after the ownership enforcement was rolled out — with aborted VM builds, volumes stuck in deleting, and Octavia load balancers going into ERROR. All interface and error counters stayed clean, which made this very hard to diagnose.
The blast radius is not limited to leaves without VNI VRFs:
BGP_GLOBALS|default is replaced wholesale with only router_id/local_asn (config_generator.py:352-372). The base-config attributes — network_import_check, ebgp_requires_policy, holdtime/keepalive, always_compare_med, log_nbr_state_changes, … — are lost on every switch.
BGP_GLOBALS_AFdefault|l2vpn_evpn (advertise-all-vni: true, advertise-svi-ip: true, dad-enabled: true) and default|ipv4_unicast/default|ipv6_unicast (ECMP max_ebgp_paths/max_ibgp_paths) are never regenerated for the default VRF, on any switch.
The per-VRF BGP_GLOBALS entries are deep-copied from the thinned-out default entry (config_generator.py:2159-2163), so VNI VRFs inherit the attribute loss as well.
Root cause
Add BGP_GLOBALS_ROUTE_ADVERTISE for L2VPN_EVPN in SONIC #1937 (71b834c, 2026-01-14) added the default-VRF entries (BGP_GLOBALS|default attributes, BGP_GLOBALS_AFdefault|*, BGP_GLOBALS_ROUTE_ADVERTISEdefault|L2VPN_EVPN|IPV4_UNICAST / …|IPV6_UNICAST) to files/sonic/config_db.json, which the Containerfile installs as /etc/sonic/config_db.json — the base config every regen starts from. The generator was only extended to emit the VRF-specific entries.
953be8a (2026-06-02) introduced the ownership model: all owned tables are popped up front (config_generator.py:323-324) and rebuilt from scratch; BGP_GLOBALS|default is assigned wholesale instead of merged. sonic: Enforce config table ownership statically #2339 (8718b2f) added the static guard test that cements this classification.
Nothing in the generator recreates the default-VRF entries: BGP_GLOBALS_AF and BGP_GLOBALS_ROUTE_ADVERTISE are only written in _add_vrf_configuration for VRFs with a VNI (config_generator.py:2113-2141).
The ownership enforcement and the "defaults live in the base config" convention from #1937 are mutually exclusive, and the enforcement won.
Expected behavior
Regenerated configs still contain the default-VRF entries: either the generator emits them itself for the default VRF, or these tables get inherited/merge semantics for the default|* keys.
Actual behavior
The owned-table semantics drop the base-config content; only entries for VRFs with a VNI are regenerated.
Reproduction
Regenerate the SONiC config for any switch without VNI VRFs and diff the BGP_GLOBALS* tables against files/sonic/config_db.json: BGP_GLOBALS_AF and BGP_GLOBALS_ROUTE_ADVERTISE come back empty, BGP_GLOBALS|default contains only router_id and local_asn.
Suggested fix
Under the ownership model, operator- or image-provided content in owned tables is explicitly unsupported, so the consistent fix is for the generator to own the default-VRF entries too: emit the BGP_GLOBALS|default attributes, the BGP_GLOBALS_AFdefault|ipv4_unicast / default|ipv6_unicast / default|l2vpn_evpn entries, and the BGP_GLOBALS_ROUTE_ADVERTISEdefault|L2VPN_EVPN|IPV4_UNICAST / …|IPV6_UNICAST entries as hardcoded SONiC policy (values as currently shipped in files/sonic/config_db.json), and drop the then-redundant entries from the base config. The per-VRF BGP_GLOBALS copy then picks up the full attribute set again automatically.
A regression test should assert that a device without VNI VRFs still gets the default-VRF entries in all three tables.
Summary
Since the table-ownership enforcement (953be8a, refined in #2339),
generate_sonic_config()drops the content of every owned table up front and rebuilds it from NetBox data and hardcoded policy.BGP_GLOBALS,BGP_GLOBALS_AF, andBGP_GLOBALS_ROUTE_ADVERTISEare owned tables (part ofSCAFFOLDED_OWNED_TABLE_KEYS), but the generator only repopulates them for VRFs with an EVPN VNI (_add_vrf_configuration). The default-VRF entries that the baseconfig_db.jsondeliberately ships — introduced in #1937 with the split "default entries in base config_db.json for the default VRF, VRF-specific entries from the generator" — no longer survive regeneration.Impact
On leaves without VNI VRFs, the regenerated config contains an empty
BGP_GLOBALS_AFand an emptyBGP_GLOBALS_ROUTE_ADVERTISE. In our production pod, the data leaves consequently stopped advertising default-VRF IPv4 unicast routes into EVPN. All traffic that has to transit the fabric to subnets attached to a different leaf (NetApp NVMe over TCP storage) was silently dropped. Because of per-flow ECMP, roughly half of all new storage connections failed. The result was recurring platform-wide incidents since 2026-06-19 — shortly after the ownership enforcement was rolled out — with aborted VM builds, volumes stuck indeleting, and Octavia load balancers going intoERROR. All interface and error counters stayed clean, which made this very hard to diagnose.The blast radius is not limited to leaves without VNI VRFs:
BGP_GLOBALS|defaultis replaced wholesale with onlyrouter_id/local_asn(config_generator.py:352-372). The base-config attributes —network_import_check,ebgp_requires_policy,holdtime/keepalive,always_compare_med,log_nbr_state_changes, … — are lost on every switch.BGP_GLOBALS_AFdefault|l2vpn_evpn(advertise-all-vni: true,advertise-svi-ip: true,dad-enabled: true) anddefault|ipv4_unicast/default|ipv6_unicast(ECMPmax_ebgp_paths/max_ibgp_paths) are never regenerated for the default VRF, on any switch.BGP_GLOBALSentries are deep-copied from the thinned-out default entry (config_generator.py:2159-2163), so VNI VRFs inherit the attribute loss as well.Root cause
BGP_GLOBALS|defaultattributes,BGP_GLOBALS_AFdefault|*,BGP_GLOBALS_ROUTE_ADVERTISEdefault|L2VPN_EVPN|IPV4_UNICAST/…|IPV6_UNICAST) tofiles/sonic/config_db.json, which the Containerfile installs as/etc/sonic/config_db.json— the base config every regen starts from. The generator was only extended to emit the VRF-specific entries.BGP_GLOBALS|defaultis assigned wholesale instead of merged. sonic: Enforce config table ownership statically #2339 (8718b2f) added the static guard test that cements this classification.BGP_GLOBALS_AFandBGP_GLOBALS_ROUTE_ADVERTISEare only written in_add_vrf_configurationfor VRFs with a VNI (config_generator.py:2113-2141).The ownership enforcement and the "defaults live in the base config" convention from #1937 are mutually exclusive, and the enforcement won.
Expected behavior
Regenerated configs still contain the default-VRF entries: either the generator emits them itself for the default VRF, or these tables get inherited/merge semantics for the
default|*keys.Actual behavior
The owned-table semantics drop the base-config content; only entries for VRFs with a VNI are regenerated.
Reproduction
Regenerate the SONiC config for any switch without VNI VRFs and diff the
BGP_GLOBALS*tables againstfiles/sonic/config_db.json:BGP_GLOBALS_AFandBGP_GLOBALS_ROUTE_ADVERTISEcome back empty,BGP_GLOBALS|defaultcontains onlyrouter_idandlocal_asn.Suggested fix
Under the ownership model, operator- or image-provided content in owned tables is explicitly unsupported, so the consistent fix is for the generator to own the default-VRF entries too: emit the
BGP_GLOBALS|defaultattributes, theBGP_GLOBALS_AFdefault|ipv4_unicast/default|ipv6_unicast/default|l2vpn_evpnentries, and theBGP_GLOBALS_ROUTE_ADVERTISEdefault|L2VPN_EVPN|IPV4_UNICAST/…|IPV6_UNICASTentries as hardcoded SONiC policy (values as currently shipped infiles/sonic/config_db.json), and drop the then-redundant entries from the base config. The per-VRFBGP_GLOBALScopy then picks up the full attribute set again automatically.A regression test should assert that a device without VNI VRFs still gets the default-VRF entries in all three tables.
References
osism/tasks/conductor/sonic/config_generator.py: owned-table drop (323-324),BGP_GLOBALS|defaultwholesale assignment (352-372), VNI-only regeneration (2113-2141), per-VRF copy (2159-2163)