Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ proptest = "1.4"
serial_test = "3.2"
ddm-api = { path = "ddm-api" }
ddm-types = { path = "ddm-types" }
gateway-client = { git = "https://github.com/oxidecomputer/omicron", branch = "main" }

[workspace.dependencies.opte-ioctl]
git = "https://github.com/oxidecomputer/opte"
Expand Down
15 changes: 15 additions & 0 deletions mg-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ api_versions!([
// | example for the next person.
// v
// (next_int, IDENT),
(3, SWITCH_IDENTIFIERS),
(2, IPV6_BASIC),
(1, INITIAL),
]);
Expand Down Expand Up @@ -371,6 +372,20 @@ pub trait MgAdminApi {
async fn static_list_v6_routes(
ctx: RequestContext<Self::Context>,
) -> Result<HttpResponseOk<GetRibResult>, HttpError>;

#[endpoint {method = GET, path = "/switch/identifiers", versions = VERSION_SWITCH_IDENTIFIERS.. }]
async fn switch_identifiers(
ctx: RequestContext<Self::Context>,
) -> Result<HttpResponseOk<SwitchIdentifiers>, HttpError>;
}

/// Identifiers for a switch.
#[derive(Clone, Debug, JsonSchema, Serialize)]
pub struct SwitchIdentifiers {
/// The slot number of the switch being managed.
///
/// MGS uses u16 for this internally.
pub slot: Option<u16>,
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
Expand Down
1 change: 1 addition & 0 deletions mgd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ omicron-common.workspace = true
hostname.workspace = true
uuid.workspace = true
smf.workspace = true
gateway-client.workspace = true

[dev-dependencies]
tempfile = "3"
Expand Down
6 changes: 6 additions & 0 deletions mgd/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,12 @@ impl MgAdminApi for MgAdminApiImpl {
) -> Result<HttpResponseOk<GetRibResult>, HttpError> {
static_admin::static_list_v6_routes(ctx).await
}

async fn switch_identifiers(
ctx: RequestContext<Self::Context>,
) -> Result<HttpResponseOk<SwitchIdentifiers>, HttpError> {
static_admin::switch_identifiers(ctx).await
}
}

pub fn api_description() -> ApiDescription<Arc<HandlerContext>> {
Expand Down
50 changes: 49 additions & 1 deletion mgd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rdb::{BfdPeerConfig, BgpNeighborInfo, BgpRouterInfo};
use signal::handle_signals;
use slog::Logger;
use std::collections::{BTreeMap, BTreeSet};
use std::net::{IpAddr, Ipv6Addr};
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
use std::sync::{Arc, Mutex};
use std::thread::Builder;
use uuid::Uuid;
Expand Down Expand Up @@ -88,6 +88,10 @@ struct RunArgs {
/// Id of the sled this router is running on.
#[arg(long)]
sled_uuid: Option<Uuid>,

/// SocketAddr the MGS service is listening on.
#[arg(long, default_value = "[::1]:12225")]
mgs_addr: SocketAddr,
}

fn main() {
Expand Down Expand Up @@ -123,6 +127,12 @@ async fn run(args: RunArgs) {
oximeter_port: args.oximeter_port,
});

detect_switch_slot(
context.clone(),
args.mgs_addr,
tokio::runtime::Handle::current(),
);

if let Err(e) = sig_tx.send(context.clone()).await {
dlog!(log, error, "error sending handler context to signal handler: {e}";
"params" => format!("tep {tep_ula}, dir {}, oximeter_port {}",
Expand Down Expand Up @@ -202,6 +212,44 @@ async fn run(args: RunArgs) {
j.await.expect("API server quit unexpectedly");
}

fn detect_switch_slot(
ctx: Arc<HandlerContext>,
mgs_socket_addr: SocketAddr,
rt: tokio::runtime::Handle,
) {
let url = format!("http://{mgs_socket_addr}");
let client_log = ctx.log.new(slog::o!("unit" => "gateway-client"));
let task = async move || {
let client = gateway_client::Client::new(&url, client_log);
let ctx = ctx.clone();

loop {
// check in with gateway
let gateway_client::types::SpIdentifier { slot, .. } = match client
.sp_local_switch_id()
.await
{
Ok(v) => *v,
Err(e) => {
slog::error!(ctx.log, "failed to resolve switch slot"; "error" => %e);
tokio::time::sleep(tokio::time::Duration::from_secs(10))
.await;
continue;
}
};

slog::info!(ctx.log, "we are in switch slot {slot}");

// update db
let mut db = ctx.db.clone();
db.set_slot(Some(slot));
break;
}
};

rt.spawn(task());
}

fn init_bgp(args: &RunArgs, log: &Logger) -> BgpContext {
let addr_to_session = Arc::new(Mutex::new(BTreeMap::new()));
if !args.no_bgp_dispatcher {
Expand Down
7 changes: 7 additions & 0 deletions mgd/src/static_admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,10 @@ pub async fn static_list_v6_routes(

Ok(HttpResponseOk(static_rib))
}

pub(crate) async fn switch_identifiers(
ctx: RequestContext<Arc<HandlerContext>>,
) -> Result<HttpResponseOk<mg_api::SwitchIdentifiers>, HttpError> {
let slot = ctx.context().db.slot();
Ok(HttpResponseOk(mg_api::SwitchIdentifiers { slot }))
}
Loading