From: Gabriel Goller <g.goller@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH proxmox-ve-rs 05/15] tests: fabrics: add test for fabrics in VRFs
Date: Fri, 21 Aug 2026 16:03:49 +0200 [thread overview]
Message-ID: <20260821140404.322081-6-g.goller@proxmox.com> (raw)
In-Reply-To: <20260821140404.322081-1-g.goller@proxmox.com>
Add an integration test covering OSPF and BGP fabrics assigned to
multiple SDN zone VRFs.
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
.../tests/fabric/cfg/vrf/fabrics.cfg | 43 ++++++
.../tests/fabric/cfg/vrf/route-maps.cfg | 15 ++
proxmox-ve-config/tests/fabric/helper.rs | 20 +++
proxmox-ve-config/tests/fabric/main.rs | 75 ++++++++--
.../fabric/snapshots/fabric__vrf_pve.snap | 134 ++++++++++++++++++
5 files changed, 275 insertions(+), 12 deletions(-)
create mode 100644 proxmox-ve-config/tests/fabric/cfg/vrf/fabrics.cfg
create mode 100644 proxmox-ve-config/tests/fabric/cfg/vrf/route-maps.cfg
create mode 100644 proxmox-ve-config/tests/fabric/snapshots/fabric__vrf_pve.snap
diff --git a/proxmox-ve-config/tests/fabric/cfg/vrf/fabrics.cfg b/proxmox-ve-config/tests/fabric/cfg/vrf/fabrics.cfg
new file mode 100644
index 000000000000..05a1cb57642a
--- /dev/null
+++ b/proxmox-ve-config/tests/fabric/cfg/vrf/fabrics.cfg
@@ -0,0 +1,43 @@
+ospf_fabric: ospfred
+ area 0
+ ip_prefix 10.0.0.0/24
+ zone red
+
+ospf_fabric: ospfblue
+ area 0
+ ip_prefix 10.0.0.0/24
+ zone blue
+
+ospf_node: ospfred_pve
+ interfaces name=ens18
+ ip 10.0.0.1
+
+ospf_node: ospfblue_pve
+ interfaces name=ens19
+ ip 10.0.0.1
+
+bgp_fabric: bgpred
+ bfd 0
+ ip_prefix 10.1.0.0/24
+ route_map_in red-in
+ route_map_out red-out
+ zone red
+
+bgp_fabric: bgpblue
+ bfd 0
+ ip_prefix 10.1.0.0/24
+ route_map_in blue-in
+ route_map_out blue-out
+ zone blue
+
+bgp_node: bgpred_pve
+ asn 65001
+ interfaces name=ens20
+ ip 10.1.0.1
+ role internal
+
+bgp_node: bgpblue_pve
+ asn 65002
+ interfaces name=ens21
+ ip 10.1.0.1
+ role internal
diff --git a/proxmox-ve-config/tests/fabric/cfg/vrf/route-maps.cfg b/proxmox-ve-config/tests/fabric/cfg/vrf/route-maps.cfg
new file mode 100644
index 000000000000..b382fc369b51
--- /dev/null
+++ b/proxmox-ve-config/tests/fabric/cfg/vrf/route-maps.cfg
@@ -0,0 +1,15 @@
+route-map-entry: blue-in_10
+ action permit
+ set key=local-preference,value=200
+
+route-map-entry: blue-out_10
+ action permit
+ set key=metric,value=20
+
+route-map-entry: red-in_10
+ action permit
+ set key=local-preference,value=100
+
+route-map-entry: red-out_10
+ action permit
+ set key=metric,value=10
diff --git a/proxmox-ve-config/tests/fabric/helper.rs b/proxmox-ve-config/tests/fabric/helper.rs
index 93404b8eb7af..ec464d334a4c 100644
--- a/proxmox-ve-config/tests/fabric/helper.rs
+++ b/proxmox-ve-config/tests/fabric/helper.rs
@@ -18,6 +18,24 @@ macro_rules! get_fabrics_config {
}};
}
+#[allow(unused_macros)]
+macro_rules! get_route_maps_config {
+ () => {{
+ fn f() {}
+ fn type_name_of<T>(_: T) -> &'static str {
+ std::any::type_name::<T>()
+ }
+ let mut name = type_name_of(f);
+
+ name = match &name[..name.len() - 3].rfind(':') {
+ Some(pos) => &name[pos + 1..name.len() - 3],
+ None => &name[..name.len() - 3],
+ };
+ let real_filename = format!("tests/fabric/cfg/{name}/route-maps.cfg");
+ &std::fs::read_to_string(real_filename).expect("cannot find route-map config file")
+ }};
+}
+
#[allow(unused_macros)]
macro_rules! reference_name {
($suffix:expr) => {{
@@ -40,4 +58,6 @@ macro_rules! reference_name {
#[allow(unused_imports)]
pub(crate) use get_fabrics_config;
#[allow(unused_imports)]
+pub(crate) use get_route_maps_config;
+#[allow(unused_imports)]
pub(crate) use reference_name;
diff --git a/proxmox-ve-config/tests/fabric/main.rs b/proxmox-ve-config/tests/fabric/main.rs
index f65c5d26aeed..249816b54327 100644
--- a/proxmox-ve-config/tests/fabric/main.rs
+++ b/proxmox-ve-config/tests/fabric/main.rs
@@ -3,14 +3,19 @@ use std::net::Ipv4Addr;
use std::str::FromStr;
use proxmox_frr::ser::bgp::{AddressFamilies, BgpRouter, CommonAddressFamilyOptions, L2vpnEvpnAF};
-use proxmox_frr::ser::{FrrConfig, FrrProtocol, VrfName, serializer::dump};
-use proxmox_ve_config::sdn::fabric::{
- FabricConfig,
- frr::build_fabric,
- section_config::{
- fabric::{FabricId, FabricUpdater},
- node::NodeId,
+use proxmox_frr::ser::route_map::{AccessAction, RouteMapEntry, RouteMapName};
+use proxmox_frr::ser::{FrrConfig, FrrProtocol, IpProtocolRouteMap, VrfName, serializer::dump};
+use proxmox_section_config::typed::ApiSectionDataEntry;
+use proxmox_ve_config::sdn::{
+ fabric::{
+ FabricConfig,
+ frr::build_fabric,
+ section_config::{
+ fabric::{FabricId, FabricUpdater},
+ node::NodeId,
+ },
},
+ route_map::{RouteMap, frr::build_frr_route_maps},
};
mod helper;
@@ -286,9 +291,31 @@ bgp_node: bgp_pve
"#;
let config = FabricConfig::parse_section_config(raw).unwrap();
let mut frr_config = FrrConfig::default();
+ let correct_src = RouteMapName::new("correct_src".to_owned());
+ let correct_src_entry = RouteMapEntry {
+ seq: 1,
+ action: AccessAction::Permit,
+ matches: Vec::new(),
+ sets: Vec::new(),
+ custom_frr_config: Vec::new(),
+ call: None,
+ exit_action: None,
+ };
+ frr_config
+ .routemaps
+ .insert(correct_src.clone(), vec![correct_src_entry.clone()]);
+ frr_config.protocol_routemaps.insert(
+ FrrProtocol::Bgp,
+ IpProtocolRouteMap {
+ v4: Some(correct_src.clone()),
+ v6: None,
+ },
+ );
build_fabric(NodeId::from_str("pve").unwrap(), config, &mut frr_config).unwrap();
+ assert_eq!(frr_config.routemaps[&correct_src], vec![correct_src_entry]);
+
let ospf_routemap = &frr_config.vrf_protocol_routemaps
[&VrfName::Custom("vrf_zoneone".to_owned())][&FrrProtocol::Ospf];
assert_eq!(
@@ -307,14 +334,38 @@ bgp_node: bgp_pve
.get(&FrrProtocol::Ospf)
.is_none()
);
- assert!(
- frr_config
- .protocol_routemaps
- .get(&FrrProtocol::Bgp)
- .is_none()
+ assert_eq!(
+ frr_config.protocol_routemaps[&FrrProtocol::Bgp].v4,
+ Some(correct_src)
);
}
+#[test]
+fn vrf() {
+ let config = FabricConfig::parse_section_config(helper::get_fabrics_config!()).unwrap();
+ let route_maps =
+ RouteMap::parse_section_config("route-maps.cfg", helper::get_route_maps_config!()).unwrap();
+ let mut frr_config = FrrConfig::default();
+
+ build_frr_route_maps(
+ route_maps
+ .into_iter()
+ .map(|(_, route_map_entry)| route_map_entry),
+ &mut frr_config,
+ )
+ .unwrap();
+ build_fabric(
+ NodeId::from_str("pve").expect("invalid nodeid"),
+ config,
+ &mut frr_config,
+ )
+ .unwrap();
+
+ let output = dump(&frr_config).expect("error dumping stuff");
+
+ insta::assert_snapshot!(helper::reference_name!("pve"), output);
+}
+
#[test]
fn bgp_default() {
let config = FabricConfig::parse_section_config(helper::get_fabrics_config!()).unwrap();
diff --git a/proxmox-ve-config/tests/fabric/snapshots/fabric__vrf_pve.snap b/proxmox-ve-config/tests/fabric/snapshots/fabric__vrf_pve.snap
new file mode 100644
index 000000000000..84973240deb4
--- /dev/null
+++ b/proxmox-ve-config/tests/fabric/snapshots/fabric__vrf_pve.snap
@@ -0,0 +1,134 @@
+---
+source: proxmox-ve-config/tests/fabric/main.rs
+expression: output
+---
+!
+router bgp 65002 vrf vrf_blue
+ bgp router-id 10.1.0.1
+ no bgp default ipv4-unicast
+ neighbor bgpblue peer-group
+ neighbor bgpblue remote-as external
+ neighbor ens21 interface peer-group bgpblue
+ !
+ address-family ipv4 unicast
+ network 10.1.0.1/32
+ neighbor bgpblue activate
+ neighbor bgpblue soft-reconfiguration inbound
+ neighbor bgpblue route-map pve_bgp_bgpblue_in in
+ neighbor bgpblue route-map blue-out out
+ exit-address-family
+exit
+!
+router bgp 65001 vrf vrf_red
+ bgp router-id 10.1.0.1
+ no bgp default ipv4-unicast
+ neighbor bgpred peer-group
+ neighbor bgpred remote-as external
+ neighbor ens20 interface peer-group bgpred
+ !
+ address-family ipv4 unicast
+ network 10.1.0.1/32
+ neighbor bgpred activate
+ neighbor bgpred soft-reconfiguration inbound
+ neighbor bgpred route-map pve_bgp_bgpred_in in
+ neighbor bgpred route-map red-out out
+ exit-address-family
+exit
+!
+router ospf vrf vrf_blue
+ ospf router-id 10.0.0.1
+exit
+!
+router ospf vrf vrf_red
+ ospf router-id 10.0.0.1
+exit
+!
+interface dummy_ospfblue vrf vrf_blue
+ ip ospf area 0
+ ip ospf passive
+exit
+!
+interface dummy_ospfred vrf vrf_red
+ ip ospf area 0
+ ip ospf passive
+exit
+!
+interface ens18 vrf vrf_red
+ ip ospf area 0
+ ip ospf network point-to-point
+exit
+!
+interface ens19 vrf vrf_blue
+ ip ospf area 0
+ ip ospf network point-to-point
+exit
+!
+access-list pve_bgp_bgpblue_ips permit 10.1.0.0/24
+!
+access-list pve_bgp_bgpred_ips permit 10.1.0.0/24
+!
+access-list pve_ospf_ospfblue_ips permit 10.0.0.0/24
+!
+access-list pve_ospf_ospfred_ips permit 10.0.0.0/24
+!
+route-map blue-in permit 10
+ set local-preference 200
+exit
+!
+route-map blue-out permit 10
+ set metric 20
+exit
+!
+route-map pve_bgp_bgpblue_in permit 10
+ match ip address pve_bgp_bgpblue_ips
+ call blue-in
+exit
+!
+route-map pve_bgp_bgpred_in permit 10
+ match ip address pve_bgp_bgpred_ips
+ call red-in
+exit
+!
+route-map pve_bgp_vrf_blue permit 100
+ match ip address pve_bgp_bgpblue_ips
+ set src 10.1.0.1
+exit
+!
+route-map pve_bgp_vrf_blue permit 65535
+exit
+!
+route-map pve_bgp_vrf_red permit 110
+ match ip address pve_bgp_bgpred_ips
+ set src 10.1.0.1
+exit
+!
+route-map pve_bgp_vrf_red permit 65535
+exit
+!
+route-map pve_ospf_vrf_blue permit 120
+ match ip address pve_ospf_ospfblue_ips
+ set src 10.0.0.1
+exit
+!
+route-map pve_ospf_vrf_red permit 130
+ match ip address pve_ospf_ospfred_ips
+ set src 10.0.0.1
+exit
+!
+route-map red-in permit 10
+ set local-preference 100
+exit
+!
+route-map red-out permit 10
+ set metric 10
+exit
+!
+vrf vrf_blue
+ ip protocol bgp route-map pve_bgp_vrf_blue
+ ip protocol ospf route-map pve_ospf_vrf_blue
+exit-vrf
+!
+vrf vrf_red
+ ip protocol bgp route-map pve_bgp_vrf_red
+ ip protocol ospf route-map pve_ospf_vrf_red
+exit-vrf
--
2.47.3
next prev parent reply other threads:[~2026-08-21 14:05 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 14:03 [RFC manager/network/proxmox{-ve-rs,-perl-rs} 00/15] SDN VRF support Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-ve-rs 01/15] frr: add VRF-aware OSPF rendering Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-ve-rs 02/15] sdn: add zone references to OSPF and BGP fabrics Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-ve-rs 03/15] sdn: generate fabric routing configuration in zone VRFs Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-ve-rs 04/15] sdn: fix VRF route-map scoping and zone ID validation Gabriel Goller
2026-08-21 14:03 ` Gabriel Goller [this message]
2026-08-21 14:03 ` [PATCH proxmox-perl-rs 06/15] pve-rs: fabrics: assign network interfaces to configured VRFs Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-perl-rs 07/15] pve-rs: fabrics: make per-fabric status queries VRF-aware Gabriel Goller
2026-08-21 14:03 ` [PATCH proxmox-perl-rs 08/15] pve-rs: fabrics: include VRF routes in aggregate status Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-network 09/15] sdn: add optional VRFs for simple zones Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-network 10/15] sdn: allow fabrics to use simple zone VRFs Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-network 11/15] sdn: always generate EVPN " Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-network 12/15] api: sdn: allow EVPN zones as fabric VRFs Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-network 13/15] api: sdn: disallow BGP fabrics in EVPN zone VRFs Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-manager 14/15] ui: sdn: add VRF zone selection for fabrics Gabriel Goller
2026-08-21 14:03 ` [PATCH pve-manager 15/15] ui: sdn: expose EVPN zones as fabric VRFs Gabriel Goller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260821140404.322081-6-g.goller@proxmox.com \
--to=g.goller@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox