[pve-devel] [PATCH pve-manager 4/4] api2: network: check vlan permissions for local bridges

Alexandre Derumier aderumier at odiso.com
Fri May 26 09:27:24 CEST 2023


We need to display the bridge is the user have a permission
on any vlan on the bridge.

to avoid to check permissions on 4096 vlans for each bridge
(could be slow with a lot of bridges),
we first list vlans where acls are defined.

(4000 check took 60ms on 10year xeon server, should be enough
for any network where the total number of vlans is limited)

Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/API2/Network.pm | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/PVE/API2/Network.pm b/PVE/API2/Network.pm
index ba3b3e0e..39f17d14 100644
--- a/PVE/API2/Network.pm
+++ b/PVE/API2/Network.pm
@@ -240,17 +240,35 @@ __PACKAGE__->register_method({
 
 	if (my $tfilter = $param->{type}) {
 	    my $vnets;
+	    my $bridges_vlans_acl = {};
 	    #check access for local bridges
 	    my $can_access_vnet = sub {
+		my $bridge = $_[0];
 		return 1 if $authuser eq 'root at pam';
 		return 1 if $rpcenv->check_any($authuser, "/sdn/zones/local", ['SDN.Audit', 'SDN.Allocate'], 1);
-		return 1 if $rpcenv->check_any($authuser, "/sdn/vnets/$_[0]", ['SDN.Audit', 'SDN.Allocate'], 1);
+		return 1 if $rpcenv->check($authuser, "/sdn/vnets/$bridge", ['SDN.Audit'], 1);
+		my $bridge_vlan = $bridges_vlans_acl->{$bridge};
+		for my $tag (sort keys %$bridge_vlan) {
+		    return 1 if $rpcenv->check($authuser, "/sdn/vnets/$bridge.$tag", ['SDN.Audit'], 1);
+		}
 	    };
 
 	    if ($have_sdn && $param->{type} eq 'any_bridge') {
 		$vnets = PVE::Network::SDN::get_local_vnets(); # returns already access-filtered
 	    }
 
+	    #find all vlans where we have specific acls
+	    if ($tfilter =~ /^any(_local)?_bridge$/) {
+		my $cfg = $rpcenv->{user_cfg};
+		my $vnets_acl_root = $cfg->{acl_root}->{children}->{sdn}->{children}->{vnets};
+		PVE::AccessControl::iterate_acl_tree("/", $vnets_acl_root, sub {
+		    my ($path, $node) = @_;
+		    if ($path =~ /\/(.*)\.(\d+)$/) {
+			$bridges_vlans_acl->{$1}->{$2} = 1;
+		    }
+		});
+	    }
+
 	    for my $k (sort keys $ifaces->%*) {
 		my $type = $ifaces->{$k}->{type};
 		my $match = $tfilter eq $type || ($tfilter =~ /^any(_local)?_bridge$/ && ($type eq 'bridge' || $type eq 'OVSBridge'));
-- 
2.30.2





More information about the pve-devel mailing list