From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-network v3 23/44] api2: add prefix list module
Date: Mon, 4 May 2026 13:39:20 +0200 [thread overview]
Message-ID: <20260504113943.159905-24-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20260504113943.159905-1-s.hanreich@proxmox.com>
Contains the CRUD functionality for prefix lists:
GET /prefix-lists - lists all prefix lists
GET /prefix-lists/<id> - get prefix list <id>
POST /prefix-lists - create a new prefix list
PUT /prefix-lists/<id> - update prefix list <id>
DELETE /prefix-lists/<id> - delete prefix list <id>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
src/PVE/API2/Network/SDN.pm | 7 +
src/PVE/API2/Network/SDN/Makefile | 1 +
src/PVE/API2/Network/SDN/PrefixLists.pm | 259 ++++++++++++++++++++++++
src/PVE/Network/SDN/PrefixLists.pm | 21 ++
4 files changed, 288 insertions(+)
create mode 100644 src/PVE/API2/Network/SDN/PrefixLists.pm
diff --git a/src/PVE/API2/Network/SDN.pm b/src/PVE/API2/Network/SDN.pm
index cc5ac25..778a29b 100644
--- a/src/PVE/API2/Network/SDN.pm
+++ b/src/PVE/API2/Network/SDN.pm
@@ -22,6 +22,7 @@ use PVE::API2::Network::SDN::Zones;
use PVE::API2::Network::SDN::Ipams;
use PVE::API2::Network::SDN::Dns;
use PVE::API2::Network::SDN::Fabrics;
+use PVE::API2::Network::SDN::PrefixLists;
use base qw(PVE::RESTHandler);
@@ -55,6 +56,11 @@ __PACKAGE__->register_method({
path => 'fabrics',
});
+__PACKAGE__->register_method({
+ subclass => "PVE::API2::Network::SDN::PrefixLists",
+ path => 'prefix-lists',
+});
+
__PACKAGE__->register_method({
name => 'index',
path => '',
@@ -87,6 +93,7 @@ __PACKAGE__->register_method({
{ id => 'ipams' },
{ id => 'dns' },
{ id => 'fabrics' },
+ { id => 'prefix-lists' },
];
return $res;
diff --git a/src/PVE/API2/Network/SDN/Makefile b/src/PVE/API2/Network/SDN/Makefile
index 08371d2..7a89311 100644
--- a/src/PVE/API2/Network/SDN/Makefile
+++ b/src/PVE/API2/Network/SDN/Makefile
@@ -7,6 +7,7 @@ SOURCES=Vnets.pm\
Ips.pm\
Fabrics.pm\
RouteMaps.pm\
+ PrefixLists.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/src/PVE/API2/Network/SDN/PrefixLists.pm b/src/PVE/API2/Network/SDN/PrefixLists.pm
new file mode 100644
index 0000000..bc8e118
--- /dev/null
+++ b/src/PVE/API2/Network/SDN/PrefixLists.pm
@@ -0,0 +1,259 @@
+package PVE::API2::Network::SDN::PrefixLists;
+
+use strict;
+use warnings;
+
+use PVE::Exception qw(raise_param_exc);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Network::SDN::PrefixLists;
+use PVE::Tools qw(extract_param);
+
+use PVE::RESTHandler;
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method({
+ name => 'list_prefix_lists',
+ path => '',
+ method => 'GET',
+ permissions => {
+ description =>
+ "Only returns prefix list entries where you have 'Sys.Audit' or 'Sys.Modify' permissions.",
+ user => 'all',
+ },
+ description => "List Prefix Lists",
+ parameters => {
+ properties => {
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => {},
+ },
+ links => [{ rel => 'child', href => "{id}" }],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $pending = extract_param($param, 'pending');
+ my $running = extract_param($param, 'running');
+
+ my $digest;
+ my $prefix_lists;
+
+ if ($pending) {
+ my $current_config = PVE::Network::SDN::PrefixLists::config();
+ my $running_config = PVE::Network::SDN::PrefixLists::config(1);
+
+ my $pending_prefix_lists = PVE::Network::SDN::pending_config(
+ { 'prefix-lists' => { ids => $running_config->list() } },
+ { ids => $current_config->list() },
+ 'prefix-lists',
+ );
+
+ $digest = $current_config->digest();
+ $prefix_lists = $pending_prefix_lists->{ids};
+ } elsif ($running) {
+ $prefix_lists = PVE::Network::SDN::PrefixLists::config(1)->list();
+ } else {
+ my $current_config = PVE::Network::SDN::PrefixLists::config();
+
+ $digest = $current_config->digest();
+ $prefix_lists = $current_config->list();
+ }
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+ my $prefix_list_privs = ['SDN.Audit'];
+
+ my @res;
+ for my $prefix_list_id (sort keys $prefix_lists->%*) {
+ next
+ if !$rpcenv->check_any(
+ $authuser,
+ "/prefix-lists/$prefix_list_id",
+ $prefix_list_privs,
+ 1,
+ );
+ $prefix_lists->{$prefix_list_id}->{digest} = $digest if $digest;
+ push @res, $prefix_lists->{$prefix_list_id};
+ }
+
+ return \@res;
+ },
+});
+
+__PACKAGE__->register_method({
+ name => 'get_prefix_list_entry',
+ path => '{id}',
+ method => 'GET',
+ permissions => {
+ check => ['perm', '/sdn/prefix-lists/{id}', ['SDN.Audit']],
+ },
+ description => "Get Prefix List",
+ parameters => {
+ properties => {
+ id => get_standard_option('pve-sdn-prefix-list-id'),
+ },
+ },
+ returns => {
+ type => "object",
+ properties => {},
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $prefix_list_id = extract_param($param, 'id');
+ my $prefix_list_entry = PVE::Network::SDN::PrefixLists::config()->get($prefix_list_id);
+
+ raise_param_exc({ 'id' => "$prefix_list_id doesn't exist" })
+ if !$prefix_list_entry;
+
+ return $prefix_list_entry;
+ },
+});
+
+__PACKAGE__->register_method({
+ name => 'create_prefix_list_entry',
+ path => '',
+ method => 'POST',
+ protected => 1,
+ permissions => {
+ check => ['perm', '/sdn/prefix-lists', ['SDN.Allocate']],
+ },
+ description => "Create Prefix List",
+ parameters => {
+ properties => {
+ digest => get_standard_option('pve-config-digest'),
+ 'lock-token' => get_standard_option('pve-sdn-lock-token'),
+ PVE::Network::SDN::PrefixLists::prefix_list_properties(0)->%*,
+ },
+ },
+ returns => {
+ type => "null",
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $lock_token = extract_param($param, 'lock-token');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+ my $config = PVE::Network::SDN::PrefixLists::config();
+
+ my $digest = extract_param($param, 'digest');
+ PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest;
+
+ $config->create($param);
+ PVE::Network::SDN::PrefixLists::write_config($config);
+ },
+ "creating prefix list failed",
+ $lock_token,
+ );
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method({
+ name => 'update_prefix_list_entry',
+ path => '{id}',
+ method => 'PUT',
+ protected => 1,
+ permissions => {
+ check => ['perm', '/sdn/prefix-lists/{id}', ['SDN.Allocate']],
+ },
+ description => "Update Prefix List",
+ parameters => {
+ properties => {
+ digest => get_standard_option('pve-config-digest'),
+ 'lock-token' => get_standard_option('pve-sdn-lock-token'),
+ PVE::Network::SDN::PrefixLists::prefix_list_properties(1)->%*,
+ },
+ },
+ returns => {
+ type => "null",
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $lock_token = extract_param($param, 'lock-token');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+ my $config = PVE::Network::SDN::PrefixLists::config();
+
+ my $digest = extract_param($param, 'digest');
+ PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest;
+
+ my $prefix_list_id = extract_param($param, 'id');
+ my $delete = extract_param($param, 'delete');
+
+ $config->update($prefix_list_id, $param, $delete);
+ PVE::Network::SDN::PrefixLists::write_config($config);
+ },
+ "updating prefix list failed",
+ $lock_token,
+ );
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method({
+ name => 'delete_prefix_list_entry',
+ path => '{id}',
+ method => 'DELETE',
+ protected => 1,
+ permissions => {
+ check => ['perm', '/sdn/prefix-lists/{id}', ['SDN.Allocate']],
+ },
+ description => "Delete Prefix List",
+ parameters => {
+ properties => {
+ digest => get_standard_option('pve-config-digest'),
+ 'lock-token' => get_standard_option('pve-sdn-lock-token'),
+ id => get_standard_option('pve-sdn-prefix-list-id'),
+ },
+ },
+ returns => {
+ type => "null",
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $lock_token = extract_param($param, 'lock-token');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+ my $config = PVE::Network::SDN::PrefixLists::config();
+
+ my $digest = extract_param($param, 'digest');
+ PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest;
+
+ my $prefix_list_id = extract_param($param, 'id');
+ PVE::Network::SDN::PrefixLists::check_references($prefix_list_id);
+
+ $config->delete($prefix_list_id);
+ PVE::Network::SDN::PrefixLists::write_config($config);
+ },
+ "deleting prefix list failed",
+ $lock_token,
+ );
+
+ return;
+ },
+});
+
+1;
diff --git a/src/PVE/Network/SDN/PrefixLists.pm b/src/PVE/Network/SDN/PrefixLists.pm
index ced2ebf..4cd7fdb 100644
--- a/src/PVE/Network/SDN/PrefixLists.pm
+++ b/src/PVE/Network/SDN/PrefixLists.pm
@@ -7,6 +7,7 @@ use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_lock_file cfs_write_file
use PVE::JSONSchema qw(get_standard_option);
use PVE::INotify;
use PVE::Network::SDN;
+use PVE::Network::SDN::RouteMaps;
use PVE::RS::SDN::PrefixLists;
PVE::JSONSchema::register_format(
@@ -73,6 +74,26 @@ sub write_config {
cfs_write_file("sdn/prefix-lists.cfg", $config->to_raw(), 1);
}
+sub check_references {
+ my ($prefix_list_id) = @_;
+
+ my $route_map_entries = PVE::Network::SDN::RouteMaps::config()->list();
+ for my $route_map_entry (values $route_map_entries->%*) {
+ for my $match_action_property_string ($route_map_entry->{match}->@*) {
+ my $match_action = PVE::JSONSchema::parse_property_string(
+ $PVE::Network::SDN::RouteMaps::ROUTE_MAP_MATCH_FORMAT,
+ $match_action_property_string,
+ );
+
+ next if $match_action->{key} !~ m/^(.*)-prefix-list$/;
+
+ die
+ "prefix list $prefix_list_id is still referenced by route map entry $route_map_entry->{'route-map-id'} #$route_map_entry->{'order'}"
+ if $match_action->{value} eq $prefix_list_id;
+ }
+ }
+}
+
sub prefix_list_properties {
my ($update) = @_;
--
2.47.3
next prev parent reply other threads:[~2026-05-04 11:43 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-04 11:38 [PATCH access-control/cluster/manager/network/proxmox{-ve-rs,-perl-rs} v3 00/44] Add support for route maps / prefix lists to SDN Stefan Hanreich
2026-05-04 11:38 ` [PATCH pve-cluster v3 01/44] cfs: add 'sdn/route-maps.cfg' to observed files Stefan Hanreich
2026-05-04 11:38 ` [PATCH pve-cluster v3 02/44] cfs: add 'sdn/prefix-lists.cfg' " Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-access-control v3 03/44] permissions: add ACL path for prefix-lists and route-maps Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 04/44] frr: add constructor to prefix list name Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 05/44] sdn-types: add common route-map helper types Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 06/44] frr: change order type to u16 Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 07/44] frr: implement routemap match/set statements via adjacent tagging Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 08/44] frr: implement support for call and exit action Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 09/44] frr-templates: change route maps template to adapt to new frr types Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 10/44] ve-config: fabrics: adapt frr config generation Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 11/44] ve-config: add prefix list section config Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 12/44] ve-config: frr: implement frr config generation for prefix lists Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 13/44] ve-config: add route map section config Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 14/44] ve-config: frr: implement frr config generation for route maps Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 15/44] ve-config: add prefix lists integration tests Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-ve-rs v3 16/44] ve-config: add route maps " Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-perl-rs v3 17/44] pve-rs: sdn: add route maps module Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-perl-rs v3 18/44] pve-rs: sdn: add prefix lists module Stefan Hanreich
2026-05-04 11:39 ` [PATCH proxmox-perl-rs v3 19/44] sdn: add prefix list / route maps to frr config generation helper Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 20/44] controller: bgp: evpn: adapt to new match / set frr config syntax Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 21/44] sdn: add prefix lists module Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 22/44] sdn: add route map module Stefan Hanreich
2026-05-04 11:39 ` Stefan Hanreich [this message]
2026-05-04 11:39 ` [PATCH pve-network v3 24/44] api2: add route maps module Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 25/44] api2: add route map module Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 26/44] api2: add route map entry module Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 27/44] evpn controller: add route_map_{in,out} parameter Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 28/44] bgp controller: allow configuring custom route maps Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 29/44] sdn: change detection for route maps / prefix lists Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 30/44] sdn: generate route map / prefix list configuration on sdn apply Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 31/44] sdn: frr: consider route maps and prefix lists in dry-run Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 32/44] fabrics: ospf: openfabric: add route_filter property Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 33/44] tests: add simple route map test case Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 34/44] tests: add bgp evpn route map/prefix list testcase Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 35/44] tests: add route map with prefix " Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-network v3 36/44] tests: add exit node with custom route map testcase Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 37/44] ui: sdn: add route map selector Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 38/44] ui: sdn: add prefix list selector Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 39/44] ui: sdn: add panel for managing prefix lists Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 40/44] ui: sdn: add panel for managing route map entries Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 41/44] ui: sdn: bgp controller: allow configuring route maps Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 42/44] ui: sdn: evpn " Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 43/44] ui: sdn: openfabric: add route filter Stefan Hanreich
2026-05-04 11:39 ` [PATCH pve-manager v3 44/44] ui: sdn: ospf: add route filter setting Stefan Hanreich
2026-05-04 16:37 ` superseded: [PATCH access-control/cluster/manager/network/proxmox{-ve-rs,-perl-rs} v3 00/44] Add support for route maps / prefix lists to SDN 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=20260504113943.159905-24-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox