diff --git a/rust/agama-dbus-server/src/network/model.rs b/rust/agama-dbus-server/src/network/model.rs index 9d48127a19..61a5884fdb 100644 --- a/rust/agama-dbus-server/src/network/model.rs +++ b/rust/agama-dbus-server/src/network/model.rs @@ -222,6 +222,7 @@ pub enum Connection { Wireless(WirelessConnection), Loopback(LoopbackConnection), Dummy(DummyConnection), + Vlan(VlanConnection), } impl Connection { @@ -238,6 +239,10 @@ impl Connection { DeviceType::Loopback => Connection::Loopback(LoopbackConnection { base }), DeviceType::Ethernet => Connection::Ethernet(EthernetConnection { base }), DeviceType::Dummy => Connection::Dummy(DummyConnection { base }), + DeviceType::Vlan => Connection::Vlan(VlanConnection { + base, + ..Default::default() + }), } } @@ -249,6 +254,7 @@ impl Connection { Connection::Wireless(conn) => &conn.base, Connection::Loopback(conn) => &conn.base, Connection::Dummy(conn) => &conn.base, + Connection::Vlan(conn) => &conn.base, } } @@ -258,6 +264,7 @@ impl Connection { Connection::Wireless(conn) => &mut conn.base, Connection::Loopback(conn) => &mut conn.base, Connection::Dummy(conn) => &mut conn.base, + Connection::Vlan(conn) => &mut conn.base, } } @@ -315,6 +322,7 @@ impl Connection { matches!(self, Connection::Loopback(_)) || matches!(self, Connection::Ethernet(_)) || matches!(self, Connection::Dummy(_)) + || matches!(self, Connection::Vlan(_)) } pub fn mac_address(&self) -> String { @@ -556,6 +564,26 @@ pub struct DummyConnection { pub base: BaseConnection, } +#[derive(Debug, Default, PartialEq, Clone)] +pub struct VlanConnection { + pub base: BaseConnection, + pub vlan: VlanConfig, +} + +#[derive(Debug, Default, PartialEq, Clone)] +pub enum VlanProtocol { + #[default] + Ieee802_1Q, + Ieee802Ad, +} + +#[derive(Debug, Default, PartialEq, Clone)] +pub struct VlanConfig { + pub parent: String, + pub id: u32, + pub protocol: VlanProtocol, +} + #[derive(Debug, Default, PartialEq, Clone)] pub struct WirelessConfig { pub mode: WirelessMode, diff --git a/rust/agama-dbus-server/src/network/nm/dbus.rs b/rust/agama-dbus-server/src/network/nm/dbus.rs index 11cc97c19a..c40aba5a3e 100644 --- a/rust/agama-dbus-server/src/network/nm/dbus.rs +++ b/rust/agama-dbus-server/src/network/nm/dbus.rs @@ -18,6 +18,7 @@ const WIRELESS_KEY: &str = "802-11-wireless"; const WIRELESS_SECURITY_KEY: &str = "802-11-wireless-security"; const LOOPBACK_KEY: &str = "loopback"; const DUMMY_KEY: &str = "dummy"; +const VLAN_KEY: &str = "vlan"; /// Converts a connection struct into a HashMap that can be sent over D-Bus. /// @@ -49,6 +50,14 @@ pub fn connection_to_dbus(conn: &Connection) -> NestedHash { connection_dbus.insert("type", DUMMY_KEY.into()); } + if let Connection::Vlan(vlan) = conn { + connection_dbus.insert("type", VLAN_KEY.into()); + let vlan_dbus = vlan_config_to_dbus(vlan); + for (k, v) in vlan_dbus { + result.insert(k, v); + } + } + result.insert("connection", connection_dbus); result } @@ -66,6 +75,13 @@ pub fn connection_from_dbus(conn: OwnedNestedHash) -> Option { })); } + if let Some(vlan_config) = vlan_config_from_dbus(&conn) { + return Some(Connection::Vlan(VlanConnection { + base, + vlan: vlan_config, + })); + } + if conn.get(DUMMY_KEY).is_some() { return Some(Connection::Dummy(DummyConnection { base })); }; @@ -250,6 +266,23 @@ fn wireless_config_to_dbus(conn: &WirelessConnection) -> NestedHash { ]) } +fn vlan_config_to_dbus(conn: &VlanConnection) -> NestedHash { + let cfg = &conn.vlan; + let vlan: HashMap<&str, zvariant::Value> = HashMap::from([ + ("id", cfg.id.into()), + ("parent", cfg.parent.clone().into()), + ( + "protocol", + match cfg.protocol { + VlanProtocol::Ieee802_1Q => "802.1Q".into(), + VlanProtocol::Ieee802Ad => "802.1ad".into(), + }, + ), + ]); + + NestedHash::from([("vlan", vlan)]) +} + /// Converts a MatchConfig struct into a HashMap that can be sent over D-Bus. /// /// * `match_config`: MatchConfig to convert. @@ -507,6 +540,41 @@ fn wireless_config_from_dbus(conn: &OwnedNestedHash) -> Option { Some(wireless_config) } +fn vlan_config_from_dbus(conn: &OwnedNestedHash) -> Option { + let Some(vlan) = conn.get(VLAN_KEY) else { + return None; + }; + + let Some(id) = vlan.get("id") else { + return None; + }; + let id = id.downcast_ref::()?; + + let Some(parent) = vlan.get("parent") else { + return None; + }; + let parent: &str = parent.downcast_ref()?; + + let protocol = match vlan.get("protocol") { + Some(x) => { + let x: &str = x.downcast_ref()?; + if x == "802.1ad" { + VlanProtocol::Ieee802Ad + } else { + VlanProtocol::Ieee802_1Q + } + } + _ => VlanProtocol::Ieee802_1Q, + }; + + Some(VlanConfig { + id: *id, + parent: String::from(parent), + protocol, + ..Default::default() + }) +} + /// Determines whether a value is empty. /// /// TODO: Generalize for other kind of values, like dicts or arrays. diff --git a/rust/agama-lib/src/network/types.rs b/rust/agama-lib/src/network/types.rs index 10daa400c1..3dfdf07124 100644 --- a/rust/agama-lib/src/network/types.rs +++ b/rust/agama-lib/src/network/types.rs @@ -30,6 +30,7 @@ pub enum DeviceType { Ethernet = 1, Wireless = 2, Dummy = 3, + Vlan = 4, } #[derive(Debug, Error, PartialEq)] @@ -45,6 +46,7 @@ impl TryFrom for DeviceType { 1 => Ok(DeviceType::Ethernet), 2 => Ok(DeviceType::Wireless), 3 => Ok(DeviceType::Dummy), + 4 => Ok(DeviceType::Vlan), _ => Err(InvalidDeviceType(value)), } }