From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 15EC81FF13F for ; Thu, 07 May 2026 17:18:29 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 60CE9BBE; Thu, 7 May 2026 17:18:26 +0200 (CEST) Date: Thu, 7 May 2026 17:17:51 +0200 From: Gabriel Goller To: Lukas Sichert Subject: Re: [PATCH access-control/cluster/manager/network/proxmox{-ve-rs,-perl-rs} v5 00/46] Add support for route maps / prefix lists to SDN Message-ID: Mail-Followup-To: Lukas Sichert , Stefan Hanreich , pve-devel@lists.proxmox.com References: <20260505153720.412180-1-s.hanreich@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: User-Agent: NeoMutt/20241002-35-39f9a6 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1778166963777 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.029 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: I4DMTE7KHPB7S6DOVPDKJXNBHHD5OZ5Z X-Message-ID-Hash: I4DMTE7KHPB7S6DOVPDKJXNBHHD5OZ5Z X-MailFrom: g.goller@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 CC: pve-devel@lists.proxmox.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On 07.05.2026 13:57, Lukas Sichert wrote: > On 2026-05-05 17:36, Stefan Hanreich wrote: > > > ## Introduction > > > > This patch adds support for managing route maps and prefix lists to the SDN > > stack. With this patch series, route maps can be applied to the BGP and EVPN > > controller for incoming / outgoing route filtering. Additionally, prefix lists > > can be used to filter routes that should be installed by a fabric into the > > kernel routing table, overriding the default behavior of only installing routes > > from the configured IP prefix. There are currently some other features in > > development that would make use of route maps as well, namely: > > > > * VRF route leaking > > * Route Redistribution for Fabrics > > On my host there are two SimpleZones configured. In the first SimpleZone > there is a VM, which shall be called tm1 from now on. In the VNet there > is a cluster consisting of the nodes cl1, cl2 and cl3. All the nodes can > reach each other. On the cluster I configured an EVPN with an OpenFabric > underlay, configured cl1 as the exit node and enabled 'Advertise > Subnets'. In the EVPN Zone I created the 10.0.10.0/24 subnet. > > Then on cl1 I added a bgp controller with EBGP and 'ebgp-multihop' set > to 10 and the ip of tm1 set as peer. On tm1 I also added a bgp > controller with the same configuration, but with cl1 as peer and a > different ASN. In both cases I ran into a problem where 'delete' was not > defined in the schema, but this could be resolved by applying [1]. > EBGP multihop was enabled here, because the traffic between the > SimpleZones was routed via my host, which did not have a BGP controller > configured. > > I could then verify, that the 10.0.10.0/24 subnet was correctly > adveritsed from cl1 to tm1. After configuring prefix lists and > route-maps on both cl1 and tm1 I could verify that both incoming and > outgoing route-maps work, as the 10.0.10.0/24 was not advertised > anymore. > > Here I ran into a problem though. I configured a prefix list with > Prefix: 10.0.10.0/22 > Prefix<=:21 > This is of course wrong, but it is not checked, so applying it is > possible. Here maybe a check in the frontend would be useful. > After applying I got a warning and even after correcting the prefix list > the warning did not go away. After deleting and reconfiguring the list > it worked again, but apparently, when adding Prefix<=:, it is only > possible to alter the value, not delete it. Deleting will just be > ignored. Quick patch that should fix this -- not sure if this still applies on top of pve-manager after the last api-changes: diff --git a/www/manager6/sdn/PrefixListPanel.js b/www/manager6/sdn/PrefixListPanel.js index 8becf83435..bd4ce491dd 100644 --- a/www/manager6/sdn/PrefixListPanel.js +++ b/www/manager6/sdn/PrefixListPanel.js @@ -10,7 +10,16 @@ Ext.define('PVE.sdn.PrefixListEntry', { extend: 'Ext.data.Model', - fields: ['id', 'action', 'prefix', 'le', 'ge', 'pending'], + fields: [ + 'id', + 'action', + 'prefix', + // keep empty optional fields as '' so clearing a value does not mark + // untouched empty fields as dirty when the form returns ''. + { name: 'le', defaultValue: '' }, + { name: 'ge', defaultValue: '' }, + 'pending', + ], }); Ext.define('PVE.sdn.EditPrefixListWindow', { @@ -52,6 +61,48 @@ isCreate: false, + validatePrefixRange: function(name) { + let me = this; + let prefix = me.down('[name=prefix]').getValue(); + let value = me.down(`[name=${name}]`).getValue(); + + if (value === '') { + return true; + } + + let match = Proxmox.Utils.IP64_cidr_match.exec(prefix); + if (!match) { + return true; + } + + // IP64_cidr_match stores the IPv6 prefix length in match[1], + // and the IPv4 prefix length in match[2]. + let isIPv6 = match[1] !== undefined; + let maskLength = Number(isIPv6 ? match[1] : match[2]); + let maxLength = isIPv6 ? 128 : 32; + let label = name === 'le' ? gettext('Prefix <=') : gettext('Prefix >='); + let number = Number(value); + + if (!/^\d+$/.test(value) || number < maskLength || number > maxLength) { + return Ext.String.format( + gettext('{0} must be between {1} and {2}'), + label, + maskLength, + maxLength, + ); + } + + // only report the cross-field difference on the 'ge' input, so a valid + // 'le' value does not get marked invalid because of an invalid 'ge'. + let le = me.down('[name=le]').getValue(); + let ge = me.down('[name=ge]').getValue(); + if (name === 'ge' && le !== '' && Number(ge) > Number(le)) { + return gettext('Prefix >= must be less than or equal to Prefix <='); + } + + return true; + }, + items: [ { xtype: 'proxmoxKVComboBox', @@ -68,16 +119,27 @@ fieldLabel: gettext('Prefix'), name: 'prefix', vtype: 'IP64CIDRAddress', + allowBlank: false, }, { xtype: 'proxmoxtextfield', fieldLabel: gettext('Prefix <='), name: 'le', + skipEmptyText: false, + maskRe: /[0-9]/, + validator: function() { + return this.up('window').validatePrefixRange('le'); + }, }, { xtype: 'proxmoxtextfield', fieldLabel: gettext('Prefix >='), name: 'ge', + skipEmptyText: false, + maskRe: /[0-9]/, + validator: function() { + return this.up('window').validatePrefixRange('ge'); + }, }, ], @@ -294,8 +356,10 @@ .getData() .items .map((item) => { - let data = item.data; + // Clone record data before dropping grid-only metadata for serialization. + let data = Ext.apply({}, item.data); delete data.id; + delete data.pending; return PVE.Parser.printPropertyString(data); }); One other thing I noticed is that we don't allow prefixes lower than /8 on ipv4 and lower than /64 on ipv6. This is weird, because in frr 0.0.0.0/0 is usually used as a "allow-all" prefix. Not sure if we can change the existing input format or if that will break something (its also used in migration and replication). Will check that tomorrow.