nmstate/nm/query_apply/
lldp.rs1use std::fmt::Write;
4
5use super::super::nm_dbus::{
6 NmConnection, NmLldpNeighbor, NmLldpNeighbor8021Vlan,
7};
8
9use crate::{
10 LldpAddressFamily, LldpChassisId, LldpConfig, LldpMacPhy, LldpMaxFrameSize,
11 LldpMgmtAddr, LldpMgmtAddrs, LldpNeighborTlv, LldpPortId, LldpPpvids,
12 LldpSystemCapabilities, LldpSystemDescription, LldpSystemName, LldpVlan,
13 LldpVlans,
14};
15
16pub(crate) fn is_lldp_enabled(nm_conn: &NmConnection) -> bool {
17 nm_conn.connection.as_ref().and_then(|s| s.lldp) == Some(true)
18}
19
20pub(crate) fn get_lldp(nm_infos: Vec<NmLldpNeighbor>) -> LldpConfig {
21 let mut neighbors = Vec::new();
22 for nm_info in nm_infos {
23 let tlvs = nm_neighbor_to_nmstate(&nm_info);
24 if !tlvs.is_empty() {
25 neighbors.push(tlvs);
26 }
27 }
28 LldpConfig {
29 enabled: true,
30 neighbors,
31 }
32}
33
34fn nm_neighbor_to_nmstate(nm_info: &NmLldpNeighbor) -> Vec<LldpNeighborTlv> {
35 let mut ret = Vec::new();
36
37 if let Some(c) = get_sys_name(nm_info) {
38 ret.push(c)
39 }
40 if let Some(c) = get_sys_description(nm_info) {
41 ret.push(c)
42 }
43 if let Some(c) = get_sys_caps(nm_info) {
44 ret.push(c)
45 }
46 if let Some(c) = get_chassis_id(nm_info) {
47 ret.push(c)
48 }
49 if let Some(c) = get_port_id(nm_info) {
50 ret.push(c)
51 }
52 if let Some(c) = get_vlans(nm_info) {
53 ret.push(c)
54 }
55 if let Some(c) = get_mac_phy_conf(nm_info) {
56 ret.push(c)
57 }
58 if let Some(c) = get_ppvids(nm_info) {
59 ret.push(c)
60 }
61 if let Some(c) = get_mgmt_addrs(nm_info) {
62 ret.push(c)
63 }
64 if let Some(c) = get_max_frame_size(nm_info) {
65 ret.push(c)
66 }
67
68 ret
69}
70
71impl From<&[NmLldpNeighbor8021Vlan]> for LldpVlans {
72 fn from(nm_vlans: &[NmLldpNeighbor8021Vlan]) -> Self {
73 let mut vlans = Vec::new();
74 for nm_vlan in nm_vlans {
75 if let (Some(vid), Some(name)) = (nm_vlan.vid, &nm_vlan.name) {
76 vlans.push(LldpVlan {
77 vid,
78 name: name.to_string(),
79 });
80 }
81 }
82
83 LldpVlans::new(vlans)
84 }
85}
86
87fn u8_addr_to_mac_string(data: &[u8]) -> String {
88 let mut addr = String::new();
89 for (i, &val) in data.iter().enumerate() {
90 let _ = write!(addr, "{val:02X}");
91 if i != data.len() - 1 {
92 addr.push(':');
93 }
94 }
95 addr
96}
97
98fn get_chassis_id(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
99 if let (Some(id_type), Some(id)) =
100 (nm_info.chassis_id_type, nm_info.chassis_id.as_deref())
101 {
102 if let Ok(id_type) = u8::try_from(id_type) {
103 return Some(LldpNeighborTlv::ChassisId(LldpChassisId::new(
104 id.to_string(),
105 id_type.into(),
106 )));
107 } else {
108 log::warn!(
109 "Got unsupported chassis_id_type {id_type}, expecting u8"
110 );
111 }
112 }
113 None
114}
115
116fn get_port_id(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
117 if let (Some(id_type), Some(id)) =
118 (nm_info.port_id_type, nm_info.port_id.as_deref())
119 {
120 if let Ok(id_type) = u8::try_from(id_type) {
121 return Some(LldpNeighborTlv::PortId(LldpPortId::new(
122 id.to_string(),
123 id_type.into(),
124 )));
125 } else {
126 log::warn!("Got unsupported port_id_type {id_type}, expecting u8");
127 }
128 }
129 None
130}
131
132fn get_sys_caps(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
133 if let Some(s) = nm_info.system_capabilities {
134 if let Ok(caps) = u16::try_from(s) {
135 return Some(LldpNeighborTlv::SystemCapabilities(
136 LldpSystemCapabilities::from(caps),
137 ));
138 }
139 }
140 None
141}
142
143fn get_sys_name(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
144 if let Some(s) = nm_info.system_name.as_deref() {
145 return Some(LldpNeighborTlv::SystemName(LldpSystemName::new(
146 s.to_string(),
147 )));
148 }
149 None
150}
151
152fn get_sys_description(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
153 if let Some(s) = nm_info.system_description.as_deref() {
154 return Some(LldpNeighborTlv::SystemDescription(
155 LldpSystemDescription::new(s.to_string()),
156 ));
157 }
158 None
159}
160
161fn get_vlans(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
162 if let Some(nm_vlans) = nm_info.ieee_802_1_vlans.as_deref() {
163 return Some(LldpNeighborTlv::Ieee8021Vlans(nm_vlans.into()));
164 }
165 None
166}
167
168fn get_mac_phy_conf(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
169 if let Some(nm_conf) = nm_info.ieee_802_3_mac_phy_conf.as_ref() {
170 if let (Some(a), Some(p), Some(o)) = (
171 nm_conf.autoneg,
172 nm_conf.pmd_autoneg_cap,
173 nm_conf.operational_mau_type,
174 ) {
175 if let (Ok(o), Ok(p)) = (u16::try_from(o), u16::try_from(p)) {
176 return Some(LldpNeighborTlv::Ieee8023MacPhyConf(
177 LldpMacPhy::new(a > 0, o, p),
178 ));
179 }
180 }
181 }
182 None
183}
184
185fn get_ppvids(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
186 if let Some(nm_ppvids) = nm_info.ieee_802_1_ppvids.as_ref() {
187 let mut ppvids = Vec::new();
188 for nm_ppvid in nm_ppvids {
189 if let Some(p) = nm_ppvid.ppvid {
190 ppvids.push(p);
191 }
192 }
193 return Some(LldpNeighborTlv::Ieee8021Ppvids(LldpPpvids::new(ppvids)));
194 }
195 None
196}
197
198fn get_mgmt_addrs(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
199 if let Some(nm_mgmt_addrs) = nm_info.management_addresses.as_deref() {
200 let mut addrs = Vec::new();
201 for nm_mgmt_addr in nm_mgmt_addrs {
202 if let (Some(at), Some(a), Some(it), Some(i)) = (
203 nm_mgmt_addr.address_subtype,
204 nm_mgmt_addr.address.as_ref(),
205 nm_mgmt_addr.interface_number_subtype,
206 nm_mgmt_addr.interface_number,
207 ) {
208 if let Ok(at) = u16::try_from(at) {
209 let mut mgmt_addr = LldpMgmtAddr::default();
210 let at = LldpAddressFamily::from(at);
211 let addr = match at {
212 LldpAddressFamily::Ipv4 => {
213 if a.len() != 4 {
214 continue;
215 }
216 std::net::Ipv4Addr::new(a[0], a[1], a[2], a[3])
217 .to_string()
218 }
219 LldpAddressFamily::Ipv6 => {
220 if a.len() != 16 {
221 continue;
222 }
223 let mut buff = [0u8; 16];
224 buff.copy_from_slice(&a[..16]);
225 std::net::Ipv6Addr::from(buff).to_string()
226 }
227 LldpAddressFamily::Mac => u8_addr_to_mac_string(a),
228 _ => {
229 continue;
230 }
231 };
232
233 mgmt_addr.address_subtype = at;
234 mgmt_addr.address = addr;
235 mgmt_addr.interface_number_subtype = it;
236 mgmt_addr.interface_number = i;
237 addrs.push(mgmt_addr);
238 }
239 }
240 }
241 return Some(LldpNeighborTlv::ManagementAddresses(LldpMgmtAddrs::new(
242 addrs,
243 )));
244 }
245 None
246}
247
248fn get_max_frame_size(nm_info: &NmLldpNeighbor) -> Option<LldpNeighborTlv> {
249 if let Some(s) = nm_info.ieee_802_3_max_frame_size {
250 return Some(LldpNeighborTlv::Ieee8023MaxFrameSize(
251 LldpMaxFrameSize::new(s),
252 ));
253 }
254 None
255}