Skip to content

Commit

Permalink
Added http API for networking
Browse files Browse the repository at this point in the history
  • Loading branch information
teclator committed Mar 5, 2024
1 parent 9ae1ae3 commit 2dcc8df
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 36 deletions.
2 changes: 1 addition & 1 deletion rust/agama-dbus-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ tokio-stream = "0.1.14"
gettext-rs = { version = "0.7.0", features = ["gettext-system"] }
regex = "1.10.2"
once_cell = "1.18.0"
macaddr = "1.0"
macaddr = { version = "1.0", features = ["serde_std"] }
async-trait = "0.1.75"
axum = { version = "0.7.4", features = ["ws"] }
serde_json = "1.0.113"
Expand Down
2 changes: 1 addition & 1 deletion rust/agama-dbus-server/src/agama-web-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async fn serve_command(address: &str) -> anyhow::Result<()> {
run_monitor(tx.clone()).await?;

let config = web::ServiceConfig::load().unwrap();
let service = web::service(config, tx);
let service = web::service(config, tx).await;
axum::serve(listener, service)
.await
.expect("could not mount app on listener");
Expand Down
1 change: 1 addition & 0 deletions rust/agama-dbus-server/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub mod error;
pub mod model;
mod nm;
pub mod system;
pub mod web;

pub use action::Action;
pub use adapter::{Adapter, NetworkAdapterError};
Expand Down
11 changes: 9 additions & 2 deletions rust/agama-dbus-server/src/network/action.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::network::model::Connection;
use crate::network::model::{Connection, Device};
use agama_lib::network::types::DeviceType;
use tokio::sync::oneshot;
use uuid::Uuid;
Expand All @@ -24,8 +24,10 @@ pub enum Action {
/// Gets a connection
GetConnection(Uuid, Responder<Option<Connection>>),
/// Gets a connection
GetConnections(Responder<Vec<Connection>>),
/// Gets a connection path
GetConnectionPath(Uuid, Responder<Option<OwnedObjectPath>>),
/// Gets a connection
/// Gets a connection path by id
GetConnectionPathById(String, Responder<Option<OwnedObjectPath>>),
/// Get connections paths
GetConnectionsPaths(Responder<Vec<OwnedObjectPath>>),
Expand All @@ -34,6 +36,11 @@ pub enum Action {
Uuid,
Responder<Result<ControllerConnection, NetworkStateError>>,
),
/// Gets a device
GetDevice(String, Responder<Option<Device>>),
GetDevices(Responder<Vec<Device>>),
/// Gets a device path
GetDevicePath(String, Responder<Option<OwnedObjectPath>>),
/// Get devices paths
GetDevicesPaths(Responder<Vec<OwnedObjectPath>>),
/// Sets a controller's ports. It uses the Uuid of the controller and the IDs or interface names
Expand Down
10 changes: 10 additions & 0 deletions rust/agama-dbus-server/src/network/dbus/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ impl Tree {
self.objects.devices_paths()
}

pub fn device_path(&self, name: &str) -> Option<OwnedObjectPath> {
self.objects.device_path(name).map(|o| o.into())
}

/// Returns all connection paths.
pub fn connections_paths(&self) -> Vec<OwnedObjectPath> {
self.objects.connections_paths()
Expand Down Expand Up @@ -237,6 +241,12 @@ impl ObjectsRegistry {
path
}

/// Returns the path for a device.
///
/// * `name`: device name.
pub fn device_path(&self, name: &str) -> Option<ObjectPath> {
self.devices.get(name).map(|p| p.as_ref())
}
/// Returns the path for a connection.
///
/// * `uuid`: connection ID.
Expand Down
83 changes: 57 additions & 26 deletions rust/agama-dbus-server/src/network/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use crate::network::error::NetworkStateError;
use agama_lib::network::types::{BondMode, DeviceType, SSID};
use cidr::IpInet;
use serde::Serialize;
use serde_with::{serde_as, skip_serializing_none, DisplayFromStr};
use std::{
collections::HashMap,
default::Default,
Expand All @@ -16,7 +18,7 @@ use thiserror::Error;
use uuid::Uuid;
use zbus::zvariant::Value;

#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, utoipa::ToSchema)]
pub struct NetworkState {
pub devices: Vec<Device>,
pub connections: Vec<Connection>,
Expand Down Expand Up @@ -368,17 +370,21 @@ mod tests {
}

/// Network device
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct Device {
pub name: String,
#[serde(rename = "type")]
pub type_: DeviceType,
}

/// Represents an availble network connection.
#[derive(Debug, Clone, PartialEq)]
/// Represents a known network connection.
#[serde_as]
#[skip_serializing_none]
#[derive(Debug, Clone, PartialEq, Serialize, utoipa::ToSchema)]
pub struct Connection {
pub id: String,
pub uuid: Uuid,
#[serde_as(as = "DisplayFromStr")]
pub mac_address: MacAddress,
pub ip_config: IpConfig,
pub status: Status,
Expand Down Expand Up @@ -459,7 +465,7 @@ impl Default for Connection {
}
}

#[derive(Default, Debug, PartialEq, Clone)]
#[derive(Default, Debug, PartialEq, Clone, Serialize)]
pub enum ConnectionConfig {
#[default]
Ethernet,
Expand All @@ -471,7 +477,7 @@ pub enum ConnectionConfig {
Bridge(BridgeConfig),
}

#[derive(Default, Debug, PartialEq, Clone)]
#[derive(Default, Debug, PartialEq, Clone, Serialize)]
pub enum PortConfig {
#[default]
None,
Expand All @@ -494,7 +500,7 @@ impl From<WirelessConfig> for ConnectionConfig {
#[error("Invalid MAC address: {0}")]
pub struct InvalidMacAddress(String);

#[derive(Debug, Default, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
pub enum MacAddress {
MacAddress(macaddr::MacAddr6),
Preserve,
Expand Down Expand Up @@ -554,39 +560,47 @@ impl From<InvalidMacAddress> for zbus::fdo::Error {
}
}

#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize)]
pub enum Status {
#[default]
Up,
Down,
Removed,
}

#[derive(Default, Debug, PartialEq, Clone)]
#[skip_serializing_none]
#[derive(Default, Debug, PartialEq, Clone, Serialize)]
pub struct IpConfig {
pub method4: Ipv4Method,
pub method6: Ipv6Method,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub addresses: Vec<IpInet>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub nameservers: Vec<IpAddr>,
pub gateway4: Option<IpAddr>,
pub gateway6: Option<IpAddr>,
pub routes4: Option<Vec<IpRoute>>,
pub routes6: Option<Vec<IpRoute>>,
}

#[derive(Debug, Default, PartialEq, Clone)]
#[skip_serializing_none]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct MatchConfig {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub driver: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub interface: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub path: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub kernel: Vec<String>,
}

#[derive(Debug, Error)]
#[error("Unknown IP configuration method name: {0}")]
pub struct UnknownIpMethod(String);

#[derive(Debug, Default, Copy, Clone, PartialEq)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Serialize)]
pub enum Ipv4Method {
#[default]
Disabled = 0,
Expand Down Expand Up @@ -621,7 +635,7 @@ impl FromStr for Ipv4Method {
}
}

#[derive(Debug, Default, Copy, Clone, PartialEq)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Serialize)]
pub enum Ipv6Method {
#[default]
Disabled = 0,
Expand Down Expand Up @@ -668,10 +682,12 @@ impl From<UnknownIpMethod> for zbus::fdo::Error {
}
}

#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct IpRoute {
pub destination: IpInet,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_hop: Option<IpAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metric: Option<u32>,
}

Expand All @@ -694,7 +710,7 @@ impl From<&IpRoute> for HashMap<&str, Value<'_>> {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub enum VlanProtocol {
#[default]
IEEE802_1Q,
Expand Down Expand Up @@ -727,22 +743,29 @@ impl fmt::Display for VlanProtocol {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct VlanConfig {
pub parent: String,
pub id: u32,
pub protocol: VlanProtocol,
}

#[derive(Debug, Default, PartialEq, Clone)]
#[serde_as]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct WirelessConfig {
pub mode: WirelessMode,
#[serde_as(as = "DisplayFromStr")]
pub ssid: SSID,
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<String>,
pub security: SecurityProtocol,
#[serde(skip_serializing_if = "Option::is_none")]
pub band: Option<WirelessBand>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channel: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bssid: Option<macaddr::MacAddr6>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wep_security: Option<WEPSecurity>,
pub hidden: bool,
}
Expand All @@ -758,7 +781,7 @@ impl TryFrom<ConnectionConfig> for WirelessConfig {
}
}

#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize)]
pub enum WirelessMode {
Unknown = 0,
AdHoc = 1,
Expand Down Expand Up @@ -796,7 +819,7 @@ impl fmt::Display for WirelessMode {
}
}

#[derive(Debug, Clone, Copy, Default, PartialEq)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize)]
pub enum SecurityProtocol {
#[default]
WEP, // No encryption or WEP ("none")
Expand Down Expand Up @@ -842,15 +865,16 @@ impl TryFrom<&str> for SecurityProtocol {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct WEPSecurity {
pub auth_alg: WEPAuthAlg,
pub wep_key_type: WEPKeyType,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
pub wep_key_index: u32,
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub enum WEPKeyType {
#[default]
Unknown = 0,
Expand All @@ -871,7 +895,7 @@ impl TryFrom<u32> for WEPKeyType {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub enum WEPAuthAlg {
#[default]
Unset,
Expand Down Expand Up @@ -906,7 +930,7 @@ impl fmt::Display for WEPAuthAlg {
}
}

#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
pub enum WirelessBand {
A, // 5GHz
BG, // 2.4GHz
Expand Down Expand Up @@ -934,7 +958,7 @@ impl TryFrom<&str> for WirelessBand {
}
}

#[derive(Debug, Default, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
pub struct BondOptions(pub HashMap<String, String>);

impl TryFrom<&str> for BondOptions {
Expand Down Expand Up @@ -967,7 +991,7 @@ impl fmt::Display for BondOptions {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct BondConfig {
pub mode: BondMode,
pub options: BondOptions,
Expand All @@ -984,18 +1008,25 @@ impl TryFrom<ConnectionConfig> for BondConfig {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct BridgeConfig {
pub stp: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub forward_delay: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hello_time: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_age: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ageing_time: Option<u32>,
}

#[derive(Debug, Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Serialize)]
pub struct BridgePortConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_cost: Option<u32>,
}
15 changes: 15 additions & 0 deletions rust/agama-dbus-server/src/network/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ impl<T: Adapter> NetworkSystem<T> {
let conn = self.state.get_connection_by_uuid(uuid);
tx.send(conn.cloned()).unwrap();
}
Action::GetConnections(tx) => {
tx.send(self.state.connections.clone()).unwrap();
}
Action::GetConnectionPath(uuid, tx) => {
let tree = self.tree.lock().await;
let path = tree.connection_path(uuid);
Expand All @@ -92,6 +95,18 @@ impl<T: Adapter> NetworkSystem<T> {
let result = self.get_controller_action(uuid);
tx.send(result).unwrap()
}
Action::GetDevice(name, tx) => {
let device = self.state.get_device(name.as_str());
tx.send(device.cloned()).unwrap();
}
Action::GetDevicePath(name, tx) => {
let tree = self.tree.lock().await;
let path = tree.device_path(name.as_str());
tx.send(path).unwrap();
}
Action::GetDevices(tx) => {
tx.send(self.state.devices.clone()).unwrap();
}
Action::GetDevicesPaths(tx) => {
let tree = self.tree.lock().await;
tx.send(tree.devices_paths()).unwrap();
Expand Down
Loading

0 comments on commit 2dcc8df

Please sign in to comment.