all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH proxmox-ve-rs 7/9] ve-config: add route map section config
Date: Wed, 25 Mar 2026 10:41:20 +0100	[thread overview]
Message-ID: <20260325094142.174364-10-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20260325094142.174364-1-s.hanreich@proxmox.com>

Those types represent FRR route maps inside a section config format.
For an example of the exact format and its FRR representation see the
module-level documentation.

One section config entry maps to one route map entry. A route map
consists of one or more route map entries inside the section config.
The ID of a section encodes the name of the route map as well as the
order # of the entry.

The route map module exports specific types for the API that handle
converting the section config ID, because currently it is only
possible to deserialize section config IDs to Strings. To avoid
having to implement the parsing logic along every step of the stack
(Perl backend, UI), use specific API types in the public API that
handle parsing the section ID into route map name and order.

Contrary to most SDN entities, route maps IDs can be 32 characters
long instead of 8 and support underscores as well as hyphens. This is
because the restriction of having to generate network interface names
does not apply to FRR entities, so we can be more lenient with IDs
here, allowing users to specify more descriptive names.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 proxmox-ve-config/debian/control       |   2 +
 proxmox-ve-config/src/sdn/mod.rs       |   1 +
 proxmox-ve-config/src/sdn/route_map.rs | 491 +++++++++++++++++++++++++
 3 files changed, 494 insertions(+)
 create mode 100644 proxmox-ve-config/src/sdn/route_map.rs

diff --git a/proxmox-ve-config/debian/control b/proxmox-ve-config/debian/control
index 440cf73..5206340 100644
--- a/proxmox-ve-config/debian/control
+++ b/proxmox-ve-config/debian/control
@@ -24,6 +24,7 @@ Build-Depends-Arch: cargo:native <!nocheck>,
  librust-serde-1+default-dev <!nocheck>,
  librust-serde-1+derive-dev <!nocheck>,
  librust-serde-json-1+default-dev <!nocheck>,
+ librust-serde-with-3+default-dev <!nocheck>,
  librust-thiserror-2+default-dev <!nocheck>,
  librust-tracing-0.1+default-dev (>= 0.1.37-~~) <!nocheck>
 Maintainer: Proxmox Support Team <support@proxmox.com>
@@ -55,6 +56,7 @@ Depends:
  librust-serde-1+default-dev,
  librust-serde-1+derive-dev,
  librust-serde-json-1+default-dev,
+ librust-serde-with-3+default-dev,
  librust-thiserror-2+default-dev,
  librust-tracing-0.1+default-dev (>= 0.1.37-~~)
 Suggests:
diff --git a/proxmox-ve-config/src/sdn/mod.rs b/proxmox-ve-config/src/sdn/mod.rs
index 344c02c..24069ad 100644
--- a/proxmox-ve-config/src/sdn/mod.rs
+++ b/proxmox-ve-config/src/sdn/mod.rs
@@ -2,6 +2,7 @@ pub mod config;
 pub mod fabric;
 pub mod ipam;
 pub mod prefix_list;
+pub mod route_map;
 
 use std::{error::Error, fmt::Display, str::FromStr};
 
diff --git a/proxmox-ve-config/src/sdn/route_map.rs b/proxmox-ve-config/src/sdn/route_map.rs
new file mode 100644
index 0000000..3f4da56
--- /dev/null
+++ b/proxmox-ve-config/src/sdn/route_map.rs
@@ -0,0 +1,491 @@
+//! Section config types for FRR Route Maps.
+//!
+//! This module contains the API types required for representing FRR Route Maps as section config.
+//! Each entry in the section config maps to a Route Map entry, *not* a route map as a whole, the
+//! order of the entry is encoded in the ID of the Route Map.
+//!
+//! Route maps in FRR consists of at least one entry, which are ordered by their given sequence
+//! number / order. Each entry has a default matching policy, which is applied if the matching
+//! conditions of the entry are met.
+//!
+//! An example for a simple FRR Route Map entry loooks like this:
+//!
+//! ```text
+//! route-map test permit 10
+//!  match ip next-hop address 192.0.2.1
+//!  set local-preference 200
+//! ```
+//!
+//! The corresponding representation as a section config entry looks like this:
+//!
+//! ```text
+//! route-map-entry: test_10
+//!  action permit
+//!  match key=ip-next-hop-address,value=192.0.2.1
+//!  set key=local-preference,value=200
+//! ```
+//!
+//! Match and Set Actions are encoded as an array with a property string that has a key and an
+//! optional value paramter, because some options do not require an additional value.
+//!
+//! This abstraction currently supports Match and Set actions, but not call actions and exit
+//! actions.
+
+use core::net::IpAddr;
+
+use anyhow::format_err;
+use const_format::concatcp;
+
+use proxmox_network_types::ip_address::api_types::{Ipv4Addr, Ipv6Addr};
+use proxmox_sdn_types::{
+    bgp::{EvpnRouteType, SetMetricValue, SetTagValue},
+    IntegerWithSign, Vni,
+};
+use serde::{Deserialize, Serialize};
+
+use proxmox_schema::{
+    api, api_string_type, const_regex, property_string::PropertyString, ApiStringFormat, ApiType,
+    EnumEntry, ObjectSchema, Schema, StringSchema, Updater, UpdaterType,
+};
+
+use crate::sdn::prefix_list::PrefixListId;
+
+pub const ROUTE_MAP_ID_REGEX_STR: &str =
+    r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-_]){0,30}(?:[a-zA-Z0-9]){0,1})";
+
+pub const ROUTE_MAP_ORDER_REGEX_STR: &str = r"\d+";
+
+const_regex! {
+    pub ROUTE_MAP_ID_REGEX = concatcp!(r"^", ROUTE_MAP_ID_REGEX_STR, r"$");
+    pub ROUTE_MAP_SECTION_ID_REGEX = concatcp!(r"^", ROUTE_MAP_ID_REGEX_STR, r"_", ROUTE_MAP_ORDER_REGEX_STR, r"$");
+}
+
+pub const ROUTE_MAP_SECTION_ID_FORMAT: ApiStringFormat =
+    ApiStringFormat::Pattern(&ROUTE_MAP_SECTION_ID_REGEX);
+
+pub const ROUTE_MAP_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&ROUTE_MAP_ID_REGEX);
+
+api_string_type! {
+    /// ID of a Route Map..
+    #[api(format: &ROUTE_MAP_ID_FORMAT)]
+    #[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, UpdaterType)]
+    pub struct RouteMapId(String);
+}
+
+/// The ID of a Route Map entry in the section config (name + order).
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct RouteMapEntryId {
+    /// name of the Route Map
+    route_map_id: RouteMapId,
+    /// seq nr of the Route Map
+    order: u32,
+}
+
+impl RouteMapEntryId {
+    /// Create a new Route Map Entry ID.
+    pub fn new(route_map_id: RouteMapId, order: u32) -> Self {
+        Self {
+            route_map_id,
+            order,
+        }
+    }
+
+    /// Returns the name part of the Route Map section id.
+    pub fn route_map_id(&self) -> &RouteMapId {
+        &self.route_map_id
+    }
+
+    /// Returns the order part of the Route Map section id.
+    pub fn order(&self) -> u32 {
+        self.order
+    }
+}
+
+impl ApiType for RouteMapEntryId {
+    const API_SCHEMA: Schema = StringSchema::new("ID of a SDN node in the section config")
+        .format(&ROUTE_MAP_SECTION_ID_FORMAT)
+        .schema();
+}
+
+impl std::fmt::Display for RouteMapEntryId {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "{}_{}", self.route_map_id, self.order)
+    }
+}
+
+proxmox_serde::forward_serialize_to_display!(RouteMapEntryId);
+
+impl std::str::FromStr for RouteMapEntryId {
+    type Err = anyhow::Error;
+
+    fn from_str(value: &str) -> Result<Self, Self::Err> {
+        let (name, order) = value
+            .rsplit_once("_")
+            .ok_or_else(|| format_err!("invalid RouteMap section id: {}", value))?;
+
+        Ok(Self {
+            route_map_id: RouteMapId::from_string(name.to_string())?,
+            order: order.parse()?,
+        })
+    }
+}
+
+proxmox_serde::forward_deserialize_to_from_str!(RouteMapEntryId);
+
+#[api(
+    "id-property": "id",
+    "id-schema": {
+        type: String,
+        description: "Route Map Section ID",
+        format: &ROUTE_MAP_SECTION_ID_FORMAT,
+    },
+    "type-key": "type",
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+/// The Route Map section config type.
+pub enum RouteMap {
+    RouteMapEntry(RouteMapEntry),
+}
+
+#[api()]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+/// Matching policy of a Route Map entry.
+pub enum RouteMapAction {
+    /// Permit
+    Permit,
+    /// Deny
+    Deny,
+}
+
+#[api(
+    properties: {
+        set: {
+            type: Array,
+            description: "A list of Set actions to perform in this entry.",
+            optional: true,
+            items: {
+                type: String,
+                description: "A specific Set action.",
+                format: &ApiStringFormat::PropertyString(&SetAction::API_SCHEMA),
+            }
+        },
+        "match": {
+            type: Array,
+            description: "A list of Match actions to perform in this entry.",
+            optional: true,
+            items: {
+                type: String,
+                description: "A specific match action.",
+                format: &ApiStringFormat::PropertyString(&MatchAction::API_SCHEMA),
+            }
+        },
+    }
+)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+/// Route Map Entry
+///
+/// Represents one entry in a Route Map. One Route Map is made up of one or more entries, that are
+/// executed in order of their ordering number.
+pub struct RouteMapEntry {
+    id: RouteMapEntryId,
+    action: RouteMapAction,
+    #[serde(default, rename = "set")]
+    set_actions: Vec<PropertyString<SetAction>>,
+    #[serde(default, rename = "match")]
+    match_actions: Vec<PropertyString<MatchAction>>,
+}
+
+impl RouteMapEntry {
+    /// Return the ID of the Route Map.
+    pub fn id(&self) -> &RouteMapEntryId {
+        &self.id
+    }
+
+    /// Sets the action for this entry.
+    pub fn set_action(&mut self, action: RouteMapAction) {
+        self.action = action;
+    }
+
+    /// Set the set actions for this route map entry.
+    pub fn set_set_actions(
+        &mut self,
+        set_actions: impl IntoIterator<Item = PropertyString<SetAction>>,
+    ) {
+        self.set_actions = set_actions.into_iter().collect();
+    }
+
+    /// Set the match actions for this route map entry.
+    pub fn set_match_actions(
+        &mut self,
+        match_actions: impl IntoIterator<Item = PropertyString<MatchAction>>,
+    ) {
+        self.match_actions = match_actions.into_iter().collect();
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "key", content = "value")]
+/// A Route Map set action
+pub enum SetAction {
+    IpNextHopPeerAddress,
+    IpNextHopUnchanged,
+    IpNextHop(Ipv4Addr),
+    Ip6NextHopPeerAddress,
+    Ip6NextHopPreferGlobal,
+    Ip6NextHop(Ipv6Addr),
+    Weight(#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")] u32),
+    Tag(SetTagValue),
+    Metric(SetMetricValue),
+    LocalPreference(IntegerWithSign),
+    Src(IpAddr),
+}
+
+impl ApiType for SetAction {
+    const API_SCHEMA: Schema = ObjectSchema::new(
+        "FRR set action",
+        &[
+            (
+                "key",
+                false,
+                &StringSchema::new("The key indicating which value should be set.")
+                    .format(&ApiStringFormat::Enum(&[
+                        EnumEntry::new(
+                            "ip-next-hop-peer-address",
+                            "Sets the BGP nexthop address to the IPv4 peer address.",
+                        ),
+                        EnumEntry::new("ip-next-hop-unchanged", "Leaves the nexthop unchanged."),
+                        EnumEntry::new(
+                            "ip-next-hop",
+                            "Sets the nexthop to the given IPv4 address.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-next-hop-peer-address",
+                            "Sets the BGP nexthop address to the IPv6 peer address.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-next-hop-prefer-global",
+                            "If a LLA and GUA are received, prefer the GUA.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-next-hop",
+                            "Sets the nexthop to the given IPv6 address.",
+                        ),
+                        EnumEntry::new(
+                            "local-preference",
+                            "Sets the local preference for this route.",
+                        ),
+                        EnumEntry::new("tag", "Sets a tag for the route."),
+                        EnumEntry::new("weight", "Sets the weight for the route."),
+                        EnumEntry::new("metric", "Sets the metric for the route."),
+                        EnumEntry::new(
+                            "src",
+                            "The source address to insert into the kernel routing table.",
+                        ),
+                    ]))
+                    .schema(),
+            ),
+            (
+                "value",
+                true,
+                &StringSchema::new("The value that should be set - depends on the given key.")
+                    .schema(),
+            ),
+        ],
+    )
+    .schema();
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "key", content = "value")]
+pub enum MatchAction {
+    RouteType(EvpnRouteType),
+    Vni(Vni),
+    IpAddressPrefixList(PrefixListId),
+    Ip6AddressPrefixList(PrefixListId),
+    IpNextHopPrefixList(PrefixListId),
+    Ip6NextHopPrefixList(PrefixListId),
+    IpNextHopAddress(Ipv4Addr),
+    Ip6NextHopAddress(Ipv6Addr),
+    Tag(SetTagValue),
+    Metric(#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")] u32),
+    LocalPreference(#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")] u32),
+    Peer(String),
+}
+
+impl ApiType for MatchAction {
+    const API_SCHEMA: Schema = ObjectSchema::new(
+        "FRR set action",
+        &[
+            (
+                "key",
+                false,
+                &StringSchema::new("The key indicating on which value to match.")
+                    .format(&ApiStringFormat::Enum(&[
+                        EnumEntry::new("route-type", "Match the EVPN route type."),
+                        EnumEntry::new("vni", "Match the VNI of an EVPN route."),
+                        EnumEntry::new(
+                            "ip-address-prefix-list",
+                            "Match the IPv4 CIDR to a prefix-list.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-address-prefix-list",
+                            "Match the IPv6 CIDR to a prefix-list",
+                        ),
+                        EnumEntry::new(
+                            "ip-next-hop-prefix-list",
+                            "Match the IPv4 next-hop to a prefix-list.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-next-hop-prefix-list",
+                            "Match the IPv4 next-hop to a prefix-list.",
+                        ),
+                        EnumEntry::new(
+                            "ip-next-hop-address",
+                            "Match the next-hop to an IPv4 address.",
+                        ),
+                        EnumEntry::new(
+                            "ip6-next-hop-address",
+                            "Match the next-hop to an IPv6 address.",
+                        ),
+                        EnumEntry::new("metric", "Match the metric of the route."),
+                        EnumEntry::new("local-preference", "Match the local preference."),
+                        EnumEntry::new(
+                            "peer",
+                            "Match the peer IP address, interface name or peer group.",
+                        ),
+                    ]))
+                    .schema(),
+            ),
+            (
+                "value",
+                true,
+                &StringSchema::new("The value that should be matched - depends on the given key.")
+                    .schema(),
+            ),
+        ],
+    )
+    .schema();
+}
+
+pub mod api {
+    //! API type for Route Map Entries.
+    //!
+    //! Since Route Map Entries encode information in their ID, these types help converting to /
+    //! from the Section Config types.
+    use super::*;
+
+    #[api(
+        properties: {
+            set: {
+                type: Array,
+                description: "A list of set actions for this Route Map entry",
+                optional: true,
+                items: {
+                    type: String,
+                    description: "A set action",
+                    format: &ApiStringFormat::PropertyString(&SetAction::API_SCHEMA),
+            }
+            },
+            "match": {
+                type: Array,
+                description: "A list of match actions for this Route Map entry",
+                optional: true,
+                items: {
+                    type: String,
+                    description: "A match action",
+                    format: &ApiStringFormat::PropertyString(&MatchAction::API_SCHEMA),
+                }
+            },
+        }
+    )]
+    #[derive(Debug, Clone, Serialize, Deserialize, Updater)]
+    #[serde(rename_all = "kebab-case")]
+    /// Route Map entry
+    pub struct RouteMapEntry {
+        /// name of the Route Map
+        #[updater(skip)]
+        pub route_map_id: RouteMapId,
+        /// seq nr of the Route Map
+        #[updater(skip)]
+        #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]
+        pub order: u32,
+        pub action: RouteMapAction,
+        #[serde(default, rename = "set")]
+        pub set_actions: Vec<PropertyString<SetAction>>,
+        #[serde(default, rename = "match")]
+        pub match_actions: Vec<PropertyString<MatchAction>>,
+    }
+
+    impl RouteMapEntry {
+        /// Return the ID of the Route Map this entry belongs to.
+        pub fn route_map_id(&self) -> &RouteMapId {
+            &self.route_map_id
+        }
+
+        /// Return the order for this Route Map entry.
+        pub fn order(&self) -> u32 {
+            self.order
+        }
+    }
+
+    #[derive(Debug, Clone, Serialize, Deserialize, Hash)]
+    #[serde(rename_all = "kebab-case")]
+    /// Deletable properties for Route Map entries.
+    pub enum RouteMapDeletableProperties {
+        SetActions,
+        MatchActions,
+    }
+
+    impl From<super::RouteMapEntry> for RouteMapEntry {
+        fn from(value: super::RouteMapEntry) -> RouteMapEntry {
+            RouteMapEntry {
+                route_map_id: value.id.route_map_id,
+                order: value.id.order,
+                action: value.action,
+                set_actions: value.set_actions,
+                match_actions: value.match_actions,
+            }
+        }
+    }
+
+    impl From<RouteMapEntry> for super::RouteMapEntry {
+        fn from(value: RouteMapEntry) -> super::RouteMapEntry {
+            super::RouteMapEntry {
+                id: RouteMapEntryId {
+                    route_map_id: value.route_map_id,
+                    order: value.order,
+                },
+                action: value.action,
+                set_actions: value.set_actions,
+                match_actions: value.match_actions,
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use proxmox_section_config::typed::ApiSectionDataEntry;
+
+    use super::*;
+
+    #[test]
+    fn test_simple_route_map() -> Result<(), anyhow::Error> {
+        let section_config = r#"
+route-map-entry: test_underscore_123
+  action permit
+  set key=tag,value=23487
+  set key=tag,value=untagged
+  set key=metric,value=+rtt
+  set key=local-preference,value=-12345
+  set key=ip-next-hop,value=192.0.2.0
+  match key=vni,value=23487
+  match key=vni,value=23487
+"#;
+
+        RouteMap::parse_section_config("route-maps.cfg", section_config)?;
+        Ok(())
+    }
+}
-- 
2.47.3





  parent reply	other threads:[~2026-03-25  9:49 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-25  9:41 [PATCH cluster/network/proxmox{-ve-rs,-perl-rs} 00/27] Add support for route maps / prefix lists to SDN Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-cluster 1/2] cfs: add 'sdn/route-maps.cfg' to observed files Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-cluster 2/2] cfs: add 'sdn/prefix-lists.cfg' " Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 1/9] sdn-types: add common route-map helper types Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 2/9] frr: implement routemap match/set statements via adjacent tagging Stefan Hanreich
2026-03-26 14:44   ` Hannes Laimer
2026-03-27  9:02     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 3/9] frr: allow rendering prefix-lists/route-maps separately Stefan Hanreich
2026-03-25 14:32   ` Gabriel Goller
2026-03-26 12:17     ` Stefan Hanreich
2026-03-27 10:50   ` Hannes Laimer
2026-03-27 11:34     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 4/9] frr-templates: change route maps template to adapt to new types Stefan Hanreich
2026-03-25 14:33   ` Gabriel Goller
2026-03-25 14:58     ` Gabriel Goller
2026-03-27 11:01   ` Hannes Laimer
2026-03-27 11:17     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 5/9] ve-config: add prefix list section config Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 6/9] ve-config: frr: implement frr config generation for prefix lists Stefan Hanreich
2026-03-25  9:41 ` Stefan Hanreich [this message]
2026-03-25 14:35   ` [PATCH proxmox-ve-rs 7/9] ve-config: add route map section config Gabriel Goller
2026-03-26 13:49     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 8/9] ve-config: frr: implement frr config generation for route maps Stefan Hanreich
2026-03-25 15:03   ` Gabriel Goller
2026-03-26 13:50     ` Stefan Hanreich
2026-03-27 11:17   ` Hannes Laimer
2026-03-27 11:21     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-ve-rs 9/9] ve-config: fabrics: adapt frr config generation to new format Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-perl-rs 1/3] pve-rs: sdn: add route maps module Stefan Hanreich
2026-03-26 10:32   ` Wolfgang Bumiller
2026-03-26 13:57     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-perl-rs 2/3] pve-rs: sdn: add prefix lists module Stefan Hanreich
2026-03-25  9:41 ` [PATCH proxmox-perl-rs 3/3] sdn: add prefix list / route maps to frr config generation helper Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 01/13] controller: bgp: evpn: adapt to new match / set frr config syntax Stefan Hanreich
2026-03-26 15:19   ` Hannes Laimer
2026-03-27 10:05     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 02/13] sdn: add prefix lists module Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 03/13] api2: add prefix list module Stefan Hanreich
2026-03-26 15:01   ` Hannes Laimer
2026-03-27  9:57     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 04/13] sdn: add route map module Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 05/13] api2: add route maps api module Stefan Hanreich
2026-03-26 15:05   ` Hannes Laimer
2026-03-27  9:57     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 06/13] api2: add route map module Stefan Hanreich
2026-03-26 15:07   ` Hannes Laimer
2026-03-27  9:57     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 07/13] api2: add route map entry module Stefan Hanreich
2026-03-26 15:13   ` Hannes Laimer
2026-03-27 10:01     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 08/13] evpn controller: add route_map_{in,out} parameter Stefan Hanreich
2026-03-27 10:44   ` Hannes Laimer
2026-03-27 11:12     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 09/13] sdn: generate route map / prefix list configuration on sdn apply Stefan Hanreich
2026-03-27 10:47   ` Hannes Laimer
2026-03-27 11:13     ` Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 10/13] tests: add simple route map test case Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 11/13] tests: add bgp evpn route map/prefix list testcase Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 12/13] tests: add route map with prefix " Stefan Hanreich
2026-03-25  9:41 ` [PATCH pve-network 13/13] bgp controller: allow configuring custom route maps Stefan Hanreich
2026-03-25 11:38 ` [PATCH cluster/network/proxmox{-ve-rs,-perl-rs} 00/27] Add support for route maps / prefix lists to SDN Stefan Hanreich
2026-03-27 10:17 ` 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=20260325094142.174364-10-s.hanreich@proxmox.com \
    --to=s.hanreich@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal