[pve-devel] [PATCH proxmox-ve-rs v4 22/22] frr: add global ipv6 forwarding
Gabriel Goller
g.goller at proxmox.com
Wed Jul 2 16:50:13 CEST 2025
When a fabric with a ipv6 prefix is created, the FRR "ipv6 forwarding"
option is added to every node in the fabric. This enables forwarding for
*all* interfaces. Forwarding is needed for non-full-mesh topologies,
e.g.:
┌─────┐ ┌─────┐ ┌─────┐
│Node1│──────│Node2│──────│Node3│
└─────┘ └─────┘ └─────┘
Where -- without forwarding -- Node1 wouldn't be able to reach Node3.
With IPv4 this is quite easy, we can just enable IPv4 forwarding on each
interface contained in the fabric. This is done using `ip-forward 1` in
the ifupdown config file. With IPv6 this is a bit more tricky. There is
no simple way to enable IPv6 forwarding on a per-interface basis. See
[0] under 'conf/all/forwarding'. To enable IPv6 per-interface, we would
need to enable it globally and then add firewall rules to drop every
packet on the forward chain for all the other interfaces not contained
on the fabric. This is kinda tricky to persist and even more confusing
for users to debug.
So our solution is to just enable ipv6 forwarding globally if the user
creates a ipv6 fabric. The UI will have a big warning once a ipv6
address is inserted and this behavior will also be mentioned in the
docs.
[0]: https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
Signed-off-by: Gabriel Goller <g.goller at proxmox.com>
---
proxmox-frr/src/lib.rs | 11 +++++++++++
proxmox-frr/src/serializer.rs | 13 ++++++++++++-
proxmox-ve-config/src/sdn/fabric/frr.rs | 7 ++++++-
proxmox-ve-config/src/sdn/frr.rs | 3 ++-
.../snapshots/fabric__openfabric_dualstack_pve.snap | 2 ++
.../snapshots/fabric__openfabric_ipv6_only_pve.snap | 2 ++
6 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/proxmox-frr/src/lib.rs b/proxmox-frr/src/lib.rs
index 4c093e8e9bf4..84916c909118 100644
--- a/proxmox-frr/src/lib.rs
+++ b/proxmox-frr/src/lib.rs
@@ -191,6 +191,16 @@ impl Display for CommonInterfaceName {
}
}
+/// Forwarding configuration of FRR.
+///
+/// This enables IPv6 global forwarding, so forwarding is enabled on
+/// every interface. IPv4 forwarding is intentionally missing because it can be
+/// enabled on a per-interface basis using ifupdown2, which is much better.
+#[derive(Clone, Debug, PartialEq, Eq, Default)]
+pub struct Forwarding {
+ pub ipv6_forwarding: bool,
+}
+
/// Main FRR config.
///
/// Contains the two main frr building blocks: routers and interfaces. It also holds other
@@ -203,6 +213,7 @@ pub struct FrrConfig {
pub access_lists: Vec<AccessList>,
pub routemaps: Vec<RouteMap>,
pub protocol_routemaps: BTreeSet<ProtocolRouteMap>,
+ pub forwarding: Forwarding,
}
impl FrrConfig {
diff --git a/proxmox-frr/src/serializer.rs b/proxmox-frr/src/serializer.rs
index 3f8a1fc7619c..cc51ec72c64e 100644
--- a/proxmox-frr/src/serializer.rs
+++ b/proxmox-frr/src/serializer.rs
@@ -4,7 +4,7 @@ use crate::{
openfabric::{OpenfabricInterface, OpenfabricRouter},
ospf::{OspfInterface, OspfRouter},
route_map::{AccessList, AccessListName, ProtocolRouteMap, RouteMap},
- FrrConfig, Interface, InterfaceName, Router, RouterName,
+ Forwarding, FrrConfig, Interface, InterfaceName, Router, RouterName,
};
pub struct FrrConfigBlob<'a> {
@@ -45,6 +45,7 @@ impl FrrSerializer for &FrrConfig {
self.routemaps().try_for_each(|map| map.serialize(f))?;
self.protocol_routemaps()
.try_for_each(|pm| pm.serialize(f))?;
+ self.forwarding.serialize(f)?;
Ok(())
}
}
@@ -201,3 +202,13 @@ impl FrrSerializer for &ProtocolRouteMap {
Ok(())
}
}
+
+impl FrrSerializer for Forwarding {
+ fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result {
+ if self.ipv6_forwarding {
+ writeln!(f, "ipv6 forwarding")?;
+ writeln!(f, "!")?;
+ }
+ Ok(())
+ }
+}
diff --git a/proxmox-ve-config/src/sdn/fabric/frr.rs b/proxmox-ve-config/src/sdn/fabric/frr.rs
index 185795648208..0465991ae88c 100644
--- a/proxmox-ve-config/src/sdn/fabric/frr.rs
+++ b/proxmox-ve-config/src/sdn/fabric/frr.rs
@@ -7,7 +7,7 @@ use proxmox_frr::{
AccessAction, AccessList, AccessListName, AccessListRule, ProtocolRouteMap, ProtocolType,
RouteMap, RouteMapMatch, RouteMapMatchInner, RouteMapName, RouteMapSet,
},
- FrrConfig, FrrWord, Interface, InterfaceName, Router, RouterName,
+ Forwarding, FrrConfig, FrrWord, Interface, InterfaceName, Router, RouterName,
};
use proxmox_network_types::ip_address::Cidr;
use proxmox_sdn_types::net::Net;
@@ -38,6 +38,7 @@ pub fn build_fabric(
let mut routemap_seq = 100;
let mut current_router_id: Option<Ipv4Addr> = None;
let mut current_net: Option<Net> = None;
+ let mut ipv6_forwarding = false;
for (fabric_id, entry) in config.into_inner().iter() {
match entry {
@@ -48,6 +49,8 @@ pub fn build_fabric(
continue;
};
+ ipv6_forwarding = ipv6_forwarding || node.ip6().is_some();
+
if current_net.is_none() {
current_net = match (node.ip(), node.ip6()) {
(Some(ip), _) => Some(ip.into()),
@@ -237,6 +240,8 @@ pub fn build_fabric(
}
}
}
+
+ frr_config.forwarding = Forwarding { ipv6_forwarding };
Ok(())
}
diff --git a/proxmox-ve-config/src/sdn/frr.rs b/proxmox-ve-config/src/sdn/frr.rs
index f7929c1f6c16..ac42de2f5c2d 100644
--- a/proxmox-ve-config/src/sdn/frr.rs
+++ b/proxmox-ve-config/src/sdn/frr.rs
@@ -1,6 +1,6 @@
use std::collections::{BTreeMap, BTreeSet};
-use proxmox_frr::FrrConfig;
+use proxmox_frr::{Forwarding, FrrConfig};
use crate::common::valid::Valid;
use crate::sdn::fabric::{section_config::node::NodeId, FabricConfig};
@@ -33,6 +33,7 @@ impl FrrConfigBuilder {
access_lists: Vec::new(),
routemaps: Vec::new(),
protocol_routemaps: BTreeSet::new(),
+ forwarding: Forwarding::default(),
};
crate::sdn::fabric::frr::build_fabric(current_node, self.fabrics, &mut frr_config)?;
diff --git a/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_dualstack_pve.snap b/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_dualstack_pve.snap
index 48ac9092045e..95e0b5f92174 100644
--- a/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_dualstack_pve.snap
+++ b/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_dualstack_pve.snap
@@ -44,3 +44,5 @@ ip protocol openfabric route-map pve_openfabric
!
ipv6 protocol openfabric route-map pve_openfabric6
!
+ipv6 forwarding
+!
diff --git a/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_ipv6_only_pve.snap b/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_ipv6_only_pve.snap
index d7ab1d7e2a61..29a480e486ca 100644
--- a/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_ipv6_only_pve.snap
+++ b/proxmox-ve-config/tests/fabric/snapshots/fabric__openfabric_ipv6_only_pve.snap
@@ -32,3 +32,5 @@ exit
!
ipv6 protocol openfabric route-map pve_openfabric6
!
+ipv6 forwarding
+!
--
2.39.5
More information about the pve-devel
mailing list