1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4use std::ops::Deref;
5
6use anyhow::Context;
7use byteorder::{ByteOrder, NativeEndian};
8use netlink_packet_utils::DecodeError;
9use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
10use netlink_packet_utils::parsers::{parse_ip, parse_mac, parse_u8, parse_u16, parse_u32};
11use netlink_packet_utils::traits::{Emitable, Parseable};
12
13const IFLA_BOND_AD_INFO_AGGREGATOR: u16 = 1;
14const IFLA_BOND_AD_INFO_NUM_PORTS: u16 = 2;
15const IFLA_BOND_AD_INFO_ACTOR_KEY: u16 = 3;
16const IFLA_BOND_AD_INFO_PARTNER_KEY: u16 = 4;
17const IFLA_BOND_AD_INFO_PARTNER_MAC: u16 = 5;
18
19const IFLA_BOND_MODE: u16 = 1;
20const IFLA_BOND_ACTIVE_PORT: u16 = 2;
21const IFLA_BOND_MIIMON: u16 = 3;
22const IFLA_BOND_UPDELAY: u16 = 4;
23const IFLA_BOND_DOWNDELAY: u16 = 5;
24const IFLA_BOND_USE_CARRIER: u16 = 6;
25const IFLA_BOND_ARP_INTERVAL: u16 = 7;
26const IFLA_BOND_ARP_IP_TARGET: u16 = 8;
27const IFLA_BOND_ARP_VALIDATE: u16 = 9;
28const IFLA_BOND_ARP_ALL_TARGETS: u16 = 10;
29const IFLA_BOND_PRIMARY: u16 = 11;
30const IFLA_BOND_PRIMARY_RESELECT: u16 = 12;
31const IFLA_BOND_FAIL_OVER_MAC: u16 = 13;
32const IFLA_BOND_XMIT_HASH_POLICY: u16 = 14;
33const IFLA_BOND_RESEND_IGMP: u16 = 15;
34const IFLA_BOND_NUM_PEER_NOTIF: u16 = 16;
35const IFLA_BOND_ALL_PORTS_ACTIVE: u16 = 17;
36const IFLA_BOND_MIN_LINKS: u16 = 18;
37const IFLA_BOND_LP_INTERVAL: u16 = 19;
38const IFLA_BOND_PACKETS_PER_PORT: u16 = 20;
39const IFLA_BOND_AD_LACP_RATE: u16 = 21;
40const IFLA_BOND_AD_SELECT: u16 = 22;
41const IFLA_BOND_AD_INFO: u16 = 23;
42const IFLA_BOND_AD_ACTOR_SYS_PRIO: u16 = 24;
43const IFLA_BOND_AD_USER_PORT_KEY: u16 = 25;
44const IFLA_BOND_AD_ACTOR_SYSTEM: u16 = 26;
45const IFLA_BOND_TLB_DYNAMIC_LB: u16 = 27;
46const IFLA_BOND_PEER_NOTIF_DELAY: u16 = 28;
47const IFLA_BOND_AD_LACP_ACTIVE: u16 = 29;
48const IFLA_BOND_MISSED_MAX: u16 = 30;
49const IFLA_BOND_NS_IP6_TARGET: u16 = 31;
50
51const BOND_MODE_ROUNDROBIN: u8 = 0;
52const BOND_MODE_ACTIVEBACKUP: u8 = 1;
53const BOND_MODE_XOR: u8 = 2;
54const BOND_MODE_BROADCAST: u8 = 3;
55const BOND_MODE_8023AD: u8 = 4;
56const BOND_MODE_TLB: u8 = 5;
57const BOND_MODE_ALB: u8 = 6;
58
59#[derive(Debug, Clone, Eq, PartialEq)]
60#[non_exhaustive]
61pub enum BondAdInfo {
62 Aggregator(u16),
63 NumPorts(u16),
64 ActorKey(u16),
65 PartnerKey(u16),
66 PartnerMac([u8; 6]),
67 Other(DefaultNla),
68}
69
70impl Nla for BondAdInfo {
71 fn value_len(&self) -> usize {
72 match self {
73 Self::Aggregator(_) | Self::NumPorts(_) | Self::ActorKey(_) | Self::PartnerKey(_) => 2,
74 Self::PartnerMac(_) => 6,
75 Self::Other(v) => v.value_len(),
76 }
77 }
78
79 fn kind(&self) -> u16 {
80 match self {
81 Self::Aggregator(_) => IFLA_BOND_AD_INFO_AGGREGATOR,
82 Self::NumPorts(_) => IFLA_BOND_AD_INFO_NUM_PORTS,
83 Self::ActorKey(_) => IFLA_BOND_AD_INFO_ACTOR_KEY,
84 Self::PartnerKey(_) => IFLA_BOND_AD_INFO_PARTNER_KEY,
85 Self::PartnerMac(_) => IFLA_BOND_AD_INFO_PARTNER_MAC,
86 Self::Other(v) => v.kind(),
87 }
88 }
89
90 fn emit_value(&self, buffer: &mut [u8]) {
91 match self {
92 Self::Aggregator(d) | Self::NumPorts(d) | Self::ActorKey(d) | Self::PartnerKey(d) => {
93 NativeEndian::write_u16(buffer, *d)
94 }
95 Self::PartnerMac(mac) => buffer.copy_from_slice(mac),
96 Self::Other(v) => v.emit_value(buffer),
97 }
98 }
99}
100
101impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for BondAdInfo {
102 type Error = DecodeError;
103 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
104 let payload = buf.value();
105 Ok(match buf.kind() {
106 IFLA_BOND_AD_INFO_AGGREGATOR => Self::Aggregator(
107 parse_u16(payload).context("invalid IFLA_BOND_AD_INFO_AGGREGATOR value")?,
108 ),
109 IFLA_BOND_AD_INFO_NUM_PORTS => Self::NumPorts(
110 parse_u16(payload).context("invalid IFLA_BOND_AD_INFO_NUM_PORTS value")?,
111 ),
112 IFLA_BOND_AD_INFO_ACTOR_KEY => Self::ActorKey(
113 parse_u16(payload).context("invalid IFLA_BOND_AD_INFO_ACTOR_KEY value")?,
114 ),
115 IFLA_BOND_AD_INFO_PARTNER_KEY => Self::PartnerKey(
116 parse_u16(payload).context("invalid IFLA_BOND_AD_INFO_PARTNER_KEY value")?,
117 ),
118 IFLA_BOND_AD_INFO_PARTNER_MAC => Self::PartnerMac(
119 parse_mac(payload).context("invalid IFLA_BOND_AD_INFO_PARTNER_MAC value")?,
120 ),
121 _ => Self::Other(
122 DefaultNla::parse(buf)
123 .context(format!("invalid NLA for {}: {payload:?}", buf.kind()))?,
124 ),
125 })
126 }
127}
128
129#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
130#[non_exhaustive]
131pub enum BondMode {
132 #[default]
133 BalanceRr,
134 ActiveBackup,
135 BalanceXor,
136 Broadcast,
137 Ieee8023Ad,
138 BalanceTlb,
139 BalanceAlb,
140 Other(u8),
141}
142
143impl From<u8> for BondMode {
144 fn from(d: u8) -> Self {
145 match d {
146 BOND_MODE_ROUNDROBIN => Self::BalanceRr,
147 BOND_MODE_ACTIVEBACKUP => Self::ActiveBackup,
148 BOND_MODE_XOR => Self::BalanceXor,
149 BOND_MODE_BROADCAST => Self::Broadcast,
150 BOND_MODE_8023AD => Self::Ieee8023Ad,
151 BOND_MODE_TLB => Self::BalanceTlb,
152 BOND_MODE_ALB => Self::BalanceAlb,
153 _ => Self::Other(d),
154 }
155 }
156}
157
158impl From<BondMode> for u8 {
159 fn from(d: BondMode) -> Self {
160 match d {
161 BondMode::BalanceRr => BOND_MODE_ROUNDROBIN,
162 BondMode::ActiveBackup => BOND_MODE_ACTIVEBACKUP,
163 BondMode::BalanceXor => BOND_MODE_XOR,
164 BondMode::Broadcast => BOND_MODE_BROADCAST,
165 BondMode::Ieee8023Ad => BOND_MODE_8023AD,
166 BondMode::BalanceTlb => BOND_MODE_TLB,
167 BondMode::BalanceAlb => BOND_MODE_ALB,
168 BondMode::Other(d) => d,
169 }
170 }
171}
172
173impl std::fmt::Display for BondMode {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 let kernel_name = match self {
176 BondMode::BalanceRr => "balance-rr",
177 BondMode::ActiveBackup => "active-backup",
178 BondMode::BalanceXor => "balance-xor",
179 BondMode::Broadcast => "broadcast",
180 BondMode::Ieee8023Ad => "802.3ad",
181 BondMode::BalanceTlb => "balance-tlb",
182 BondMode::BalanceAlb => "balance-alb",
183 BondMode::Other(d) => return write!(f, "unknown-variant ({d})"),
184 };
185
186 f.write_str(kernel_name)
187 }
188}
189
190struct BondIpAddrNla {
195 index: u16,
196 addr: IpAddr,
197}
198
199struct BondIpAddrNlaList(Vec<BondIpAddrNla>);
200
201impl Deref for BondIpAddrNlaList {
202 type Target = Vec<BondIpAddrNla>;
203
204 fn deref(&self) -> &Self::Target {
205 &self.0
206 }
207}
208
209impl From<&Vec<Ipv4Addr>> for BondIpAddrNlaList {
210 fn from(addrs: &Vec<Ipv4Addr>) -> Self {
211 let mut nlas = Vec::new();
212 for (i, addr) in addrs.iter().enumerate() {
213 let nla = BondIpAddrNla { index: i as u16, addr: IpAddr::V4(*addr) };
214 nlas.push(nla);
215 }
216 BondIpAddrNlaList(nlas)
217 }
218}
219
220impl From<&Vec<Ipv6Addr>> for BondIpAddrNlaList {
221 fn from(addrs: &Vec<Ipv6Addr>) -> Self {
222 let mut nlas = Vec::new();
223 for (i, addr) in addrs.iter().enumerate() {
224 let nla = BondIpAddrNla { index: i as u16, addr: IpAddr::V6(*addr) };
225 nlas.push(nla);
226 }
227 BondIpAddrNlaList(nlas)
228 }
229}
230
231impl Nla for BondIpAddrNla {
232 fn value_len(&self) -> usize {
233 if self.addr.is_ipv4() { 4 } else { 16 }
234 }
235 fn emit_value(&self, buffer: &mut [u8]) {
236 match self.addr {
237 IpAddr::V4(addr) => buffer.copy_from_slice(&addr.octets()),
238 IpAddr::V6(addr) => buffer.copy_from_slice(&addr.octets()),
239 }
240 }
241 fn kind(&self) -> u16 {
242 self.index
243 }
244}
245
246#[derive(Debug, PartialEq, Eq, Clone)]
247#[non_exhaustive]
248pub enum InfoBond {
249 Mode(BondMode),
250 ActivePort(u32),
251 MiiMon(u32),
252 UpDelay(u32),
253 DownDelay(u32),
254 UseCarrier(u8),
255 ArpInterval(u32),
256 ArpIpTarget(Vec<Ipv4Addr>),
257 ArpValidate(u32),
258 ArpAllTargets(u32),
259 Primary(u32),
260 PrimaryReselect(u8),
261 FailOverMac(u8),
262 XmitHashPolicy(u8),
263 ResendIgmp(u32),
264 NumPeerNotif(u8),
265 AllPortsActive(u8),
266 MinLinks(u32),
267 LpInterval(u32),
268 PacketsPerPort(u32),
269 AdLacpRate(u8),
270 AdSelect(u8),
271 AdInfo(Vec<BondAdInfo>),
272 AdActorSysPrio(u16),
273 AdUserPortKey(u16),
274 AdActorSystem([u8; 6]),
275 TlbDynamicLb(u8),
276 PeerNotifDelay(u32),
277 AdLacpActive(u8),
278 MissedMax(u8),
279 NsIp6Target(Vec<Ipv6Addr>),
280 Other(DefaultNla),
281}
282
283impl Nla for InfoBond {
284 fn value_len(&self) -> usize {
285 match self {
286 Self::Mode(_)
287 | Self::UseCarrier(_)
288 | Self::PrimaryReselect(_)
289 | Self::FailOverMac(_)
290 | Self::XmitHashPolicy(_)
291 | Self::NumPeerNotif(_)
292 | Self::AllPortsActive(_)
293 | Self::AdLacpActive(_)
294 | Self::AdLacpRate(_)
295 | Self::AdSelect(_)
296 | Self::TlbDynamicLb(_)
297 | Self::MissedMax(_) => 1,
298 Self::AdActorSysPrio(_) | Self::AdUserPortKey(_) => 2,
299 Self::ActivePort(_)
300 | Self::MiiMon(_)
301 | Self::UpDelay(_)
302 | Self::DownDelay(_)
303 | Self::ArpInterval(_)
304 | Self::ArpValidate(_)
305 | Self::ArpAllTargets(_)
306 | Self::Primary(_)
307 | Self::ResendIgmp(_)
308 | Self::MinLinks(_)
309 | Self::LpInterval(_)
310 | Self::PacketsPerPort(_)
311 | Self::PeerNotifDelay(_) => 4,
312 Self::ArpIpTarget(ref addrs) => BondIpAddrNlaList::from(addrs).as_slice().buffer_len(),
313 Self::NsIp6Target(ref addrs) => BondIpAddrNlaList::from(addrs).as_slice().buffer_len(),
314 Self::AdActorSystem(_) => 6,
315 Self::AdInfo(infos) => infos.as_slice().buffer_len(),
316 Self::Other(v) => v.value_len(),
317 }
318 }
319
320 fn emit_value(&self, buffer: &mut [u8]) {
321 match self {
322 Self::Mode(value) => buffer[0] = (*value).into(),
323 Self::UseCarrier(value)
324 | Self::PrimaryReselect(value)
325 | Self::FailOverMac(value)
326 | Self::XmitHashPolicy(value)
327 | Self::NumPeerNotif(value)
328 | Self::AllPortsActive(value)
329 | Self::AdLacpActive(value)
330 | Self::AdLacpRate(value)
331 | Self::AdSelect(value)
332 | Self::TlbDynamicLb(value)
333 | Self::MissedMax(value) => buffer[0] = *value,
334 Self::AdActorSysPrio(value) | Self::AdUserPortKey(value) => {
335 NativeEndian::write_u16(buffer, *value)
336 }
337 Self::ActivePort(value)
338 | Self::MiiMon(value)
339 | Self::UpDelay(value)
340 | Self::DownDelay(value)
341 | Self::ArpInterval(value)
342 | Self::ArpValidate(value)
343 | Self::ArpAllTargets(value)
344 | Self::Primary(value)
345 | Self::ResendIgmp(value)
346 | Self::MinLinks(value)
347 | Self::LpInterval(value)
348 | Self::PacketsPerPort(value)
349 | Self::PeerNotifDelay(value) => NativeEndian::write_u32(buffer, *value),
350 Self::AdActorSystem(bytes) => buffer.copy_from_slice(bytes),
351 Self::ArpIpTarget(addrs) => BondIpAddrNlaList::from(addrs).as_slice().emit(buffer),
352 Self::NsIp6Target(addrs) => BondIpAddrNlaList::from(addrs).as_slice().emit(buffer),
353 Self::AdInfo(infos) => infos.as_slice().emit(buffer),
354 Self::Other(v) => v.emit_value(buffer),
355 }
356 }
357
358 fn kind(&self) -> u16 {
359 match self {
360 Self::Mode(_) => IFLA_BOND_MODE,
361 Self::ActivePort(_) => IFLA_BOND_ACTIVE_PORT,
362 Self::MiiMon(_) => IFLA_BOND_MIIMON,
363 Self::UpDelay(_) => IFLA_BOND_UPDELAY,
364 Self::DownDelay(_) => IFLA_BOND_DOWNDELAY,
365 Self::UseCarrier(_) => IFLA_BOND_USE_CARRIER,
366 Self::ArpInterval(_) => IFLA_BOND_ARP_INTERVAL,
367 Self::ArpIpTarget(_) => IFLA_BOND_ARP_IP_TARGET,
368 Self::ArpValidate(_) => IFLA_BOND_ARP_VALIDATE,
369 Self::ArpAllTargets(_) => IFLA_BOND_ARP_ALL_TARGETS,
370 Self::Primary(_) => IFLA_BOND_PRIMARY,
371 Self::PrimaryReselect(_) => IFLA_BOND_PRIMARY_RESELECT,
372 Self::FailOverMac(_) => IFLA_BOND_FAIL_OVER_MAC,
373 Self::XmitHashPolicy(_) => IFLA_BOND_XMIT_HASH_POLICY,
374 Self::ResendIgmp(_) => IFLA_BOND_RESEND_IGMP,
375 Self::NumPeerNotif(_) => IFLA_BOND_NUM_PEER_NOTIF,
376 Self::AllPortsActive(_) => IFLA_BOND_ALL_PORTS_ACTIVE,
377 Self::MinLinks(_) => IFLA_BOND_MIN_LINKS,
378 Self::LpInterval(_) => IFLA_BOND_LP_INTERVAL,
379 Self::PacketsPerPort(_) => IFLA_BOND_PACKETS_PER_PORT,
380 Self::AdLacpRate(_) => IFLA_BOND_AD_LACP_RATE,
381 Self::AdSelect(_) => IFLA_BOND_AD_SELECT,
382 Self::AdInfo(_) => IFLA_BOND_AD_INFO,
383 Self::AdActorSysPrio(_) => IFLA_BOND_AD_ACTOR_SYS_PRIO,
384 Self::AdUserPortKey(_) => IFLA_BOND_AD_USER_PORT_KEY,
385 Self::AdActorSystem(_) => IFLA_BOND_AD_ACTOR_SYSTEM,
386 Self::TlbDynamicLb(_) => IFLA_BOND_TLB_DYNAMIC_LB,
387 Self::PeerNotifDelay(_) => IFLA_BOND_PEER_NOTIF_DELAY,
388 Self::AdLacpActive(_) => IFLA_BOND_AD_LACP_ACTIVE,
389 Self::MissedMax(_) => IFLA_BOND_MISSED_MAX,
390 Self::NsIp6Target(_) => IFLA_BOND_NS_IP6_TARGET,
391 Self::Other(v) => v.kind(),
392 }
393 }
394}
395
396impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBond {
397 type Error = DecodeError;
398 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
399 let payload = buf.value();
400 Ok(match buf.kind() {
401 IFLA_BOND_MODE => {
402 Self::Mode(parse_u8(payload).context("invalid IFLA_BOND_MODE value")?.into())
403 }
404 IFLA_BOND_ACTIVE_PORT => {
405 Self::ActivePort(parse_u32(payload).context("invalid IFLA_BOND_ACTIVE_PORT value")?)
406 }
407 IFLA_BOND_MIIMON => {
408 Self::MiiMon(parse_u32(payload).context("invalid IFLA_BOND_MIIMON value")?)
409 }
410 IFLA_BOND_UPDELAY => {
411 Self::UpDelay(parse_u32(payload).context("invalid IFLA_BOND_UPDELAY value")?)
412 }
413 IFLA_BOND_DOWNDELAY => {
414 Self::DownDelay(parse_u32(payload).context("invalid IFLA_BOND_DOWNDELAY value")?)
415 }
416 IFLA_BOND_USE_CARRIER => {
417 Self::UseCarrier(parse_u8(payload).context("invalid IFLA_BOND_USE_CARRIER value")?)
418 }
419 IFLA_BOND_ARP_INTERVAL => Self::ArpInterval(
420 parse_u32(payload).context("invalid IFLA_BOND_ARP_INTERVAL value")?,
421 ),
422 IFLA_BOND_ARP_IP_TARGET => {
423 let mut addrs = Vec::<Ipv4Addr>::new();
424 for nla in NlasIterator::new(payload) {
425 let nla = &nla.context("invalid IFLA_BOND_ARP_IP_TARGET value")?;
426 if let Ok(IpAddr::V4(addr)) = parse_ip(nla.value()) {
427 addrs.push(addr);
428 }
429 }
430 Self::ArpIpTarget(addrs)
431 }
432 IFLA_BOND_ARP_VALIDATE => Self::ArpValidate(
433 parse_u32(payload).context("invalid IFLA_BOND_ARP_VALIDATE value")?,
434 ),
435 IFLA_BOND_ARP_ALL_TARGETS => Self::ArpAllTargets(
436 parse_u32(payload).context("invalid IFLA_BOND_ARP_ALL_TARGETS value")?,
437 ),
438 IFLA_BOND_PRIMARY => {
439 Self::Primary(parse_u32(payload).context("invalid IFLA_BOND_PRIMARY value")?)
440 }
441 IFLA_BOND_PRIMARY_RESELECT => Self::PrimaryReselect(
442 parse_u8(payload).context("invalid IFLA_BOND_PRIMARY_RESELECT value")?,
443 ),
444 IFLA_BOND_FAIL_OVER_MAC => Self::FailOverMac(
445 parse_u8(payload).context("invalid IFLA_BOND_FAIL_OVER_MAC value")?,
446 ),
447 IFLA_BOND_XMIT_HASH_POLICY => Self::XmitHashPolicy(
448 parse_u8(payload).context("invalid IFLA_BOND_XMIT_HASH_POLICY value")?,
449 ),
450 IFLA_BOND_RESEND_IGMP => {
451 Self::ResendIgmp(parse_u32(payload).context("invalid IFLA_BOND_RESEND_IGMP value")?)
452 }
453 IFLA_BOND_NUM_PEER_NOTIF => Self::NumPeerNotif(
454 parse_u8(payload).context("invalid IFLA_BOND_NUM_PEER_NOTIF value")?,
455 ),
456 IFLA_BOND_ALL_PORTS_ACTIVE => Self::AllPortsActive(
457 parse_u8(payload).context("invalid IFLA_BOND_ALL_PORTS_ACTIVE value")?,
458 ),
459 IFLA_BOND_MIN_LINKS => {
460 Self::MinLinks(parse_u32(payload).context("invalid IFLA_BOND_MIN_LINKS value")?)
461 }
462 IFLA_BOND_LP_INTERVAL => {
463 Self::LpInterval(parse_u32(payload).context("invalid IFLA_BOND_LP_INTERVAL value")?)
464 }
465 IFLA_BOND_PACKETS_PER_PORT => Self::PacketsPerPort(
466 parse_u32(payload).context("invalid IFLA_BOND_PACKETS_PER_PORT value")?,
467 ),
468 IFLA_BOND_AD_LACP_RATE => {
469 Self::AdLacpRate(parse_u8(payload).context("invalid IFLA_BOND_AD_LACP_RATE value")?)
470 }
471 IFLA_BOND_AD_SELECT => {
472 Self::AdSelect(parse_u8(payload).context("invalid IFLA_BOND_AD_SELECT value")?)
473 }
474 IFLA_BOND_AD_INFO => {
475 let mut infos = Vec::new();
476 let err = "failed to parse IFLA_BOND_AD_INFO";
477 for nla in NlasIterator::new(payload) {
478 let nla = &nla.context(err)?;
479 let info = BondAdInfo::parse(nla).context(err)?;
480 infos.push(info);
481 }
482 Self::AdInfo(infos)
483 }
484 IFLA_BOND_AD_ACTOR_SYS_PRIO => Self::AdActorSysPrio(
485 parse_u16(payload).context("invalid IFLA_BOND_AD_ACTOR_SYS_PRIO value")?,
486 ),
487 IFLA_BOND_AD_USER_PORT_KEY => Self::AdUserPortKey(
488 parse_u16(payload).context("invalid IFLA_BOND_AD_USER_PORT_KEY value")?,
489 ),
490 IFLA_BOND_AD_ACTOR_SYSTEM => Self::AdActorSystem(
491 parse_mac(payload).context("invalid IFLA_BOND_AD_ACTOR_SYSTEM value")?,
492 ),
493 IFLA_BOND_TLB_DYNAMIC_LB => Self::TlbDynamicLb(
494 parse_u8(payload).context("invalid IFLA_BOND_TLB_DYNAMIC_LB value")?,
495 ),
496 IFLA_BOND_PEER_NOTIF_DELAY => Self::PeerNotifDelay(
497 parse_u32(payload).context("invalid IFLA_BOND_PEER_NOTIF_DELAY value")?,
498 ),
499 IFLA_BOND_AD_LACP_ACTIVE => Self::AdLacpActive(
500 parse_u8(payload).context("invalid IFLA_BOND_AD_LACP_ACTIVE value")?,
501 ),
502 IFLA_BOND_MISSED_MAX => {
503 Self::MissedMax(parse_u8(payload).context("invalid IFLA_BOND_MISSED_MAX value")?)
504 }
505 IFLA_BOND_NS_IP6_TARGET => {
506 let mut addrs = Vec::<Ipv6Addr>::new();
507 for nla in NlasIterator::new(payload) {
508 let nla = &nla.context("invalid IFLA_BOND_NS_IP6_TARGET value")?;
509 if let Ok(IpAddr::V6(addr)) = parse_ip(nla.value()) {
510 addrs.push(addr);
511 }
512 }
513 Self::NsIp6Target(addrs)
514 }
515 _ => Self::Other(
516 DefaultNla::parse(buf)
517 .context(format!("invalid NLA for {}: {payload:?}", buf.kind()))?,
518 ),
519 })
520 }
521}