1use std::os::unix::io::RawFd;
4
5use anyhow::Context;
6use byteorder::{ByteOrder, NativeEndian};
7use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED};
8use netlink_packet_utils::parsers::{parse_i32, parse_string, parse_u32, parse_u8};
9use netlink_packet_utils::traits::{Emitable, Parseable, ParseableParametrized};
10use netlink_packet_utils::DecodeError;
11
12#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
13use super::af_spec::VecAfSpecBridge;
14use super::af_spec::VecAfSpecUnspec;
15use super::buffer_tool::expand_buffer_if_small;
16use super::ext_mask::VecLinkExtentMask;
17use super::link_info::VecLinkInfo;
18#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
19use super::proto_info::VecLinkProtoInfoBridge;
20use super::proto_info::VecLinkProtoInfoInet6;
21use super::sriov::{VecLinkVfInfo, VecLinkVfPort};
22use super::stats::LINK_STATS_LEN;
23use super::stats64::LINK_STATS64_LEN;
24use super::xdp::VecLinkXdp;
25use super::{
26 AfSpecBridge, AfSpecUnspec, LinkEvent, LinkExtentMask, LinkInfo, LinkPhysId,
27 LinkProtoInfoBridge, LinkProtoInfoInet6, LinkProtocolDownReason, LinkVfInfo, LinkVfPort,
28 LinkWirelessEvent, LinkXdp, Map, MapBuffer, Prop, State, Stats, Stats64, Stats64Buffer,
29 StatsBuffer,
30};
31use crate::AddressFamily;
32
33const IFLA_ADDRESS: u16 = 1;
34const IFLA_BROADCAST: u16 = 2;
35const IFLA_IFNAME: u16 = 3;
36const IFLA_MTU: u16 = 4;
37const IFLA_LINK: u16 = 5;
38const IFLA_QDISC: u16 = 6;
39const IFLA_STATS: u16 = 7;
40const IFLA_MASTER: u16 = 10;
45const IFLA_WIRELESS: u16 = 11;
46const IFLA_PROTINFO: u16 = 12;
47const IFLA_TXQLEN: u16 = 13;
48const IFLA_MAP: u16 = 14;
49const IFLA_OPERSTATE: u16 = 16;
52const IFLA_LINKMODE: u16 = 17;
53const IFLA_LINKINFO: u16 = 18;
54const IFLA_NET_NS_PID: u16 = 19;
55const IFLA_IFALIAS: u16 = 20;
56const IFLA_NUM_VF: u16 = 21;
57const IFLA_VFINFO_LIST: u16 = 22;
58const IFLA_STATS64: u16 = 23;
59const IFLA_VF_PORTS: u16 = 24;
60const IFLA_PORT_SELF: u16 = 25;
61const IFLA_AF_SPEC: u16 = 26;
62const IFLA_GROUP: u16 = 27;
63const IFLA_NET_NS_FD: u16 = 28;
64const IFLA_EXT_MASK: u16 = 29;
65const IFLA_PROMISCUITY: u16 = 30;
66const IFLA_NUM_TX_QUEUES: u16 = 31;
67const IFLA_NUM_RX_QUEUES: u16 = 32;
68const IFLA_CARRIER: u16 = 33;
69const IFLA_PHYS_PORT_ID: u16 = 34;
70const IFLA_CARRIER_CHANGES: u16 = 35;
71const IFLA_PHYS_SWITCH_ID: u16 = 36;
72const IFLA_LINK_NETNSID: u16 = 37;
73const IFLA_PHYS_PORT_NAME: u16 = 38;
74const IFLA_PROTO_DOWN: u16 = 39;
75const IFLA_GSO_MAX_SEGS: u16 = 40;
76const IFLA_GSO_MAX_SIZE: u16 = 41;
77const IFLA_XDP: u16 = 43;
79const IFLA_EVENT: u16 = 44;
80const IFLA_NEW_NETNSID: u16 = 45;
81const IFLA_IF_NETNSID: u16 = 46;
82const IFLA_CARRIER_UP_COUNT: u16 = 47;
83const IFLA_CARRIER_DOWN_COUNT: u16 = 48;
84const IFLA_NEW_IFINDEX: u16 = 49;
85const IFLA_MIN_MTU: u16 = 50;
86const IFLA_MAX_MTU: u16 = 51;
87const IFLA_PROP_LIST: u16 = 52;
88const IFLA_PERM_ADDRESS: u16 = 54;
89const IFLA_PROTO_DOWN_REASON: u16 = 55;
90
91#[derive(Debug, PartialEq, Eq, Clone)]
102#[non_exhaustive]
103pub enum LinkAttribute {
104 VfInfoList(Vec<LinkVfInfo>),
105 VfPorts(Vec<LinkVfPort>),
106 PortSelf(LinkVfPort),
107 PhysPortId(LinkPhysId),
108 PhysSwitchId(LinkPhysId),
109 Xdp(Vec<LinkXdp>),
110 Event(LinkEvent),
111 NewNetnsId(i32),
112 IfNetnsId(i32),
113 CarrierUpCount(u32),
114 CarrierDownCount(u32),
115 NewIfIndex(i32),
116 LinkInfo(Vec<LinkInfo>),
117 Wireless(LinkWirelessEvent),
118 ProtoInfoBridge(Vec<LinkProtoInfoBridge>),
119 ProtoInfoInet6(Vec<LinkProtoInfoInet6>),
120 ProtoInfoUnknown(DefaultNla),
121 PropList(Vec<Prop>),
122 ProtoDownReason(Vec<LinkProtocolDownReason>),
123 Address(Vec<u8>),
124 Broadcast(Vec<u8>),
125 PermAddress(Vec<u8>),
128 IfName(String),
129 Qdisc(String),
130 IfAlias(String),
131 PhysPortName(String),
132 Mode(u8),
133 Carrier(u8),
134 ProtoDown(u8),
135 Mtu(u32),
136 Link(u32),
137 Controller(u32),
138 TxQueueLen(u32),
139 NetNsPid(u32),
140 NumVf(u32),
141 Group(u32),
142 NetNsFd(RawFd),
143 ExtMask(Vec<LinkExtentMask>),
144 Promiscuity(u32),
145 NumTxQueues(u32),
146 NumRxQueues(u32),
147 CarrierChanges(u32),
148 GsoMaxSegs(u32),
149 GsoMaxSize(u32),
150 MinMtu(u32),
152 MaxMtu(u32),
154 LinkNetNsId(i32),
155 OperState(State),
156 Stats(Stats),
157 Stats64(Stats64),
158 Map(Map),
159 AfSpecUnspec(Vec<AfSpecUnspec>),
162 AfSpecBridge(Vec<AfSpecBridge>),
163 AfSpecUnknown(Vec<u8>),
164 Other(DefaultNla),
165}
166
167impl Nla for LinkAttribute {
168 fn value_len(&self) -> usize {
169 match self {
170 Self::VfInfoList(v) => v.as_slice().buffer_len(),
171 Self::VfPorts(v) => v.as_slice().buffer_len(),
172 Self::PortSelf(v) => v.buffer_len(),
173 Self::PhysPortId(v) => v.buffer_len(),
174 Self::PhysSwitchId(v) => v.buffer_len(),
175 Self::Event(v) => v.buffer_len(),
176 Self::Wireless(v) => v.buffer_len(),
177 Self::ProtoInfoBridge(v) => v.as_slice().buffer_len(),
178 Self::ProtoInfoInet6(v) => v.as_slice().buffer_len(),
179 Self::ProtoDownReason(v) => v.as_slice().buffer_len(),
180
181 Self::Address(bytes)
182 | Self::Broadcast(bytes)
183 | Self::PermAddress(bytes)
184 | Self::AfSpecUnknown(bytes) => bytes.len(),
185
186 Self::IfName(string)
187 | Self::Qdisc(string)
188 | Self::IfAlias(string)
189 | Self::PhysPortName(string) => string.as_bytes().len() + 1,
190
191 Self::Mode(_) | Self::Carrier(_) | Self::ProtoDown(_) => 1,
192
193 Self::Mtu(_)
194 | Self::NewNetnsId(_)
195 | Self::IfNetnsId(_)
196 | Self::Link(_)
197 | Self::Controller(_)
198 | Self::TxQueueLen(_)
199 | Self::NetNsPid(_)
200 | Self::NumVf(_)
201 | Self::Group(_)
202 | Self::NetNsFd(_)
203 | Self::ExtMask(_)
204 | Self::Promiscuity(_)
205 | Self::NumTxQueues(_)
206 | Self::NumRxQueues(_)
207 | Self::CarrierChanges(_)
208 | Self::GsoMaxSegs(_)
209 | Self::GsoMaxSize(_)
210 | Self::LinkNetNsId(_)
211 | Self::MinMtu(_)
212 | Self::CarrierUpCount(_)
213 | Self::CarrierDownCount(_)
214 | Self::NewIfIndex(_)
215 | Self::MaxMtu(_) => 4,
216
217 Self::OperState(_) => 1,
218 Self::Stats(_) => LINK_STATS_LEN,
219 Self::Stats64(_) => LINK_STATS64_LEN,
220 Self::Map(nla) => nla.buffer_len(),
221 Self::LinkInfo(nlas) => nlas.as_slice().buffer_len(),
222 Self::Xdp(nlas) => nlas.as_slice().buffer_len(),
223 Self::PropList(nlas) => nlas.as_slice().buffer_len(),
224 Self::AfSpecUnspec(nlas) => nlas.as_slice().buffer_len(),
225 Self::AfSpecBridge(nlas) => nlas.as_slice().buffer_len(),
226 Self::ProtoInfoUnknown(attr) => attr.value_len(),
227 Self::Other(attr) => attr.value_len(),
228 }
229 }
230
231 fn emit_value(&self, buffer: &mut [u8]) {
232 match self {
233 Self::VfInfoList(v) => v.as_slice().emit(buffer),
234 Self::VfPorts(v) => v.as_slice().emit(buffer),
235 Self::PortSelf(v) => v.emit(buffer),
236 Self::PhysPortId(v) => v.emit(buffer),
237 Self::PhysSwitchId(v) => v.emit(buffer),
238 Self::Event(v) => v.emit(buffer),
239 Self::Wireless(v) => v.emit(buffer),
240 Self::ProtoInfoBridge(v) => v.as_slice().emit(buffer),
241 Self::ProtoInfoInet6(v) => v.as_slice().emit(buffer),
242 Self::ProtoDownReason(v) => v.as_slice().emit(buffer),
243 Self::Address(bytes)
244 | Self::Broadcast(bytes)
245 | Self::PermAddress(bytes)
246 | Self::AfSpecUnknown(bytes) => buffer.copy_from_slice(bytes.as_slice()),
247
248 Self::IfName(string)
249 | Self::Qdisc(string)
250 | Self::IfAlias(string)
251 | Self::PhysPortName(string) => {
252 buffer[..string.len()].copy_from_slice(string.as_bytes());
253 buffer[string.len()] = 0;
254 }
255
256 Self::Mode(val) | Self::Carrier(val) | Self::ProtoDown(val) => buffer[0] = *val,
257
258 Self::Mtu(value)
259 | Self::Link(value)
260 | Self::Controller(value)
261 | Self::TxQueueLen(value)
262 | Self::NetNsPid(value)
263 | Self::NumVf(value)
264 | Self::Group(value)
265 | Self::Promiscuity(value)
266 | Self::NumTxQueues(value)
267 | Self::NumRxQueues(value)
268 | Self::CarrierChanges(value)
269 | Self::CarrierUpCount(value)
270 | Self::CarrierDownCount(value)
271 | Self::GsoMaxSegs(value)
272 | Self::GsoMaxSize(value)
273 | Self::MinMtu(value)
274 | Self::MaxMtu(value) => NativeEndian::write_u32(buffer, *value),
275
276 Self::ExtMask(value) => {
277 NativeEndian::write_u32(buffer, u32::from(&VecLinkExtentMask(value.to_vec())))
278 }
279
280 Self::LinkNetNsId(v)
281 | Self::NetNsFd(v)
282 | Self::NewNetnsId(v)
283 | Self::NewIfIndex(v)
284 | Self::IfNetnsId(v) => NativeEndian::write_i32(buffer, *v),
285 Self::Stats(nla) => nla.emit(buffer),
286 Self::Map(nla) => nla.emit(buffer),
287 Self::Stats64(nla) => nla.emit(buffer),
288 Self::OperState(state) => buffer[0] = (*state).into(),
289 Self::LinkInfo(nlas) => nlas.as_slice().emit(buffer),
290 Self::Xdp(nlas) => nlas.as_slice().emit(buffer),
291 Self::PropList(nlas) => nlas.as_slice().emit(buffer),
292 Self::AfSpecUnspec(nlas) => nlas.as_slice().emit(buffer),
293 Self::AfSpecBridge(nlas) => nlas.as_slice().emit(buffer),
294 Self::ProtoInfoUnknown(attr) | Self::Other(attr) => attr.emit_value(buffer),
295 }
296 }
297
298 fn kind(&self) -> u16 {
299 match self {
300 Self::VfInfoList(_) => IFLA_VFINFO_LIST,
301 Self::VfPorts(_) => IFLA_VF_PORTS,
302 Self::PortSelf(_) => IFLA_PORT_SELF,
303 Self::PhysPortId(_) => IFLA_PHYS_PORT_ID,
304 Self::PhysSwitchId(_) => IFLA_PHYS_SWITCH_ID,
305 Self::LinkInfo(_) => IFLA_LINKINFO,
306 Self::Wireless(_) => IFLA_WIRELESS,
307 Self::ProtoInfoBridge(_) | Self::ProtoInfoInet6(_) => IFLA_PROTINFO,
308 Self::ProtoInfoUnknown(attr) => attr.kind(),
309 Self::Xdp(_) => IFLA_XDP,
310 Self::Event(_) => IFLA_EVENT,
311 Self::NewNetnsId(_) => IFLA_NEW_NETNSID,
312 Self::IfNetnsId(_) => IFLA_IF_NETNSID,
313 Self::CarrierUpCount(_) => IFLA_CARRIER_UP_COUNT,
314 Self::CarrierDownCount(_) => IFLA_CARRIER_DOWN_COUNT,
315 Self::NewIfIndex(_) => IFLA_NEW_IFINDEX,
316 Self::PropList(_) => IFLA_PROP_LIST | NLA_F_NESTED,
317 Self::ProtoDownReason(_) => IFLA_PROTO_DOWN_REASON,
318 Self::Address(_) => IFLA_ADDRESS,
319 Self::Broadcast(_) => IFLA_BROADCAST,
320 Self::PermAddress(_) => IFLA_PERM_ADDRESS,
321 Self::IfName(_) => IFLA_IFNAME,
322 Self::Qdisc(_) => IFLA_QDISC,
323 Self::IfAlias(_) => IFLA_IFALIAS,
324 Self::PhysPortName(_) => IFLA_PHYS_PORT_NAME,
325 Self::Mode(_) => IFLA_LINKMODE,
326 Self::Carrier(_) => IFLA_CARRIER,
327 Self::ProtoDown(_) => IFLA_PROTO_DOWN,
328 Self::Mtu(_) => IFLA_MTU,
329 Self::Link(_) => IFLA_LINK,
330 Self::Controller(_) => IFLA_MASTER,
331 Self::TxQueueLen(_) => IFLA_TXQLEN,
332 Self::NetNsPid(_) => IFLA_NET_NS_PID,
333 Self::NumVf(_) => IFLA_NUM_VF,
334 Self::Group(_) => IFLA_GROUP,
335 Self::NetNsFd(_) => IFLA_NET_NS_FD,
336 Self::ExtMask(_) => IFLA_EXT_MASK,
337 Self::Promiscuity(_) => IFLA_PROMISCUITY,
338 Self::NumTxQueues(_) => IFLA_NUM_TX_QUEUES,
339 Self::NumRxQueues(_) => IFLA_NUM_RX_QUEUES,
340 Self::CarrierChanges(_) => IFLA_CARRIER_CHANGES,
341 Self::GsoMaxSegs(_) => IFLA_GSO_MAX_SEGS,
342 Self::GsoMaxSize(_) => IFLA_GSO_MAX_SIZE,
343 Self::MinMtu(_) => IFLA_MIN_MTU,
344 Self::MaxMtu(_) => IFLA_MAX_MTU,
345 Self::LinkNetNsId(_) => IFLA_LINK_NETNSID,
346 Self::OperState(_) => IFLA_OPERSTATE,
347 Self::Map(_) => IFLA_MAP,
348 Self::Stats(_) => IFLA_STATS,
349 Self::Stats64(_) => IFLA_STATS64,
350 Self::AfSpecUnspec(_) | Self::AfSpecBridge(_) | Self::AfSpecUnknown(_) => IFLA_AF_SPEC,
351 Self::Other(attr) => attr.kind(),
352 }
353 }
354}
355
356impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NlaBuffer<&'a T>, AddressFamily>
357 for LinkAttribute
358{
359 type Error = DecodeError;
360 fn parse_with_param(
361 buf: &NlaBuffer<&'a T>,
362 interface_family: AddressFamily,
363 ) -> Result<Self, DecodeError> {
364 let payload = buf.value();
365 Ok(match buf.kind() {
366 IFLA_VFINFO_LIST => {
367 let err = |payload| format!("invalid IFLA_VFINFO_LIST {payload:?}");
368 Self::VfInfoList(
369 VecLinkVfInfo::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
370 .context(err(payload))?
371 .0,
372 )
373 }
374 IFLA_VF_PORTS => {
375 let err = |payload| format!("invalid IFLA_VF_PORTS {payload:?}");
376 Self::VfPorts(
377 VecLinkVfPort::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
378 .context(err(payload))?
379 .0,
380 )
381 }
382 IFLA_PORT_SELF => {
383 let err = |payload| format!("invalid IFLA_PORT_SELF {payload:?}");
384 Self::PortSelf(
385 LinkVfPort::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
386 .context(err(payload))?,
387 )
388 }
389 IFLA_PHYS_PORT_ID => Self::PhysPortId(
390 LinkPhysId::parse(payload)
391 .context(format!("invalid IFLA_PHYS_PORT_ID value {payload:?}"))?,
392 ),
393 IFLA_PHYS_SWITCH_ID => Self::PhysSwitchId(
394 LinkPhysId::parse(payload)
395 .context(format!("invalid IFLA_PHYS_SWITCH_ID value {payload:?}"))?,
396 ),
397 IFLA_WIRELESS => Self::Wireless(
398 LinkWirelessEvent::parse(payload)
399 .context(format!("invalid IFLA_WIRELESS {payload:?}"))?,
400 ),
401 IFLA_PROTINFO => {
402 let err = |payload| format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}");
403 match interface_family {
404 AddressFamily::Inet6 => Self::ProtoInfoInet6(
405 VecLinkProtoInfoInet6::parse(
406 &NlaBuffer::new_checked(payload).context(err(payload))?,
407 )
408 .context(err(payload))?
409 .0,
410 ),
411 #[cfg(any(target_os = "linux", target_os = "fuchsia",))]
412 AddressFamily::Bridge => Self::ProtoInfoBridge(
413 VecLinkProtoInfoBridge::parse(&NlaBuffer::new_checked(payload)?)
414 .context(format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}"))?
415 .0,
416 ),
417 _ => Self::ProtoInfoUnknown(DefaultNla::parse(buf).context(format!(
418 "invalid IFLA_PROTINFO for \
419 {interface_family:?}: {payload:?}"
420 ))?),
421 }
422 }
423 IFLA_EVENT => Self::Event(
424 LinkEvent::parse(payload).context(format!("invalid IFLA_EVENT {payload:?}"))?,
425 ),
426 IFLA_NEW_NETNSID => {
427 Self::NewNetnsId(parse_i32(payload).context("invalid IFLA_NEW_NETNSID value")?)
428 }
429 IFLA_IF_NETNSID => {
430 Self::IfNetnsId(parse_i32(payload).context("invalid IFLA_IF_NETNSID value")?)
431 }
432 IFLA_CARRIER_UP_COUNT => Self::CarrierUpCount(
433 parse_u32(payload).context("invalid IFLA_CARRIER_UP_COUNT value")?,
434 ),
435 IFLA_CARRIER_DOWN_COUNT => Self::CarrierDownCount(
436 parse_u32(payload).context("invalid IFLA_CARRIER_DOWN_COUNT value")?,
437 ),
438 IFLA_NEW_IFINDEX => {
439 Self::NewIfIndex(parse_i32(payload).context("invalid IFLA_NEW_IFINDEX value")?)
440 }
441
442 IFLA_PROP_LIST => {
443 let error_msg = "invalid IFLA_PROP_LIST value";
444 let mut nlas = vec![];
445 for nla in NlasIterator::new(payload) {
446 let nla = &nla.context(error_msg)?;
447 let parsed = Prop::parse(nla).context(error_msg)?;
448 nlas.push(parsed);
449 }
450 Self::PropList(nlas)
451 }
452 IFLA_PROTO_DOWN_REASON => {
453 let mut nlas = vec![];
454 for nla in NlasIterator::new(payload) {
455 let nla = &nla.context("invalid IFLA_PROTO_DOWN_REASON value")?;
456 let parsed = LinkProtocolDownReason::parse(nla)?;
457 nlas.push(parsed);
458 }
459 Self::ProtoDownReason(nlas)
460 }
461 IFLA_ADDRESS => Self::Address(payload.to_vec()),
465 IFLA_BROADCAST => Self::Broadcast(payload.to_vec()),
466 IFLA_PERM_ADDRESS => Self::PermAddress(payload.to_vec()),
467 IFLA_IFNAME => {
469 Self::IfName(parse_string(payload).context("invalid IFLA_IFNAME value")?)
470 }
471 IFLA_QDISC => Self::Qdisc(parse_string(payload).context("invalid IFLA_QDISC value")?),
472 IFLA_IFALIAS => {
473 Self::IfAlias(parse_string(payload).context("invalid IFLA_IFALIAS value")?)
474 }
475 IFLA_PHYS_PORT_NAME => Self::PhysPortName(
476 parse_string(payload).context("invalid IFLA_PHYS_PORT_NAME value")?,
477 ),
478 IFLA_LINKMODE => Self::Mode(parse_u8(payload).context("invalid IFLA_LINKMODE value")?),
479 IFLA_CARRIER => Self::Carrier(parse_u8(payload).context("invalid IFLA_CARRIER value")?),
480 IFLA_PROTO_DOWN => {
481 Self::ProtoDown(parse_u8(payload).context("invalid IFLA_PROTO_DOWN value")?)
482 }
483
484 IFLA_MTU => Self::Mtu(parse_u32(payload).context("invalid IFLA_MTU value")?),
485 IFLA_LINK => Self::Link(parse_u32(payload).context("invalid IFLA_LINK value")?),
486 IFLA_MASTER => {
487 Self::Controller(parse_u32(payload).context("invalid IFLA_MASTER value")?)
488 }
489 IFLA_TXQLEN => {
490 Self::TxQueueLen(parse_u32(payload).context("invalid IFLA_TXQLEN value")?)
491 }
492 IFLA_NET_NS_PID => {
493 Self::NetNsPid(parse_u32(payload).context("invalid IFLA_NET_NS_PID value")?)
494 }
495 IFLA_NUM_VF => Self::NumVf(parse_u32(payload).context("invalid IFLA_NUM_VF value")?),
496 IFLA_GROUP => Self::Group(parse_u32(payload).context("invalid IFLA_GROUP value")?),
497 IFLA_NET_NS_FD => {
498 Self::NetNsFd(parse_i32(payload).context("invalid IFLA_NET_NS_FD value")?)
499 }
500 IFLA_EXT_MASK => Self::ExtMask(
501 VecLinkExtentMask::from(parse_u32(payload).context("invalid IFLA_EXT_MASK value")?)
502 .0,
503 ),
504 IFLA_PROMISCUITY => {
505 Self::Promiscuity(parse_u32(payload).context("invalid IFLA_PROMISCUITY value")?)
506 }
507 IFLA_NUM_TX_QUEUES => {
508 Self::NumTxQueues(parse_u32(payload).context("invalid IFLA_NUM_TX_QUEUES value")?)
509 }
510 IFLA_NUM_RX_QUEUES => {
511 Self::NumRxQueues(parse_u32(payload).context("invalid IFLA_NUM_RX_QUEUES value")?)
512 }
513 IFLA_CARRIER_CHANGES => Self::CarrierChanges(
514 parse_u32(payload).context("invalid IFLA_CARRIER_CHANGES value")?,
515 ),
516 IFLA_GSO_MAX_SEGS => {
517 Self::GsoMaxSegs(parse_u32(payload).context("invalid IFLA_GSO_MAX_SEGS value")?)
518 }
519 IFLA_GSO_MAX_SIZE => {
520 Self::GsoMaxSize(parse_u32(payload).context("invalid IFLA_GSO_MAX_SIZE value")?)
521 }
522 IFLA_MIN_MTU => Self::MinMtu(parse_u32(payload).context("invalid IFLA_MIN_MTU value")?),
523 IFLA_MAX_MTU => Self::MaxMtu(parse_u32(payload).context("invalid IFLA_MAX_MTU value")?),
524 IFLA_LINK_NETNSID => {
525 Self::LinkNetNsId(parse_i32(payload).context("invalid IFLA_LINK_NETNSID value")?)
526 }
527 IFLA_OPERSTATE => {
528 Self::OperState(parse_u8(payload).context("invalid IFLA_OPERSTATE value")?.into())
529 }
530 IFLA_MAP => {
531 let err = |payload| format!("Invalid IFLA_MAP value {:?}", payload);
532 Self::Map(
533 super::Map::parse(&MapBuffer::new_checked(payload).context(err(payload))?)
534 .context(err(payload))?,
535 )
536 }
537 IFLA_STATS => Self::Stats(
538 super::Stats::parse(&StatsBuffer::new(
539 expand_buffer_if_small(payload, LINK_STATS_LEN, "IFLA_STATS").as_slice(),
540 ))
541 .context(format!("Invalid IFLA_STATS value {:?}", payload))?,
542 ),
543 IFLA_STATS64 => {
544 let payload = expand_buffer_if_small(payload, LINK_STATS64_LEN, "IFLA_STATS64");
545 Self::Stats64(
546 super::Stats64::parse(&Stats64Buffer::new(payload.as_slice()))
547 .context(format!("Invalid IFLA_STATS64 value {:?}", payload))?,
548 )
549 }
550 IFLA_AF_SPEC => match interface_family {
551 AddressFamily::Unspec => {
552 let err = "invalid IFLA_AF_SPEC value for AF_UNSPEC";
553 Self::AfSpecUnspec(
554 VecAfSpecUnspec::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
555 .context(err)?
556 .0,
557 )
558 }
559 #[cfg(any(target_os = "linux", target_os = "fuchsia",))]
560 AddressFamily::Bridge => {
561 let err = "invalid IFLA_AF_SPEC value for AF_BRIDGE";
562 Self::AfSpecBridge(
563 VecAfSpecBridge::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
564 .context(err)?
565 .0,
566 )
567 }
568 _ => Self::AfSpecUnknown(payload.to_vec()),
569 },
570 IFLA_LINKINFO => {
571 let err = "invalid IFLA_LINKINFO value";
572 Self::LinkInfo(
573 VecLinkInfo::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
574 .context(err)?
575 .0,
576 )
577 }
578 IFLA_XDP => {
579 let err = "invalid IFLA_XDP value";
580 let buf = NlaBuffer::new_checked(payload).context(err)?;
581 Self::Xdp(VecLinkXdp::parse(&buf).context(err)?.0)
582 }
583 kind => {
584 Self::Other(DefaultNla::parse(buf).context(format!("unknown NLA type {kind}"))?)
585 }
586 })
587 }
588}