Skip to content

Wrap up RFD 619 migration#724

Open
taspelund wants to merge 28 commits intomainfrom
trey/rfd_619_wrapup
Open

Wrap up RFD 619 migration#724
taspelund wants to merge 28 commits intomainfrom
trey/rfd_619_wrapup

Conversation

@taspelund
Copy link
Copy Markdown
Contributor

Many types were not fully migrated to the RFD 619 conventions in #611 and #665. This PR seeks to remedy that.

As a whole, this PR is simply a re-organization of existing code rather than a functional change.
It does so by splitting some crates apart (introducing $CRATE-types and $CRATE-types-versions for it) and attempting to bring some order to this chaos. In some cases, types were moved into a more fitting home (e.g. BFD types moving out of rdb/mgd crates and into bfd-types).

The exception to no functional changes is that the operation_id in the OpenAPI spec does change for a handful of methods.
These are all broken out into a new dropshot API version for mg-api: ENDPOINT_RENAME.
This results in clients seeing a different method name when importing the latest API version via mg-admin-client.
Aside from the method/operation_id name change, the API remains byte-compatible.

I had claude help with the grunt work on this one, and the commit messages describe the implementation plan it followed (including some course corrections).

Phase 0: capture baseline (cargo nextest 241 passing, clippy clean,
openapi check fresh) before structural migration to RFD 619 layout.

Phase 1: scaffold three new versions crates and v6/v7/v8 module
directories in mg-types-versions:
- mg-common-types + mg-common-types-versions (new)
- bgp-types + bgp-types-versions (new)
- rdb-types/versions (new sibling under existing rdb-types)
- mg-types/versions: add v6 (rib_exported_string_key),
  v7 (operation_id_cleanup), v8 (bgp_src_addr) module dirs

No types are migrated yet; module directories are empty placeholders.
The new facade crates re-export from latest. mg-common-types-versions
already includes v1::net (TunnelOrigin, Ipv6Prefix, Ipv4Prefix,
IpPrefix) but consumers have not yet been re-pointed; that lands in
Phase 2a.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…lFilter to rdb-types-versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Move Path and BgpPathProperties out of rdb/src/types.rs into
rdb-types-versions: v1::path holds the pre-UNNUMBERED shape (peer is
IpAddr), v5::path holds the UNNUMBERED shape (peer is PeerId,
nexthop_interface added). Conversions live in v5 (newer module);
the BgpPathProperties -> v1 fallback for PeerId::Interface is silent
(Ipv6Addr::UNSPECIFIED). impl Ord for Path and as_stale move to
rdb-types-versions/impls/path.rs. From<StaticRouteKey> for Path stays
in rdb/src/types.rs until StaticRouteKey migrates.

Split mg-types-versions::rib::GetRibResult per version: v1 references
v1::path::Path, v5 references v5::path::Path; latest re-exports v5.
Free fn v5::rib::get_rib_result_into_v1 downgrades for shims.

Version-gate static_list_v{4,6}_routes in mg-api so prior-version docs
keep their v1-shaped Path. Latest endpoints scoped to VERSION_UNNUMBERED..;
shims static_list_v4_routes_v1 (..VERSION_UNNUMBERED) and
static_list_v6_routes_v2 (VERSION_IPV6_BASIC..VERSION_UNNUMBERED) call
the latest impl and downgrade. Both pairs pin operation_id explicitly so
generated clients see one method per endpoint across versions.

OpenAPI: all 11 blessed docs (mg-admin v1..v8, ddm-admin v1, both
*-latest) byte-identical to baseline.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…ions

Move ImportExportPolicyV1 → v1::policy::ImportExportPolicy (suffix dropped;
schemars(rename) annotation no longer needed since the Rust name now matches
the schema name naturally). Move ImportExportPolicy{,4,6} → v4::policy::*.
Conversions From<v1::policy::ImportExportPolicy> for ImportExportPolicy{4,6}
live in the v4 module. The as_ipv4_policy/as_ipv6_policy/from_per_af_policies
inherent methods on the v1 type move into impls/policy.rs.

The combined v4::policy::ImportExportPolicy enum is internal-only (no
JsonSchema), so there is no schema-name collision with v1::policy::Import
ExportPolicy in any blessed OpenAPI doc. Verified all 9 docs byte-identical.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…ypes

Move BgpRouterInfo into v1::router; BfdPeerConfig + SessionMode into
v1::bfd. BfdPeerConfig and SessionMode schemas verified byte-identical
across all 8 blessed mg-admin docs.

The remaining trio (BgpNeighborInfo, BgpUnnumberedNeighborInfo,
BgpNeighborParameters) is not present in any blessed OpenAPI document --
they are internal db-persistence types with vestigial JsonSchema
derives. BgpNeighborParameters references ImportExportPolicy{4,6}, which
live in v4 per the prior Phase 2b sub-step, so the only-prior-versions
rule forces all three into v4::neighbor.

OpenAPI: all 9 blessed docs (mg-admin v1..v8, ddm-admin v1) plus both
*-latest symlinks byte-identical to baseline.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
mg-types-versions/src/initial/bfd.rs was importing rdb::BfdPeerConfig
(a floating identifier from the rdb facade), violating
RFD 619 §determinations-only-prior-versions. Switch to
rdb_types_versions::v1::bfd::BfdPeerConfig.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…rsions

Move the 12 leaf wire-message enumerations (MessageType,
OptionalParameterCode, CapabilityCode, Safi, PathAttributeTypeCode,
AsPathType, ErrorCode, HeaderErrorSubcode, OpenErrorSubcode,
UpdateErrorSubcode, CeaseErrorSubcode, PathOrigin) into
bgp-types-versions::v1::messages, plus Afi into
bgp-types-versions::v4::messages. Their Display/slog::Value impls and
the Afi <-> rdb-types-versions::v1::AddressFamily conversions go to
bgp-types-versions::impls::messages (orphan-rule case 1).

The three From impls that take protocol types as input (From<&Message>
for MessageType, From<PathAttributeValue> for PathAttributeTypeCode,
From<Capability> for CapabilityCode) become free functions in
bgp/src/messages.rs (message_type_of, path_attribute_type_code_of,
capability_code_of) since their input types live in bgp/ and pulling
them into bgp-types-versions would break the leaf-crate property
(orphan-rule case 2). The handful of call sites are updated.

bgp-types-versions::error::WireError is scaffolded with the parse-only
+ leaf wire-error variants (TooSmall, TooLarge, NoMarker, BadLength,
BadVersion, Eom, Parse, Io, Unassigned, Experimental, InvalidCode,
ReservedCapability/Code, ReservedOptionalParameter, InvalidMessageType,
BadBgpIdentifier, MalformedAttributeList, InvalidNlriPrefix,
InvalidPrefixLength, plus the 11 TryFromPrimitiveError variants for the
moved enums). bgp::error::Error gains a #[from] WireError variant for
future ?-upcasting; existing variants stay put because the parse code
that produces them still lives in bgp/.

bgp-types-versions gains nom/num_enum/thiserror/slog/rdb-types-versions
deps plus an optional clap feature (Afi has #[cfg_attr(feature=clap,
derive(ValueEnum))]); the bgp crate's clap feature now passes through.

The migrated types' Rust paths (bgp::messages::TYPE) still resolve via
pub use re-exports, so no downstream code changes beyond the call-site
updates above. Verified all 11 blessed OpenAPI docs sha256-identical to
baseline; cargo fmt --check, cargo clippy --workspace -- -D warnings,
and cargo nextest (241 passed) all clean.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…rsions

Move seven leaf wire-message types into bgp-types-versions::messages:
Tlv, Header, Community, AddPathElement (v1) and BgpNexthop,
Ipv6DoubleNexthop, ExtendedNexthopElement (v4). Header gains the
MAX_MESSAGE_SIZE constant alongside its existing WIRE_SIZE associated
const, both also re-exported from bgp::messages so existing call sites
in bgp::connection_tcp continue to compile unchanged.

Inherent methods on the moved types (Header::new/to_wire/from_wire,
BgpNexthop::from_bytes/to_bytes/byte_len, ExtendedNexthopElement::
is_v4_over_v6/is_v6_over_v4) and their Display/From impls move to
bgp-types-versions::impls::messages (orphan-rule case 1: every input
type is std or already migrated). Header and BgpNexthop parse paths
now produce WireError instead of bgp::Error; bgp::Error already grew
a #[from] WireError variant in chunk 1, so ? propagation through the
session-time call sites is unchanged. WireError gains an
InvalidAddress(String) variant to cover BgpNexthop::from_bytes.

bgp::messages keeps backward-compatible pub use re-exports so the
crate-public Rust paths (bgp::messages::Header etc.) still resolve.
The is_v4_over_v6/is_v6_over_v4 helpers become pub (they were private
methods before, but only consumed from inside bgp/, so widening them
is a no-op for downstream consumers).

Verified all 11 OpenAPI documents fresh with no schema drift; cargo
fmt --check, cargo clippy --workspace -- -D warnings, and cargo
nextest (241 passed) all clean.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…s-versions

Move the MP-BGP PathAttribute family into bgp-types-versions. The
12-variant PathAttributeTypeCode (incorrectly placed at v1::messages in
chunk 1) moves to v4::messages where it belongs; a 10-variant V1 form is
introduced at v1::messages with #[schemars(rename = "PathAttributeTypeCode")]
to keep the v1 admin schema byte-identical.

v4::messages additions: PathAttribute, PathAttributeType,
PathAttributeValue, PathAttributeTypeCode (12-variant), Aggregator,
As4Aggregator, As4PathSegment, MpReachNlri, MpReachIpv4Unicast,
MpReachIpv6Unicast, MpUnreachNlri, MpUnreachIpv4Unicast,
MpUnreachIpv6Unicast, and the path_attribute_flags constants module.

v1::messages additions (the v1 wire-shape compat types, formerly
named *V1 in bgp::messages): Prefix, PathAttribute, PathAttributeType,
PathAttributeTypeCode, PathAttributeValue. These are re-exported from
bgp::messages under their historical *V1 aliases to minimize call-site
churn.

impls/messages.rs gains Display impls for the new types, the
self-contained inherent methods (Aggregator/As4Aggregator
to_wire/from_wire/to_bytes; MpReach/MpUnreach afi/safi/nexthop/
ipv4_unicast/ipv6_unicast/is_empty/len), the v4 → v1 cross-version
From conversions, and reabsorbed-into-From impls for
path_attribute_type_code_of and From<PathAttributeValue> for
PathAttribute.

In bgp/src/messages.rs the type definitions become re-exports from
bgp_types::messages. Wire methods that produce bgp::error::Error or
UpdateParseErrorReason (PathAttribute::to_wire / from_bytes,
PathAttributeType::to_wire / error_action, PathAttributeValue::to_wire /
from_wire, As4PathSegment::to_wire / from_wire, MpReachNlri::to_wire /
from_wire, MpUnreachNlri::to_wire / from_wire) become free fns
(path_attribute_to_wire, path_attribute_from_bytes,
path_attribute_type_to_wire, path_attribute_type_error_action,
path_attribute_value_to_wire, path_attribute_value_from_wire,
as4_path_segment_to_wire, as4_path_segment_from_wire,
mp_reach_nlri_to_wire, mp_reach_nlri_from_wire,
mp_unreach_nlri_to_wire, mp_unreach_nlri_from_wire). Internal call
sites in bgp/src/messages.rs are updated.

WireError::PathAttributeCode in bgp-types-versions::error switches
from v1::messages::PathAttributeTypeCode (10-variant) to
v4::messages::PathAttributeTypeCode (12-variant) since wire parsing
operates on the MP-BGP form.

Verification: cargo fmt --check; cargo clippy --workspace -- -D warnings;
cargo nextest run --workspace (241 passed); cargo run -p xtask -- openapi
check (11 fresh, 0 stale, 0 failed). All blessed mg-admin/ddm-admin
schemas remain sha256-identical to baseline.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…nd to bgp-types-versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…rorSubcode to bgp-types-versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
… RouteRefreshMessage to bgp-types-versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…types-versions, drop UpdateMessage::errors field

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…erParameters families to mg-types-versions

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…fo/FsmStateKindV1 to mg-types-versions

Migrates the v1 and v2 forms of the PeerInfo family to mg-types-versions:
- v1::bgp::FsmStateKind (was params::FsmStateKindV1, 7-variant pre-IPV6_BASIC).
- v1::bgp::DynamicTimerInfo (was params::DynamicTimerInfoV1, 2-field).
- v1::bgp::PeerTimers (was params::PeerTimersV1).
- v1::bgp::PeerInfo (was params::PeerInfoV1).
- v2::bgp::PeerInfo (was params::PeerInfoV2).
- v4::bgp::DynamicTimerInfo (the latest 3-field form, re-exported as latest).

Cross-version conversions in mg-types-versions/src/impls/bgp.rs:
- From<bgp_types_versions::v2::session::FsmStateKind> for v1::bgp::FsmStateKind
- From<v2::bgp::PeerInfo> for v1::bgp::PeerInfo

The latest PeerInfo (v5 shape) and latest PeerTimers (v5 shape) remain in
bgp/src/params.rs because their public fields embed BgpCapability,
PeerCounters, and StaticTimerInfo, all of which are scheduled for sub-chunk
6c. mg-types-versions cannot depend on bgp, so those types must migrate
together. Sub-chunk 6c will pull the remaining PeerInfo/PeerTimers latest
forms across once the unversioned-but-published group lands.

bgp/src/params.rs preserves the existing public surface via re-export
aliases so call sites in mgd/mg-api are unchanged.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…d rdb tail to versions crates

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…ffixed convention

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…rse module

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…dules

Three orphan-rule-adjacent violations found in `mg-types-versions/src/impls/`:

- `From<latest::static_routes::StaticRoute{4,6}> for rdb::StaticRouteKey`
  forced `mg-types-versions` to depend on `rdb` (a business-logic crate).
  Replaced with free fns at the only call site (`mgd/src/static_admin.rs`).
- `From<rdb::db::Rib> for {latest, v1}::rib::Rib` had the same problem.
  Replaced with `rib_latest_from_rdb` / `rib_v1_from_rdb` free fns in
  `mg-types/src/rib.rs` (the facade crate, which already depends on both
  `rdb` and `rdb-types-versions`).

`mg-types-versions` no longer depends on `rdb`. The Phase 3 audit
(`rg "use {bgp,rdb,mg_common,ddm}::"` and the corresponding `_types::`
sweep across all `*-types-versions/src/`) is now clean.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…or migrated paths

Adds `docs/types-organization.md` as a tangible reference for where
schema-published types now live: facade vs versions crate pairs, the
crate map, a type -> crate quick reference, and recipes for adding new
types and new API versions. Calls out the leaf-crate rule, the
internal-vs-published distinction, and the boundary helpers (free
functions in the facade crate or at call sites) used when both source
and target of a conversion are foreign.

`docs/bgp-architecture.md` and `docs/bgp-unnumbered.md` were scanned for
stale type-path references and are unchanged: they reference types only
by short name (`MessageHistory`, `FsmStateKind`, `Path`, `PeerId`),
which remain valid via the facade re-exports.

`README.md` was scanned for moved type paths and is unchanged.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
…ports

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Adds a dedicated facade+versions crate pair for BFD types and migrates
`BfdPeerState`, `BfdPeerConfig`, `BfdPeerInfo`, and `SessionMode` into
`bfd-types-versions::v1`. This was the last leaf-crate-rule violation in
`mg-types-versions` — its `bfd.workspace = true` dependency (and the
transitive edge into `rdb`/`mg-common`) is now gone.

Type relocations:
- `BfdPeerState` (was `bfd::BfdPeerState`) -> `bfd_types_versions::v1`,
  with the `wire_format()` helper carried along as an inherent method.
- `BfdPeerConfig` and `SessionMode` (was
  `rdb_types_versions::v1::bfd::*`) -> `bfd_types_versions::v1`.
- `BfdPeerInfo` (was `mg_types_versions::v1::bfd`) ->
  `bfd_types_versions::v1`. `mg_types_versions::v1::bfd` keeps only
  `DeleteBfdPeerPathParams` (an admin-API path-params shape, not a BFD
  type proper).

Call-site updates: `bfd`, `rdb`, `mg-api`, and `mgd` now import BFD
types from the `bfd-types` facade. `bfd::BfdPeerState` continues to work
via a `pub use` re-export.

OpenAPI verification: `cargo run -p xtask -- openapi check` reports zero
stale documents — all schemas (`BfdPeerState`, `BfdPeerConfig`,
`BfdPeerInfo`, `SessionMode`) emit byte-identical JsonSchema output, so
no client regeneration is required.

Drive-by: also fixes a stale doc comment in `bgp/src/session.rs` that
referred to the (since-renamed) `UpdateMessage::from_wire()` method;
the actual function is the free fn `update_message_from_wire`.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Extends the per-domain test-* jobs to cover their corresponding type
crates so any future tests added there get picked up automatically:

- test-bfd: adds `bfd-types` and `bfd-types-versions`.
- test-bgp: adds `bgp-types` and `bgp-types-versions` (alongside bgp);
  adds `mg-types` and `mg-types-versions` (alongside mgd).
- test-rdb: adds `rdb-types` and `rdb-types-versions` (alongside rdb).

Bare `-p rdb-types` is ambiguous because omicron transitively pins an
upstream copy of rdb-types via mg-admin-client, leaving two rdb-types
nodes in Cargo.lock. The Package ID Spec form
`path+file://$PWD/../rdb-types` selects the local crate unambiguously.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
Squashes adjacent same-prefix `pub use`/`use` lines into single
braced statements and lifts scattered branch-added re-exports to the
top of each file. Touches only items the branch already added or
moved; pre-existing imports and test-module imports are left alone.

- bgp/src/messages.rs: 20 scattered `pub use bgp_types::messages::*`
  and `pub use bgp_types_versions::*` lines -> four consolidated
  blocks at the top.
- bgp/src/session.rs: three scattered uses -> top of file; trims a
  stale doc-comment block whose content is now redundant.
- bgp/src/params.rs: drops single-use `v{1,2,4,5,8}_bgp` aliases in
  favor of fully-qualified `pub use mg_types_versions::vN::bgp::{...}`.
- mg-types/versions/src/latest.rs, mg-common-types/versions/src/latest.rs,
  mg-types/src/rib.rs, bfd/src/lib.rs: minor adjacent-run merges.

OpenAPI verified byte-identical (`cargo xtask openapi check`: all 10
documents fresh). 152 of 152 bgp+bfd tests still pass.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
@taspelund taspelund requested a review from rcgoodfellow April 28, 2026 07:29
@taspelund taspelund self-assigned this Apr 28, 2026
@taspelund taspelund added ddm Delay Driven Multipath dependencies mgd Maghemite daemon rust Pull requests that update rust code labels Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ddm Delay Driven Multipath dependencies mgd Maghemite daemon rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant