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