[pve-devel] [PATCH proxmox-firewall 02/14] firewall: add connmark rule with VMID to all guest chains
Christoph Heiss
c.heiss at proxmox.com
Mon Mar 17 15:11:39 CET 2025
Adds a connmark attribute with the VMID inside to anything flowing
in/out the guest, which are also carried over to all conntrack entries.
This enables differentiating conntrack entries between VMs for
live-migration.
Signed-off-by: Christoph Heiss <c.heiss at proxmox.com>
---
Depends on patch #1 being applied first to proxmox-ve-rs & a appropriate
crate bump.
proxmox-firewall/src/firewall.rs | 14 ++-
.../integration_tests__firewall.snap | 85 ++++++++++++++++++-
proxmox-nftables/src/expression.rs | 9 ++
proxmox-nftables/src/statement.rs | 10 ++-
4 files changed, 114 insertions(+), 4 deletions(-)
diff --git a/proxmox-firewall/src/firewall.rs b/proxmox-firewall/src/firewall.rs
index 88fb460..9f7df56 100644
--- a/proxmox-firewall/src/firewall.rs
+++ b/proxmox-firewall/src/firewall.rs
@@ -6,7 +6,9 @@ use anyhow::{bail, Error};
use proxmox_nftables::command::{Add, Commands, Delete, Flush};
use proxmox_nftables::expression::{Meta, Payload};
use proxmox_nftables::helper::NfVec;
-use proxmox_nftables::statement::{AnonymousLimit, Log, LogLevel, Match, Set, SetOperation};
+use proxmox_nftables::statement::{
+ AnonymousLimit, Log, LogLevel, Mangle, Match, Set, SetOperation,
+};
use proxmox_nftables::types::{
AddElement, AddRule, ChainPart, MapValue, RateTimescale, SetName, TableFamily, TableName,
TablePart, Verdict,
@@ -934,7 +936,15 @@ impl Firewall {
vmid: Some(vmid),
};
- commands.reserve(config.rules().len());
+ commands.reserve(config.rules().len() + 1);
+
+ // Add a connmark to anything in/out the guest, to be able to later
+ // track/filter per guest, e.g. in the pve-conntrack-tool.
+ // Need to be first, such that it is always applied.
+ commands.push(Add::rule(AddRule::from_statement(
+ chain.clone(),
+ Mangle::ct_mark(vmid),
+ )));
for config_rule in config.rules() {
for rule in NftRule::from_config_rule(config_rule, &env)? {
diff --git a/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap b/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap
index 9194fc6..aa29e6e 100644
--- a/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap
+++ b/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap
@@ -1,7 +1,6 @@
---
source: proxmox-firewall/tests/integration_tests.rs
expression: "firewall.full_host_fw().expect(\"firewall can be generated\")"
-snapshot_kind: text
---
{
"nftables": [
@@ -4373,6 +4372,27 @@ snapshot_kind: text
}
}
},
+ {
+ "add": {
+ "rule": {
+ "family": "bridge",
+ "table": "proxmox-firewall-guests",
+ "chain": "guest-100-in",
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 100
+ }
+ }
+ ]
+ }
+ }
+ },
{
"add": {
"rule": {
@@ -4648,6 +4668,27 @@ snapshot_kind: text
}
}
},
+ {
+ "add": {
+ "rule": {
+ "family": "bridge",
+ "table": "proxmox-firewall-guests",
+ "chain": "guest-100-out",
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 100
+ }
+ }
+ ]
+ }
+ }
+ },
{
"add": {
"rule": {
@@ -5034,6 +5075,27 @@ snapshot_kind: text
}
}
},
+ {
+ "add": {
+ "rule": {
+ "family": "bridge",
+ "table": "proxmox-firewall-guests",
+ "chain": "guest-101-in",
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 101
+ }
+ }
+ ]
+ }
+ }
+ },
{
"add": {
"rule": {
@@ -5096,6 +5158,27 @@ snapshot_kind: text
}
}
},
+ {
+ "add": {
+ "rule": {
+ "family": "bridge",
+ "table": "proxmox-firewall-guests",
+ "chain": "guest-101-out",
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 101
+ }
+ }
+ ]
+ }
+ }
+ },
{
"add": {
"rule": {
diff --git a/proxmox-nftables/src/expression.rs b/proxmox-nftables/src/expression.rs
index e9ef94f..cbafe85 100644
--- a/proxmox-nftables/src/expression.rs
+++ b/proxmox-nftables/src/expression.rs
@@ -12,6 +12,8 @@ use proxmox_ve_config::firewall::types::port::{PortEntry, PortList};
use proxmox_ve_config::firewall::types::rule_match::{IcmpCode, IcmpType, Icmpv6Code, Icmpv6Type};
#[cfg(feature = "config-ext")]
use proxmox_ve_config::firewall::types::Cidr;
+#[cfg(feature = "config-ext")]
+use proxmox_ve_config::guest::types::Vmid;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
@@ -267,6 +269,13 @@ impl From<&BridgeName> for Expression {
}
}
+#[cfg(feature = "config-ext")]
+impl From<Vmid> for Expression {
+ fn from(value: Vmid) -> Self {
+ Expression::Number(value.raw_value().into())
+ }
+}
+
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Meta {
key: String,
diff --git a/proxmox-nftables/src/statement.rs b/proxmox-nftables/src/statement.rs
index 5483368..3264e6c 100644
--- a/proxmox-nftables/src/statement.rs
+++ b/proxmox-nftables/src/statement.rs
@@ -10,6 +10,7 @@ use proxmox_ve_config::firewall::types::rule::Verdict as ConfigVerdict;
#[cfg(feature = "config-ext")]
use proxmox_ve_config::guest::types::Vmid;
+use crate::expression::Ct;
use crate::expression::Meta;
use crate::helper::{NfVec, Null};
use crate::types::{RateTimescale, RateUnit, Verdict};
@@ -370,12 +371,19 @@ pub struct Mangle {
}
impl Mangle {
- pub fn set_mark(value: impl Into<Expression>) -> Self {
+ pub fn meta_mark(value: impl Into<Expression>) -> Self {
Self {
key: Meta::new("mark").into(),
value: value.into(),
}
}
+
+ pub fn ct_mark(value: impl Into<Expression>) -> Self {
+ Self {
+ key: Ct::new("mark", None).into(),
+ value: value.into(),
+ }
+ }
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
--
2.48.1
More information about the pve-devel
mailing list