[pve-devel] [PATCH proxmox-firewall v4 2/9] config: tests: add support for loading sdn and ipam config
Stefan Hanreich
s.hanreich at proxmox.com
Fri Nov 15 13:09:30 CET 2024
Also add example SDN configuration files that get automatically
loaded, which can be used for future tests.
Signed-off-by: Stefan Hanreich <s.hanreich at proxmox.com>
Reviewed-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
Tested-by: Gabriel Goller <g.goller at proxmox.com>
Tested-by: Hannes Dürr <h.duerr at proxmox.com>
---
proxmox-firewall/src/config.rs | 69 +++++++++++++++++++
.../tests/input/.running-config.json | 45 ++++++++++++
proxmox-firewall/tests/input/ipam.db | 32 +++++++++
proxmox-firewall/tests/integration_tests.rs | 10 +++
proxmox-nftables/src/types.rs | 2 +-
5 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 proxmox-firewall/tests/input/.running-config.json
create mode 100644 proxmox-firewall/tests/input/ipam.db
diff --git a/proxmox-firewall/src/config.rs b/proxmox-firewall/src/config.rs
index 5bd2512..c27aac6 100644
--- a/proxmox-firewall/src/config.rs
+++ b/proxmox-firewall/src/config.rs
@@ -16,6 +16,10 @@ use proxmox_ve_config::guest::{GuestEntry, GuestMap};
use proxmox_nftables::command::{CommandOutput, Commands, List, ListOutput};
use proxmox_nftables::types::ListChain;
use proxmox_nftables::NftClient;
+use proxmox_ve_config::sdn::{
+ config::{RunningConfig, SdnConfig},
+ ipam::{Ipam, IpamJson},
+};
pub trait FirewallConfigLoader {
fn cluster(&self) -> Result<Option<Box<dyn io::BufRead>>, Error>;
@@ -27,6 +31,8 @@ pub trait FirewallConfigLoader {
guest: &GuestEntry,
) -> Result<Option<Box<dyn io::BufRead>>, Error>;
fn guest_firewall_config(&self, vmid: &Vmid) -> Result<Option<Box<dyn io::BufRead>>, Error>;
+ fn sdn_running_config(&self) -> Result<Option<Box<dyn io::BufRead>>, Error>;
+ fn ipam(&self) -> Result<Option<Box<dyn io::BufRead>>, Error>;
}
#[derive(Default)]
@@ -58,6 +64,9 @@ fn open_config_file(path: &str) -> Result<Option<File>, Error> {
const CLUSTER_CONFIG_PATH: &str = "/etc/pve/firewall/cluster.fw";
const HOST_CONFIG_PATH: &str = "/etc/pve/local/host.fw";
+const SDN_RUNNING_CONFIG_PATH: &str = "/etc/pve/sdn/.running-config";
+const SDN_IPAM_PATH: &str = "/etc/pve/priv/ipam.db";
+
impl FirewallConfigLoader for PveFirewallConfigLoader {
fn cluster(&self) -> Result<Option<Box<dyn io::BufRead>>, Error> {
log::info!("loading cluster config");
@@ -119,6 +128,32 @@ impl FirewallConfigLoader for PveFirewallConfigLoader {
Ok(None)
}
+
+ fn sdn_running_config(&self) -> Result<Option<Box<dyn io::BufRead>>, Error> {
+ log::info!("loading SDN running-config");
+
+ let fd = open_config_file(SDN_RUNNING_CONFIG_PATH)?;
+
+ if let Some(file) = fd {
+ let buf_reader = Box::new(BufReader::new(file)) as Box<dyn io::BufRead>;
+ return Ok(Some(buf_reader));
+ }
+
+ Ok(None)
+ }
+
+ fn ipam(&self) -> Result<Option<Box<dyn io::BufRead>>, Error> {
+ log::info!("loading IPAM config");
+
+ let fd = open_config_file(SDN_IPAM_PATH)?;
+
+ if let Some(file) = fd {
+ let buf_reader = Box::new(BufReader::new(file)) as Box<dyn io::BufRead>;
+ return Ok(Some(buf_reader));
+ }
+
+ Ok(None)
+ }
}
pub trait NftConfigLoader {
@@ -150,6 +185,8 @@ pub struct FirewallConfig {
host_config: HostConfig,
guest_config: BTreeMap<Vmid, GuestConfig>,
nft_config: BTreeMap<String, ListChain>,
+ sdn_config: Option<SdnConfig>,
+ ipam_config: Option<Ipam>,
}
impl FirewallConfig {
@@ -207,6 +244,28 @@ impl FirewallConfig {
Ok(guests)
}
+ pub fn parse_sdn(
+ firewall_loader: &dyn FirewallConfigLoader,
+ ) -> Result<Option<SdnConfig>, Error> {
+ Ok(match firewall_loader.sdn_running_config()? {
+ Some(data) => {
+ let running_config: RunningConfig = serde_json::from_reader(data)?;
+ Some(SdnConfig::try_from(running_config)?)
+ }
+ _ => None,
+ })
+ }
+
+ pub fn parse_ipam(firewall_loader: &dyn FirewallConfigLoader) -> Result<Option<Ipam>, Error> {
+ Ok(match firewall_loader.ipam()? {
+ Some(data) => {
+ let raw_ipam: IpamJson = serde_json::from_reader(data)?;
+ Some(Ipam::try_from(raw_ipam)?)
+ }
+ _ => None,
+ })
+ }
+
pub fn parse_nft(
nft_loader: &dyn NftConfigLoader,
) -> Result<BTreeMap<String, ListChain>, Error> {
@@ -233,6 +292,8 @@ impl FirewallConfig {
cluster_config: Self::parse_cluster(firewall_loader)?,
host_config: Self::parse_host(firewall_loader)?,
guest_config: Self::parse_guests(firewall_loader)?,
+ sdn_config: Self::parse_sdn(firewall_loader)?,
+ ipam_config: Self::parse_ipam(firewall_loader)?,
nft_config: Self::parse_nft(nft_loader)?,
})
}
@@ -253,6 +314,14 @@ impl FirewallConfig {
&self.nft_config
}
+ pub fn sdn(&self) -> Option<&SdnConfig> {
+ self.sdn_config.as_ref()
+ }
+
+ pub fn ipam(&self) -> Option<&Ipam> {
+ self.ipam_config.as_ref()
+ }
+
pub fn is_enabled(&self) -> bool {
self.cluster().is_enabled() && self.host().nftables()
}
diff --git a/proxmox-firewall/tests/input/.running-config.json b/proxmox-firewall/tests/input/.running-config.json
new file mode 100644
index 0000000..a4511f0
--- /dev/null
+++ b/proxmox-firewall/tests/input/.running-config.json
@@ -0,0 +1,45 @@
+{
+ "subnets": {
+ "ids": {
+ "test-10.101.0.0-16": {
+ "gateway": "10.101.1.1",
+ "snat": 1,
+ "vnet": "public",
+ "dhcp-range": [
+ "start-address=10.101.99.100,end-address=10.101.99.200"
+ ],
+ "type": "subnet"
+ },
+ "test-fd80::-64": {
+ "snat": 1,
+ "gateway": "fd80::1",
+ "dhcp-range": [
+ "start-address=fd80::1000,end-address=fd80::ffff"
+ ],
+ "vnet": "public",
+ "type": "subnet"
+ }
+ }
+ },
+ "version": 49,
+ "vnets": {
+ "ids": {
+ "public": {
+ "zone": "test",
+ "type": "vnet"
+ }
+ }
+ },
+ "zones": {
+ "ids": {
+ "test": {
+ "dhcp": "dnsmasq",
+ "ipam": "pve",
+ "type": "simple"
+ }
+ }
+ },
+ "controllers": {
+ "ids": {}
+ }
+}
diff --git a/proxmox-firewall/tests/input/ipam.db b/proxmox-firewall/tests/input/ipam.db
new file mode 100644
index 0000000..ac2901e
--- /dev/null
+++ b/proxmox-firewall/tests/input/ipam.db
@@ -0,0 +1,32 @@
+{
+ "zones": {
+ "public": {
+ "subnets": {
+ "10.101.0.0/16": {
+ "ips": {
+ "10.101.1.1": {
+ "gateway": 1
+ },
+ "10.101.1.100": {
+ "vmid": "101",
+ "mac": "BC:24:11:11:22:33",
+ "hostname": null
+ }
+ }
+ },
+ "fd80::/64": {
+ "ips": {
+ "fd80::1": {
+ "gateway": 1
+ },
+ "fd80::1000": {
+ "mac": "BC:24:11:11:22:33",
+ "vmid": "101",
+ "hostname": "test-vm"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/proxmox-firewall/tests/integration_tests.rs b/proxmox-firewall/tests/integration_tests.rs
index e9baffe..5de1a4e 100644
--- a/proxmox-firewall/tests/integration_tests.rs
+++ b/proxmox-firewall/tests/integration_tests.rs
@@ -69,6 +69,16 @@ impl FirewallConfigLoader for MockFirewallConfigLoader {
Ok(None)
}
+
+ fn sdn_running_config(&self) -> Result<Option<Box<dyn std::io::BufRead>>, Error> {
+ Ok(Some(Box::new(
+ include_str!("input/.running-config.json").as_bytes(),
+ )))
+ }
+
+ fn ipam(&self) -> Result<Option<Box<dyn std::io::BufRead>>, Error> {
+ Ok(Some(Box::new(include_str!("input/ipam.db").as_bytes())))
+ }
}
struct MockNftConfigLoader {}
diff --git a/proxmox-nftables/src/types.rs b/proxmox-nftables/src/types.rs
index a83e958..3101436 100644
--- a/proxmox-nftables/src/types.rs
+++ b/proxmox-nftables/src/types.rs
@@ -636,7 +636,7 @@ impl SetName {
};
let name = match name.scope() {
- IpsetScope::Datacenter => name.to_string(),
+ IpsetScope::Datacenter | IpsetScope::Sdn => name.to_string(),
IpsetScope::Guest => {
if let Some(vmid) = vmid {
format!("guest-{vmid}/{}", name.name())
--
2.39.5
More information about the pve-devel
mailing list