1use std::{
4 net::{IpAddr, Ipv4Addr, Ipv6Addr},
5 ops::Deref,
6};
7
8use netlink_packet_core::{
9 emit_u16, emit_u32, parse_ip, parse_mac, parse_u16, parse_u32, parse_u8,
10 DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
11 NlasIterator, Parseable,
12};
13
14const IFLA_BOND_AD_INFO_AGGREGATOR: u16 = 1;
15const IFLA_BOND_AD_INFO_NUM_PORTS: u16 = 2;
16const IFLA_BOND_AD_INFO_ACTOR_KEY: u16 = 3;
17const IFLA_BOND_AD_INFO_PARTNER_KEY: u16 = 4;
18const IFLA_BOND_AD_INFO_PARTNER_MAC: u16 = 5;
19
20const IFLA_BOND_MODE: u16 = 1;
21const IFLA_BOND_ACTIVE_PORT: u16 = 2;
22const IFLA_BOND_MIIMON: u16 = 3;
23const IFLA_BOND_UPDELAY: u16 = 4;
24const IFLA_BOND_DOWNDELAY: u16 = 5;
25const IFLA_BOND_USE_CARRIER: u16 = 6;
26const IFLA_BOND_ARP_INTERVAL: u16 = 7;
27const IFLA_BOND_ARP_IP_TARGET: u16 = 8;
28const IFLA_BOND_ARP_VALIDATE: u16 = 9;
29const IFLA_BOND_ARP_ALL_TARGETS: u16 = 10;
30const IFLA_BOND_PRIMARY: u16 = 11;
31const IFLA_BOND_PRIMARY_RESELECT: u16 = 12;
32const IFLA_BOND_FAIL_OVER_MAC: u16 = 13;
33const IFLA_BOND_XMIT_HASH_POLICY: u16 = 14;
34const IFLA_BOND_RESEND_IGMP: u16 = 15;
35const IFLA_BOND_NUM_PEER_NOTIF: u16 = 16;
36const IFLA_BOND_ALL_PORTS_ACTIVE: u16 = 17;
37const IFLA_BOND_MIN_LINKS: u16 = 18;
38const IFLA_BOND_LP_INTERVAL: u16 = 19;
39const IFLA_BOND_PACKETS_PER_PORT: u16 = 20;
40const IFLA_BOND_AD_LACP_RATE: u16 = 21;
41const IFLA_BOND_AD_SELECT: u16 = 22;
42const IFLA_BOND_AD_INFO: u16 = 23;
43const IFLA_BOND_AD_ACTOR_SYS_PRIO: u16 = 24;
44const IFLA_BOND_AD_USER_PORT_KEY: u16 = 25;
45const IFLA_BOND_AD_ACTOR_SYSTEM: u16 = 26;
46const IFLA_BOND_TLB_DYNAMIC_LB: u16 = 27;
47const IFLA_BOND_PEER_NOTIF_DELAY: u16 = 28;
48const IFLA_BOND_AD_LACP_ACTIVE: u16 = 29;
49const IFLA_BOND_MISSED_MAX: u16 = 30;
50const IFLA_BOND_NS_IP6_TARGET: u16 = 31;
51
52const BOND_MODE_ROUNDROBIN: u8 = 0;
53const BOND_MODE_ACTIVEBACKUP: u8 = 1;
54const BOND_MODE_XOR: u8 = 2;
55const BOND_MODE_BROADCAST: u8 = 3;
56const BOND_MODE_8023AD: u8 = 4;
57const BOND_MODE_TLB: u8 = 5;
58const BOND_MODE_ALB: u8 = 6;
59
60const BOND_STATE_ACTIVE: u8 = 0;
61const BOND_STATE_BACKUP: u8 = 1;
62
63const BOND_ARP_VALIDATE_NONE: u32 = 0;
64const BOND_ARP_VALIDATE_ACTIVE: u32 = 1 << BOND_STATE_ACTIVE as u32;
65const BOND_ARP_VALIDATE_BACKUP: u32 = 1 << BOND_STATE_BACKUP as u32;
66const BOND_ARP_VALIDATE_ALL: u32 =
67 BOND_ARP_VALIDATE_ACTIVE | BOND_ARP_VALIDATE_BACKUP;
68const BOND_ARP_FILTER: u32 = BOND_ARP_VALIDATE_ALL + 1;
69const BOND_ARP_FILTER_ACTIVE: u32 = BOND_ARP_FILTER | BOND_ARP_VALIDATE_ACTIVE;
70const BOND_ARP_FILTER_BACKUP: u32 = BOND_ARP_FILTER | BOND_ARP_VALIDATE_BACKUP;
71const BOND_XMIT_POLICY_LAYER2: u8 = 0;
72const BOND_XMIT_POLICY_LAYER34: u8 = 1;
73const BOND_XMIT_POLICY_LAYER23: u8 = 2;
74const BOND_XMIT_POLICY_ENCAP23: u8 = 3;
75const BOND_XMIT_POLICY_ENCAP34: u8 = 4;
76const BOND_XMIT_POLICY_VLAN_SRCMAC: u8 = 5;
77const BOND_OPT_ARP_ALL_TARGETS_ANY: u32 = 0;
78const BOND_OPT_ARP_ALL_TARGETS_ALL: u32 = 1;
79const BOND_PRI_RESELECT_ALWAYS: u8 = 0;
80const BOND_PRI_RESELECT_BETTER: u8 = 1;
81const BOND_PRI_RESELECT_FAILURE: u8 = 2;
82const BOND_FOM_NONE: u8 = 0;
83const BOND_FOM_ACTIVE: u8 = 1;
84const BOND_FOM_FOLLOW: u8 = 2;
85
86#[derive(Debug, Clone, Eq, PartialEq)]
87#[non_exhaustive]
88pub enum BondAdInfo {
89 Aggregator(u16),
90 NumPorts(u16),
91 ActorKey(u16),
92 PartnerKey(u16),
93 PartnerMac([u8; 6]),
94 Other(DefaultNla),
95}
96
97impl Nla for BondAdInfo {
98 fn value_len(&self) -> usize {
99 match self {
100 Self::Aggregator(_)
101 | Self::NumPorts(_)
102 | Self::ActorKey(_)
103 | Self::PartnerKey(_) => 2,
104 Self::PartnerMac(_) => 6,
105 Self::Other(v) => v.value_len(),
106 }
107 }
108
109 fn kind(&self) -> u16 {
110 match self {
111 Self::Aggregator(_) => IFLA_BOND_AD_INFO_AGGREGATOR,
112 Self::NumPorts(_) => IFLA_BOND_AD_INFO_NUM_PORTS,
113 Self::ActorKey(_) => IFLA_BOND_AD_INFO_ACTOR_KEY,
114 Self::PartnerKey(_) => IFLA_BOND_AD_INFO_PARTNER_KEY,
115 Self::PartnerMac(_) => IFLA_BOND_AD_INFO_PARTNER_MAC,
116 Self::Other(v) => v.kind(),
117 }
118 }
119
120 fn emit_value(&self, buffer: &mut [u8]) {
121 match self {
122 Self::Aggregator(d)
123 | Self::NumPorts(d)
124 | Self::ActorKey(d)
125 | Self::PartnerKey(d) => emit_u16(buffer, *d).unwrap(),
126 Self::PartnerMac(mac) => buffer.copy_from_slice(mac),
127 Self::Other(v) => v.emit_value(buffer),
128 }
129 }
130}
131
132impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for BondAdInfo {
133 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
134 let payload = buf.value();
135 Ok(match buf.kind() {
136 IFLA_BOND_AD_INFO_AGGREGATOR => Self::Aggregator(
137 parse_u16(payload)
138 .context("invalid IFLA_BOND_AD_INFO_AGGREGATOR value")?,
139 ),
140 IFLA_BOND_AD_INFO_NUM_PORTS => Self::NumPorts(
141 parse_u16(payload)
142 .context("invalid IFLA_BOND_AD_INFO_NUM_PORTS value")?,
143 ),
144 IFLA_BOND_AD_INFO_ACTOR_KEY => Self::ActorKey(
145 parse_u16(payload)
146 .context("invalid IFLA_BOND_AD_INFO_ACTOR_KEY value")?,
147 ),
148 IFLA_BOND_AD_INFO_PARTNER_KEY => Self::PartnerKey(
149 parse_u16(payload)
150 .context("invalid IFLA_BOND_AD_INFO_PARTNER_KEY value")?,
151 ),
152 IFLA_BOND_AD_INFO_PARTNER_MAC => Self::PartnerMac(
153 parse_mac(payload)
154 .context("invalid IFLA_BOND_AD_INFO_PARTNER_MAC value")?,
155 ),
156 _ => Self::Other(DefaultNla::parse(buf).context(format!(
157 "invalid NLA for {}: {payload:?}",
158 buf.kind()
159 ))?),
160 })
161 }
162}
163
164#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
165#[non_exhaustive]
166pub enum BondMode {
167 #[default]
168 BalanceRr,
169 ActiveBackup,
170 BalanceXor,
171 Broadcast,
172 Ieee8023Ad,
173 BalanceTlb,
174 BalanceAlb,
175 Other(u8),
176}
177
178impl From<u8> for BondMode {
179 fn from(d: u8) -> Self {
180 match d {
181 BOND_MODE_ROUNDROBIN => Self::BalanceRr,
182 BOND_MODE_ACTIVEBACKUP => Self::ActiveBackup,
183 BOND_MODE_XOR => Self::BalanceXor,
184 BOND_MODE_BROADCAST => Self::Broadcast,
185 BOND_MODE_8023AD => Self::Ieee8023Ad,
186 BOND_MODE_TLB => Self::BalanceTlb,
187 BOND_MODE_ALB => Self::BalanceAlb,
188 _ => Self::Other(d),
189 }
190 }
191}
192
193impl From<BondMode> for u8 {
194 fn from(d: BondMode) -> Self {
195 match d {
196 BondMode::BalanceRr => BOND_MODE_ROUNDROBIN,
197 BondMode::ActiveBackup => BOND_MODE_ACTIVEBACKUP,
198 BondMode::BalanceXor => BOND_MODE_XOR,
199 BondMode::Broadcast => BOND_MODE_BROADCAST,
200 BondMode::Ieee8023Ad => BOND_MODE_8023AD,
201 BondMode::BalanceTlb => BOND_MODE_TLB,
202 BondMode::BalanceAlb => BOND_MODE_ALB,
203 BondMode::Other(d) => d,
204 }
205 }
206}
207
208impl std::fmt::Display for BondMode {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 let kernel_name = match self {
211 BondMode::BalanceRr => "balance-rr",
212 BondMode::ActiveBackup => "active-backup",
213 BondMode::BalanceXor => "balance-xor",
214 BondMode::Broadcast => "broadcast",
215 BondMode::Ieee8023Ad => "802.3ad",
216 BondMode::BalanceTlb => "balance-tlb",
217 BondMode::BalanceAlb => "balance-alb",
218 BondMode::Other(d) => return write!(f, "unknown-variant ({d})"),
219 };
220
221 f.write_str(kernel_name)
222 }
223}
224
225#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
226#[non_exhaustive]
227pub enum BondArpValidate {
228 #[default]
229 None,
230 Active,
231 Backup,
232 All,
233 Filter,
234 FilterActive,
235 FilterBackup,
236 Other(u32),
237}
238
239impl From<BondArpValidate> for u32 {
240 fn from(value: BondArpValidate) -> Self {
241 match value {
242 BondArpValidate::None => BOND_ARP_VALIDATE_NONE,
243 BondArpValidate::Active => BOND_ARP_VALIDATE_ACTIVE,
244 BondArpValidate::Backup => BOND_ARP_VALIDATE_BACKUP,
245 BondArpValidate::All => BOND_ARP_VALIDATE_ALL,
246 BondArpValidate::Filter => BOND_ARP_FILTER,
247 BondArpValidate::FilterActive => BOND_ARP_FILTER_ACTIVE,
248 BondArpValidate::FilterBackup => BOND_ARP_FILTER_BACKUP,
249 BondArpValidate::Other(d) => d,
250 }
251 }
252}
253
254impl From<u32> for BondArpValidate {
255 fn from(value: u32) -> Self {
256 match value {
257 BOND_ARP_VALIDATE_NONE => BondArpValidate::None,
258 BOND_ARP_VALIDATE_ACTIVE => BondArpValidate::Active,
259 BOND_ARP_VALIDATE_BACKUP => BondArpValidate::Backup,
260 BOND_ARP_VALIDATE_ALL => BondArpValidate::All,
261 BOND_ARP_FILTER => BondArpValidate::Filter,
262 BOND_ARP_FILTER_ACTIVE => BondArpValidate::FilterActive,
263 BOND_ARP_FILTER_BACKUP => BondArpValidate::FilterBackup,
264 d => BondArpValidate::Other(d),
265 }
266 }
267}
268
269impl std::fmt::Display for BondArpValidate {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 let kernel_name = match self {
272 BondArpValidate::None => "none",
273 BondArpValidate::Active => "active",
274 BondArpValidate::Backup => "backup",
275 BondArpValidate::All => "all",
276 BondArpValidate::Filter => "filter",
277 BondArpValidate::FilterActive => "filter_active",
278 BondArpValidate::FilterBackup => "filter_backup",
279 BondArpValidate::Other(d) => {
280 return write!(f, "unknown-variant ({d})")
281 }
282 };
283 f.write_str(kernel_name)
284 }
285}
286
287#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
288#[non_exhaustive]
289pub enum BondPrimaryReselect {
290 #[default]
291 Always,
292 Better,
293 Failure,
294 Other(u8),
295}
296
297impl From<BondPrimaryReselect> for u8 {
298 fn from(value: BondPrimaryReselect) -> Self {
299 match value {
300 BondPrimaryReselect::Always => BOND_PRI_RESELECT_ALWAYS,
301 BondPrimaryReselect::Better => BOND_PRI_RESELECT_BETTER,
302 BondPrimaryReselect::Failure => BOND_PRI_RESELECT_FAILURE,
303 BondPrimaryReselect::Other(d) => d,
304 }
305 }
306}
307
308impl From<u8> for BondPrimaryReselect {
309 fn from(value: u8) -> Self {
310 match value {
311 BOND_PRI_RESELECT_ALWAYS => BondPrimaryReselect::Always,
312 BOND_PRI_RESELECT_BETTER => BondPrimaryReselect::Better,
313 BOND_PRI_RESELECT_FAILURE => BondPrimaryReselect::Failure,
314 d => BondPrimaryReselect::Other(d),
315 }
316 }
317}
318
319impl std::fmt::Display for BondPrimaryReselect {
320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 let kernel_name = match self {
322 BondPrimaryReselect::Always => "always",
323 BondPrimaryReselect::Better => "better",
324 BondPrimaryReselect::Failure => "failure",
325 BondPrimaryReselect::Other(d) => {
326 return write!(f, "unknown-variant ({d})")
327 }
328 };
329 f.write_str(kernel_name)
330 }
331}
332
333#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
334#[non_exhaustive]
335pub enum BondXmitHashPolicy {
336 #[default]
337 Layer2,
338 Layer34,
339 Layer23,
340 Encap23,
341 Encap34,
342 VlanSrcMac,
343 Other(u8),
344}
345
346impl From<BondXmitHashPolicy> for u8 {
347 fn from(value: BondXmitHashPolicy) -> Self {
348 match value {
349 BondXmitHashPolicy::Layer2 => BOND_XMIT_POLICY_LAYER2,
350 BondXmitHashPolicy::Layer34 => BOND_XMIT_POLICY_LAYER34,
351 BondXmitHashPolicy::Layer23 => BOND_XMIT_POLICY_LAYER23,
352 BondXmitHashPolicy::Encap23 => BOND_XMIT_POLICY_ENCAP23,
353 BondXmitHashPolicy::Encap34 => BOND_XMIT_POLICY_ENCAP34,
354 BondXmitHashPolicy::VlanSrcMac => BOND_XMIT_POLICY_VLAN_SRCMAC,
355 BondXmitHashPolicy::Other(d) => d,
356 }
357 }
358}
359
360impl From<u8> for BondXmitHashPolicy {
361 fn from(value: u8) -> Self {
362 match value {
363 BOND_XMIT_POLICY_LAYER2 => BondXmitHashPolicy::Layer2,
364 BOND_XMIT_POLICY_LAYER34 => BondXmitHashPolicy::Layer34,
365 BOND_XMIT_POLICY_LAYER23 => BondXmitHashPolicy::Layer23,
366 BOND_XMIT_POLICY_ENCAP23 => BondXmitHashPolicy::Encap23,
367 BOND_XMIT_POLICY_ENCAP34 => BondXmitHashPolicy::Encap34,
368 BOND_XMIT_POLICY_VLAN_SRCMAC => BondXmitHashPolicy::VlanSrcMac,
369 d => BondXmitHashPolicy::Other(d),
370 }
371 }
372}
373
374impl std::fmt::Display for BondXmitHashPolicy {
375 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376 let kernel_name = match self {
377 BondXmitHashPolicy::Layer2 => "layer2",
378 BondXmitHashPolicy::Layer34 => "layer34",
379 BondXmitHashPolicy::Layer23 => "layer23",
380 BondXmitHashPolicy::Encap23 => "encap23",
381 BondXmitHashPolicy::Encap34 => "encap34",
382 BondXmitHashPolicy::VlanSrcMac => "vlan-src-mac",
383 BondXmitHashPolicy::Other(d) => {
384 return write!(f, "unknown-variant ({d})")
385 }
386 };
387 f.write_str(kernel_name)
388 }
389}
390
391#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
392#[non_exhaustive]
393pub enum BondArpAllTargets {
394 #[default]
395 Any,
396 All,
397 Other(u32),
398}
399
400impl From<BondArpAllTargets> for u32 {
401 fn from(value: BondArpAllTargets) -> Self {
402 match value {
403 BondArpAllTargets::All => BOND_OPT_ARP_ALL_TARGETS_ALL,
404 BondArpAllTargets::Any => BOND_OPT_ARP_ALL_TARGETS_ANY,
405 BondArpAllTargets::Other(d) => d,
406 }
407 }
408}
409
410impl From<u32> for BondArpAllTargets {
411 fn from(value: u32) -> Self {
412 match value {
413 BOND_OPT_ARP_ALL_TARGETS_ANY => BondArpAllTargets::Any,
414 BOND_OPT_ARP_ALL_TARGETS_ALL => BondArpAllTargets::All,
415 d => BondArpAllTargets::Other(d),
416 }
417 }
418}
419
420impl std::fmt::Display for BondArpAllTargets {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 let kernel_name = match self {
423 BondArpAllTargets::Any => "any",
424 BondArpAllTargets::All => "all",
425 BondArpAllTargets::Other(d) => {
426 return write!(f, "unknown-variant ({d})")
427 }
428 };
429 f.write_str(kernel_name)
430 }
431}
432
433#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
434#[non_exhaustive]
435pub enum BondFailOverMac {
436 #[default]
437 None,
438 Active,
439 Follow,
440 Other(u8),
441}
442
443impl From<BondFailOverMac> for u8 {
444 fn from(value: BondFailOverMac) -> Self {
445 match value {
446 BondFailOverMac::None => BOND_FOM_NONE,
447 BondFailOverMac::Active => BOND_FOM_ACTIVE,
448 BondFailOverMac::Follow => BOND_FOM_FOLLOW,
449 BondFailOverMac::Other(d) => d,
450 }
451 }
452}
453
454impl From<u8> for BondFailOverMac {
455 fn from(value: u8) -> Self {
456 match value {
457 BOND_FOM_NONE => BondFailOverMac::None,
458 BOND_FOM_ACTIVE => BondFailOverMac::Active,
459 BOND_FOM_FOLLOW => BondFailOverMac::Follow,
460 d => BondFailOverMac::Other(d),
461 }
462 }
463}
464
465impl std::fmt::Display for BondFailOverMac {
466 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
467 let kernel_name = match self {
468 BondFailOverMac::None => "none",
469 BondFailOverMac::Active => "active",
470 BondFailOverMac::Follow => "follow",
471 BondFailOverMac::Other(d) => {
472 return write!(f, "unknown-variant ({d})")
473 }
474 };
475 f.write_str(kernel_name)
476 }
477}
478
479struct BondIpAddrNla {
484 index: u16,
485 addr: IpAddr,
486}
487
488struct BondIpAddrNlaList(Vec<BondIpAddrNla>);
489
490impl Deref for BondIpAddrNlaList {
491 type Target = Vec<BondIpAddrNla>;
492
493 fn deref(&self) -> &Self::Target {
494 &self.0
495 }
496}
497
498impl From<&Vec<Ipv4Addr>> for BondIpAddrNlaList {
499 fn from(addrs: &Vec<Ipv4Addr>) -> Self {
500 let mut nlas = Vec::new();
501 for (i, addr) in addrs.iter().enumerate() {
502 let nla = BondIpAddrNla {
503 index: i as u16,
504 addr: IpAddr::V4(*addr),
505 };
506 nlas.push(nla);
507 }
508 BondIpAddrNlaList(nlas)
509 }
510}
511
512impl From<&Vec<Ipv6Addr>> for BondIpAddrNlaList {
513 fn from(addrs: &Vec<Ipv6Addr>) -> Self {
514 let mut nlas = Vec::new();
515 for (i, addr) in addrs.iter().enumerate() {
516 let nla = BondIpAddrNla {
517 index: i as u16,
518 addr: IpAddr::V6(*addr),
519 };
520 nlas.push(nla);
521 }
522 BondIpAddrNlaList(nlas)
523 }
524}
525
526impl Nla for BondIpAddrNla {
527 fn value_len(&self) -> usize {
528 if self.addr.is_ipv4() {
529 4
530 } else {
531 16
532 }
533 }
534 fn emit_value(&self, buffer: &mut [u8]) {
535 match self.addr {
536 IpAddr::V4(addr) => buffer.copy_from_slice(&addr.octets()),
537 IpAddr::V6(addr) => buffer.copy_from_slice(&addr.octets()),
538 }
539 }
540 fn kind(&self) -> u16 {
541 self.index
542 }
543}
544
545#[derive(Debug, PartialEq, Eq, Clone)]
546#[non_exhaustive]
547pub enum InfoBond {
548 Mode(BondMode),
549 ActivePort(u32),
550 MiiMon(u32),
551 UpDelay(u32),
552 DownDelay(u32),
553 UseCarrier(u8),
554 ArpInterval(u32),
555 ArpIpTarget(Vec<Ipv4Addr>),
556 ArpValidate(BondArpValidate),
557 ArpAllTargets(BondArpAllTargets),
558 Primary(u32),
559 PrimaryReselect(BondPrimaryReselect),
560 FailOverMac(BondFailOverMac),
561 XmitHashPolicy(BondXmitHashPolicy),
562 ResendIgmp(u32),
563 NumPeerNotif(u8),
564 AllPortsActive(u8),
565 MinLinks(u32),
566 LpInterval(u32),
567 PacketsPerPort(u32),
568 AdLacpRate(u8),
569 AdSelect(u8),
570 AdInfo(Vec<BondAdInfo>),
571 AdActorSysPrio(u16),
572 AdUserPortKey(u16),
573 AdActorSystem([u8; 6]),
574 TlbDynamicLb(u8),
575 PeerNotifDelay(u32),
576 AdLacpActive(u8),
577 MissedMax(u8),
578 NsIp6Target(Vec<Ipv6Addr>),
579 Other(DefaultNla),
580}
581
582impl Nla for InfoBond {
583 fn value_len(&self) -> usize {
584 match self {
585 Self::Mode(_)
586 | Self::UseCarrier(_)
587 | Self::PrimaryReselect(_)
588 | Self::FailOverMac(_)
589 | Self::XmitHashPolicy(_)
590 | Self::NumPeerNotif(_)
591 | Self::AllPortsActive(_)
592 | Self::AdLacpActive(_)
593 | Self::AdLacpRate(_)
594 | Self::AdSelect(_)
595 | Self::TlbDynamicLb(_)
596 | Self::MissedMax(_) => 1,
597 Self::AdActorSysPrio(_) | Self::AdUserPortKey(_) => 2,
598 Self::ActivePort(_)
599 | Self::MiiMon(_)
600 | Self::UpDelay(_)
601 | Self::DownDelay(_)
602 | Self::ArpInterval(_)
603 | Self::ArpValidate(_)
604 | Self::ArpAllTargets(_)
605 | Self::Primary(_)
606 | Self::ResendIgmp(_)
607 | Self::MinLinks(_)
608 | Self::LpInterval(_)
609 | Self::PacketsPerPort(_)
610 | Self::PeerNotifDelay(_) => 4,
611 Self::ArpIpTarget(ref addrs) => {
612 BondIpAddrNlaList::from(addrs).as_slice().buffer_len()
613 }
614 Self::NsIp6Target(ref addrs) => {
615 BondIpAddrNlaList::from(addrs).as_slice().buffer_len()
616 }
617 Self::AdActorSystem(_) => 6,
618 Self::AdInfo(infos) => infos.as_slice().buffer_len(),
619 Self::Other(v) => v.value_len(),
620 }
621 }
622
623 fn emit_value(&self, buffer: &mut [u8]) {
624 match self {
625 Self::Mode(value) => buffer[0] = (*value).into(),
626 Self::XmitHashPolicy(value) => buffer[0] = (*value).into(),
627 Self::PrimaryReselect(value) => buffer[0] = (*value).into(),
628 Self::UseCarrier(value)
629 | Self::NumPeerNotif(value)
630 | Self::AllPortsActive(value)
631 | Self::AdLacpActive(value)
632 | Self::AdLacpRate(value)
633 | Self::AdSelect(value)
634 | Self::TlbDynamicLb(value)
635 | Self::MissedMax(value) => buffer[0] = *value,
636 Self::FailOverMac(value) => buffer[0] = (*value).into(),
637 Self::AdActorSysPrio(value) | Self::AdUserPortKey(value) => {
638 emit_u16(buffer, *value).unwrap()
639 }
640 Self::ArpValidate(value) => {
641 emit_u32(buffer, (*value).into()).unwrap()
642 }
643 Self::ArpAllTargets(value) => {
644 emit_u32(buffer, (*value).into()).unwrap()
645 }
646 Self::ActivePort(value)
647 | Self::MiiMon(value)
648 | Self::UpDelay(value)
649 | Self::DownDelay(value)
650 | Self::ArpInterval(value)
651 | Self::Primary(value)
652 | Self::ResendIgmp(value)
653 | Self::MinLinks(value)
654 | Self::LpInterval(value)
655 | Self::PacketsPerPort(value)
656 | Self::PeerNotifDelay(value) => emit_u32(buffer, *value).unwrap(),
657 Self::AdActorSystem(bytes) => buffer.copy_from_slice(bytes),
658 Self::ArpIpTarget(addrs) => {
659 BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)
660 }
661 Self::NsIp6Target(addrs) => {
662 BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)
663 }
664 Self::AdInfo(infos) => infos.as_slice().emit(buffer),
665 Self::Other(v) => v.emit_value(buffer),
666 }
667 }
668
669 fn kind(&self) -> u16 {
670 match self {
671 Self::Mode(_) => IFLA_BOND_MODE,
672 Self::ActivePort(_) => IFLA_BOND_ACTIVE_PORT,
673 Self::MiiMon(_) => IFLA_BOND_MIIMON,
674 Self::UpDelay(_) => IFLA_BOND_UPDELAY,
675 Self::DownDelay(_) => IFLA_BOND_DOWNDELAY,
676 Self::UseCarrier(_) => IFLA_BOND_USE_CARRIER,
677 Self::ArpInterval(_) => IFLA_BOND_ARP_INTERVAL,
678 Self::ArpIpTarget(_) => IFLA_BOND_ARP_IP_TARGET,
679 Self::ArpValidate(_) => IFLA_BOND_ARP_VALIDATE,
680 Self::ArpAllTargets(_) => IFLA_BOND_ARP_ALL_TARGETS,
681 Self::Primary(_) => IFLA_BOND_PRIMARY,
682 Self::PrimaryReselect(_) => IFLA_BOND_PRIMARY_RESELECT,
683 Self::FailOverMac(_) => IFLA_BOND_FAIL_OVER_MAC,
684 Self::XmitHashPolicy(_) => IFLA_BOND_XMIT_HASH_POLICY,
685 Self::ResendIgmp(_) => IFLA_BOND_RESEND_IGMP,
686 Self::NumPeerNotif(_) => IFLA_BOND_NUM_PEER_NOTIF,
687 Self::AllPortsActive(_) => IFLA_BOND_ALL_PORTS_ACTIVE,
688 Self::MinLinks(_) => IFLA_BOND_MIN_LINKS,
689 Self::LpInterval(_) => IFLA_BOND_LP_INTERVAL,
690 Self::PacketsPerPort(_) => IFLA_BOND_PACKETS_PER_PORT,
691 Self::AdLacpRate(_) => IFLA_BOND_AD_LACP_RATE,
692 Self::AdSelect(_) => IFLA_BOND_AD_SELECT,
693 Self::AdInfo(_) => IFLA_BOND_AD_INFO,
694 Self::AdActorSysPrio(_) => IFLA_BOND_AD_ACTOR_SYS_PRIO,
695 Self::AdUserPortKey(_) => IFLA_BOND_AD_USER_PORT_KEY,
696 Self::AdActorSystem(_) => IFLA_BOND_AD_ACTOR_SYSTEM,
697 Self::TlbDynamicLb(_) => IFLA_BOND_TLB_DYNAMIC_LB,
698 Self::PeerNotifDelay(_) => IFLA_BOND_PEER_NOTIF_DELAY,
699 Self::AdLacpActive(_) => IFLA_BOND_AD_LACP_ACTIVE,
700 Self::MissedMax(_) => IFLA_BOND_MISSED_MAX,
701 Self::NsIp6Target(_) => IFLA_BOND_NS_IP6_TARGET,
702 Self::Other(v) => v.kind(),
703 }
704 }
705}
706
707impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBond {
708 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
709 let payload = buf.value();
710 Ok(match buf.kind() {
711 IFLA_BOND_MODE => Self::Mode(
712 parse_u8(payload)
713 .context("invalid IFLA_BOND_MODE value")?
714 .into(),
715 ),
716 IFLA_BOND_ACTIVE_PORT => Self::ActivePort(
717 parse_u32(payload)
718 .context("invalid IFLA_BOND_ACTIVE_PORT value")?,
719 ),
720 IFLA_BOND_MIIMON => Self::MiiMon(
721 parse_u32(payload).context("invalid IFLA_BOND_MIIMON value")?,
722 ),
723 IFLA_BOND_UPDELAY => Self::UpDelay(
724 parse_u32(payload)
725 .context("invalid IFLA_BOND_UPDELAY value")?,
726 ),
727 IFLA_BOND_DOWNDELAY => Self::DownDelay(
728 parse_u32(payload)
729 .context("invalid IFLA_BOND_DOWNDELAY value")?,
730 ),
731 IFLA_BOND_USE_CARRIER => Self::UseCarrier(
732 parse_u8(payload)
733 .context("invalid IFLA_BOND_USE_CARRIER value")?,
734 ),
735 IFLA_BOND_ARP_INTERVAL => Self::ArpInterval(
736 parse_u32(payload)
737 .context("invalid IFLA_BOND_ARP_INTERVAL value")?,
738 ),
739 IFLA_BOND_ARP_IP_TARGET => {
740 let mut addrs = Vec::<Ipv4Addr>::new();
741 for nla in NlasIterator::new(payload) {
742 let nla =
743 &nla.context("invalid IFLA_BOND_ARP_IP_TARGET value")?;
744 if let Ok(IpAddr::V4(addr)) = parse_ip(nla.value()) {
745 addrs.push(addr);
746 }
747 }
748 Self::ArpIpTarget(addrs)
749 }
750 IFLA_BOND_ARP_VALIDATE => Self::ArpValidate(
751 parse_u32(payload)
752 .context("invalid IFLA_BOND_ARP_VALIDATE value")?
753 .into(),
754 ),
755 IFLA_BOND_ARP_ALL_TARGETS => Self::ArpAllTargets(
756 parse_u32(payload)
757 .context("invalid IFLA_BOND_ARP_ALL_TARGETS value")?
758 .into(),
759 ),
760 IFLA_BOND_PRIMARY => Self::Primary(
761 parse_u32(payload)
762 .context("invalid IFLA_BOND_PRIMARY value")?,
763 ),
764 IFLA_BOND_PRIMARY_RESELECT => Self::PrimaryReselect(
765 parse_u8(payload)
766 .context("invalid IFLA_BOND_PRIMARY_RESELECT value")?
767 .into(),
768 ),
769 IFLA_BOND_FAIL_OVER_MAC => Self::FailOverMac(
770 parse_u8(payload)
771 .context("invalid IFLA_BOND_FAIL_OVER_MAC value")?
772 .into(),
773 ),
774 IFLA_BOND_XMIT_HASH_POLICY => Self::XmitHashPolicy(
775 parse_u8(payload)
776 .context("invalid IFLA_BOND_XMIT_HASH_POLICY value")?
777 .into(),
778 ),
779 IFLA_BOND_RESEND_IGMP => Self::ResendIgmp(
780 parse_u32(payload)
781 .context("invalid IFLA_BOND_RESEND_IGMP value")?,
782 ),
783 IFLA_BOND_NUM_PEER_NOTIF => Self::NumPeerNotif(
784 parse_u8(payload)
785 .context("invalid IFLA_BOND_NUM_PEER_NOTIF value")?,
786 ),
787 IFLA_BOND_ALL_PORTS_ACTIVE => Self::AllPortsActive(
788 parse_u8(payload)
789 .context("invalid IFLA_BOND_ALL_PORTS_ACTIVE value")?,
790 ),
791 IFLA_BOND_MIN_LINKS => Self::MinLinks(
792 parse_u32(payload)
793 .context("invalid IFLA_BOND_MIN_LINKS value")?,
794 ),
795 IFLA_BOND_LP_INTERVAL => Self::LpInterval(
796 parse_u32(payload)
797 .context("invalid IFLA_BOND_LP_INTERVAL value")?,
798 ),
799 IFLA_BOND_PACKETS_PER_PORT => Self::PacketsPerPort(
800 parse_u32(payload)
801 .context("invalid IFLA_BOND_PACKETS_PER_PORT value")?,
802 ),
803 IFLA_BOND_AD_LACP_RATE => Self::AdLacpRate(
804 parse_u8(payload)
805 .context("invalid IFLA_BOND_AD_LACP_RATE value")?,
806 ),
807 IFLA_BOND_AD_SELECT => Self::AdSelect(
808 parse_u8(payload)
809 .context("invalid IFLA_BOND_AD_SELECT value")?,
810 ),
811 IFLA_BOND_AD_INFO => {
812 let mut infos = Vec::new();
813 let err = "failed to parse IFLA_BOND_AD_INFO";
814 for nla in NlasIterator::new(payload) {
815 let nla = &nla.context(err)?;
816 let info = BondAdInfo::parse(nla).context(err)?;
817 infos.push(info);
818 }
819 Self::AdInfo(infos)
820 }
821 IFLA_BOND_AD_ACTOR_SYS_PRIO => Self::AdActorSysPrio(
822 parse_u16(payload)
823 .context("invalid IFLA_BOND_AD_ACTOR_SYS_PRIO value")?,
824 ),
825 IFLA_BOND_AD_USER_PORT_KEY => Self::AdUserPortKey(
826 parse_u16(payload)
827 .context("invalid IFLA_BOND_AD_USER_PORT_KEY value")?,
828 ),
829 IFLA_BOND_AD_ACTOR_SYSTEM => Self::AdActorSystem(
830 parse_mac(payload)
831 .context("invalid IFLA_BOND_AD_ACTOR_SYSTEM value")?,
832 ),
833 IFLA_BOND_TLB_DYNAMIC_LB => Self::TlbDynamicLb(
834 parse_u8(payload)
835 .context("invalid IFLA_BOND_TLB_DYNAMIC_LB value")?,
836 ),
837 IFLA_BOND_PEER_NOTIF_DELAY => Self::PeerNotifDelay(
838 parse_u32(payload)
839 .context("invalid IFLA_BOND_PEER_NOTIF_DELAY value")?,
840 ),
841 IFLA_BOND_AD_LACP_ACTIVE => Self::AdLacpActive(
842 parse_u8(payload)
843 .context("invalid IFLA_BOND_AD_LACP_ACTIVE value")?,
844 ),
845 IFLA_BOND_MISSED_MAX => Self::MissedMax(
846 parse_u8(payload)
847 .context("invalid IFLA_BOND_MISSED_MAX value")?,
848 ),
849 IFLA_BOND_NS_IP6_TARGET => {
850 let mut addrs = Vec::<Ipv6Addr>::new();
851 for nla in NlasIterator::new(payload) {
852 let nla =
853 &nla.context("invalid IFLA_BOND_NS_IP6_TARGET value")?;
854 if let Ok(IpAddr::V6(addr)) = parse_ip(nla.value()) {
855 addrs.push(addr);
856 }
857 }
858 Self::NsIp6Target(addrs)
859 }
860 _ => Self::Other(DefaultNla::parse(buf).context(format!(
861 "invalid NLA for {}: {payload:?}",
862 buf.kind()
863 ))?),
864 })
865 }
866}