use netlink_packet_core::{Emitable, Parseable};
use crate::{
link::{
BondAdSelect, BondAllPortActive, BondArpAllTargets, BondArpValidate,
BondFailOverMac, BondLacpRate, BondMode, BondPortState,
BondPrimaryReselect, BondXmitHashPolicy, ChurnState, InfoBond,
InfoBondPort, InfoData, InfoKind, InfoPortData, InfoPortKind,
LacpState, LinkAttribute, LinkFlags, LinkHeader, LinkInfo,
LinkLayerType, LinkMessage, LinkMessageBuffer, LinkMode, Map,
MiiStatus, State,
},
AddressFamily, RouteNetlinkMessage,
};
#[test]
fn test_bond_link_info() {
let raw: Vec<u8> = vec![
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x43, 0x14, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x12, 0x00, 0x09, 0x00, 0x01, 0x00, 0x62, 0x6f, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x13, 0x00,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x15, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x1e, 0x00,
0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00,
];
let expected = LinkMessage {
header: LinkHeader {
interface_family: AddressFamily::Unspec,
index: 24,
link_layer_type: LinkLayerType::Ether,
flags: LinkFlags::Broadcast
| LinkFlags::Controller
| LinkFlags::LowerUp
| LinkFlags::Multicast
| LinkFlags::Running
| LinkFlags::Up,
change_mask: LinkFlags::empty(),
},
attributes: vec![LinkAttribute::LinkInfo(vec![
LinkInfo::Kind(InfoKind::Bond),
LinkInfo::Data(InfoData::Bond(vec![
InfoBond::Mode(BondMode::BalanceRr),
InfoBond::MiiMon(0),
InfoBond::UpDelay(0),
InfoBond::DownDelay(0),
InfoBond::PeerNotifDelay(0),
InfoBond::UseCarrier(true),
InfoBond::ArpInterval(0),
InfoBond::ArpValidate(BondArpValidate::None),
InfoBond::ArpAllTargets(BondArpAllTargets::Any),
InfoBond::PrimaryReselect(BondPrimaryReselect::Always),
InfoBond::FailOverMac(BondFailOverMac::None),
InfoBond::XmitHashPolicy(BondXmitHashPolicy::Layer2),
InfoBond::ResendIgmp(1),
InfoBond::NumPeerNotif(1),
InfoBond::AllPortsActive(BondAllPortActive::Dropped),
InfoBond::MinLinks(0),
InfoBond::LpInterval(1),
InfoBond::PacketsPerPort(1),
InfoBond::AdLacpActive(true),
InfoBond::AdLacpRate(BondLacpRate::Slow),
InfoBond::AdSelect(BondAdSelect::Stable),
InfoBond::TlbDynamicLb(true),
InfoBond::MissedMax(2),
InfoBond::CoupledControl(true),
InfoBond::BroadcastNeigh(true),
])),
])],
};
assert_eq!(
expected,
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
);
let mut buf = vec![0; expected.buffer_len()];
expected.emit(&mut buf);
assert_eq!(buf, raw);
}
#[test]
fn test_bond_port_link_info() {
let raw: Vec<u8> = vec![
0x00, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00, 0x43, 0x18, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x12, 0x00, 0x09, 0x00, 0x01, 0x00,
0x76, 0x65, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x00,
0x62, 0x6f, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x05, 0x00,
0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x04, 0x00, 0x00, 0x23, 0x45, 0x67, 0x89, 0x1a, 0x00, 0x00,
0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00,
0x00, 0x00, 0x00, 0x00,
];
let expected = LinkMessage {
header: LinkHeader {
interface_family: AddressFamily::Unspec,
index: 21,
link_layer_type: LinkLayerType::Ether,
flags: LinkFlags::Broadcast
| LinkFlags::LowerUp
| LinkFlags::Multicast
| LinkFlags::Port
| LinkFlags::Running
| LinkFlags::Up,
change_mask: LinkFlags::empty(),
},
attributes: vec![LinkAttribute::LinkInfo(vec![
LinkInfo::Kind(InfoKind::Veth),
LinkInfo::PortKind(InfoPortKind::Bond),
LinkInfo::PortData(InfoPortData::BondPort(vec![
InfoBondPort::BondPortState(BondPortState::Active),
InfoBondPort::MiiStatus(MiiStatus::Up),
InfoBondPort::LinkFailureCount(0),
InfoBondPort::PermHwaddr(vec![
0x00, 0x23, 0x45, 0x67, 0x89, 0x1a,
]),
InfoBondPort::QueueId(0),
InfoBondPort::Prio(0),
])),
])],
};
assert_eq!(
expected,
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
);
let mut buf = vec![0; expected.buffer_len()];
expected.emit(&mut buf);
assert_eq!(buf, raw);
}
#[test]
fn test_parsing_link_bond_port_ad() {
let raw: Vec<u8> = vec![
0x00, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xc3, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x00, 0x62, 0x6f, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x05, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x04, 0x00, 0xf6, 0xbe, 0x32, 0x7c, 0x99, 0x6b, 0x00, 0x00,
0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x07, 0x00, 0x45, 0x00, 0x00, 0x00,
0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x00, 0x00,
];
let expected = LinkMessage {
header: LinkHeader {
interface_family: AddressFamily::Unspec,
index: 26,
link_layer_type: LinkLayerType::Ether,
flags: LinkFlags::Broadcast
| LinkFlags::LowerUp
| LinkFlags::Noarp
| LinkFlags::Port
| LinkFlags::Running
| LinkFlags::Up,
change_mask: LinkFlags::empty(),
},
attributes: vec![LinkAttribute::LinkInfo(vec![
LinkInfo::Kind(InfoKind::Dummy),
LinkInfo::PortKind(InfoPortKind::Bond),
LinkInfo::PortData(InfoPortData::BondPort(vec![
InfoBondPort::BondPortState(BondPortState::Active),
InfoBondPort::MiiStatus(MiiStatus::Up),
InfoBondPort::LinkFailureCount(0),
InfoBondPort::PermHwaddr(vec![
0xf6, 0xbe, 0x32, 0x7c, 0x99, 0x6b,
]),
InfoBondPort::QueueId(0),
InfoBondPort::Prio(0),
InfoBondPort::AdAggregatorId(1),
InfoBondPort::AdActorOperPortState(
LacpState::LACP_ACTIVITY
| LacpState::AGGREGATION
| LacpState::DEFAULTED,
),
InfoBondPort::AdPartnerOperPortState(LacpState::empty()),
InfoBondPort::AdChurnActorState(ChurnState::Monitor),
InfoBondPort::AdChurnPartnerState(ChurnState::Monitor),
InfoBondPort::ActorPortPrio(255),
])),
])],
};
assert_eq!(
expected,
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
);
let mut buf = vec![0; expected.buffer_len()];
expected.emit(&mut buf);
assert_eq!(buf, raw);
}
#[test]
fn test_bond_arp_validate() {
let raw: Vec<u8> = vec![
0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x62, 0x6f, 0x6e, 0x64,
0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00,
0x05, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0xdc, 0x05, 0x00, 0x00,
0x08, 0x00, 0x32, 0x00, 0x44, 0x00, 0x00, 0x00, 0x08, 0x00, 0x33, 0x00,
0xff, 0xff, 0x00, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1f, 0x00,
0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00, 0x00,
0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x20, 0x00,
0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x00, 0x06, 0x00, 0x6e, 0x6f, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00,
0x92, 0xb3, 0xba, 0x20, 0xd7, 0xa0, 0x00, 0x00, 0x0a, 0x00, 0x02, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
];
let expected = LinkMessage {
header: LinkHeader {
interface_family: AddressFamily::Unspec,
index: 5,
link_layer_type: LinkLayerType::Ether,
flags: LinkFlags::Broadcast
| LinkFlags::Controller
| LinkFlags::Multicast,
change_mask: LinkFlags::empty(),
},
attributes: vec![
LinkAttribute::IfName("bond0".into()),
LinkAttribute::TxQueueLen(1000),
LinkAttribute::OperState(State::Down),
LinkAttribute::Mode(LinkMode::Default),
LinkAttribute::Mtu(1500),
LinkAttribute::MinMtu(68),
LinkAttribute::MaxMtu(65535),
LinkAttribute::Group(0),
LinkAttribute::Promiscuity(0),
LinkAttribute::NumTxQueues(16),
LinkAttribute::GsoMaxSegs(65535),
LinkAttribute::GsoMaxSize(65536),
LinkAttribute::NumRxQueues(16),
LinkAttribute::Carrier(0),
LinkAttribute::Qdisc("noop".into()),
LinkAttribute::CarrierChanges(1),
LinkAttribute::CarrierUpCount(0),
LinkAttribute::CarrierDownCount(1),
LinkAttribute::ProtoDown(0),
LinkAttribute::Map(Map {
memory_start: 0,
memory_end: 0,
base_address: 0,
irq: 0,
dma: 0,
port: 0,
}),
LinkAttribute::Address(vec![0x92, 0xb3, 0xba, 0x20, 0xd7, 0xa0]),
LinkAttribute::Broadcast(vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
],
};
let packet = RouteNetlinkMessage::NewLink(expected);
let mut buf = vec![0u8; packet.buffer_len()];
packet.emit(&mut buf);
assert_eq!(raw, buf);
}
#[test]
fn test_bond_mode_from_str() {
use std::str::FromStr;
assert_eq!(BondMode::BalanceRr, "balance-rr".parse().unwrap());
assert_eq!(BondMode::ActiveBackup, "active-backup".parse().unwrap());
assert_eq!(BondMode::BalanceXor, "balance-xor".parse().unwrap());
assert_eq!(BondMode::Broadcast, "broadcast".parse().unwrap());
assert_eq!(BondMode::Ieee8023Ad, "802.3ad".parse().unwrap());
assert_eq!(BondMode::BalanceTlb, "balance-tlb".parse().unwrap());
assert_eq!(BondMode::BalanceAlb, "balance-alb".parse().unwrap());
assert_eq!(BondMode::BalanceRr, "0".parse().unwrap());
assert_eq!(BondMode::ActiveBackup, "1".parse().unwrap());
assert_eq!(BondMode::BalanceXor, "2".parse().unwrap());
assert_eq!(BondMode::Broadcast, "3".parse().unwrap());
assert_eq!(BondMode::Ieee8023Ad, "4".parse().unwrap());
assert_eq!(BondMode::BalanceTlb, "5".parse().unwrap());
assert_eq!(BondMode::BalanceAlb, "6".parse().unwrap());
assert!(BondMode::from_str("bogus").is_err());
}
#[test]
fn test_bond_arp_validate_from_str() {
use std::str::FromStr;
assert_eq!(BondArpValidate::None, "none".parse().unwrap());
assert_eq!(BondArpValidate::Active, "active".parse().unwrap());
assert_eq!(BondArpValidate::Backup, "backup".parse().unwrap());
assert_eq!(BondArpValidate::All, "all".parse().unwrap());
assert_eq!(BondArpValidate::Filter, "filter".parse().unwrap());
assert_eq!(
BondArpValidate::FilterActive,
"filter_active".parse().unwrap()
);
assert_eq!(
BondArpValidate::FilterBackup,
"filter_backup".parse().unwrap()
);
assert_eq!(BondArpValidate::None, "0".parse().unwrap());
assert_eq!(BondArpValidate::Active, "1".parse().unwrap());
assert_eq!(BondArpValidate::Backup, "2".parse().unwrap());
assert_eq!(BondArpValidate::All, "3".parse().unwrap());
assert_eq!(BondArpValidate::Filter, "4".parse().unwrap());
assert_eq!(BondArpValidate::FilterActive, "5".parse().unwrap());
assert_eq!(BondArpValidate::FilterBackup, "6".parse().unwrap());
assert!(BondArpValidate::from_str("bogus").is_err());
}
#[test]
fn test_bond_primary_reselect_from_str() {
use std::str::FromStr;
assert_eq!(BondPrimaryReselect::Always, "always".parse().unwrap());
assert_eq!(BondPrimaryReselect::Better, "better".parse().unwrap());
assert_eq!(BondPrimaryReselect::Failure, "failure".parse().unwrap());
assert_eq!(BondPrimaryReselect::Always, "0".parse().unwrap());
assert_eq!(BondPrimaryReselect::Better, "1".parse().unwrap());
assert_eq!(BondPrimaryReselect::Failure, "2".parse().unwrap());
assert!(BondPrimaryReselect::from_str("bogus").is_err());
}
#[test]
fn test_bond_xmit_hash_policy_from_str() {
use std::str::FromStr;
assert_eq!(BondXmitHashPolicy::Layer2, "layer2".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Layer34, "layer3+4".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Layer23, "layer2+3".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Encap23, "encap2+3".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Encap34, "encap3+4".parse().unwrap());
assert_eq!(
BondXmitHashPolicy::VlanSrcMac,
"vlan+srcmac".parse().unwrap()
);
assert_eq!(BondXmitHashPolicy::Layer2, "0".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Layer34, "1".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Layer23, "2".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Encap23, "3".parse().unwrap());
assert_eq!(BondXmitHashPolicy::Encap34, "4".parse().unwrap());
assert_eq!(BondXmitHashPolicy::VlanSrcMac, "5".parse().unwrap());
assert!(BondXmitHashPolicy::from_str("bogus").is_err());
}
#[test]
fn test_bond_arp_all_targets_from_str() {
use std::str::FromStr;
assert_eq!(BondArpAllTargets::Any, "any".parse().unwrap());
assert_eq!(BondArpAllTargets::All, "all".parse().unwrap());
assert_eq!(BondArpAllTargets::Any, "0".parse().unwrap());
assert_eq!(BondArpAllTargets::All, "1".parse().unwrap());
assert!(BondArpAllTargets::from_str("bogus").is_err());
}
#[test]
fn test_bond_fail_over_mac_from_str() {
use std::str::FromStr;
assert_eq!(BondFailOverMac::None, "none".parse().unwrap());
assert_eq!(BondFailOverMac::Active, "active".parse().unwrap());
assert_eq!(BondFailOverMac::Follow, "follow".parse().unwrap());
assert_eq!(BondFailOverMac::None, "0".parse().unwrap());
assert_eq!(BondFailOverMac::Active, "1".parse().unwrap());
assert_eq!(BondFailOverMac::Follow, "2".parse().unwrap());
assert!(BondFailOverMac::from_str("bogus").is_err());
}
#[test]
fn test_bond_ad_select_from_str() {
use std::str::FromStr;
assert_eq!(BondAdSelect::Stable, "stable".parse().unwrap());
assert_eq!(BondAdSelect::Bandwidth, "bandwidth".parse().unwrap());
assert_eq!(BondAdSelect::Count, "count".parse().unwrap());
assert_eq!(
BondAdSelect::ActorPortPrio,
"actor_port_prio".parse().unwrap()
);
assert_eq!(BondAdSelect::Stable, "0".parse().unwrap());
assert_eq!(BondAdSelect::Bandwidth, "1".parse().unwrap());
assert_eq!(BondAdSelect::Count, "2".parse().unwrap());
assert_eq!(BondAdSelect::ActorPortPrio, "3".parse().unwrap());
assert!(BondAdSelect::from_str("bogus").is_err());
}
#[test]
fn test_bond_lacp_rate_from_str() {
use std::str::FromStr;
assert_eq!(BondLacpRate::Slow, "slow".parse().unwrap());
assert_eq!(BondLacpRate::Fast, "fast".parse().unwrap());
assert_eq!(BondLacpRate::Slow, "0".parse().unwrap());
assert_eq!(BondLacpRate::Fast, "1".parse().unwrap());
assert!(BondLacpRate::from_str("bogus").is_err());
}
#[test]
fn test_bond_all_ports_active_from_str() {
use std::str::FromStr;
assert_eq!(BondAllPortActive::Dropped, "dropped".parse().unwrap());
assert_eq!(BondAllPortActive::Delivered, "delivered".parse().unwrap());
assert_eq!(BondAllPortActive::Dropped, "0".parse().unwrap());
assert_eq!(BondAllPortActive::Delivered, "1".parse().unwrap());
assert!(BondAllPortActive::from_str("bogus").is_err());
}
#[test]
fn test_bond_all_ports_active_display() {
assert_eq!("dropped", BondAllPortActive::Dropped.to_string());
assert_eq!("delivered", BondAllPortActive::Delivered.to_string());
assert_eq!("255", BondAllPortActive::Other(255).to_string());
}