public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: Dietmar Maurer <dietmar@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [RFC proxmox 11/22] firewall-api-types: add FirewallIcmpType
Date: Thu, 12 Mar 2026 11:51:03 +0100	[thread overview]
Message-ID: <6ioutptc6rfgjv3zhnocnwyskjrclgbuxpsuf5sdopddrbifyl@u3btu4nzz7re> (raw)
In-Reply-To: <20260216104401.3959270-12-dietmar@proxmox.com>

On Mon, Feb 16, 2026 at 11:43:49AM +0100, Dietmar Maurer wrote:
> This adds the `FirewallIcmpType` enum, which can represent ICMP types
> either as a named variant (using `FirewallIcmpTypeName`) or as a raw
> numeric value (u8).
> 
> The `FirewallIcmpTypeName` enum covers standard ICMPv4 and ICMPv6 types,
> including deprecated ones and those with codes (e.g., `destination-unreachable`).
> 
> It provides `ipv4()` and `ipv6()` helper methods to check if a specific
> named type is valid for the respective protocol.
> 
> Serialization and deserialization are handled via `serde` and `serde_plain`,
> allowing for easy conversion to/from strings.
> 
> Includes tests for serialization, deserialization, and protocol validity checks.
> ---
>  proxmox-firewall-api-types/src/icmp_type.rs | 555 ++++++++++++++++++++
>  proxmox-firewall-api-types/src/lib.rs       |   3 +
>  2 files changed, 558 insertions(+)
>  create mode 100644 proxmox-firewall-api-types/src/icmp_type.rs
> 
> diff --git a/proxmox-firewall-api-types/src/icmp_type.rs b/proxmox-firewall-api-types/src/icmp_type.rs
> new file mode 100644
> index 00000000..b45c1505
> --- /dev/null
> +++ b/proxmox-firewall-api-types/src/icmp_type.rs
> @@ -0,0 +1,555 @@
> +use std::fmt;
> +
> +use anyhow::{bail, Error};
> +use serde::{Deserialize, Serialize};
> +
> +#[cfg(feature = "enum-fallback")]
> +use proxmox_fixed_string::FixedString;
> +
> +use proxmox_schema::{ApiStringFormat, ApiType, Schema, StringSchema};
> +
> +#[derive(Debug, Copy, Clone, PartialEq)]
> +/// ICMP type, either named or numeric.
> +pub enum FirewallIcmpType {
> +    /// Named ICMP type, e.g. "echo-request"
> +    Named(FirewallIcmpTypeName),
> +    /// Numeric ICMP type, e.g. "8"
> +    Numeric(u8),
> +}
> +
> +impl ApiType for FirewallIcmpType {
> +    const API_SCHEMA: Schema = StringSchema::new(
> +        r#"ICMP type, either named or numeric.
> +        Only valid if proto equals 'icmp' or 'icmpv6'/'ipv6-icmp'."#,

^ as a "raw" string this includes the whitespace here.

Just use this a regular string with a backslash after the first line.

> +    )
> +    .format(&ApiStringFormat::VerifyFn(verify_firewall_icmp_type))
> +    .schema();
> +}
> +
> +fn verify_firewall_icmp_type(value: &str) -> Result<(), Error> {
> +    value.parse::<FirewallIcmpType>().map(|_| ())

( .map(drop) is IMO faster to read)

> +}
> +
> +impl std::str::FromStr for FirewallIcmpType {
> +    type Err = Error;
> +
> +    fn from_str(s: &str) -> Result<Self, Error> {
> +        let s = s.trim();
> +
> +        if let Ok(ty) = s.parse::<u8>() {
> +            return Ok(Self::Numeric(ty));
> +        }
> +
> +        if let Ok(named) = serde_plain::from_str::<FirewallIcmpTypeName>(s) {
> +            return Ok(Self::Named(named));
> +        }
> +
> +        bail!("{s:?} is not a valid icmp type");
> +    }
> +}
> +
> +impl fmt::Display for FirewallIcmpType {
> +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
> +        match self {
> +            FirewallIcmpType::Numeric(ty) => write!(f, "{ty}"),
> +            FirewallIcmpType::Named(ty) => write!(f, "{ty}"),
> +        }
> +    }
> +}
> +
> +serde_plain::derive_deserialize_from_fromstr!(FirewallIcmpType, "valid icmp type name or number");
> +serde_plain::derive_serialize_from_display!(FirewallIcmpType);
> +
> +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
> +#[serde(rename_all = "kebab-case")]
> +/// Named ICMP type, e.g. "echo-request".
> +pub enum FirewallIcmpTypeName {
> +    Any,
> +
> +    // IPv4 specific
> +    HostUnreachable,     // 3:1 (ICMP-TYPE, ICMP-CODE)
> +    ProtocolUnreachable, // 3:2
> +    PortUnreachable,     // 3:3
> +    FragmentationNeeded, // 3:4
> +    SourceRouteFailed,   // 3:5
> +    NetworkUnknown,      // 3:6
> +    HostUnknown,         // 3:7
> +    NetworkProhibited,   // 3:9
> +    HostProhibited,      // 3:10
> +    #[serde(rename = "TOS-network-unreachable")]
> +    TOSNetworkUnreachable, // 3:11
> +    #[serde(rename = "TOS-host-unreachable")]
> +    TOSHostUnreachable, // 3:12
> +    CommunicationProhibited, // 3:13
> +    HostPrecedenceViolation, // 3:14
> +    PrecedenceCutoff,    // 3:15
> +    SourceQuench,        // 4
> +    NetworkRedirect,     // 5:0
> +    HostRedirect,        // 5:1
> +    #[serde(rename = "TOS-network-redirect")]
> +    TOSNetworkRedirect, // 5:2
> +    #[serde(rename = "TOS-host-redirect")]
> +    TOSHostRedirect, // 5:3
> +    TimestampRequest,    // 13
> +    TimestampReply,      // 14
> +    AddressMaskRequest,  // 17
> +    AddressMaskReply,    // 18
> +    RouterAdvertisement, // 9
> +    RouterSolicitation,  // 10
> +    IpHeaderBad,         // 12:0
> +    RequiredOptionMissing, // 12:1
> +
> +    // IPv6 specific
> +    NoRoute,                // 1:0
> +    BeyondScope,            // 1:2
> +    AddressUnreachable,     // 1:3
> +    FailedPolicy,           // 1:5
> +    RejectRoute,            // 1:6
> +    PacketTooBig,           // 2
> +    BadHeader,              // 4:0
> +    UnknownHeaderType,      // 4:1
> +    UnknownOption,          // 4:2
> +    NeighborSolicitation,   // 135
> +    NeighbourSolicitation,  // 135
> +    NeighborAdvertisement,  // 136
> +    NeighbourAdvertisement, // 136
> +
> +    // Common
> +    DestinationUnreachable,  // 3:0 (v4), 1:0 (v6) ? v6 has no-route
> +    NetworkUnreachable,      // 3:0
> +    EchoReply,               // 0 (v4), 129 (v6)
> +    EchoRequest,             // 8 (v4), 128 (v6)
> +    TimeExceeded,            // 11 (v4), 3 (v6)
> +    TtlZeroDuringTransit,    // 11:0 (v4), 3:0 (v6)
> +    TtlZeroDuringReassembly, // 11:1 (v4), 3:1 (v6)
> +    ParameterProblem,        // 12 (v4), 4 (v6)
> +    Redirect,                // 5 (v4), 137 (v6)
> +
> +    #[cfg(feature = "enum-fallback")]
> +    #[serde(untagged)]
> +    /// Unknwon
> +    UnknownEnumValue(FixedString),
> +}
> +
> +serde_plain::derive_display_from_serialize!(FirewallIcmpTypeName);
> +serde_plain::derive_fromstr_from_deserialize!(FirewallIcmpTypeName);
> +
> +impl FirewallIcmpTypeName {
> +    pub const fn ipv4(&self) -> bool {
> +        match self {
> +            FirewallIcmpTypeName::Any => true,
> +            FirewallIcmpTypeName::EchoReply => true,
> +            FirewallIcmpTypeName::DestinationUnreachable => true,
> +            FirewallIcmpTypeName::NetworkUnreachable => true,
> +            FirewallIcmpTypeName::HostUnreachable => true,
> +            FirewallIcmpTypeName::ProtocolUnreachable => true,
> +            FirewallIcmpTypeName::PortUnreachable => true,
> +            FirewallIcmpTypeName::FragmentationNeeded => true,
> +            FirewallIcmpTypeName::SourceRouteFailed => true,
> +            FirewallIcmpTypeName::NetworkUnknown => true,
> +            FirewallIcmpTypeName::HostUnknown => true,
> +            FirewallIcmpTypeName::NetworkProhibited => true,
> +            FirewallIcmpTypeName::HostProhibited => true,
> +            FirewallIcmpTypeName::TOSNetworkUnreachable => true,
> +            FirewallIcmpTypeName::TOSHostUnreachable => true,
> +            FirewallIcmpTypeName::CommunicationProhibited => true,
> +            FirewallIcmpTypeName::HostPrecedenceViolation => true,
> +            FirewallIcmpTypeName::PrecedenceCutoff => true,
> +            FirewallIcmpTypeName::SourceQuench => true,
> +            FirewallIcmpTypeName::Redirect => true,
> +            FirewallIcmpTypeName::NetworkRedirect => true,
> +            FirewallIcmpTypeName::HostRedirect => true,
> +            FirewallIcmpTypeName::TOSNetworkRedirect => true,
> +            FirewallIcmpTypeName::TOSHostRedirect => true,
> +            FirewallIcmpTypeName::EchoRequest => true,
> +            FirewallIcmpTypeName::RouterAdvertisement => true,
> +            FirewallIcmpTypeName::RouterSolicitation => true,
> +            FirewallIcmpTypeName::TimeExceeded => true,
> +            FirewallIcmpTypeName::TtlZeroDuringTransit => true,
> +            FirewallIcmpTypeName::TtlZeroDuringReassembly => true,
> +            FirewallIcmpTypeName::ParameterProblem => true,
> +            FirewallIcmpTypeName::IpHeaderBad => true,
> +            FirewallIcmpTypeName::RequiredOptionMissing => true,
> +            FirewallIcmpTypeName::TimestampRequest => true,
> +            FirewallIcmpTypeName::TimestampReply => true,
> +            FirewallIcmpTypeName::AddressMaskRequest => true,
> +            FirewallIcmpTypeName::AddressMaskReply => true,
> +            _ => false,
> +        }

Clippy complains that this is a custom `matches!(self, Self::Any |
Self::EchoReply | ...)` implementation.

And I agree, since it's very hard to really see *visually* that these
are all `=> true,` and there's no `=> false,` hiding somewhere. This
*could* be better with a table-formatted match statement kept so via
`#[rustfmt::skip]`, but `matches!()` with an OR pattern makes more
sense.

Also, using `Self::` makes it much shorter again ;-)

> +    }
> +
> +    pub const fn ipv6(&self) -> bool {
> +        match self {

same here

> +            FirewallIcmpTypeName::Any => true,
> +            FirewallIcmpTypeName::EchoReply => true,
> +            FirewallIcmpTypeName::DestinationUnreachable => true,
> +            FirewallIcmpTypeName::PacketTooBig => true,
> +            FirewallIcmpTypeName::TimeExceeded => true,
> +            FirewallIcmpTypeName::ParameterProblem => true,
> +            FirewallIcmpTypeName::EchoRequest => true,
> +            FirewallIcmpTypeName::RouterSolicitation => true,
> +            FirewallIcmpTypeName::RouterAdvertisement => true,
> +            FirewallIcmpTypeName::NeighborSolicitation => true,
> +            FirewallIcmpTypeName::NeighbourSolicitation => true,
> +            FirewallIcmpTypeName::NeighborAdvertisement => true,
> +            FirewallIcmpTypeName::NeighbourAdvertisement => true,
> +            FirewallIcmpTypeName::Redirect => true,
> +            FirewallIcmpTypeName::NoRoute => true,
> +            FirewallIcmpTypeName::CommunicationProhibited => true,
> +            FirewallIcmpTypeName::BeyondScope => true,
> +            FirewallIcmpTypeName::AddressUnreachable => true,
> +            FirewallIcmpTypeName::PortUnreachable => true,
> +            FirewallIcmpTypeName::FailedPolicy => true,
> +            FirewallIcmpTypeName::RejectRoute => true,
> +            FirewallIcmpTypeName::TtlZeroDuringTransit => true,
> +            FirewallIcmpTypeName::TtlZeroDuringReassembly => true,
> +            FirewallIcmpTypeName::BadHeader => true,
> +            FirewallIcmpTypeName::UnknownHeaderType => true,
> +            FirewallIcmpTypeName::UnknownOption => true,
> +            _ => false,
> +        }
> +    }
> +}
> +
> +#[cfg(test)]
> +mod tests {
> +    use super::*;
> +
> +    #[test]
> +
> +    fn test_icmp_types() {
> +        // (name, variant, ipv4, ipv6)
> +        let tests = [
> +            ("any", FirewallIcmpTypeName::Any, true, true),
> +            ("echo-reply", FirewallIcmpTypeName::EchoReply, true, true),
> +            (
> +                "destination-unreachable",
> +                FirewallIcmpTypeName::DestinationUnreachable,
> +                true,
> +                true,
> +            ),
> +            (
> +                "network-unreachable",
> +                FirewallIcmpTypeName::NetworkUnreachable,
> +                true,
> +                false,
> +            ),
> +            (
> +                "host-unreachable",
> +                FirewallIcmpTypeName::HostUnreachable,
> +                true,
> +                false,
> +            ),
> +            (
> +                "protocol-unreachable",
> +                FirewallIcmpTypeName::ProtocolUnreachable,
> +                true,
> +                false,
> +            ),
> +            (
> +                "port-unreachable",
> +                FirewallIcmpTypeName::PortUnreachable,
> +                true,
> +                true,
> +            ),
> +            (
> +                "fragmentation-needed",
> +                FirewallIcmpTypeName::FragmentationNeeded,
> +                true,
> +                false,
> +            ),
> +            (
> +                "source-route-failed",
> +                FirewallIcmpTypeName::SourceRouteFailed,
> +                true,
> +                false,
> +            ),
> +            (
> +                "network-unknown",
> +                FirewallIcmpTypeName::NetworkUnknown,
> +                true,
> +                false,
> +            ),
> +            (
> +                "host-unknown",
> +                FirewallIcmpTypeName::HostUnknown,
> +                true,
> +                false,
> +            ),
> +            (
> +                "network-prohibited",
> +                FirewallIcmpTypeName::NetworkProhibited,
> +                true,
> +                false,
> +            ),
> +            (
> +                "host-prohibited",
> +                FirewallIcmpTypeName::HostProhibited,
> +                true,
> +                false,
> +            ),
> +            (
> +                "TOS-network-unreachable",
> +                FirewallIcmpTypeName::TOSNetworkUnreachable,
> +                true,
> +                false,
> +            ),
> +            (
> +                "TOS-host-unreachable",
> +                FirewallIcmpTypeName::TOSHostUnreachable,
> +                true,
> +                false,
> +            ),
> +            (
> +                "communication-prohibited",
> +                FirewallIcmpTypeName::CommunicationProhibited,
> +                true,
> +                true,
> +            ),
> +            (
> +                "host-precedence-violation",
> +                FirewallIcmpTypeName::HostPrecedenceViolation,
> +                true,
> +                false,
> +            ),
> +            (
> +                "precedence-cutoff",
> +                FirewallIcmpTypeName::PrecedenceCutoff,
> +                true,
> +                false,
> +            ),
> +            (
> +                "source-quench",
> +                FirewallIcmpTypeName::SourceQuench,
> +                true,
> +                false,
> +            ),
> +            ("redirect", FirewallIcmpTypeName::Redirect, true, true),
> +            (
> +                "network-redirect",
> +                FirewallIcmpTypeName::NetworkRedirect,
> +                true,
> +                false,
> +            ),
> +            (
> +                "host-redirect",
> +                FirewallIcmpTypeName::HostRedirect,
> +                true,
> +                false,
> +            ),
> +            (
> +                "TOS-network-redirect",
> +                FirewallIcmpTypeName::TOSNetworkRedirect,
> +                true,
> +                false,
> +            ),
> +            (
> +                "TOS-host-redirect",
> +                FirewallIcmpTypeName::TOSHostRedirect,
> +                true,
> +                false,
> +            ),
> +            (
> +                "echo-request",
> +                FirewallIcmpTypeName::EchoRequest,
> +                true,
> +                true,
> +            ),
> +            (
> +                "router-advertisement",
> +                FirewallIcmpTypeName::RouterAdvertisement,
> +                true,
> +                true,
> +            ),
> +            (
> +                "router-solicitation",
> +                FirewallIcmpTypeName::RouterSolicitation,
> +                true,
> +                true,
> +            ),
> +            (
> +                "time-exceeded",
> +                FirewallIcmpTypeName::TimeExceeded,
> +                true,
> +                true,
> +            ),
> +            (
> +                "ttl-zero-during-transit",
> +                FirewallIcmpTypeName::TtlZeroDuringTransit,
> +                true,
> +                true,
> +            ),
> +            (
> +                "ttl-zero-during-reassembly",
> +                FirewallIcmpTypeName::TtlZeroDuringReassembly,
> +                true,
> +                true,
> +            ),
> +            (
> +                "parameter-problem",
> +                FirewallIcmpTypeName::ParameterProblem,
> +                true,
> +                true,
> +            ),
> +            (
> +                "ip-header-bad",
> +                FirewallIcmpTypeName::IpHeaderBad,
> +                true,
> +                false,
> +            ),
> +            (
> +                "required-option-missing",
> +                FirewallIcmpTypeName::RequiredOptionMissing,
> +                true,
> +                false,
> +            ),
> +            (
> +                "timestamp-request",
> +                FirewallIcmpTypeName::TimestampRequest,
> +                true,
> +                false,
> +            ),
> +            (
> +                "timestamp-reply",
> +                FirewallIcmpTypeName::TimestampReply,
> +                true,
> +                false,
> +            ),
> +            (
> +                "address-mask-request",
> +                FirewallIcmpTypeName::AddressMaskRequest,
> +                true,
> +                false,
> +            ),
> +            (
> +                "address-mask-reply",
> +                FirewallIcmpTypeName::AddressMaskReply,
> +                true,
> +                false,
> +            ),
> +            ("no-route", FirewallIcmpTypeName::NoRoute, false, true),
> +            (
> +                "beyond-scope",
> +                FirewallIcmpTypeName::BeyondScope,
> +                false,
> +                true,
> +            ),
> +            (
> +                "address-unreachable",
> +                FirewallIcmpTypeName::AddressUnreachable,
> +                false,
> +                true,
> +            ),
> +            (
> +                "failed-policy",
> +                FirewallIcmpTypeName::FailedPolicy,
> +                false,
> +                true,
> +            ),
> +            (
> +                "reject-route",
> +                FirewallIcmpTypeName::RejectRoute,
> +                false,
> +                true,
> +            ),
> +            (
> +                "packet-too-big",
> +                FirewallIcmpTypeName::PacketTooBig,
> +                false,
> +                true,
> +            ),
> +            ("bad-header", FirewallIcmpTypeName::BadHeader, false, true),
> +            (
> +                "unknown-header-type",
> +                FirewallIcmpTypeName::UnknownHeaderType,
> +                false,
> +                true,
> +            ),
> +            (
> +                "unknown-option",
> +                FirewallIcmpTypeName::UnknownOption,
> +                false,
> +                true,
> +            ),
> +            (
> +                "neighbor-solicitation",
> +                FirewallIcmpTypeName::NeighborSolicitation,
> +                false,
> +                true,
> +            ),
> +            (
> +                "neighbour-solicitation",
> +                FirewallIcmpTypeName::NeighbourSolicitation,
> +                false,
> +                true,
> +            ),
> +            (
> +                "neighbor-advertisement",
> +                FirewallIcmpTypeName::NeighborAdvertisement,
> +                false,
> +                true,
> +            ),
> +            (
> +                "neighbour-advertisement",
> +                FirewallIcmpTypeName::NeighbourAdvertisement,
> +                false,
> +                true,
> +            ),
> +        ];
> +
> +        for (input, expected, v4, v6) in tests {
> +            let deserialized: FirewallIcmpTypeName =
> +                serde_plain::from_str(input).expect("deserialize");
> +            assert_eq!(deserialized, expected);
> +            let serialized = serde_plain::to_string(&deserialized).expect("serialize");
> +            assert_eq!(serialized, input);
> +
> +            assert_eq!(deserialized.ipv4(), v4, "ipv4 check failed for {}", input);
> +            assert_eq!(deserialized.ipv6(), v6, "ipv6 check failed for {}", input);
> +        }
> +    }
> +
> +    #[test]
> +    fn test_firewall_icmp_type_enum() {
> +        // Numeric
> +        for (input, output) in [
> +            ("0", FirewallIcmpType::Numeric(0)),
> +            ("10", FirewallIcmpType::Numeric(10)),
> +            ("255", FirewallIcmpType::Numeric(255)),
> +        ] {
> +            let ty: FirewallIcmpType = input.parse().expect("valid numeric icmp type");
> +            assert_eq!(ty, output);
> +            assert_eq!(ty.to_string(), input);
> +        }
> +
> +        // Named
> +        for (input, output) in [
> +            ("echo-request", FirewallIcmpTypeName::EchoRequest),
> +            ("any", FirewallIcmpTypeName::Any),
> +        ] {
> +            let ty: FirewallIcmpType = input.parse().expect("valid named icmp type");
> +            assert_eq!(ty, FirewallIcmpType::Named(output));
> +            assert_eq!(ty.to_string(), input);
> +        }
> +
> +        // Invalid
> +        #[cfg(not(feature = "enum-fallback"))]
> +        for input in ["echo-reques", "an", "256", "-1", "foo"] {
> +            input
> +                .parse::<FirewallIcmpType>()
> +                .expect_err("invalid icmp type");
> +        }
> +
> +        // Invalid, but with enum fallback enabled, should be parsed as unknown
> +        #[cfg(feature = "enum-fallback")]
> +        for input in ["echo-reques", "an", "256", "-1", "foo"] {
> +            let ty = input.parse::<FirewallIcmpType>().expect("valid icmp type");
> +            assert_eq!(
> +                ty,
> +                FirewallIcmpType::Named(FirewallIcmpTypeName::UnknownEnumValue(
> +                    FixedString::new(input).unwrap(),
> +                )),
> +            );
> +        }
> +    }
> +}
> diff --git a/proxmox-firewall-api-types/src/lib.rs b/proxmox-firewall-api-types/src/lib.rs
> index b099be0c..610282bb 100644
> --- a/proxmox-firewall-api-types/src/lib.rs
> +++ b/proxmox-firewall-api-types/src/lib.rs
> @@ -1,6 +1,9 @@
>  mod conntrack;
>  pub use conntrack::FirewallConntrackHelper;
>  
> +mod icmp_type;
> +pub use icmp_type::{FirewallIcmpType, FirewallIcmpTypeName};
> +
>  mod log;
>  pub use log::{
>      FirewallLogLevel, FirewallLogRateLimit, FirewallPacketRate, FirewallPacketRateTimescale,
> -- 
> 2.47.3
> 
> 
> 
> 




  reply	other threads:[~2026-03-12 10:51 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-16 10:43 [RFC proxmox 00/22] New crate for firewall api types Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 01/22] firewall-api-types: add new " Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 02/22] firewall-api-types: add README.md Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 03/22] firewall-api-types: add firewall policy types Dietmar Maurer
2026-03-12 10:17   ` Wolfgang Bumiller
2026-02-16 10:43 ` [RFC proxmox 04/22] firewall-api-types: add logging types Dietmar Maurer
2026-03-02 12:24   ` Stefan Hanreich
2026-03-05  7:04     ` Dietmar Maurer
2026-03-12 10:22       ` Wolfgang Bumiller
2026-03-12 10:31   ` Wolfgang Bumiller
2026-02-16 10:43 ` [RFC proxmox 05/22] firewall-api-types: add FirewallClusterOptions Dietmar Maurer
2026-03-02 12:27   ` Stefan Hanreich
2026-03-05  7:06     ` Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 06/22] firewall-api-types: add FirewallGuestOptions Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 07/22] firewall-api-types: add FirewallConntrackHelper enum Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 08/22] firewall-api-types: add FirewallNodeOptions struct Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 09/22] firewall-api-types: add FirewallRef type Dietmar Maurer
2026-03-12 10:36   ` Wolfgang Bumiller
2026-03-12 10:41     ` Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 10/22] firewall-api-types: add FirewallPortList types Dietmar Maurer
2026-03-02 12:17   ` Stefan Hanreich
2026-03-05  7:02     ` Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 11/22] firewall-api-types: add FirewallIcmpType Dietmar Maurer
2026-03-12 10:51   ` Wolfgang Bumiller [this message]
2026-02-16 10:43 ` [RFC proxmox 12/22] firewall-api-types: add FirewallIpsetReference type Dietmar Maurer
2026-03-02 12:39   ` Stefan Hanreich
2026-02-16 10:43 ` [RFC proxmox 13/22] firewall-api-types: add FirewallAliasReference type Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 14/22] firewall-api-types: add firewall address types Dietmar Maurer
2026-03-12 13:24   ` Wolfgang Bumiller
2026-02-16 10:43 ` [RFC proxmox 15/22] firewall-api-types: add FirewallRule type Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 16/22] firewall-api-types: use ConfigDigest from proxmox-config-digest crate Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 17/22] firewall-api-types: use COMMENT_SCHEMA from proxmox-schema crate Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 18/22] firewall-api-types: add FirewallRuleUpdater type Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 19/22] firewall-api-types: refactor FirewallRule and add FirewallRuleListEntry Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 20/22] firewall-api-types: add DeletableFirewallRuleProperty enum Dietmar Maurer
2026-02-16 10:43 ` [RFC proxmox 21/22] firewall-api-types: add FirewallAliasEntry API type Dietmar Maurer
2026-02-16 10:44 ` [RFC proxmox 22/22] firewall-api-types: add FirewallIpsetListEntry and FirewallIpsetEntry api types Dietmar Maurer
2026-02-17  6:17 ` [RFC proxmox 00/22] New crate for firewall " Hannes Laimer
2026-02-17  6:39   ` Dietmar Maurer
2026-02-17  8:17     ` Hannes Laimer
2026-03-02 13:55 ` Stefan Hanreich

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=6ioutptc6rfgjv3zhnocnwyskjrclgbuxpsuf5sdopddrbifyl@u3btu4nzz7re \
    --to=w.bumiller@proxmox.com \
    --cc=dietmar@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
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal