diff --git a/src/link/af_spec/in6_addr_gen_mode.rs b/src/link/af_spec/in6_addr_gen_mode.rs new file mode 100644 index 00000000..3a85eff5 --- /dev/null +++ b/src/link/af_spec/in6_addr_gen_mode.rs @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT + +use std::fmt::Display; + +const IN6_ADDR_GEN_MODE_EUI64: u8 = 0; +const IN6_ADDR_GEN_MODE_NONE: u8 = 1; +const IN6_ADDR_GEN_MODE_STABLE_PRIVACY: u8 = 2; +const IN6_ADDR_GEN_MODE_RANDOM: u8 = 3; + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Default)] +#[non_exhaustive] +#[repr(u8)] +pub enum In6AddrGenMode { + #[default] + Eui64, + None, + StablePrivacy, + Random, + Other(u8), +} + +impl From for In6AddrGenMode { + fn from(d: u8) -> Self { + match d { + IN6_ADDR_GEN_MODE_EUI64 => Self::Eui64, + IN6_ADDR_GEN_MODE_NONE => Self::None, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY => Self::StablePrivacy, + IN6_ADDR_GEN_MODE_RANDOM => Self::Random, + _ => Self::Other(d), + } + } +} +impl From<&In6AddrGenMode> for u8 { + fn from(v: &In6AddrGenMode) -> Self { + match v { + In6AddrGenMode::Eui64 => IN6_ADDR_GEN_MODE_EUI64, + In6AddrGenMode::None => IN6_ADDR_GEN_MODE_NONE, + In6AddrGenMode::StablePrivacy => IN6_ADDR_GEN_MODE_STABLE_PRIVACY, + In6AddrGenMode::Random => IN6_ADDR_GEN_MODE_RANDOM, + In6AddrGenMode::Other(d) => *d, + } + } +} + +impl Display for In6AddrGenMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Eui64 => write!(f, "eui64"), + Self::None => write!(f, "none"), + // https://github.com/iproute2/iproute2/blob/afbfd2f2b0a633d068990775f8e1b73b8ee83733/ip/ipaddress.c#L325-L329 + Self::StablePrivacy => write!(f, "stable_secret"), + Self::Random => write!(f, "random"), + Self::Other(d) => write!(f, "other({d})"), + } + } +} diff --git a/src/link/af_spec/inet6.rs b/src/link/af_spec/inet6.rs index 3e5e728c..a6c36067 100644 --- a/src/link/af_spec/inet6.rs +++ b/src/link/af_spec/inet6.rs @@ -20,7 +20,7 @@ use super::{ inet6_devconf::LINK_INET6_DEV_CONF_LEN, inet6_icmp::ICMP6_STATS_LEN, inet6_stats::INET6_STATS_LEN, }; -use crate::ip::parse_ipv6_addr; +use crate::{ip::parse_ipv6_addr, link::af_spec::In6AddrGenMode}; const IFLA_INET6_FLAGS: u16 = 1; const IFLA_INET6_CONF: u16 = 2; @@ -43,7 +43,7 @@ pub enum AfSpecInet6 { Stats(Inet6Stats), Icmp6Stats(Icmp6Stats), Token(Ipv6Addr), - AddrGenMode(u8), + AddrGenMode(In6AddrGenMode), RaMtu(u32), Other(DefaultNla), } @@ -89,7 +89,7 @@ impl Nla for AfSpecInet6 { Stats(ref v) => v.emit(buffer), Icmp6Stats(ref v) => v.emit(buffer), Token(v) => buffer.copy_from_slice(&v.octets()), - AddrGenMode(value) => buffer[0] = value, + AddrGenMode(ref v) => buffer[0] = v.into(), Other(ref nla) => nla.emit_value(buffer), } } @@ -168,10 +168,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AfSpecInet6 { parse_ipv6_addr(payload) .context("invalid IFLA_INET6_TOKEN value")?, ), - IFLA_INET6_ADDR_GEN_MODE => AddrGenMode( - parse_u8(payload) - .context("invalid IFLA_INET6_ADDR_GEN_MODE value")?, - ), + IFLA_INET6_ADDR_GEN_MODE => { + let mode = parse_u8(payload) + .context("invalid IFLA_INET6_ADDR_GEN_MODE")?; + AddrGenMode(In6AddrGenMode::from(mode)) + } IFLA_INET6_RA_MTU => RaMtu( parse_u32(payload) .context("invalid IFLA_INET6_RA_MTU value")?, diff --git a/src/link/af_spec/mod.rs b/src/link/af_spec/mod.rs index 1b4bb054..56e6fcec 100644 --- a/src/link/af_spec/mod.rs +++ b/src/link/af_spec/mod.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT mod bridge; +mod in6_addr_gen_mode; mod inet; mod inet6; mod inet6_cache; @@ -14,6 +15,7 @@ pub use self::bridge::{ AfSpecBridge, BridgeFlag, BridgeMode, BridgeVlanInfo, BridgeVlanInfoFlags, BridgeVlanTunnelInfo, }; +pub use self::in6_addr_gen_mode::In6AddrGenMode; pub use self::inet::{AfSpecInet, InetDevConf}; pub use self::inet6::AfSpecInet6; pub use self::inet6_cache::{Inet6CacheInfo, Inet6CacheInfoBuffer}; diff --git a/src/link/tests/statistics.rs b/src/link/tests/statistics.rs index 81084fe1..5b259c12 100644 --- a/src/link/tests/statistics.rs +++ b/src/link/tests/statistics.rs @@ -2,6 +2,7 @@ use netlink_packet_utils::{nla::DefaultNla, Emitable, Parseable}; +use crate::link::af_spec::In6AddrGenMode; use crate::link::link_flag::LinkFlags; use crate::link::{ AfSpecInet, AfSpecInet6, AfSpecUnspec, Icmp6Stats, Inet6CacheInfo, @@ -383,7 +384,7 @@ fn test_parsing_link_statistics_on_kernel_4_18() { rate_limit_host: 0, }), AfSpecInet6::Token(std::net::Ipv6Addr::UNSPECIFIED), - AfSpecInet6::AddrGenMode(1), + AfSpecInet6::AddrGenMode(In6AddrGenMode::None), ]), ]), LinkAttribute::PropList(vec![Prop::AltIfName("enp0s3".into())]), diff --git a/src/link/tests/vrf.rs b/src/link/tests/vrf.rs index 9b9c8dad..1314a8a3 100644 --- a/src/link/tests/vrf.rs +++ b/src/link/tests/vrf.rs @@ -5,6 +5,7 @@ use std::net::Ipv6Addr; use netlink_packet_utils::nla::DefaultNla; use netlink_packet_utils::{Emitable, Parseable}; +use crate::link::af_spec::In6AddrGenMode; use crate::link::link_flag::LinkFlags; use crate::link::link_info::InfoVrfPort; use crate::link::{ @@ -345,7 +346,7 @@ fn test_link_info_with_ifla_vrf_port_table() { ..Default::default() }), AfSpecInet6::Token(Ipv6Addr::UNSPECIFIED), - AfSpecInet6::AddrGenMode(0), + AfSpecInet6::AddrGenMode(In6AddrGenMode::Eui64), ]), ]), ],