Skip to content

Commit

Permalink
Merge pull request jcronenberg#1 from cfconrad/impl_bonding
Browse files Browse the repository at this point in the history
Impl bonding
  • Loading branch information
jcronenberg authored Oct 5, 2023
2 parents 518d236 + 01a3dfb commit dabe0c0
Show file tree
Hide file tree
Showing 7 changed files with 348 additions and 13 deletions.
2 changes: 2 additions & 0 deletions rust/agama-dbus-server/src/network/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub enum NetworkStateError {
InvalidIpMethod(u8),
#[error("Invalid wireless mode: '{0}'")]
InvalidWirelessMode(String),
#[error("Unknown parent kind '{0}'")]
UnknownParentKind(String),
#[error("Connection '{0}' already exists")]
ConnectionExists(Uuid),
#[error("Invalid security wireless protocol: '{0}'")]
Expand Down
51 changes: 51 additions & 0 deletions rust/agama-dbus-server/src/network/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::network::error::NetworkStateError;
use agama_lib::network::types::{DeviceType, SSID};
use cidr::IpInet;
use std::{
collections::HashMap,
default::Default,
fmt,
net::IpAddr,
Expand Down Expand Up @@ -219,6 +220,7 @@ pub enum Connection {
Ethernet(EthernetConnection),
Wireless(WirelessConnection),
Loopback(LoopbackConnection),
Bond(BondConnection),
}

impl Connection {
Expand All @@ -234,6 +236,10 @@ impl Connection {
}),
DeviceType::Loopback => Connection::Loopback(LoopbackConnection { base }),
DeviceType::Ethernet => Connection::Ethernet(EthernetConnection { base }),
DeviceType::Bond => Connection::Bond(BondConnection {
base,
..Default::default()
}),
}
}

Expand All @@ -244,6 +250,7 @@ impl Connection {
Connection::Ethernet(conn) => &conn.base,
Connection::Wireless(conn) => &conn.base,
Connection::Loopback(conn) => &conn.base,
Connection::Bond(conn) => &conn.base,
}
}

Expand All @@ -252,6 +259,7 @@ impl Connection {
Connection::Ethernet(conn) => &mut conn.base,
Connection::Wireless(conn) => &mut conn.base,
Connection::Loopback(conn) => &mut conn.base,
Connection::Bond(conn) => &mut conn.base,
}
}

Expand Down Expand Up @@ -306,6 +314,37 @@ impl Connection {
}
}

#[derive(Debug, PartialEq, Clone)]
pub enum ParentKind {
Bond,
}

impl fmt::Display for ParentKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match &self {
ParentKind::Bond => "bond",
};
write!(f, "{}", name)
}
}

impl FromStr for ParentKind {
type Err = NetworkStateError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"bond" => Ok(ParentKind::Bond),
_ => Err(NetworkStateError::UnknownParentKind(s.to_string())),
}
}
}

#[derive(Debug, Clone)]
pub struct Parent {
pub interface: String,
pub kind: ParentKind,
}

#[derive(Debug, Default, Clone)]
pub struct BaseConnection {
pub id: String,
Expand All @@ -314,6 +353,7 @@ pub struct BaseConnection {
pub status: Status,
pub interface: String,
pub match_config: MatchConfig,
pub parent: Option<Parent>,
}

impl PartialEq for BaseConnection {
Expand Down Expand Up @@ -408,6 +448,17 @@ pub struct LoopbackConnection {
}

#[derive(Debug, Default, PartialEq, Clone)]
pub struct BondConnection {
pub base: BaseConnection,
pub bond: BondConfig,
}

#[derive(Debug, Default, PartialEq, Clone)]
pub struct BondConfig {
pub options: HashMap<String, String>,
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct WirelessConfig {
pub mode: WirelessMode,
pub ssid: SSID,
Expand Down
45 changes: 44 additions & 1 deletion rust/agama-dbus-server/src/network/nm/dbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use uuid::Uuid;
use zbus::zvariant::{self, OwnedValue, Value};

const ETHERNET_KEY: &str = "802-3-ethernet";
const BOND_KEY: &str = "bond";
const WIRELESS_KEY: &str = "802-11-wireless";
const WIRELESS_SECURITY_KEY: &str = "802-11-wireless-security";
const LOOPBACK_KEY: &str = "loopback";
Expand All @@ -28,18 +29,30 @@ pub fn connection_to_dbus(conn: &Connection) -> NestedHash {
("type", ETHERNET_KEY.into()),
("interface-name", conn.interface().into()),
]);
if let Some(parent) = &conn.base().parent {
connection_dbus.insert("master", parent.interface.clone().into());
connection_dbus.insert("slave-type", parent.kind.to_string().into());
}
result.insert("ipv4", ip_config_to_ipv4_dbus(conn.ip_config()));
result.insert("ipv6", ip_config_to_ipv6_dbus(conn.ip_config()));
result.insert("match", match_config_to_dbus(conn.match_config()));

if let Connection::Wireless(wireless) = conn {
connection_dbus.insert("type", "802-11-wireless".into());
connection_dbus.insert("type", WIRELESS_KEY.into());
let wireless_dbus = wireless_config_to_dbus(wireless);
for (k, v) in wireless_dbus {
result.insert(k, v);
}
}

if let Connection::Bond(bond) = conn {
connection_dbus.insert("type", BOND_KEY.into());
let bond_dbus = bond_config_to_dbus(bond);
for (k, v) in bond_dbus {
result.insert(k, v);
}
}

result.insert("connection", connection_dbus);
result
}
Expand All @@ -57,6 +70,13 @@ pub fn connection_from_dbus(conn: OwnedNestedHash) -> Option<Connection> {
}));
}

if let Some(bond_config) = bond_config_from_dbus(&conn) {
return Some(Connection::Bond(BondConnection {
base,
bond: bond_config,
}));
}

if conn.get(LOOPBACK_KEY).is_some() {
return Some(Connection::Loopback(LoopbackConnection { base }));
};
Expand Down Expand Up @@ -211,6 +231,14 @@ fn wireless_config_to_dbus(conn: &WirelessConnection) -> NestedHash {
])
}

fn bond_config_to_dbus(conn: &BondConnection) -> NestedHash {
let config = &conn.bond;
let bond: HashMap<&str, zvariant::Value> =
HashMap::from([("options", Value::new(config.options.clone()))]);

NestedHash::from([("bond", bond)])
}

/// Converts a MatchConfig struct into a HashMap that can be sent over D-Bus.
///
/// * `match_config`: MatchConfig to convert.
Expand Down Expand Up @@ -412,6 +440,21 @@ fn wireless_config_from_dbus(conn: &OwnedNestedHash) -> Option<WirelessConfig> {
Some(wireless_config)
}

fn bond_config_from_dbus(conn: &OwnedNestedHash) -> Option<BondConfig> {
let Some(bond) = conn.get(BOND_KEY) else {
return None;
};

if let Some(dict) = bond.get("options") {
let dict: zvariant::Dict = dict.downcast_ref::<Value>()?.try_into().unwrap();
if dict.full_signature() == "a{aa}" {
let options: HashMap<String, String> = dict.try_into().unwrap();
return Some(BondConfig { options });
}
}
None
}

/// Determines whether a value is empty.
///
/// TODO: Generalize for other kind of values, like dicts or arrays.
Expand Down
2 changes: 2 additions & 0 deletions rust/agama-lib/src/network/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum DeviceType {
Loopback = 0,
Ethernet = 1,
Wireless = 2,
Bond = 3,
}

#[derive(Debug, Error, PartialEq)]
Expand All @@ -43,6 +44,7 @@ impl TryFrom<u8> for DeviceType {
0 => Ok(DeviceType::Loopback),
1 => Ok(DeviceType::Ethernet),
2 => Ok(DeviceType::Wireless),
3 => Ok(DeviceType::Bond),
_ => Err(InvalidDeviceType(value)),
}
}
Expand Down
Loading

0 comments on commit dabe0c0

Please sign in to comment.