Skip to content

MRIB: Multicast RIB implementation#675

Open
zeeshanlakhani wants to merge 20 commits into
mainfrom
zl/mrib
Open

MRIB: Multicast RIB implementation#675
zeeshanlakhani wants to merge 20 commits into
mainfrom
zl/mrib

Conversation

@zeeshanlakhani

@zeeshanlakhani zeeshanlakhani commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Implements the Multicast Routing Information Base (MRIB) for multicast support. The MRIB follows a two-table architecture (mrib_inmrib_loc) with RPF verification against the unicast RIB when sources are provided.

This PR includes:

  • rdb/src/mrib/mod.rs: core MRIB with route storage and change notifications
  • rdb/src/mrib/rpf.rs: RPF verification using poptrie for O(1) LPM lookups. A single long-lived worker rebuilds the cache on unicast loc-RIB change(s), coalescing mutation bursts through a bounded pending slot, and the cache is eventually consistent with the RIB
  • rdb/src/db.rs: MRIB persistence with sled transactions. RPF rebuild triggers ride the existing change-notification path
  • rdb/src/types.rs: validated multicast types (UnderlayMulticastIpv6, Vni)
  • mg-api/src/lib.rs: API v12 (VERSION_MULTICAST_SUPPORT) endpoints, following RFD 619 pattern (atop [mg-api] migrate to RFD 619 pattern #665)
  • mg-api-types/versions/src/multicast_support: versioned API types
  • mgd/src/mrib_admin.rs: HTTP handlers bridging API to MRIB
  • mgadm/src/mrib.rs: read-only CLI for MRIB inspection (Omicron programs the MRIB via mg-api)

Omicron is the source of truth for multicast overlay/underlay groups/addresses.

@zeeshanlakhani

Copy link
Copy Markdown
Contributor Author

@taspelund Just reopening this pointing back to main (I merged the previous PR into my multicast-e2e branch).

@zeeshanlakhani
zeeshanlakhani force-pushed the zl/mrib branch 3 times, most recently from 22b7b3e to 954f63a Compare March 31, 2026 22:31
Comment thread rdb/src/error.rs Outdated
Comment thread rdb/src/types.rs Outdated
zeeshanlakhani added a commit that referenced this pull request Apr 2, 2026
…amming

Adds multicast group subscription distribution to the DDM exchange
protocol with a V4 version bump (frozen V3 types for wire compat).

Key changes:
- V4 exchange protocol with multicast support (V3 peers are unaffected)
- UnderlayMulticastIpv6 validated newtype moved to mg-common (ff04::/64) (moved from rdb types)
- MRIB->DDM sync in mg-lower/mrib.rs
- OPTE M2P table programming on learned multicast routes
- Atomic update_imported_mcast on Db (single lock for import/delete/diff, which is a bit different from the tunnel work)
- Collapsed send_update dispatch
- Shared pull handler helpers (collect_underlay_tunnel, collect_multicast)
- MulticastPathHop constructor
- Some serde round-trip and validation tests, including for version handling

Stacked on zl/mrib (MRIB: Multicast RIB implementation [#675](#675)).
zeeshanlakhani added a commit that referenced this pull request Apr 2, 2026
Adds multicast group subscription distribution to the DDM exchange
protocol with a V4 version bump (frozen V3 types for wire compat).

Key changes:
- V4 exchange protocol with multicast support (V3 peers are unaffected)
- UnderlayMulticastIpv6 validated newtype moved to mg-common (ff04::/64) (moved from rdb types)
- MRIB->DDM sync in mg-lower/mrib.rs
- OPTE M2P hooks for learned multicast routes (requires OPTE #924)
- Atomic update_imported_mcast on Db (single lock for import/delete/diff, which is a bit different from the tunnel work)
- Collapsed send_update dispatch
- Shared pull handler helpers (collect_underlay_tunnel, collect_multicast)
- MulticastPathHop constructor
- Some serde round-trip and validation tests, including for version handling

Stacked on zl/mrib (MRIB: Multicast RIB implementation [#675](#675)).
zeeshanlakhani added a commit that referenced this pull request Apr 2, 2026
Adds multicast group subscription distribution to the DDM exchange
protocol with a V4 version bump (frozen V3 types for wire compat).

Key changes:
- V4 exchange protocol with multicast support (V3 peers are unaffected)
- UnderlayMulticastIpv6 validated newtype moved to mg-common (ff04::/64) (moved from rdb types)
- MRIB->DDM sync in mg-lower/mrib.rs
- OPTE M2P hooks for learned multicast routes (requires OPTE #924)
- Atomic update_imported_mcast on Db (single lock for import/delete/diff, which is a bit different from the tunnel work)
- Collapsed send_update dispatch
- Shared pull handler helpers (collect_underlay_tunnel, collect_multicast)
- MulticastPathHop constructor
- Some serde round-trip and validation tests, including for version handling

Stacked on zl/mrib (MRIB: Multicast RIB implementation [#675](#675)).
zeeshanlakhani added a commit that referenced this pull request Apr 7, 2026
Adds multicast group subscription distribution to the DDM exchange
protocol with a V4 version bump (frozen V3 types for wire compat).

Key changes:
- V4 exchange protocol with multicast support (V3 peers are unaffected)
- UnderlayMulticastIpv6 validated newtype moved to mg-common (ff04::/64) (moved from rdb types)
- MRIB->DDM sync in mg-lower/mrib.rs
- OPTE M2P hooks for learned multicast routes (requires OPTE #924)
- Atomic update_imported_mcast on Db (single lock for import/delete/diff, which is a bit different from the tunnel work)
- Collapsed send_update dispatch
- Shared pull handler helpers (collect_underlay_tunnel, collect_multicast)
- MulticastPathHop constructor
- Some serde round-trip and validation tests, including for version handling

Stacked on zl/mrib (MRIB: Multicast RIB implementation [#675](#675)).
@zeeshanlakhani zeeshanlakhani self-assigned this Apr 16, 2026
@zeeshanlakhani
zeeshanlakhani requested a review from taspelund May 21, 2026 00:07
@zeeshanlakhani

Copy link
Copy Markdown
Contributor Author

@taspelund all the stuff on main has been merged in btw.

The version 11 (MULTICAST_SUPPORT) MRIB types pulled omicron_common into
mg-api-types/versions for two things: the multicast address constants and
the Vni newtype. Because omicron consumes the client and api-types crates,
a normal dependency on omicron from any of them closes a build cycle, which
the `no-omicron-deps-in-client-crates` CI job rejects.

This PR makes two changes to keep that boundary clean:

The multicast address constants are duplicated into client-common::address,
the cycle-free leaf crate. It's opportune for them to be reachable at
compile time because the validated address newtypes check them at
deserialization via serde. We include test module asserts where each "copy"
is expected to match omicron_common. omicron_common remains a dev-dependency,
keeping it out of the dependency tree the CI job inspects.

On `omicron_common::Vni`, it is replaced by a local Vni(u32) newtype in mrib.rs,
alongside the other validated wire types. It enforces the 24-bit Geneve
range (RFC 8926 Section 3.3) at construction, and, via serde, at deserialization,
so an out-of-range identifier arriving over the API is rejected at the boundary.
`#[schemars(transparent)]` keeps the OpenAPI schema, and the generated client, a
bare uint32, for downstream callers.

Note: The MAX_VNI and DEFAULT_MULTICAST_VNI constants are pinned to omicron's
by the same dev-dependency drift guard.

The long-term home for both copies is probably oxnet, which is the leaf crate
omicron, dendrite, and maghemite already share.
zeeshanlakhani added a commit that referenced this pull request Jun 10, 2026
Adds multicast group subscription distribution to the DDM exchange
protocol with a V4 version bump (frozen V3 types for wire compat).

Key changes:
- V4 exchange protocol with multicast support (V3 peers are unaffected)
- UnderlayMulticastIpv6 validated newtype moved to mg-common (ff04::/64) (moved from rdb types)
- MRIB->DDM sync in mg-lower/mrib.rs
- OPTE M2P hooks for learned multicast routes (requires OPTE #924)
- Atomic update_imported_mcast on Db (single lock for import/delete/diff, which is a bit different from the tunnel work)
- Collapsed send_update dispatch
- Shared pull handler helpers (collect_underlay_tunnel, collect_multicast)
- MulticastPathHop constructor
- Some serde round-trip and validation tests, including for version handling

Stacked on zl/mrib (MRIB: Multicast RIB implementation [#675](#675)).
This replaces the interval-driven poptrie rebuild with a single long-lived
worker that rebuilds on loc-RIB change. Mutation batches already end
with a change notification, so `notify()` now triggers the rebuild as
well. Paths that bypass notification (bestpath re-runs, peer staleness marking,
direct path removal) still trigger explicitly.

This long-lived worker keeps memory bounded with a one-slot pending queue per
address family, where requests arriving within a fixed coalescing window
merge, and distinct changed prefixes widen to a full sweep.

Completed snapshots install unconditionally. A trigger that lands during a build
leaves its request in the pending slot, so a possibly stale install is followed
by a rebuild from a newer snapshot 1 coalescing window later. Installs are
serialized in the single worker, so each is newer than the last. After updates
quiesce, the final rebuild converges to the current RIB.

Optimizations:
- Snapshots derive the compact `RpfNexthops` payload in the same pass under the
RIB lock, so full path sets are never cloned, and `get_rpf_neighbor` selects a
neighbor without cloning the path set.
- The linear-scan fallback now also matches /0 default routes.

Concurrency between inline derivations and cache swaps uses a `Generation`
counter, modeled on `omicron_common::api::external::Generation`. Every cache
swap advances the generation, and `update_mrib_loc` snapshots it before a
lookup and re-derives if a swap intervened. Retries are bounded, and on
exhaustion a targeted revalidation pass is queued.

Static multicast persistence is configuration-only. `rpf_neighbor` is derived
from the unicast RIB at load and revalidation time, so it is normalized to
`None` on disk, and timestamps merge against the previously persisted entry
so idempotent upserts do not rewrite them. Persistence completes before the
MRIB publishes the change to watchers.

We also added a why section for having this cache and async machinery.

Validation fixes:
- IPv6 multicast scope classifies on the RFC 4291 scope nibble, rejecting
  reserved scopes 0 and F (RFC 7346) alongside interface- and link-local.
- IPv6 SSM classification narrows to FF3x::/32 per RFC 4607, so RFC 3306
  unicast-prefix-based addresses with a nonzero network prefix are no longer
  treated as SSM.
- Cross-family RPF neighbors are accepted, since derivation from the unicast
  RIB may resolve v4 routes through v6 nexthops (RFC 8950 style).

With these changes, the rebuild-interval setting and its plumbing are removed,
including the admin API endpoints and a regeneration of the unblessed v12
OpenAPI spec.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants