Skip to content

Commit

Permalink
plumb static route local preference (#6361)
Browse files Browse the repository at this point in the history
  • Loading branch information
rcgoodfellow authored Aug 21, 2024
1 parent 6dde3f8 commit 14b94f7
Show file tree
Hide file tree
Showing 34 changed files with 175 additions and 63 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,8 @@ macaddr = { version = "1.0.1", features = ["serde_std"] }
maplit = "1.0.2"
mockall = "0.13"
newtype_derive = "0.1.6"
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "220dd026e83142b83bd93123f465a64dd4600201" }
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "220dd026e83142b83bd93123f465a64dd4600201" }
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "73e63eaae3fe616bd7c48a20c69736d7e025836b" }
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "73e63eaae3fe616bd7c48a20c69736d7e025836b" }
multimap = "0.10.0"
nexus-auth = { path = "nexus/auth" }
nexus-client = { path = "clients/nexus-client" }
Expand Down
3 changes: 3 additions & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,9 @@ pub struct SwitchPortRouteConfig {
/// The VLAN identifier for the route. Use this if the gateway is reachable
/// over an 802.1Q tagged L2 segment.
pub vlan_id: Option<u16>,

/// Local preference indicating priority within and across protocols.
pub local_pref: Option<u32>,
}

/*
Expand Down
3 changes: 3 additions & 0 deletions common/src/api/internal/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ pub struct RouteConfig {
/// The VLAN id associated with this route.
#[serde(default)]
pub vlan_id: Option<u16>,
/// The local preference associated with this route.
#[serde(default)]
pub local_pref: Option<u32>,
}

#[derive(
Expand Down
1 change: 1 addition & 0 deletions nexus/db-model/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ table! {
dst -> Inet,
gw -> Inet,
vid -> Nullable<Int4>,
local_pref -> Nullable<Int8>,
}
}

Expand Down
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::collections::BTreeMap;
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(87, 0, 0);
pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(88, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -29,6 +29,7 @@ static KNOWN_VERSIONS: Lazy<Vec<KnownVersion>> = Lazy::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(88, "route-local-pref"),
KnownVersion::new(87, "add-clickhouse-server-enum-variants"),
KnownVersion::new(86, "snapshot-replacement"),
KnownVersion::new(85, "add-migrations-by-time-created-index"),
Expand Down
5 changes: 4 additions & 1 deletion nexus/db-model/src/switch_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ pub struct SwitchPortRouteConfig {
pub dst: IpNetwork,
pub gw: IpNetwork,
pub vid: Option<SqlU16>,
pub local_pref: Option<SqlU32>,
}

impl SwitchPortRouteConfig {
Expand All @@ -563,8 +564,9 @@ impl SwitchPortRouteConfig {
dst: IpNetwork,
gw: IpNetwork,
vid: Option<SqlU16>,
local_pref: Option<SqlU32>,
) -> Self {
Self { port_settings_id, interface_name, dst, gw, vid }
Self { port_settings_id, interface_name, dst, gw, vid, local_pref }
}
}

Expand All @@ -576,6 +578,7 @@ impl Into<external::SwitchPortRouteConfig> for SwitchPortRouteConfig {
dst: self.dst.into(),
gw: self.gw.into(),
vlan_id: self.vid.map(Into::into),
local_pref: self.local_pref.map(Into::into),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions nexus/db-queries/src/db/datastore/switch_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,7 @@ async fn do_switch_port_settings_create(
route.dst.into(),
route.gw.into(),
route.vid.map(Into::into),
route.local_pref.map(Into::into),
));
}
}
Expand Down
90 changes: 51 additions & 39 deletions nexus/src/app/background/tasks/sync_switch_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,7 @@ impl BackgroundTask for SwitchPortSettingsManager {
destination: r.dst.into(),
nexthop: r.gw.ip(),
vlan_id: r.vid.map(|x| x.0),
local_pref: r.local_pref.map(|x| x.0),
})
.collect(),
switch: *location,
Expand Down Expand Up @@ -1455,7 +1456,8 @@ fn build_sled_agent_clients(
sled_agent_clients
}

type SwitchStaticRoutes = HashSet<(Ipv4Addr, Prefix4, Option<u16>)>;
type SwitchStaticRoutes =
HashSet<(Ipv4Addr, Prefix4, Option<u16>, Option<u32>)>;

fn static_routes_to_del(
current_static_routes: HashMap<SwitchLocation, SwitchStaticRoutes>,
Expand All @@ -1471,10 +1473,11 @@ fn static_routes_to_del(
// if it's on the switch but not desired (in our db), it should be removed
let stale_routes = routes_on_switch
.difference(routes_wanted)
.map(|(nexthop, prefix, vlan_id)| StaticRoute4 {
.map(|(nexthop, prefix, vlan_id, local_pref)| StaticRoute4 {
nexthop: *nexthop,
prefix: *prefix,
vlan_id: *vlan_id,
local_pref: *local_pref,
})
.collect::<Vec<StaticRoute4>>();

Expand All @@ -1488,10 +1491,11 @@ fn static_routes_to_del(
// if no desired routes are present, all routes on this switch should be deleted
let stale_routes = routes_on_switch
.iter()
.map(|(nexthop, prefix, vlan_id)| StaticRoute4 {
.map(|(nexthop, prefix, vlan_id, local_pref)| StaticRoute4 {
nexthop: *nexthop,
prefix: *prefix,
vlan_id: *vlan_id,
local_pref: *local_pref,
})
.collect::<Vec<StaticRoute4>>();

Expand Down Expand Up @@ -1538,10 +1542,11 @@ fn static_routes_to_add(
};
let missing_routes = routes_wanted
.difference(routes_on_switch)
.map(|(nexthop, prefix, vlan_id)| StaticRoute4 {
.map(|(nexthop, prefix, vlan_id, local_pref)| StaticRoute4 {
nexthop: *nexthop,
prefix: *prefix,
vlan_id: *vlan_id,
local_pref: *local_pref,
})
.collect::<Vec<StaticRoute4>>();

Expand Down Expand Up @@ -1590,7 +1595,12 @@ fn static_routes_in_db(
}
IpAddr::V6(_) => continue,
};
routes.insert((nexthop, prefix, route.vid.map(|x| x.0)));
routes.insert((
nexthop,
prefix,
route.vid.map(|x| x.0),
route.local_pref.map(|x| x.0),
));
}

match routes_from_db.entry(*location) {
Expand Down Expand Up @@ -1768,44 +1778,46 @@ async fn static_routes_on_switch<'a>(
let mut routes_on_switch = HashMap::new();

for (location, client) in mgd_clients {
let static_routes: SwitchStaticRoutes =
match client.static_list_v4_routes().await {
Ok(routes) => {
let mut flattened = HashSet::new();
for (destination, paths) in routes.iter() {
let Ok(dst) = destination.parse() else {
error!(
log,
"failed to parse static route destination: \
let static_routes: SwitchStaticRoutes = match client
.static_list_v4_routes()
.await
{
Ok(routes) => {
let mut flattened = HashSet::new();
for (destination, paths) in routes.iter() {
let Ok(dst) = destination.parse() else {
error!(
log,
"failed to parse static route destination: \
{destination}"
);
continue;
);
continue;
};
for p in paths.iter() {
let nh = match p.nexthop {
IpAddr::V4(addr) => addr,
IpAddr::V6(addr) => {
error!(
log,
"ipv6 nexthops not supported: {addr}"
);
continue;
}
};
for p in paths.iter() {
let nh = match p.nexthop {
IpAddr::V4(addr) => addr,
IpAddr::V6(addr) => {
error!(
log,
"ipv6 nexthops not supported: {addr}"
);
continue;
}
};
flattened.insert((nh, dst, p.vlan_id));
}
flattened.insert((nh, dst, p.vlan_id, p.local_pref));
}
flattened
}
Err(_) => {
error!(
&log,
"unable to retrieve routes from switch";
"switch_location" => ?location,
);
continue;
}
};
flattened
}
Err(_) => {
error!(
&log,
"unable to retrieve routes from switch";
"switch_location" => ?location,
);
continue;
}
};
routes_on_switch.insert(*location, static_routes);
}
routes_on_switch
Expand Down
1 change: 1 addition & 0 deletions nexus/src/app/rack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ impl super::Nexus {
dst: r.destination,
gw: r.nexthop,
vid: r.vlan_id,
local_pref: r.local_pref,
})
.collect();

Expand Down
1 change: 1 addition & 0 deletions nexus/tests/integration_tests/switch_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ async fn test_port_settings_basic_crud(ctx: &ControlPlaneTestContext) {
dst: "1.2.3.0/24".parse().unwrap(),
gw: "1.2.3.4".parse().unwrap(),
vid: None,
local_pref: None,
}],
},
);
Expand Down
4 changes: 4 additions & 0 deletions nexus/types/src/external_api/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,10 @@ pub struct Route {

/// VLAN id the gateway is reachable over.
pub vid: Option<u16>,

/// Local preference for route. Higher preference indictes precedence
/// within and across protocols.
pub local_pref: Option<u32>,
}

/// Select a BGP config by a name or id.
Expand Down
8 changes: 8 additions & 0 deletions openapi/bootstrap-agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,14 @@
}
]
},
"local_pref": {
"nullable": true,
"description": "The local preference associated with this route.",
"default": null,
"type": "integer",
"format": "uint32",
"minimum": 0
},
"nexthop": {
"description": "The nexthop/gateway address.",
"type": "string",
Expand Down
8 changes: 8 additions & 0 deletions openapi/nexus-internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -4665,6 +4665,14 @@
}
]
},
"local_pref": {
"nullable": true,
"description": "The local preference associated with this route.",
"default": null,
"type": "integer",
"format": "uint32",
"minimum": 0
},
"nexthop": {
"description": "The nexthop/gateway address.",
"type": "string",
Expand Down
14 changes: 14 additions & 0 deletions openapi/nexus.json
Original file line number Diff line number Diff line change
Expand Up @@ -17180,6 +17180,13 @@
"type": "string",
"format": "ip"
},
"local_pref": {
"nullable": true,
"description": "Local preference for route. Higher preference indictes precedence within and across protocols.",
"type": "integer",
"format": "uint32",
"minimum": 0
},
"vid": {
"nullable": true,
"description": "VLAN id the gateway is reachable over.",
Expand Down Expand Up @@ -19238,6 +19245,13 @@
"description": "The interface name this route configuration is assigned to.",
"type": "string"
},
"local_pref": {
"nullable": true,
"description": "Local preference indicating priority within and across protocols.",
"type": "integer",
"format": "uint32",
"minimum": 0
},
"port_settings_id": {
"description": "The port settings object this route configuration belongs to.",
"type": "string",
Expand Down
8 changes: 8 additions & 0 deletions openapi/sled-agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -4379,6 +4379,14 @@
}
]
},
"local_pref": {
"nullable": true,
"description": "The local preference associated with this route.",
"default": null,
"type": "integer",
"format": "uint32",
"minimum": 0
},
"nexthop": {
"description": "The nexthop/gateway address.",
"type": "string",
Expand Down
8 changes: 8 additions & 0 deletions openapi/wicketd.json
Original file line number Diff line number Diff line change
Expand Up @@ -3062,6 +3062,14 @@
}
]
},
"local_pref": {
"nullable": true,
"description": "The local preference associated with this route.",
"default": null,
"type": "integer",
"format": "uint32",
"minimum": 0
},
"nexthop": {
"description": "The nexthop/gateway address.",
"type": "string",
Expand Down
Loading

0 comments on commit 14b94f7

Please sign in to comment.