diff --git a/dpd/src/transceivers/mod.rs b/dpd/src/transceivers/mod.rs index 82a2cc6..ffb61f4 100644 --- a/dpd/src/transceivers/mod.rs +++ b/dpd/src/transceivers/mod.rs @@ -94,11 +94,12 @@ impl QsfpDevice { } /// The cause of a fault on a transceiver. -#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, Serialize)] +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] #[serde(rename_all = "snake_case")] pub enum FaultReason { - /// An error occurred accessing the transceiver. - Failed, + /// An error occurred accessing the transceiver, with details about the + /// failure. + Failed { details: String }, /// Power was enabled, but did not come up in the requisite time. PowerTimeout, /// Power was enabled and later lost. diff --git a/dpd/src/transceivers/tofino_impl.rs b/dpd/src/transceivers/tofino_impl.rs index 312ef17..17b0236 100644 --- a/dpd/src/transceivers/tofino_impl.rs +++ b/dpd/src/transceivers/tofino_impl.rs @@ -1109,8 +1109,16 @@ impl Switch { port.as_qsfp_mut().unwrap().transceiver = Some(Transceiver::Faulted(FaultReason::DisabledBySp)); } else if status.failures.modules.is_set(index).unwrap() { + let details = status + .failures + .errors + .get(usize::from(index)) + .map(|err| err.to_string()) + .unwrap_or_else(|| String::from("Unknown error")); port.as_qsfp_mut().unwrap().transceiver = - Some(Transceiver::Faulted(FaultReason::Failed)); + Some(Transceiver::Faulted(FaultReason::Failed { + details, + })); } else { // At this point, the transceiver is present, and so we // _can_ check it for support. To do so requires that it be @@ -1201,7 +1209,13 @@ impl Switch { let new_transceiver = if unsupported.is_set(index).unwrap() { Transceiver::Unsupported } else if new_modules.failed.is_set(index).unwrap() { - Transceiver::Faulted(FaultReason::Failed) + let details = status + .failures + .errors + .get(usize::from(index)) + .map(|err| err.to_string()) + .unwrap_or_else(|| String::from("Unknown error")); + Transceiver::Faulted(FaultReason::Failed { details }) } else { continue; }; @@ -1327,11 +1341,28 @@ impl Switch { transceiver.in_reset = None; transceiver.interrupt_pending = None; } - } else if power.failures.modules.is_set(index).unwrap() - || vendor_info.failures.modules.is_set(index).unwrap() - { + } else if power.failures.modules.is_set(index).unwrap() { + let details = power + .failures + .errors + .get(usize::from(index)) + .map(|err| err.to_string()) + .unwrap_or_else(|| String::from("Unknown error")); + port_lock.lock().await.as_qsfp_mut().unwrap().transceiver = + Some(Transceiver::Faulted(FaultReason::Failed { + details, + })); + } else if vendor_info.failures.modules.is_set(index).unwrap() { + let details = vendor_info + .failures + .errors + .get(usize::from(index)) + .map(|err| err.to_string()) + .unwrap_or_else(|| String::from("Unknown error")); port_lock.lock().await.as_qsfp_mut().unwrap().transceiver = - Some(Transceiver::Faulted(FaultReason::Failed)); + Some(Transceiver::Faulted(FaultReason::Failed { + details, + })); } } diff --git a/openapi/dpd.json b/openapi/dpd.json index fcadc34..6aba057 100644 --- a/openapi/dpd.json +++ b/openapi/dpd.json @@ -5594,11 +5594,25 @@ "description": "The cause of a fault on a transceiver.", "oneOf": [ { - "description": "An error occurred accessing the transceiver.", - "type": "string", - "enum": [ + "description": "An error occurred accessing the transceiver, with details about the failure.", + "type": "object", + "properties": { + "failed": { + "type": "object", + "properties": { + "details": { + "type": "string" + } + }, + "required": [ + "details" + ] + } + }, + "required": [ "failed" - ] + ], + "additionalProperties": false }, { "description": "Power was enabled, but did not come up in the requisite time.", diff --git a/swadm/src/switchport.rs b/swadm/src/switchport.rs index 9450f33..a72e383 100644 --- a/swadm/src/switchport.rs +++ b/swadm/src/switchport.rs @@ -364,7 +364,13 @@ fn print_faulted_transceiver_row( port_id: &PortId, reason: &types::FaultReason, ) -> anyhow::Result<()> { - writeln!(tw, "{}\tfaulted ({:?})\t\t\t\t\t\t\t", port_id, reason) + let reason = match reason { + types::FaultReason::Failed { details } => details.as_str(), + types::FaultReason::PowerTimeout => "Power timeout", + types::FaultReason::PowerLost => "Power lost", + types::FaultReason::DisabledBySp => "Disabled by SP", + }; + writeln!(tw, "{}\tfaulted ({})\t\t\t\t\t\t\t", port_id, reason) .map_err(|e| e.into()) }