From 86e1a140353864d01f4a63e40c79ecaea635d0c0 Mon Sep 17 00:00:00 2001 From: Pau Capdevila Date: Mon, 21 Sep 2026 03:51:33 +0200 Subject: [PATCH 1/4] docs: document migrating a static external attachment to BGP Static-ness is per-attachment, not per-External, so one External can have both a static and a BGP attachment at once. Document the migration sequence and its two sharp edges: the attachment conversion and dropping spec.static can't be applied atomically, and BGP communities need to be configured on the External after the migration since they can't be set while it's still static. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pau Capdevila --- docs/user-guide/external.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index e0f53653..22ef7ac4 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -16,7 +16,9 @@ Border Leaves (or Borders) can connect to several Edge Devices. !!! note External Peering is only available on switch devices that support sub-interfaces. -Hedgehog Fabric supports both BGP-speaking and static externals. +Hedgehog Fabric supports both BGP-speaking and static externals. This choice is made per attachment, not per +`External`, so a single `External` can have both kinds of attachment at once; see +[Migrating a Static Attachment to BGP](#migrating-a-static-attachment-to-bgp). ### Connect a Border Leaf to an Edge Device @@ -173,6 +175,34 @@ spec: ip: # IP address (with prefix length) to be configured on the switch when not using Proxy mode, empty otherwise ``` +### Migrating a Static Attachment to BGP + +Static-ness is a property of the `ExternalAttachment`, not of the `External`. This means a single `External` can have +both static and BGP-speaking attachments at the same time, which allows a static uplink to be migrated to BGP without +an outage: + +1. Add a BGP `ExternalAttachment` on a second Border Leaf, pointing at the same `External`. +2. Convert the original attachment from static to BGP (remove its `static` block, add `neighbor` and `switch`). +3. Clear `spec.static.prefixes` on the `External` itself. The API refuses this while any attachment referencing it is + still static, so it can only be done after step 2. + +While a static attachment and a BGP attachment on the same `External` coexist, the static path always wins, so +traffic keeps flowing over it during steps 1 and 2. + +!!! warning + Steps 2 and 3 cannot be applied atomically. Until step 3 completes, the Border Leaf configures the newly-converted + BGP link but does not use its routes, so traffic has no working path in between: the static path stopped being + used the moment step 2 landed, and the BGP path isn't usable yet. Apply steps 2 and 3 back to back to keep this + window as short as possible. + +!!! warning + `inboundCommunity`/`outboundCommunity` cannot be set on the `External` while `spec.static.prefixes` is present, so + an `External` that started out purely static will not have them configured. Once the migration is complete, set + them to match whatever community policy the Edge Device applies (see + [BGP-speaking External object](#bgp-speaking-external-object) above). If the Edge Device filters inbound routes by + community, an `External` with no `outboundCommunity` configured will have every route it advertises silently + dropped by the Edge Device. + ### External VPC Peering To allow a specific VPC to have access to prefixes reachable via an Edge Device, bind the VPC to the corresponding From b654c706c702203f52f523e1d524466b09d3db61 Mon Sep 17 00:00:00 2001 From: Pau Capdevila Date: Mon, 21 Sep 2026 09:55:39 +0200 Subject: [PATCH 2/4] docs: merge the two migration warnings into one Two back-to-back warning admonitions read like an afterthought list; fold both sharp edges into a single warning with two bullets instead. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pau Capdevila --- docs/user-guide/external.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index 22ef7ac4..041e3071 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -190,18 +190,18 @@ While a static attachment and a BGP attachment on the same `External` coexist, t traffic keeps flowing over it during steps 1 and 2. !!! warning - Steps 2 and 3 cannot be applied atomically. Until step 3 completes, the Border Leaf configures the newly-converted - BGP link but does not use its routes, so traffic has no working path in between: the static path stopped being - used the moment step 2 landed, and the BGP path isn't usable yet. Apply steps 2 and 3 back to back to keep this - window as short as possible. - -!!! warning - `inboundCommunity`/`outboundCommunity` cannot be set on the `External` while `spec.static.prefixes` is present, so - an `External` that started out purely static will not have them configured. Once the migration is complete, set - them to match whatever community policy the Edge Device applies (see - [BGP-speaking External object](#bgp-speaking-external-object) above). If the Edge Device filters inbound routes by - community, an `External` with no `outboundCommunity` configured will have every route it advertises silently - dropped by the Edge Device. + This migration has two sharp edges: + + - Steps 2 and 3 cannot be applied atomically. Until step 3 completes, the Border Leaf configures the + newly-converted BGP link but does not use its routes, so traffic has no working path in between: the + static path stopped being used the moment step 2 landed, and the BGP path isn't usable yet. Apply steps 2 + and 3 back to back to keep this window as short as possible. + - `inboundCommunity`/`outboundCommunity` cannot be set on the `External` while `spec.static.prefixes` is + present, so an `External` that started out purely static will not have them configured. Once the migration + is complete, set them to match whatever community policy the Edge Device applies (see + [BGP-speaking External object](#bgp-speaking-external-object) above). If the Edge Device filters inbound + routes by community, an `External` with no `outboundCommunity` configured will have every route it + advertises silently dropped. ### External VPC Peering From 9a209696892600f89f5130a133e7ee136bfc1d87 Mon Sep 17 00:00:00 2001 From: Pau Capdevila Date: Mon, 21 Sep 2026 14:20:16 +0200 Subject: [PATCH 3/4] docs: fix the mechanism explanation in the migration warning The prior wording attributed the outage window to attachment/External static-flag mismatch causing the switch to skip programming the BGP link. Re-verified against a freshly fetched fabric@origin/master: the switch-agent gates BGP route-exchange per attachment (extHasBGP), not on the External's own static flag, so that part was wrong -- the earlier read was against a stale, pre-feature local checkout. The real mechanism: the API forbids setting inboundCommunity/ outboundCommunity while any static prefix remains on the External, to protect the static route's own EVPN re-origination. That's what forces step 3 to wait for step 2, and it's the actual reason a community- filtering Edge Device drops everything the Fabric advertises until step 3 completes. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pau Capdevila --- docs/user-guide/external.md | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index 041e3071..12093846 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -178,30 +178,26 @@ spec: ### Migrating a Static Attachment to BGP Static-ness is a property of the `ExternalAttachment`, not of the `External`. This means a single `External` can have -both static and BGP-speaking attachments at the same time, which allows a static uplink to be migrated to BGP without -an outage: +both static and BGP-speaking attachments at the same time, which allows a static uplink to be migrated to BGP: 1. Add a BGP `ExternalAttachment` on a second Border Leaf, pointing at the same `External`. 2. Convert the original attachment from static to BGP (remove its `static` block, add `neighbor` and `switch`). -3. Clear `spec.static.prefixes` on the `External` itself. The API refuses this while any attachment referencing it is - still static, so it can only be done after step 2. +3. Clear `spec.static.prefixes` on the `External` itself, and set `inboundCommunity`/`outboundCommunity` to match + whatever community policy the Edge Device applies (see + [BGP-speaking External object](#bgp-speaking-external-object) above). The API refuses both changes while any + attachment referencing the `External` is still static, so step 3 can only happen after step 2. While a static attachment and a BGP attachment on the same `External` coexist, the static path always wins, so traffic keeps flowing over it during steps 1 and 2. !!! warning - This migration has two sharp edges: - - - Steps 2 and 3 cannot be applied atomically. Until step 3 completes, the Border Leaf configures the - newly-converted BGP link but does not use its routes, so traffic has no working path in between: the - static path stopped being used the moment step 2 landed, and the BGP path isn't usable yet. Apply steps 2 - and 3 back to back to keep this window as short as possible. - - `inboundCommunity`/`outboundCommunity` cannot be set on the `External` while `spec.static.prefixes` is - present, so an `External` that started out purely static will not have them configured. Once the migration - is complete, set them to match whatever community policy the Edge Device applies (see - [BGP-speaking External object](#bgp-speaking-external-object) above). If the Edge Device filters inbound - routes by community, an `External` with no `outboundCommunity` configured will have every route it - advertises silently dropped. + Once step 2 removes the last static attachment, traffic has to use the BGP path, but that path cannot carry + `outboundCommunity` yet: the API forbids setting it while `spec.static.prefixes` is still present, to protect the + static route from being dropped by a community-based route-map while it still exists. If the Edge Device filters + inbound routes by community, as recommended above, every route the Fabric advertises over the new BGP session + gets silently dropped until step 3 completes, so this is a real traffic gap, not a hitless cutover. The gap is + bound by how long the switch's control plane takes to reconcile the change, typically on the order of a minute, + regardless of how quickly the API calls themselves are issued. ### External VPC Peering From d7747288d6c12605f61904640716a5e60ab2bd7d Mon Sep 17 00:00:00 2001 From: Pau Capdevila Date: Mon, 21 Sep 2026 15:46:54 +0200 Subject: [PATCH 4/4] docs: note the outage is avoidable for a fresh BGP session Per review feedback from the feature's author: since this BGP session is new, there's no prior community filter on the Edge Device to conform to. Coordinating with the Edge Device operator to defer community-based filtering until after the migration avoids the gap entirely, when that coordination is possible. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pau Capdevila --- docs/user-guide/external.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index 12093846..098bc941 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -199,6 +199,10 @@ traffic keeps flowing over it during steps 1 and 2. bound by how long the switch's control plane takes to reconcile the change, typically on the order of a minute, regardless of how quickly the API calls themselves are issued. + Since this is a new BGP session (there was no prior BGP config on the Edge Device for this External), this is + avoidable: ask the Edge Device operator to accept routes without a community for this session until step 3 + completes, then add their community-based filter afterward. + ### External VPC Peering To allow a specific VPC to have access to prefixes reachable via an Edge Device, bind the VPC to the corresponding