diff --git a/common/src/api/internal/shared.rs b/common/src/api/internal/shared.rs index e80823bb778..2baa8abce84 100644 --- a/common/src/api/internal/shared.rs +++ b/common/src/api/internal/shared.rs @@ -438,15 +438,15 @@ pub struct LldpPortConfig { /// LocallyAssigned ID type. If this is not set, it will be set to /// the port name. e.g., qsfp0/0. pub port_id: Option, + /// Port description to advertise. If this is not set, no + /// description will be advertised. + pub port_description: Option, /// System name to advertise. If this is not set, it will be /// inherited from the switch-level settings. pub system_name: Option, /// System description to advertise. If this is not set, it will be /// inherited from the switch-level settings. pub system_description: Option, - /// Port description to advertise. If this is not set, no - /// description will be advertised. - pub port_description: Option, /// Management IP addresses to advertise. If this is not set, it will be /// inherited from the switch-level settings. pub management_addrs: Option>, @@ -489,11 +489,13 @@ pub struct HostPortConfig { /// IP Address and prefix (e.g., `192.168.0.1/16`) to apply to switchport /// (must be in infra_ip pool). May also include an optional VLAN ID. pub addrs: Vec, + + pub lldp: Option, } impl From for HostPortConfig { fn from(x: PortConfigV2) -> Self { - Self { port: x.port, addrs: x.addresses } + Self { port: x.port, addrs: x.addresses, lldp: x.lldp.clone() } } } diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index 5f01a203ed5..691698b40a6 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -79,7 +79,7 @@ use omicron_common::address::{AZ_PREFIX, OXIMETER_PORT}; use omicron_common::address::{BOOTSTRAP_ARTIFACT_PORT, COCKROACH_ADMIN_PORT}; use omicron_common::api::external::Generation; use omicron_common::api::internal::shared::{ - HostPortConfig, LldpPortConfig, RackNetworkConfig, + HostPortConfig, RackNetworkConfig, }; use omicron_common::backoff::{ retry_notify, retry_policy_internal_service_aggressive, BackoffError, @@ -479,7 +479,7 @@ enum SwitchService { ManagementGatewayService, Wicketd { baseboard: Baseboard }, Dendrite { asic: DendriteAsic }, - Lldpd { baseboard: Baseboard, config: Option }, + Lldpd { baseboard: Baseboard }, Pumpkind { asic: DendriteAsic }, Tfport { pkt_source: String, asic: DendriteAsic }, Uplink, @@ -521,26 +521,6 @@ struct SwitchZoneConfigLocal { root: Utf8PathBuf, } -// The LLDP-related data from the rack configuration, used to configure the LLDP -// daemon running in the switch zone. -#[derive(Clone, Debug)] -struct LldpdConfig { - // Port-level configuration data for each port. - ports: BTreeMap, -} - -impl From<&RackNetworkConfig> for LldpdConfig { - fn from(config: &RackNetworkConfig) -> LldpdConfig { - let mut ports = BTreeMap::new(); - for p in config.ports.iter() { - if let Some(l) = &p.lldp { - ports.insert(p.port.clone(), l.clone()); - } - } - LldpdConfig { ports } - } -} - /// Describes either an Omicron-managed zone or the switch zone, used for /// functions that operate on either one or the other enum ZoneArgs<'a> { @@ -2683,11 +2663,8 @@ impl ServiceManager { smfh.refresh()?; } - SwitchService::Lldpd { baseboard, config } => { - info!( - self.inner.log, - "Setting up lldpd service: {config:#?}" - ); + SwitchService::Lldpd { baseboard } => { + info!(self.inner.log, "Setting up lldpd service"); match baseboard { Baseboard::Gimlet { @@ -3571,13 +3548,6 @@ impl ServiceManager { let mut filesystems: Vec = vec![]; let mut data_links: Vec = vec![]; - let lldp_config = - if let Some((_, Some(rack_network_config))) = underlay_info { - Some(rack_network_config.into()) - } else { - None - }; - let services = match self.inner.sled_mode { // A pure gimlet sled should not be trying to activate a switch // zone. @@ -3592,10 +3562,7 @@ impl ServiceManager { | SledMode::Scrimlet { asic: DendriteAsic::TofinoAsic } => { vec![ SwitchService::Dendrite { asic: DendriteAsic::TofinoAsic }, - SwitchService::Lldpd { - baseboard: baseboard.clone(), - config: lldp_config, - }, + SwitchService::Lldpd { baseboard: baseboard.clone() }, SwitchService::ManagementGatewayService, SwitchService::Pumpkind { asic: DendriteAsic::TofinoAsic }, SwitchService::Tfport { @@ -3615,10 +3582,7 @@ impl ServiceManager { data_links = vec!["vioif0".to_owned()]; vec![ SwitchService::Dendrite { asic }, - SwitchService::Lldpd { - baseboard: baseboard.clone(), - config: lldp_config, - }, + SwitchService::Lldpd { baseboard: baseboard.clone() }, SwitchService::ManagementGatewayService, SwitchService::Uplink, SwitchService::Wicketd { baseboard: baseboard.clone() }, @@ -3649,10 +3613,7 @@ impl ServiceManager { } vec![ SwitchService::Dendrite { asic }, - SwitchService::Lldpd { - baseboard: baseboard.clone(), - config: lldp_config, - }, + SwitchService::Lldpd { baseboard: baseboard.clone() }, SwitchService::ManagementGatewayService, SwitchService::Uplink, SwitchService::Wicketd { baseboard: baseboard.clone() }, @@ -3720,6 +3681,19 @@ impl ServiceManager { &self, our_ports: Vec, ) -> Result<(), Error> { + // Helper function to add a property-value pair + // if the config actually has a value set. + fn apv( + smfh: &SmfHelper, + prop: &str, + val: &Option, + ) -> Result<(), Error> { + if let Some(v) = val { + smfh.addpropvalue_type(prop, v, "astring")? + } + Ok(()) + } + // We expect the switch zone to be running, as we're called immediately // after `ensure_zone()` above and we just successfully configured // uplinks via DPD running in our switch zone. If somehow we're in any @@ -3742,24 +3716,76 @@ impl ServiceManager { } }; - let smfh = SmfHelper::new(&zone, &SwitchService::Uplink); + info!(self.inner.log, "ensuring scrimlet uplinks"); + + let usmfh = SmfHelper::new(&zone, &SwitchService::Uplink); + let lsmfh = SmfHelper::new( + &zone, + &SwitchService::Lldpd { baseboard: Baseboard::Unknown }, + ); // We want to delete all the properties in the `uplinks` group, but we // don't know their names, so instead we'll delete and recreate the // group, then add all our properties. - smfh.delpropgroup("uplinks")?; - smfh.addpropgroup("uplinks", "application")?; + usmfh.delpropgroup("uplinks")?; + usmfh.addpropgroup("uplinks", "application")?; for port_config in &our_ports { for addr in &port_config.addrs { - smfh.addpropvalue_type( + usmfh.addpropvalue_type( &format!("uplinks/{}_0", port_config.port,), &addr.to_string(), "astring", )?; } + + if let Some(lldp_config) = &port_config.lldp { + let group_name = format!("port_{}", port_config.port); + info!(self.inner.log, "setting up {group_name}"); + lsmfh.addpropgroup(&group_name, "application")?; + apv( + &lsmfh, + &format!("{group_name}/status"), + &Some(lldp_config.status.to_string()), + )?; + apv( + &lsmfh, + &format!("{group_name}/chassis_id"), + &lldp_config.chassis_id, + )?; + apv( + &lsmfh, + &format!("{group_name}/system_name"), + &lldp_config.system_name, + )?; + apv( + &lsmfh, + &format!("{group_name}/system_description"), + &lldp_config.system_description, + )?; + apv( + &lsmfh, + &format!("{group_name}/port_description"), + &lldp_config.port_id, + )?; + apv( + &lsmfh, + &format!("{group_name}/port_id"), + &lldp_config.port_id, + )?; + if let Some(a) = &lldp_config.management_addrs { + for address in a { + apv( + &lsmfh, + &format!("{group_name}/management_addrs"), + &Some(address.to_string()), + )?; + } + } + } } - smfh.refresh()?; + usmfh.refresh()?; + lsmfh.refresh()?; Ok(()) } @@ -3980,21 +4006,9 @@ impl ServiceManager { ); } } - SwitchService::Lldpd { config, .. } => { - // Helper function to add a property-value pair - // if the config actually has a value set. - fn apv( - smfh: &SmfHelper, - prop: &str, - val: &Option, - ) -> Result<(), Error> { - if let Some(v) = val { - smfh.addpropvalue_type(prop, v, "astring")? - } - Ok(()) - } + SwitchService::Lldpd { .. } => { + info!(self.inner.log, "Configuring lldpd service"); - info!(self.inner.log, "configuring lldpd service"); smfh.delpropvalue("config/address", "*")?; for address in &request.addresses { smfh.addpropvalue( @@ -4002,64 +4016,6 @@ impl ServiceManager { &format!("[{}]:{}", address, LLDP_PORT), )?; } - - if let Some(lldp_config) = config { - info!(self.inner.log, "Setting up lldp config"); - for (name, config) in &lldp_config.ports { - let group_name = format!("port_{name}"); - info!( - self.inner.log, - "setting up {group_name}" - ); - smfh.addpropgroup( - &group_name, - "application", - )?; - apv( - &smfh, - &format!("{group_name}/status"), - &Some(config.status.to_string()), - )?; - apv( - &smfh, - &format!("{group_name}/chassis_id"), - &config.chassis_id, - )?; - apv( - &smfh, - &format!("{group_name}/system_name"), - &config.system_name, - )?; - apv( - &smfh, - &format!( - "{group_name}/system_description" - ), - &config.system_description, - )?; - apv( - &smfh, - &format!( - "{group_name}/port_description" - ), - &config.port_id, - )?; - apv( - &smfh, - &format!("{group_name}/port_id"), - &config.port_id, - )?; - if let Some(a) = &config.management_addrs { - for address in a { - apv(&smfh, - &format!("{group_name}/management_addrs"), - &Some(address.to_string()), - )?; - } - } - } - } - smfh.refresh()?; } SwitchService::Tfport { .. } => {