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
545const BOND_ALL_PORT_ACTIVE_DROPPED: u8 = 0;
546const BOND_ALL_PORT_ACTIVE_DELIEVERD: u8 = 1;
547
548#[derive(Debug, PartialEq, Eq, Clone, Copy)]
551pub enum BondAllPortActive {
552 Dropped,
553 Delivered,
554 Other(u8),
555}
556
557impl From<u8> for BondAllPortActive {
558 fn from(d: u8) -> Self {
559 match d {
560 BOND_ALL_PORT_ACTIVE_DROPPED => Self::Dropped,
561 BOND_ALL_PORT_ACTIVE_DELIEVERD => Self::Delivered,
562 _ => Self::Other(d),
563 }
564 }
565}
566
567impl From<BondAllPortActive> for u8 {
568 fn from(v: BondAllPortActive) -> u8 {
569 match v {
570 BondAllPortActive::Dropped => BOND_ALL_PORT_ACTIVE_DROPPED,
571 BondAllPortActive::Delivered => BOND_ALL_PORT_ACTIVE_DELIEVERD,
572 BondAllPortActive::Other(d) => d,
573 }
574 }
575}
576
577const AD_LACP_SLOW: u8 = 0;
578const AD_LACP_FAST: u8 = 1;
579
580#[derive(Debug, PartialEq, Eq, Clone, Copy)]
583pub enum BondLacpRate {
584 Slow,
585 Fast,
586 Other(u8),
587}
588
589impl From<u8> for BondLacpRate {
590 fn from(d: u8) -> Self {
591 match d {
592 AD_LACP_SLOW => Self::Slow,
593 AD_LACP_FAST => Self::Fast,
594 _ => Self::Other(d),
595 }
596 }
597}
598
599impl From<BondLacpRate> for u8 {
600 fn from(v: BondLacpRate) -> u8 {
601 match v {
602 BondLacpRate::Slow => AD_LACP_SLOW,
603 BondLacpRate::Fast => AD_LACP_FAST,
604 BondLacpRate::Other(d) => d,
605 }
606 }
607}
608
609#[derive(Debug, PartialEq, Eq, Clone)]
610#[non_exhaustive]
611pub enum InfoBond {
612 Mode(BondMode),
613 ActivePort(u32),
614 MiiMon(u32),
615 UpDelay(u32),
616 DownDelay(u32),
617 UseCarrier(bool),
620 ArpInterval(u32),
621 ArpIpTarget(Vec<Ipv4Addr>),
622 ArpValidate(BondArpValidate),
623 ArpAllTargets(BondArpAllTargets),
624 Primary(u32),
625 PrimaryReselect(BondPrimaryReselect),
626 FailOverMac(BondFailOverMac),
627 XmitHashPolicy(BondXmitHashPolicy),
628 ResendIgmp(u32),
629 NumPeerNotif(u8),
630 AllPortsActive(BondAllPortActive),
633 MinLinks(u32),
634 LpInterval(u32),
635 PacketsPerPort(u32),
636 AdLacpRate(BondLacpRate),
639 AdSelect(u8),
640 AdInfo(Vec<BondAdInfo>),
641 AdActorSysPrio(u16),
642 AdUserPortKey(u16),
643 AdActorSystem([u8; 6]),
644 TlbDynamicLb(bool),
647 PeerNotifDelay(u32),
648 AdLacpActive(bool),
650 MissedMax(u8),
651 NsIp6Target(Vec<Ipv6Addr>),
652 Other(DefaultNla),
653}
654
655impl Nla for InfoBond {
656 fn value_len(&self) -> usize {
657 match self {
658 Self::Mode(_)
659 | Self::UseCarrier(_)
660 | Self::PrimaryReselect(_)
661 | Self::FailOverMac(_)
662 | Self::XmitHashPolicy(_)
663 | Self::NumPeerNotif(_)
664 | Self::AllPortsActive(_)
665 | Self::AdLacpActive(_)
666 | Self::AdLacpRate(_)
667 | Self::AdSelect(_)
668 | Self::TlbDynamicLb(_)
669 | Self::MissedMax(_) => 1,
670 Self::AdActorSysPrio(_) | Self::AdUserPortKey(_) => 2,
671 Self::ActivePort(_)
672 | Self::MiiMon(_)
673 | Self::UpDelay(_)
674 | Self::DownDelay(_)
675 | Self::ArpInterval(_)
676 | Self::ArpValidate(_)
677 | Self::ArpAllTargets(_)
678 | Self::Primary(_)
679 | Self::ResendIgmp(_)
680 | Self::MinLinks(_)
681 | Self::LpInterval(_)
682 | Self::PacketsPerPort(_)
683 | Self::PeerNotifDelay(_) => 4,
684 Self::ArpIpTarget(ref addrs) => {
685 BondIpAddrNlaList::from(addrs).as_slice().buffer_len()
686 }
687 Self::NsIp6Target(ref addrs) => {
688 BondIpAddrNlaList::from(addrs).as_slice().buffer_len()
689 }
690 Self::AdActorSystem(_) => 6,
691 Self::AdInfo(infos) => infos.as_slice().buffer_len(),
692 Self::Other(v) => v.value_len(),
693 }
694 }
695
696 fn emit_value(&self, buffer: &mut [u8]) {
697 match self {
698 Self::Mode(value) => buffer[0] = (*value).into(),
699 Self::XmitHashPolicy(value) => buffer[0] = (*value).into(),
700 Self::PrimaryReselect(value) => buffer[0] = (*value).into(),
701 Self::NumPeerNotif(value)
702 | Self::AdSelect(value)
703 | Self::MissedMax(value) => buffer[0] = *value,
704 Self::UseCarrier(value)
705 | Self::AdLacpActive(value)
706 | Self::TlbDynamicLb(value) => buffer[0] = (*value).into(),
707 Self::AdLacpRate(value) => buffer[0] = (*value).into(),
708 Self::AllPortsActive(value) => buffer[0] = (*value).into(),
709 Self::FailOverMac(value) => buffer[0] = (*value).into(),
710 Self::AdActorSysPrio(value) | Self::AdUserPortKey(value) => {
711 emit_u16(buffer, *value).unwrap()
712 }
713 Self::ArpValidate(value) => {
714 emit_u32(buffer, (*value).into()).unwrap()
715 }
716 Self::ArpAllTargets(value) => {
717 emit_u32(buffer, (*value).into()).unwrap()
718 }
719 Self::ActivePort(value)
720 | Self::MiiMon(value)
721 | Self::UpDelay(value)
722 | Self::DownDelay(value)
723 | Self::ArpInterval(value)
724 | Self::Primary(value)
725 | Self::ResendIgmp(value)
726 | Self::MinLinks(value)
727 | Self::LpInterval(value)
728 | Self::PacketsPerPort(value)
729 | Self::PeerNotifDelay(value) => emit_u32(buffer, *value).unwrap(),
730 Self::AdActorSystem(bytes) => buffer.copy_from_slice(bytes),
731 Self::ArpIpTarget(addrs) => {
732 BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)
733 }
734 Self::NsIp6Target(addrs) => {
735 BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)
736 }
737 Self::AdInfo(infos) => infos.as_slice().emit(buffer),
738 Self::Other(v) => v.emit_value(buffer),
739 }
740 }
741
742 fn kind(&self) -> u16 {
743 match self {
744 Self::Mode(_) => IFLA_BOND_MODE,
745 Self::ActivePort(_) => IFLA_BOND_ACTIVE_PORT,
746 Self::MiiMon(_) => IFLA_BOND_MIIMON,
747 Self::UpDelay(_) => IFLA_BOND_UPDELAY,
748 Self::DownDelay(_) => IFLA_BOND_DOWNDELAY,
749 Self::UseCarrier(_) => IFLA_BOND_USE_CARRIER,
750 Self::ArpInterval(_) => IFLA_BOND_ARP_INTERVAL,
751 Self::ArpIpTarget(_) => IFLA_BOND_ARP_IP_TARGET,
752 Self::ArpValidate(_) => IFLA_BOND_ARP_VALIDATE,
753 Self::ArpAllTargets(_) => IFLA_BOND_ARP_ALL_TARGETS,
754 Self::Primary(_) => IFLA_BOND_PRIMARY,
755 Self::PrimaryReselect(_) => IFLA_BOND_PRIMARY_RESELECT,
756 Self::FailOverMac(_) => IFLA_BOND_FAIL_OVER_MAC,
757 Self::XmitHashPolicy(_) => IFLA_BOND_XMIT_HASH_POLICY,
758 Self::ResendIgmp(_) => IFLA_BOND_RESEND_IGMP,
759 Self::NumPeerNotif(_) => IFLA_BOND_NUM_PEER_NOTIF,
760 Self::AllPortsActive(_) => IFLA_BOND_ALL_PORTS_ACTIVE,
761 Self::MinLinks(_) => IFLA_BOND_MIN_LINKS,
762 Self::LpInterval(_) => IFLA_BOND_LP_INTERVAL,
763 Self::PacketsPerPort(_) => IFLA_BOND_PACKETS_PER_PORT,
764 Self::AdLacpRate(_) => IFLA_BOND_AD_LACP_RATE,
765 Self::AdSelect(_) => IFLA_BOND_AD_SELECT,
766 Self::AdInfo(_) => IFLA_BOND_AD_INFO,
767 Self::AdActorSysPrio(_) => IFLA_BOND_AD_ACTOR_SYS_PRIO,
768 Self::AdUserPortKey(_) => IFLA_BOND_AD_USER_PORT_KEY,
769 Self::AdActorSystem(_) => IFLA_BOND_AD_ACTOR_SYSTEM,
770 Self::TlbDynamicLb(_) => IFLA_BOND_TLB_DYNAMIC_LB,
771 Self::PeerNotifDelay(_) => IFLA_BOND_PEER_NOTIF_DELAY,
772 Self::AdLacpActive(_) => IFLA_BOND_AD_LACP_ACTIVE,
773 Self::MissedMax(_) => IFLA_BOND_MISSED_MAX,
774 Self::NsIp6Target(_) => IFLA_BOND_NS_IP6_TARGET,
775 Self::Other(v) => v.kind(),
776 }
777 }
778}
779
780impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBond {
781 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
782 let payload = buf.value();
783 Ok(match buf.kind() {
784 IFLA_BOND_MODE => Self::Mode(
785 parse_u8(payload)
786 .context("invalid IFLA_BOND_MODE value")?
787 .into(),
788 ),
789 IFLA_BOND_ACTIVE_PORT => Self::ActivePort(
790 parse_u32(payload)
791 .context("invalid IFLA_BOND_ACTIVE_PORT value")?,
792 ),
793 IFLA_BOND_MIIMON => Self::MiiMon(
794 parse_u32(payload).context("invalid IFLA_BOND_MIIMON value")?,
795 ),
796 IFLA_BOND_UPDELAY => Self::UpDelay(
797 parse_u32(payload)
798 .context("invalid IFLA_BOND_UPDELAY value")?,
799 ),
800 IFLA_BOND_DOWNDELAY => Self::DownDelay(
801 parse_u32(payload)
802 .context("invalid IFLA_BOND_DOWNDELAY value")?,
803 ),
804 IFLA_BOND_USE_CARRIER => Self::UseCarrier(
805 parse_u8(payload)
806 .context("invalid IFLA_BOND_USE_CARRIER value")?
807 > 0,
808 ),
809 IFLA_BOND_ARP_INTERVAL => Self::ArpInterval(
810 parse_u32(payload)
811 .context("invalid IFLA_BOND_ARP_INTERVAL value")?,
812 ),
813 IFLA_BOND_ARP_IP_TARGET => {
814 let mut addrs = Vec::<Ipv4Addr>::new();
815 for nla in NlasIterator::new(payload) {
816 let nla =
817 &nla.context("invalid IFLA_BOND_ARP_IP_TARGET value")?;
818 if let Ok(IpAddr::V4(addr)) = parse_ip(nla.value()) {
819 addrs.push(addr);
820 }
821 }
822 Self::ArpIpTarget(addrs)
823 }
824 IFLA_BOND_ARP_VALIDATE => Self::ArpValidate(
825 parse_u32(payload)
826 .context("invalid IFLA_BOND_ARP_VALIDATE value")?
827 .into(),
828 ),
829 IFLA_BOND_ARP_ALL_TARGETS => Self::ArpAllTargets(
830 parse_u32(payload)
831 .context("invalid IFLA_BOND_ARP_ALL_TARGETS value")?
832 .into(),
833 ),
834 IFLA_BOND_PRIMARY => Self::Primary(
835 parse_u32(payload)
836 .context("invalid IFLA_BOND_PRIMARY value")?,
837 ),
838 IFLA_BOND_PRIMARY_RESELECT => Self::PrimaryReselect(
839 parse_u8(payload)
840 .context("invalid IFLA_BOND_PRIMARY_RESELECT value")?
841 .into(),
842 ),
843 IFLA_BOND_FAIL_OVER_MAC => Self::FailOverMac(
844 parse_u8(payload)
845 .context("invalid IFLA_BOND_FAIL_OVER_MAC value")?
846 .into(),
847 ),
848 IFLA_BOND_XMIT_HASH_POLICY => Self::XmitHashPolicy(
849 parse_u8(payload)
850 .context("invalid IFLA_BOND_XMIT_HASH_POLICY value")?
851 .into(),
852 ),
853 IFLA_BOND_RESEND_IGMP => Self::ResendIgmp(
854 parse_u32(payload)
855 .context("invalid IFLA_BOND_RESEND_IGMP value")?,
856 ),
857 IFLA_BOND_NUM_PEER_NOTIF => Self::NumPeerNotif(
858 parse_u8(payload)
859 .context("invalid IFLA_BOND_NUM_PEER_NOTIF value")?,
860 ),
861 IFLA_BOND_ALL_PORTS_ACTIVE => Self::AllPortsActive(
862 parse_u8(payload)
863 .context("invalid IFLA_BOND_ALL_PORTS_ACTIVE value")?
864 .into(),
865 ),
866 IFLA_BOND_MIN_LINKS => Self::MinLinks(
867 parse_u32(payload)
868 .context("invalid IFLA_BOND_MIN_LINKS value")?,
869 ),
870 IFLA_BOND_LP_INTERVAL => Self::LpInterval(
871 parse_u32(payload)
872 .context("invalid IFLA_BOND_LP_INTERVAL value")?,
873 ),
874 IFLA_BOND_PACKETS_PER_PORT => Self::PacketsPerPort(
875 parse_u32(payload)
876 .context("invalid IFLA_BOND_PACKETS_PER_PORT value")?,
877 ),
878 IFLA_BOND_AD_LACP_RATE => Self::AdLacpRate(
879 parse_u8(payload)
880 .context("invalid IFLA_BOND_AD_LACP_RATE value")?
881 .into(),
882 ),
883 IFLA_BOND_AD_SELECT => Self::AdSelect(
884 parse_u8(payload)
885 .context("invalid IFLA_BOND_AD_SELECT value")?,
886 ),
887 IFLA_BOND_AD_INFO => {
888 let mut infos = Vec::new();
889 let err = "failed to parse IFLA_BOND_AD_INFO";
890 for nla in NlasIterator::new(payload) {
891 let nla = &nla.context(err)?;
892 let info = BondAdInfo::parse(nla).context(err)?;
893 infos.push(info);
894 }
895 Self::AdInfo(infos)
896 }
897 IFLA_BOND_AD_ACTOR_SYS_PRIO => Self::AdActorSysPrio(
898 parse_u16(payload)
899 .context("invalid IFLA_BOND_AD_ACTOR_SYS_PRIO value")?,
900 ),
901 IFLA_BOND_AD_USER_PORT_KEY => Self::AdUserPortKey(
902 parse_u16(payload)
903 .context("invalid IFLA_BOND_AD_USER_PORT_KEY value")?,
904 ),
905 IFLA_BOND_AD_ACTOR_SYSTEM => Self::AdActorSystem(
906 parse_mac(payload)
907 .context("invalid IFLA_BOND_AD_ACTOR_SYSTEM value")?,
908 ),
909 IFLA_BOND_TLB_DYNAMIC_LB => Self::TlbDynamicLb(
910 parse_u8(payload)
911 .context("invalid IFLA_BOND_TLB_DYNAMIC_LB value")?
912 > 0,
913 ),
914 IFLA_BOND_PEER_NOTIF_DELAY => Self::PeerNotifDelay(
915 parse_u32(payload)
916 .context("invalid IFLA_BOND_PEER_NOTIF_DELAY value")?,
917 ),
918 IFLA_BOND_AD_LACP_ACTIVE => Self::AdLacpActive(
919 parse_u8(payload)
920 .context("invalid IFLA_BOND_AD_LACP_ACTIVE value")?
921 > 0,
922 ),
923 IFLA_BOND_MISSED_MAX => Self::MissedMax(
924 parse_u8(payload)
925 .context("invalid IFLA_BOND_MISSED_MAX value")?,
926 ),
927 IFLA_BOND_NS_IP6_TARGET => {
928 let mut addrs = Vec::<Ipv6Addr>::new();
929 for nla in NlasIterator::new(payload) {
930 let nla =
931 &nla.context("invalid IFLA_BOND_NS_IP6_TARGET value")?;
932 if let Ok(IpAddr::V6(addr)) = parse_ip(nla.value()) {
933 addrs.push(addr);
934 }
935 }
936 Self::NsIp6Target(addrs)
937 }
938 _ => Self::Other(DefaultNla::parse(buf).context(format!(
939 "invalid NLA for {}: {payload:?}",
940 buf.kind()
941 ))?),
942 })
943 }
944}