use std::fmt::Write;
use super::super::nm_dbus::{
NmConnection, NmLldpNeighbor, NmLldpNeighbor8021Vlan,
};
use crate::{
LldpAddressFamily, LldpChassisId, LldpConfig, LldpMacPhy, LldpMaxFrameSize,
LldpMgmtAddr, LldpMgmtAddrs, LldpNeighborTlv, LldpPortId, LldpPpvids,
LldpSystemCapabilities, LldpSystemDescription, LldpSystemName, LldpVlan,
LldpVlans,
};
pub(crate) fn is_lldp_enabled(nm_conn: &NmConnection) -> bool {
nm_conn.connection.as_ref().and_then(|s| s.lldp) == Some(true)
}
pub(crate) fn get_lldp(nm_infos: Vec<NmLldpNeighbor>) -> LldpConfig {
let mut neighbors = Vec::new();
for nm_info in nm_infos {
let tlvs = nm_neighbor_to_nmstate(&nm_info);
if !tlvs.is_empty() {
neighbors.push(tlvs);
}
}
LldpConfig {
enabled: true,
neighbors,
}
}
fn nm_neighbor_to_nmstate(nm_info: &NmLldpNeighbor) -> Vec<LldpNeighborTlv> {
let mut ret = Vec::new();
if let Some(c) = get_sys_name(nm_info) {
ret.push(c)
}
if let Some(c) = get_sys_description(nm_info) {
ret.push(c)
}
if let Some(c) = get_sys_caps(nm_info) {
ret.push(c)
}
if let Some(c) = get_chassis_id(nm_info) {
ret.push(c)
}
if let Some(c) = get_port_id(nm_info) {
ret.push(c)
}
if let Some(c) = get_vlans(nm_info) {
ret.push(c)
}
if let Some(c) = get_mac_phy_conf(nm_info) {
ret.push(c)
}
if let Some(c) = get_ppvids(nm_info) {
ret.push(c)
}
if let Some(c) = get_mgmt_addrs(nm_info) {
ret.push(c)
}
if let Some(c) = get_max_frame_size(nm_info) {
ret.push(c)
}
ret
}
impl From<&[NmLldpNeighbor8021Vlan]> for LldpVlans {
fn from(nm_vlans: &[NmLldpNeighbor8021Vlan]) -> Self {
let mut vlans = Vec::new();
for nm_vlan in nm_vlans {
if let (Some(vid), Some(name)) = (nm_vlan.vid, &nm_vlan.name) {
vlans.push(LldpVlan {
vid,
name: name.to_string(),
});
}
}
LldpVlans::new(vlans)
}
}
fn u8_addr_to_mac_string(data: &[u8]) -> String {
let mut addr = String::new();
for (i, &val) in data.iter().enumerate() {
let _ = write!(addr, "{val:02X}");
if i != data.len() - 1 {
addr.push(':');
}
}
addr
}
fn get_chassis_id(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let (Some(id_type), Some(id)) =
(nm_info.chassis_id_type, nm_info.chassis_id.as_deref())
{
if let Ok(id_type) = u8::try_from(id_type) {
return Some(LldpNeighborTlv::ChassisId(LldpChassisId::new(
id.to_string(),
id_type.into(),
)));
} else {
log::warn!(
"Got unsupported chassis_id_type {}, expecting u8",
id_type
);
}
}
None
}
fn get_port_id(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let (Some(id_type), Some(id)) =
(nm_info.port_id_type, nm_info.port_id.as_deref())
{
if let Ok(id_type) = u8::try_from(id_type) {
return Some(LldpNeighborTlv::PortId(LldpPortId::new(
id.to_string(),
id_type.into(),
)));
} else {
log::warn!(
"Got unsupported port_id_type {}, expecting u8",
id_type
);
}
}
None
}
fn get_sys_caps(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(s) = nm_info.system_capabilities {
if let Ok(caps) = u16::try_from(s) {
return Some(LldpNeighborTlv::SystemCapabilities(
LldpSystemCapabilities::from(caps),
));
}
}
None
}
fn get_sys_name(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(s) = nm_info.system_name.as_deref() {
return Some(LldpNeighborTlv::SystemName(LldpSystemName::new(
s.to_string(),
)));
}
None
}
fn get_sys_description(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(s) = nm_info.system_description.as_deref() {
return Some(LldpNeighborTlv::SystemDescription(
LldpSystemDescription::new(s.to_string()),
));
}
None
}
fn get_vlans(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(nm_vlans) = nm_info.ieee_802_1_vlans.as_deref() {
return Some(LldpNeighborTlv::Ieee8021Vlans(nm_vlans.into()));
}
None
}
fn get_mac_phy_conf(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(nm_conf) = nm_info.ieee_802_3_mac_phy_conf.as_ref() {
if let (Some(a), Some(p), Some(o)) = (
nm_conf.autoneg,
nm_conf.pmd_autoneg_cap,
nm_conf.operational_mau_type,
) {
if let (Ok(o), Ok(p)) = (u16::try_from(o), u16::try_from(p)) {
return Some(LldpNeighborTlv::Ieee8023MacPhyConf(
LldpMacPhy::new(a > 0, o, p),
));
}
}
}
None
}
fn get_ppvids(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(nm_ppvids) = nm_info.ieee_802_1_ppvids.as_ref() {
let mut ppvids = Vec::new();
for nm_ppvid in nm_ppvids {
if let Some(p) = nm_ppvid.ppvid {
ppvids.push(p);
}
}
return Some(LldpNeighborTlv::Ieee8021Ppvids(LldpPpvids::new(ppvids)));
}
None
}
fn get_mgmt_addrs(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(nm_mgmt_addrs) = nm_info.management_addresses.as_deref() {
let mut addrs = Vec::new();
for nm_mgmt_addr in nm_mgmt_addrs {
if let (Some(at), Some(a), Some(it), Some(i)) = (
nm_mgmt_addr.address_subtype,
nm_mgmt_addr.address.as_ref(),
nm_mgmt_addr.interface_number_subtype,
nm_mgmt_addr.interface_number,
) {
if let Ok(at) = u16::try_from(at) {
let mut mgmt_addr = LldpMgmtAddr::default();
let at = LldpAddressFamily::from(at);
let addr = match at {
LldpAddressFamily::Ipv4 => {
if a.len() != 4 {
continue;
}
std::net::Ipv4Addr::new(a[0], a[1], a[2], a[3])
.to_string()
}
LldpAddressFamily::Ipv6 => {
if a.len() != 16 {
continue;
}
let mut buff = [0u8; 16];
buff.copy_from_slice(&a[..16]);
std::net::Ipv6Addr::from(buff).to_string()
}
LldpAddressFamily::Mac => u8_addr_to_mac_string(a),
_ => {
continue;
}
};
mgmt_addr.address_subtype = at;
mgmt_addr.address = addr;
mgmt_addr.interface_number_subtype = it;
mgmt_addr.interface_number = i;
addrs.push(mgmt_addr);
}
}
}
return Some(LldpNeighborTlv::ManagementAddresses(LldpMgmtAddrs::new(
addrs,
)));
}
None
}
fn get_max_frame_size(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
if let Some(s) = nm_info.ieee_802_3_max_frame_size {
return Some(LldpNeighborTlv::Ieee8023MaxFrameSize(
LldpMaxFrameSize::new(s),
));
}
None
}