Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
unknown member VNIs, mixed same-request L2VNI+ES edits, RR-only/no-segment
actor deployments, and live segment actor spawn from a zero-ES startup model.

- **EVPN Type 5 overlay-index gateway injection.** `AddEvpnRoute` and
`rustbgpctl evpn add-ip-prefix` can now inject a Type 5 IP Prefix route with
an optional non-zero Gateway Address for controller-supplied overlay-index
testing. Empty `gateway` preserves the existing interface-less gateway-zero
shape; non-zero ESI and native local overlay-index origination remain out of
scope.

- **ADR-0063 EVPN runtime convergence — single Ethernet Segment redefine.**
`EvpnService.ApplyEvpnRuntime` can now commit exactly one redefined
`[[ethernet_segments]]` entry when the candidate has no L2VNI, IP-VRF, or
Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ the active planning surface.
| P1 | **Mega-module splits — engineering velocity** | Four source files have grown past comfortable rebase boundaries and now serialize every contributor: `src/peer_manager.rs` (~6.4k LoC), `src/evpn_originator.rs` (~4.1k), `src/main.rs` (~4.6k), `crates/api/src/event_service.rs` (~2.3k). Every multi-PR batch in the last two release cycles has hit at least one conflict here, and the `#[expect(clippy::too_many_lines)]` annotation count is up to 90 workspace-wide. Splitting them lets parallel PRs land cleanly and unblocks the cleanups in the sustainability subsection below. | Each of the four modules either drops below ~2k LoC or gains a clear top-level module structure (sub-modules per concern) so future PRs can land in narrower files; `#[expect(clippy::too_many_lines)]` count trends down rather than up. |
| P2 | **EVPN runtime instance mutation implementation** | `[[evpn_instances]]`, `[[evpn_ip_vrfs]]`, and `[[ethernet_segments]]` are still startup-pinned. ADR-0063 now defines the safe mutation contract: a single command-driven EVPN coordinator, validation-first model updates, and explicit drain/replay across IMET, Type 2, Type 5, DF/ES, and Linux owned state. The foundation has a generationed runtime model, `GetEvpnRuntime` / `rustbgpctl evpn runtime` status, the coordinator core / commit gate, the public `EvpnService.ApplyEvpnRuntime` API contract wired through daemon-owned parsing, full candidate validation, validate-only planning, no-op apply, credential-redacted audit summaries, the IMET controller with per-VNI originate/withdraw, and an Ethernet Segment owner/control surface that keeps Type 1/4 state under `src/evpn_segment.rs`. A daemon actor converger now commits seven live shapes — a **single L2VNI add**, a **single L2VNI delete** when the VNI is not an Ethernet Segment member (including IP-VRF deployments where only derived link metadata changes), a **single IP-VRF add**, a **single standalone IP-VRF delete** with no L2VNI links, and a **single Ethernet Segment add/delete/redefine** — via ordered IMET origination/withdraw + IP-VRF metadata / effective-table / desired-ES-snapshot republish to the dataplane supervisor, Type 2 / Type 5 originators, SVI task, and segment actor, with rollback on partial failure; other non-noop shapes still fail closed without advancing or degrading the committed generation. | Implement the remaining convergence shapes — linked IP-VRF delete / tenant teardown, ES-aware L2VNI delete, L2VNI/IP-VRF redefine, mixed L2VNI + IP-VRF, multi-element edits, and an ES referencing a runtime-added member VNI (segment actor is startup-pinned) — so all non-noop EVPN runtime edits can commit; keep SIGHUP restart-required until the coordinator can safely converge them ([#210](https://github.com/lance0/rustbgpd/issues/210)). |
| P2 | **Runtime-vs-file diff and config UX** | gRPC owns truth after startup; operators need better tooling to compare a candidate TOML to live runtime state. | `rustbgpd --diff` / CLI path can compare candidate file to effective runtime including peer groups and hot-applied policy. |
| P2 | **Overlay-index IRB / EVPN remaining standards** | Needed for fuller data-center EVPN parity, but lower adoption value than hardening the shipped Interface-less path. Receive-side RFC 9135 §9.2 recursion now resolves non-zero Type 5 Gateway Address routes through unambiguous linked Type 2 MAC/IP state, keeps unresolved or ambiguous gateways fail-closed, and exposes current projection-drop counts through bounded Prometheus `evpn_ip_vrf_remote_prefix_drops{vrf,reason}` labels plus `IpVrfState.remote_prefix_drop_counts` in gRPC / CLI status. | Add local origination and a first protected overlay-index interop smoke. |
| P2 | **Overlay-index IRB / EVPN remaining standards** | Needed for fuller data-center EVPN parity, but lower adoption value than hardening the shipped Interface-less path. Receive-side RFC 9135 §9.2 recursion now resolves non-zero Type 5 Gateway Address routes through unambiguous linked Type 2 MAC/IP state, keeps unresolved or ambiguous gateways fail-closed, exposes current projection-drop counts through bounded Prometheus `evpn_ip_vrf_remote_prefix_drops{vrf,reason}` labels plus `IpVrfState.remote_prefix_drop_counts` in gRPC / CLI status, and lets controllers inject non-zero Gateway Address Type 5 routes for targeted overlay-index testing. | Add native local origination and a first protected overlay-index interop smoke. |

### Sustainability / Engineering Velocity

Expand Down Expand Up @@ -617,7 +617,7 @@ Each moves overall parity 3-5% while disproportionately improving real-world usa
- [x] **EVPN Phase 3 partial — ADR-0059 aliasing dataplane ECMP via FDB nexthop groups** (v0.19.0, ADR-0059, PRs #84 / #86 / #87 / #88 / #89) — multi-homed Type 2 routes on the receive path now program FDB nexthop groups (`NDA_NH_ID` / `NHA_FDB`). Slices 1-4 plus M40 protected self-hosted kernel-dataplane smoke against FRR EVPN-MH 10.3.1 all shipped on `main`. M40 16/16 PASS first-shot validates kernel programming under the expected `NHG_TAG | n` / `VTEP_NH_TAG | n` tag scheme. Slice 3.5 follow-ups (periodic `RTM_GETNEXTHOP` drift recovery, `apply_aliasing_ecmp` operator off-switch, IPv6 alias members) deferred at v0.19.0 and shipped post-release in PRs #91 / #92 / #93.
- [x] **EVPN Phase 3 partial — ADR-0059 slice 3.5 aliasing-ECMP hardening** (v0.20.0, ADR-0059, PRs #91 / #92 / #93) — the three slice 3.5 follow-ups have shipped on `main`: PR 1 (`apply_aliasing_ecmp` per-instance off-switch — `[[evpn_instances]].apply_aliasing_ecmp` TOML knob, default `true`, restart-required, diff layer takes `&EvpnInstanceTable` to gate the FDB-NHG dispatch on the per-VNI bit), PR 2 (periodic `RTM_GETNEXTHOP` drift recovery — every `periodic_dump` interval the reconcile actor re-dumps tagged kernel NHIDs and heals missing/mis-shaped per-VTEP members, missing or member-set-drifted groups, stale tagged FDB rows from a prior daemon, and untracked tagged NHIDs in kernel; permanent dump failures latch drift off mirroring startup-adoption semantics; the `(VNI, MAC)` desired-intent guard prevents stale-row cleanup from removing forwarding state for a MAC we still intend to program), PR 3 (homogeneous IPv6 alias members — `encode_add_fdb_member` picks `AF_INET` / `AF_INET6` from the gateway form, `NexthopSocket::add_fdb_member` no longer rejects v6, diff layer's `all_v4` predicate becomes `all_same_family`). Post-v0.20 cleanup: the obsolete `NexthopError::Ipv6Unsupported` compatibility variant has been removed on `main` for v0.21.0.
- [x] **EVPN Phase 3 — Production-default multi-homing enforcement** — ADR-0059 aliasing dataplane ECMP via FDB nexthop groups has **fully shipped on `main`**: slice 1 (portable intent — `RemoteMacEntry::alias_group_key`, PR #84), slice 2 (`nexthop_raw` netlink primitive, PR #86), slice 3a (state types + apply primitive + CVE-2025-39851 guard, PR #87), slice 3b (PR #88, the operational-behavior-change slice — diff Pass 1b + reconcile actor coordinator + `NexthopOps` impls + startup NHID adoption + Docker-runnable netns test + actor-level FDB-NHG coverage), slice 4 (PR #89, M40 protected self-hosted kernel-dataplane smoke against FRR EVPN-MH 10.3.1 — 16/16 PASS first-shot validates that rustbgpd consumes real FRR EVPN-MH routes and programs an FDB-NHG on the receiving VTEP, with the expected `NHG_TAG | n` / `VTEP_NH_TAG | n` tag scheme and a clean drain-to-single-dst transition when an alias withdraws), and slice 3.5 (PRs #91 / #92 / #93 — operator off-switch, periodic drift recovery, IPv6 alias members). M39 / M40 / M42 and the `fdb_nhg` / `fib_runtime` Docker selectors are now in the protected self-hosted `kernel-dataplane` CI workflow. The Gate 8b 24 h MAC-churn soak plus M37 local-origination 24 h soak cleared the default-flip gate; `apply_bum_enforcement` and `apply_aliasing_ecmp` now default to `true` while explicit `false` remains supported for opt-out deployments.
- [ ] **EVPN Gate 9 follow-ups — overlay-index IRB** — Gate 9 slice 6 ships the Interface-less symmetric IRB model, auto-derived Route Targets (RFC 8365 §5.1.2.1) are available as an explicit config opt-in for `[[evpn_instances]]` and `[[evpn_ip_vrfs]]`, and receive-side RFC 9135 §9.2 recursion now resolves non-zero Type 5 Gateway Address routes through linked Type 2 MAC/IP state in L2VNIs linked to the target IP-VRF, tie-breaking contenders by MAC mobility sequence and resolving a multi-homed single MAC to a deterministic next_hop. Missing links, unresolved gateways, gateways resolving to multiple distinct MACs, self-originated rows, quarantined MACs, mass-withdraw-filtered Type 2 rows, RT misses, and L3VNI mismatches stay fail-closed. Remaining standards-completeness items: local overlay-index origination, multi-homed-gateway ECMP, API/status detail for recursive drops, and a protected interop smoke.
- [ ] **EVPN Gate 9 follow-ups — overlay-index IRB** — Gate 9 slice 6 ships the Interface-less symmetric IRB model, auto-derived Route Targets (RFC 8365 §5.1.2.1) are available as an explicit config opt-in for `[[evpn_instances]]` and `[[evpn_ip_vrfs]]`, and receive-side RFC 9135 §9.2 recursion now resolves non-zero Type 5 Gateway Address routes through linked Type 2 MAC/IP state in L2VNIs linked to the target IP-VRF, tie-breaking contenders by MAC mobility sequence and resolving a multi-homed single MAC to a deterministic next_hop. Controller injection can synthesize non-zero Gateway Address Type 5 routes while native IP-VRF origination remains Interface-less. Missing links, unresolved gateways, gateways resolving to multiple distinct MACs, self-originated rows, quarantined MACs, mass-withdraw-filtered Type 2 rows, RT misses, and L3VNI mismatches stay fail-closed. Remaining standards-completeness items: native local overlay-index origination, multi-homed-gateway ECMP, protected interop smoke, and any future per-route recursive-drop detail operators prove they need beyond the current bounded counters.
- [ ] **EVPN Phase 4 — Adjacent standards** — PBB-EVPN (RFC 7623), EVPN-MVPN integration (RFC 9251, Route Types 6/7/8), MPLS encapsulation, Add-Path for EVPN (RFC 9252). Service-provider EVPN use cases.
- [ ] **EVPN polish + observability gaps** (low-priority, Phase 1 known limitations):
- [x] Type 5 (IP Prefix) interop test against FRR (M30b, `tests/interop/m30b-evpn-type5-frr.clab.yml`) — single-VTEP origination from FRR vrf1 / L3VNI 100; rustbgpd RR decodes the Type 5 NLRI and surfaces RD, prefix, next-hop, VNI label, RT extended community, and VXLAN encap via `ListEvpnRoutes`. Withdrawal validated. RR-reflection of Type 5 (2-VTEP topology, ORIGINATOR_ID + CLUSTER_LIST asserts) tracked as M30c.
Expand Down
Loading
Loading