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.he...@proxmox.com> --- Changes v1 -> v2: * rebased on latest master proxmox-firewall/src/firewall.rs | 14 +++- .../integration_tests__firewall.snap | 84 +++++++++++++++++++ proxmox-nftables/src/expression.rs | 9 ++ proxmox-nftables/src/statement.rs | 10 ++- 4 files changed, 114 insertions(+), 3 deletions(-) diff --git a/proxmox-firewall/src/firewall.rs b/proxmox-firewall/src/firewall.rs index 086b96c..552c6d3 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, @@ -944,7 +946,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 ad54ad0..e3db8ae 100644 --- a/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap +++ b/proxmox-firewall/tests/snapshots/integration_tests__firewall.snap @@ -4489,6 +4489,27 @@ expression: "firewall.full_host_fw().expect(\"firewall can be generated\")" } } }, + { + "add": { + "rule": { + "family": "bridge", + "table": "proxmox-firewall-guests", + "chain": "guest-100-in", + "expr": [ + { + "mangle": { + "key": { + "ct": { + "key": "mark" + } + }, + "value": 100 + } + } + ] + } + } + }, { "add": { "rule": { @@ -4764,6 +4785,27 @@ expression: "firewall.full_host_fw().expect(\"firewall can be generated\")" } } }, + { + "add": { + "rule": { + "family": "bridge", + "table": "proxmox-firewall-guests", + "chain": "guest-100-out", + "expr": [ + { + "mangle": { + "key": { + "ct": { + "key": "mark" + } + }, + "value": 100 + } + } + ] + } + } + }, { "add": { "rule": { @@ -5150,6 +5192,27 @@ expression: "firewall.full_host_fw().expect(\"firewall can be generated\")" } } }, + { + "add": { + "rule": { + "family": "bridge", + "table": "proxmox-firewall-guests", + "chain": "guest-101-in", + "expr": [ + { + "mangle": { + "key": { + "ct": { + "key": "mark" + } + }, + "value": 101 + } + } + ] + } + } + }, { "add": { "rule": { @@ -5212,6 +5275,27 @@ expression: "firewall.full_host_fw().expect(\"firewall can be generated\")" } } }, + { + "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.49.0 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel