From 17fad80fcd6d31444c648f5c5d01cc58992e5c0a Mon Sep 17 00:00:00 2001 From: xujunjie-cover Date: Mon, 1 Jul 2024 20:29:15 +0800 Subject: [PATCH] link: ipvlan: Change flag mode from u16 to bitflag. default => bridge; 0x01 => private; 0x02 => vepa; Signed-off-by: xujunjie-cover --- src/link/link_info/ipvlan.rs | 41 ++++++++++++++++++++++++-------- src/link/link_info/mod.rs | 4 +++- src/link/mod.rs | 7 +++--- src/link/tests/ipvlan.rs | 45 +++++++++++++++++++++++++++++++++--- src/link/tests/ipvtap.rs | 6 ++--- 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/src/link/link_info/ipvlan.rs b/src/link/link_info/ipvlan.rs index a08cc2f2..3cc1e0e0 100644 --- a/src/link/link_info/ipvlan.rs +++ b/src/link/link_info/ipvlan.rs @@ -16,7 +16,7 @@ const IFLA_IPVLAN_FLAGS: u16 = 2; #[non_exhaustive] pub enum InfoIpVlan { Mode(IpVlanMode), - Flags(u16), + Flags(IpVlanFlags), Other(DefaultNla), } @@ -33,7 +33,7 @@ impl Nla for InfoIpVlan { use self::InfoIpVlan::*; match self { Mode(value) => NativeEndian::write_u16(buffer, (*value).into()), - Flags(value) => NativeEndian::write_u16(buffer, *value), + Flags(f) => NativeEndian::write_u16(buffer, f.bits()), Other(nla) => nla.emit_value(buffer), } } @@ -58,10 +58,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpVlan { .context("invalid IFLA_IPVLAN_MODE value")? .into(), ), - IFLA_IPVLAN_FLAGS => Flags( + IFLA_IPVLAN_FLAGS => Self::Flags(IpVlanFlags::from_bits_retain( parse_u16(payload) - .context("invalid IFLA_IPVLAN_FLAGS value")?, - ), + .context("failed to parse IFLA_IPVLAN_FLAGS")?, + )), kind => Other(DefaultNla::parse(buf).context(format!( "unknown NLA type {kind} for IFLA_INFO_DATA(ipvlan)" ))?), @@ -73,7 +73,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpVlan { #[non_exhaustive] pub enum InfoIpVtap { Mode(IpVtapMode), - Flags(u16), + Flags(IpVtapFlags), Other(DefaultNla), } @@ -90,7 +90,7 @@ impl Nla for InfoIpVtap { use self::InfoIpVtap::*; match self { Mode(value) => NativeEndian::write_u16(buffer, (*value).into()), - Flags(value) => NativeEndian::write_u16(buffer, *value), + Flags(f) => NativeEndian::write_u16(buffer, f.bits()), Other(nla) => nla.emit_value(buffer), } } @@ -115,10 +115,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpVtap { .context("invalid IFLA_IPVLAN_MODE value")? .into(), ), - IFLA_IPVLAN_FLAGS => Flags( + IFLA_IPVLAN_FLAGS => Self::Flags(IpVtapFlags::from_bits_retain( parse_u16(payload) - .context("invalid IFLA_IPVLAN_FLAGS value")?, - ), + .context("failed to parse IFLA_IPVLAN_FLAGS")?, + )), kind => Other(DefaultNla::parse(buf).context(format!( "unknown NLA type {kind} for IFLA_INFO_DATA(ipvlan)" ))?), @@ -165,3 +165,24 @@ impl From for u16 { } } } + +const IPVLAN_F_PRIVATE: u16 = 0x01; +const IPVLAN_F_VEPA: u16 = 0x02; + +bitflags! { + #[non_exhaustive] + #[derive(Debug, Clone, Copy, Eq, PartialEq)] + pub struct IpVlanFlags: u16 { + const Private = IPVLAN_F_PRIVATE; + const Vepa = IPVLAN_F_VEPA; + const _ = !0; + } +} + +impl Default for IpVlanFlags { + fn default() -> Self { + Self::empty() + } +} + +pub type IpVtapFlags = IpVlanFlags; diff --git a/src/link/link_info/mod.rs b/src/link/link_info/mod.rs index d6ba12fd..297291e9 100644 --- a/src/link/link_info/mod.rs +++ b/src/link/link_info/mod.rs @@ -47,7 +47,9 @@ pub use self::info_data::InfoData; pub use self::info_port::{InfoPortData, InfoPortKind, InfoVrfPort}; pub use self::infos::{InfoKind, LinkInfo}; pub use self::ipoib::InfoIpoib; -pub use self::ipvlan::{InfoIpVlan, InfoIpVtap, IpVlanMode, IpVtapMode}; +pub use self::ipvlan::{ + InfoIpVlan, InfoIpVtap, IpVlanFlags, IpVlanMode, IpVtapFlags, IpVtapMode, +}; pub use self::mac_vlan::{InfoMacVlan, InfoMacVtap, MacVlanMode, MacVtapMode}; pub use self::macsec::{ InfoMacSec, MacSecCipherId, MacSecOffload, MacSecValidate, diff --git a/src/link/mod.rs b/src/link/mod.rs index d0d17b55..34af172b 100644 --- a/src/link/mod.rs +++ b/src/link/mod.rs @@ -45,9 +45,10 @@ pub use self::link_info::{ InfoGreTun, InfoGreTun6, InfoGtp, InfoHsr, InfoIpVlan, InfoIpVtap, InfoIpoib, InfoKind, InfoMacSec, InfoMacVlan, InfoMacVtap, InfoPortData, InfoPortKind, InfoSitTun, InfoTun, InfoVeth, InfoVlan, InfoVrf, - InfoVrfPort, InfoVti, InfoVxlan, InfoXfrm, IpVlanMode, IpVtapMode, - LinkInfo, LinkXstats, MacSecCipherId, MacSecOffload, MacSecValidate, - MacVlanMode, MacVtapMode, MiiStatus, VlanQosMapping, + InfoVrfPort, InfoVti, InfoVxlan, InfoXfrm, IpVlanFlags, IpVlanMode, + IpVtapFlags, IpVtapMode, LinkInfo, LinkXstats, MacSecCipherId, + MacSecOffload, MacSecValidate, MacVlanMode, MacVtapMode, MiiStatus, + VlanQosMapping, }; pub use self::link_layer_type::LinkLayerType; pub use self::link_state::State; diff --git a/src/link/tests/ipvlan.rs b/src/link/tests/ipvlan.rs index b3eaa7fe..b76a5387 100644 --- a/src/link/tests/ipvlan.rs +++ b/src/link/tests/ipvlan.rs @@ -4,8 +4,8 @@ use netlink_packet_utils::{Emitable, Parseable}; use crate::link::link_flag::LinkFlags; use crate::link::{ - InfoData, InfoIpVlan, InfoKind, IpVlanMode, LinkAttribute, LinkHeader, - LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, + InfoData, InfoIpVlan, InfoKind, IpVlanFlags, IpVlanMode, LinkAttribute, + LinkHeader, LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, }; use crate::AddressFamily; @@ -31,7 +31,46 @@ fn test_ipvlan_link_info() { LinkInfo::Kind(InfoKind::IpVlan), LinkInfo::Data(InfoData::IpVlan(vec![ InfoIpVlan::Mode(IpVlanMode::L2), - InfoIpVlan::Flags(2), + InfoIpVlan::Flags(IpVlanFlags::Vepa), + ])), + ])], + }; + + 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_ipvlan_bridge_link_info() { + let raw: Vec = vec![ + 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x01, 0x00, + 0x69, 0x70, 0x76, 0x6c, 0x61, 0x6e, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let expected = LinkMessage { + header: LinkHeader { + interface_family: AddressFamily::Unspec, + index: 18, + link_layer_type: LinkLayerType::Ether, + flags: LinkFlags::Broadcast | LinkFlags::Multicast, + change_mask: LinkFlags::empty(), + }, + attributes: vec![LinkAttribute::LinkInfo(vec![ + LinkInfo::Kind(InfoKind::IpVlan), + LinkInfo::Data(InfoData::IpVlan(vec![ + InfoIpVlan::Mode(IpVlanMode::L2), + InfoIpVlan::Flags(IpVlanFlags::default()), ])), ])], }; diff --git a/src/link/tests/ipvtap.rs b/src/link/tests/ipvtap.rs index 9839c0d1..c87c72d2 100644 --- a/src/link/tests/ipvtap.rs +++ b/src/link/tests/ipvtap.rs @@ -4,8 +4,8 @@ use netlink_packet_utils::{Emitable, Parseable}; use crate::link::link_flag::LinkFlags; use crate::link::{ - InfoData, InfoIpVtap, InfoKind, IpVtapMode, LinkAttribute, LinkHeader, - LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, + InfoData, InfoIpVtap, InfoKind, IpVtapFlags, IpVtapMode, LinkAttribute, + LinkHeader, LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, }; use crate::AddressFamily; @@ -31,7 +31,7 @@ fn test_ipvtap_link_info() { LinkInfo::Kind(InfoKind::IpVtap), LinkInfo::Data(InfoData::IpVtap(vec![ InfoIpVtap::Mode(IpVtapMode::L2), - InfoIpVtap::Flags(2), + InfoIpVtap::Flags(IpVtapFlags::Vepa), ])), ])], };