From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 9E6681FF141 for ; Tue, 05 May 2026 17:43:43 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2A13DCB6A; Tue, 5 May 2026 17:43:33 +0200 (CEST) From: Stefan Hanreich To: pve-devel@lists.proxmox.com Subject: [PATCH pve-network v5 32/46] sdn: commit route map / prefix list configuration on sdn apply Date: Tue, 5 May 2026 17:37:00 +0200 Message-ID: <20260505153720.412180-33-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260505153720.412180-1-s.hanreich@proxmox.com> References: <20260505153720.412180-1-s.hanreich@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1777995342930 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.646 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: MIFX4IHU37H72CM37RKONSXUFMHXREVR X-Message-ID-Hash: MIFX4IHU37H72CM37RKONSXUFMHXREVR X-MailFrom: s.hanreich@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Commit the newly introduced configuration files to the running configuration when applying the SDN configuration, so the FRR config generation logic can use them to generate the FRR configuration for them. In addition read back the route map / prefix list configuration when detecting changes to the FRR configuration and rolling back. Add the non-primitive keys from the route map / prefix list configuration to the encode_value function, in order to properly detect changes. Signed-off-by: Stefan Hanreich --- src/PVE/API2/Network/SDN.pm | 8 ++++++++ src/PVE/Network/SDN.pm | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/PVE/API2/Network/SDN.pm b/src/PVE/API2/Network/SDN.pm index ef64df2..f0d8159 100644 --- a/src/PVE/API2/Network/SDN.pm +++ b/src/PVE/API2/Network/SDN.pm @@ -261,6 +261,14 @@ __PACKAGE__->register_method({ my $parsed_fabrics_config = PVE::RS::SDN::Fabrics->running_config($fabrics_config); PVE::Network::SDN::Fabrics::write_config($parsed_fabrics_config); + my $route_map_config = $running_config->{'route-maps'}->{ids} // {}; + my $parsed_route_map_config = PVE::RS::SDN::Fabrics->running_config($route_map_config); + PVE::Network::SDN::RouteMaps::write_config($parsed_route_map_config); + + my $prefix_list_config = $running_config->{'prefix-lists'}->{ids} // {}; + my $parsed_prefix_list_config = PVE::RS::SDN::Fabrics->running_config($prefix_list_config); + PVE::Network::SDN::PrefixLists::write_config($parsed_prefix_list_config); + PVE::Network::SDN::delete_global_lock() if $lock_token && $release_lock; }; diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm index 0bb36bf..5d9dbc5 100644 --- a/src/PVE/Network/SDN.pm +++ b/src/PVE/Network/SDN.pm @@ -25,6 +25,8 @@ use PVE::Network::SDN::Subnets; use PVE::Network::SDN::Dhcp; use PVE::Network::SDN::Frr; use PVE::Network::SDN::Fabrics; +use PVE::Network::SDN::RouteMaps; +use PVE::Network::SDN::PrefixLists; my $RUNNING_CFG_FILENAME = "sdn/.running-config"; @@ -122,12 +124,15 @@ configuration and then evaluate it. sub running_config_has_frr { my $running_config = PVE::Network::SDN::running_config(); - # both can be empty if the SDN configuration was never applied + # all can be empty if the SDN configuration was never applied my $controllers = $running_config->{controllers}->{ids} // {}; my $fabrics = $running_config->{fabrics}->{ids} // {}; + my $route_maps = $running_config->{'route-maps'}->{ids} // {}; + my $prefix_lists = $running_config->{'prefix-lists'}->{ids} // {}; + my $local_frr_config = PVE::Network::SDN::Frr::local_frr_config_exists(); - return %$controllers || %$fabrics || $local_frr_config; + return %$controllers || %$fabrics || %$route_maps || %$prefix_lists || $local_frr_config; } sub pending_config { @@ -207,12 +212,16 @@ sub compile_running_cfg { my $controllers_cfg = PVE::Network::SDN::Controllers::config(); my $subnets_cfg = PVE::Network::SDN::Subnets::config(); my $fabrics_cfg = PVE::Network::SDN::Fabrics::config(); + my $route_maps_cfg = PVE::Network::SDN::RouteMaps::config(); + my $prefix_lists_cfg = PVE::Network::SDN::PrefixLists::config(); my $vnets = { ids => $vnets_cfg->{ids} }; my $zones = { ids => $zones_cfg->{ids} }; my $controllers = { ids => $controllers_cfg->{ids} }; my $subnets = { ids => $subnets_cfg->{ids} }; my $fabrics = { ids => $fabrics_cfg->to_sections() }; + my $route_maps = { ids => $route_maps_cfg->to_sections() }; + my $prefix_lists = { ids => $prefix_lists_cfg->to_sections() }; $cfg = { version => $version, @@ -221,6 +230,8 @@ sub compile_running_cfg { controllers => $controllers, subnets => $subnets, fabrics => $fabrics, + 'route-maps' => $route_maps, + 'prefix-lists' => $prefix_lists, }; return $cfg; @@ -241,6 +252,8 @@ sub has_pending_changes { vnets => PVE::Network::SDN::Vnets::config(), subnets => PVE::Network::SDN::Subnets::config(), controllers => PVE::Network::SDN::Controllers::config(), + 'route-maps' => { ids => PVE::Network::SDN::RouteMaps::config()->to_sections()}, + 'prefix-lists' => { ids => PVE::Network::SDN::PrefixLists::config()->to_sections()}, }; for my $config_file (keys %$config_files) { @@ -425,9 +438,11 @@ configuration. =cut sub generate_frr_raw_config { - my ($running_config, $fabric_config) = @_; + my ($running_config, $fabric_config, $route_map_config, $prefix_list_config) = @_; $running_config = PVE::Network::SDN::running_config() if !$running_config; + $prefix_list_config = PVE::Network::SDN::PrefixLists::config(1) if !$prefix_list_config; + $route_map_config = PVE::Network::SDN::RouteMaps::config(1) if !$route_map_config; $fabric_config = PVE::Network::SDN::Fabrics::config(1) if !$fabric_config; my $frr_config = {}; @@ -438,7 +453,11 @@ sub generate_frr_raw_config { my $nodename = PVE::INotify::nodename(); return PVE::RS::SDN::get_frr_raw_config( - $frr_config->{'frr'}, $fabric_config, $nodename, + $frr_config->{'frr'}, + $prefix_list_config, + $route_map_config, + $fabric_config, + $nodename, ); } @@ -484,7 +503,15 @@ sub generate_dhcp_config { sub encode_value { my ($type, $key, $value) = @_; - if ($key eq 'nodes' || $key eq 'exitnodes' || $key eq 'dhcp-range' || $key eq 'interfaces') { + if ( + $key eq 'nodes' + || $key eq 'exitnodes' + || $key eq 'dhcp-range' + || $key eq 'interfaces' + || $key eq 'entries' + || $key eq 'match' + || $key eq 'set' + ) { if (ref($value) eq 'HASH') { return join(',', sort keys(%$value)); } elsif (ref($value) eq 'ARRAY') { -- 2.47.3