]> git.proxmox.com Git - pve-network.git/commitdiff
subnets/ipam: allow same subnet on different zones
authorAlexandre Derumier <aderumier@odiso.com>
Mon, 5 Oct 2020 15:09:08 +0000 (17:09 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 8 Oct 2020 09:05:28 +0000 (11:05 +0200)
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
14 files changed:
PVE/API2/Network/SDN/Subnets.pm
PVE/API2/Network/SDN/Vnets.pm
PVE/API2/Network/SDN/Zones.pm
PVE/Network/SDN/Dns/PowerdnsPlugin.pm
PVE/Network/SDN/Ipams/NetboxPlugin.pm
PVE/Network/SDN/Ipams/PVEPlugin.pm
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
PVE/Network/SDN/Ipams/Plugin.pm
PVE/Network/SDN/SubnetPlugin.pm
PVE/Network/SDN/Subnets.pm
PVE/Network/SDN/VnetPlugin.pm
PVE/Network/SDN/Vnets.pm
PVE/Network/SDN/Zones/EvpnPlugin.pm
PVE/Network/SDN/Zones/SimplePlugin.pm

index 1e65ed404fb5ffd8814f65ec50455f9df86e77f6..a3bc10b04d3ba6c6983a6f549cf7e2ad4744e491 100644 (file)
@@ -28,7 +28,6 @@ my $api_sdn_subnets_config = sub {
 
     my $scfg = dclone(PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id));
     $scfg->{subnet} = $id;
-    $scfg->{cidr} = $id =~ s/-/\//r;
     $scfg->{digest} = $cfg->{digest};
 
     return $scfg;
@@ -168,7 +167,6 @@ __PACKAGE__->register_method ({
 
        my $type = extract_param($param, 'type');
        my $cidr = extract_param($param, 'subnet');
-       my $id = $cidr =~ s/\//-/r;
 
        # create /etc/pve/sdn directory
        PVE::Cluster::check_cfs_quorum();
@@ -183,7 +181,9 @@ __PACKAGE__->register_method ({
                my $vnet = $param->{vnet};
                my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone};
                my $zone = $zone_cfg->{ids}->{$zoneid};      
-
+               my $id = $cidr =~ s/\//-/r;
+               $id = "$zoneid-$id";
+               
                my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 1, 1);
 
                my $scfg = undef;
@@ -192,7 +192,9 @@ __PACKAGE__->register_method ({
                }
 
                $cfg->{ids}->{$id} = $opts;
-               PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts);
+
+               my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
+               PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet);
 
                PVE::Network::SDN::Subnets::write_config($cfg);
 
@@ -237,7 +239,8 @@ __PACKAGE__->register_method ({
 
            raise_param_exc({ ipam => "you can't change ipam"}) if $opts->{ipam} && $scfg->{ipam} && $opts->{ipam} ne $scfg->{ipam};
 
-           PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts, $scfg);
+           my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
+           PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet);
 
            PVE::Network::SDN::Subnets::write_config($cfg);
 
index 5fe524bfd797a6c3b8f2df7da40902012273e00d..3a995a8145ac457633cbeb062770aec286fcee67 100644 (file)
@@ -17,6 +17,7 @@ use PVE::API2::Network::SDN::Subnets;
 use Storable qw(dclone);
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::RPCEnvironment;
+use PVE::Exception qw(raise raise_param_exc);
 
 use PVE::RESTHandler;
 
@@ -193,9 +194,7 @@ __PACKAGE__->register_method ({
            my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
             $plugin->vnet_update_hook($cfg->{ids}->{$id});
 
-           my $subnet_cfg = PVE::Network::SDN::Subnets::config();
-
-           PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
+           PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
 
            PVE::Network::SDN::Vnets::write_config($cfg);
 
@@ -226,7 +225,12 @@ __PACKAGE__->register_method ({
 
            PVE::SectionConfig::assert_if_modified($cfg, $digest);
 
+
            my $opts = PVE::Network::SDN::VnetPlugin->check_config($id, $param, 0, 1);
+           raise_param_exc({ zone => "missing zone"}) if !$opts->{zone};
+           my $subnets = PVE::Network::SDN::Vnets::get_subnets($id);
+           raise_param_exc({ zone => "can't change zone if subnets exists"}) if($subnets && $opts->{zone} ne $cfg->{ids}->{$id}->{zone});
+
            $cfg->{ids}->{$id} = $opts;
 
            my $zone_cfg = PVE::Network::SDN::Zones::config();
@@ -235,9 +239,7 @@ __PACKAGE__->register_method ({
            my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
            $plugin->vnet_update_hook($cfg->{ids}->{$id});
 
-           my $subnet_cfg = PVE::Network::SDN::Subnets::config();
-
-           PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
+           PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
 
            PVE::Network::SDN::Vnets::write_config($cfg);
 
index 54f087d060ba769c63766e4303e2ae548d717a06..5ae577b3840f9c5cc5a4db17b21cc3f8bc3c8dc0 100644 (file)
@@ -9,6 +9,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file);
 use PVE::Network::SDN;
 use PVE::Network::SDN::Vnets;
 use PVE::Network::SDN::Zones;
+use PVE::Network::SDN::Subnets;
 use PVE::Network::SDN::Dns;
 use PVE::Network::SDN::Zones::Plugin;
 use PVE::Network::SDN::Zones::VlanPlugin;
@@ -263,6 +264,16 @@ __PACKAGE__->register_method ({
            my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($scfg->{type});
            my $opts = $plugin->check_config($id, $param, 0, 1);
 
+           if($opts->{ipam} ne $scfg->{ipam}) {
+
+               #don't allow ipam change if subnet are defined
+               my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+               foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
+                   my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets_cfg, $subnetid);
+                   raise_param_exc({ ipam => "can't change ipam if subnet if already defined for this zone"}) if $subnet->{zone} eq $id;
+               }
+           }
+
            foreach my $k (%$opts) {
                $scfg->{$k} = $opts->{$k};
            }
index 5b98e87b852b8014e060090a474fbd77c58034b0..b00432e2b59f1af4b947699691531e164d288c29 100644 (file)
@@ -186,11 +186,11 @@ sub verify_zone {
 }
 
 sub get_reversedns_zone {
-    my ($class, $plugin_config, $subnetid, $ip) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
 
-    my ($network, $mask) = split(/-/, $subnetid);
+    my $cidr = $subnet->{cidr};
+    my $mask = $subnet->{mask};
 
-    my $cidr = "$ip/$mask";
     my $zone = "";
 
     if (Net::IP::ip_is_ipv4($ip)) {
index 01f82f2201f576547285e6984dabc33d69ad4831..d696b0865d55a28116ff5cb093b97e2243d98d34 100644 (file)
@@ -30,7 +30,7 @@ sub options {
 sub add_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
     my $gateway = $subnet->{gateway};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
@@ -40,13 +40,11 @@ sub add_subnet {
 
     #create subnet
     if (!$internalid) {
-       my ($network, $mask) = split(/-/, $subnetid);
 
        my $params = { prefix => $cidr };
 
        eval {
                my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/prefixes/", $headers, $params);
-               $subnet->{ipamid} = $result->{id} if defined($result->{id});
        };
        if ($@) {
            die "error add subnet to ipam: $@";
@@ -58,7 +56,7 @@ sub add_subnet {
 sub del_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $gateway = $subnet->{gateway};
@@ -66,9 +64,8 @@ sub del_subnet {
 
     my $internalid = get_prefix_id($url, $cidr, $headers);
     return if !$internalid;
-    #fixme: check that prefix is empty exluding gateway, before delete
 
-    PVE::Network::SDN::Ipams::NetboxPlugin::del_ip($class, $plugin_config, $subnetid, $gateway) if $gateway;
+    return; #fixme: check that prefix is empty exluding gateway, before delete
 
     eval {
        PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers);
@@ -80,9 +77,9 @@ sub del_subnet {
 }
 
 sub add_ip {
-    my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
 
-    my ($network, $mask) = split(/-/, $subnetid);
+    my $mask = $subnet->{mask};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $section = $plugin_config->{section};
@@ -102,7 +99,8 @@ sub add_ip {
 sub add_next_freeip {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
@@ -125,7 +123,7 @@ sub add_next_freeip {
 }
 
 sub del_ip {
-    my ($class, $plugin_config, $subnetid, $ip) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
 
     return if !$ip;
 
index 3b616954999f546de325376e99bf1cfcd042d724..0779b53c1408b1cc9fb55bad7665b6e5fa983ea4 100644 (file)
@@ -7,6 +7,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file
 use PVE::Tools;
 use JSON;
 use NetAddr::IP;
+use Net::IP;
 use Digest::SHA;
 
 use base('PVE::Network::SDN::Ipams::Plugin');
@@ -33,15 +34,22 @@ sub options {
 sub add_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $zone = $subnet->{zone};
     my $gateway = $subnet->{gateway};
 
+
     cfs_lock_file($ipamdb_file, undef, sub {
-       my $config = read_db();
-       #create subnet
-       if (!defined($config->{subnets}->{$cidr})) {
-           $config->{subnets}->{$cidr}->{ips} = {};
-           write_db($config);
+       my $db = {};
+       $db = read_db();
+
+       $db->{zones}->{$zone} = {} if !$db->{zones}->{$zone};
+       my $zonedb = $db->{zones}->{$zone};
+
+       if(!$zonedb->{subnets}->{$cidr}) {
+           #create subnet
+           $zonedb->{subnets}->{$cidr}->{ips} = {};
+           write_db($db);
        }
     });
     die "$@" if $@;
@@ -50,14 +58,22 @@ sub add_subnet {
 sub del_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $zone = $subnet->{zone};
 
     cfs_lock_file($ipamdb_file, undef, sub {
 
        my $db = read_db();
-       my $ips = $db->{subnets}->{$cidr}->{ips};
-       die "cannot delete subnet '$cidr', not empty\n" if keys %{$ips} > 0;
-       delete $db->{subnets}->{$cidr};
+
+       my $dbzone = $db->{zones}->{$zone};
+       die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
+       my $dbsubnet = $dbzone->{subnets}->{$cidr};
+       die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet;
+
+       die "cannot delete subnet '$cidr', not empty\n" if keys %{$dbsubnet->{ips}} > 0;
+
+       delete $dbzone->{subnets}->{$cidr};
+
        write_db($db);
     });
     die "$@" if $@;
@@ -65,19 +81,24 @@ sub del_subnet {
 }
 
 sub add_ip {
-    my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $zone = $subnet->{zone};
 
     cfs_lock_file($ipamdb_file, undef, sub {
 
        my $db = read_db();
-       my $s = $db->{subnets}->{$cidr};
 
-       die "IP '$ip' already exist\n" if defined($s->{ips}->{$ip});
+       my $dbzone = $db->{zones}->{$zone};
+       die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
+       my $dbsubnet = $dbzone->{subnets}->{$cidr};
+       die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet;
+
+       die "IP '$ip' already exist\n" if defined($dbsubnet->{ips}->{$ip});
+
+       $dbsubnet->{ips}->{$ip} = 1;
 
-       #verify that ip is valid for this subnet
-       $s->{ips}->{$ip} = 1;
        write_db($db);
     });
     die "$@" if $@;
@@ -86,49 +107,64 @@ sub add_ip {
 sub add_next_freeip {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $network = $subnet->{network};
+    my $zone = $subnet->{zone};
+    my $mask = $subnet->{mask};
     my $freeip = undef;
 
     cfs_lock_file($ipamdb_file, undef, sub {
 
        my $db = read_db();
-       my $s = $db->{subnets}->{$cidr};
-       my $iplist = new NetAddr::IP($cidr);
-       my $broadcast = $iplist->broadcast();
-
-       while (1) {
-           $iplist++;
-           last if $iplist eq $broadcast;
-           my $ip = $iplist->addr();
-           next if defined($s->{ips}->{$ip});
-           $freeip = $ip;
-           last;
+       my $dbzone = $db->{zones}->{$zone};
+       die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
+       my $dbsubnet = $dbzone->{subnets}->{$cidr};
+       die "subnet '$cidr' doesn't exist in IPAM DB" if !$dbsubnet;
+
+       if (Net::IP::ip_is_ipv4($network) && $mask == 32) {
+           die "cannot find free IP in subnet '$cidr'\n" if defined($dbsubnet->{ips}->{$network});
+           $freeip = $network;
+       } else {
+           my $iplist = new NetAddr::IP($cidr);
+           my $broadcast = $iplist->broadcast();
+
+           while(1) {
+               $iplist++;
+               last if $iplist eq $broadcast;
+               my $ip = $iplist->addr();
+               next if defined($dbsubnet->{ips}->{$ip});
+               $freeip = $ip;
+               last;
+           }
        }
 
        die "can't find free ip in subnet '$cidr'\n" if !$freeip;
 
-       $s->{ips}->{$freeip} = 1;
+       $dbsubnet->{ips}->{$freeip} = 1;
        write_db($db);
     });
     die "$@" if $@;
 
-    my ($network, $mask) = split(/-/, $subnetid);
     return "$freeip/$mask";
 }
 
 sub del_ip {
-    my ($class, $plugin_config, $subnetid, $ip) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $zone = $subnet->{zone};
 
     cfs_lock_file($ipamdb_file, undef, sub {
 
        my $db = read_db();
-       my $s = $db->{subnets}->{$cidr};
-       return if !$ip;
+       die "zone $zone don't exist in ipam db" if !$db->{zones}->{$zone};
+       my $dbzone = $db->{zones}->{$zone};
+       die "subnet $cidr don't exist in ipam db" if !$dbzone->{subnets}->{$cidr};
+       my $dbsubnet = $dbzone->{subnets}->{$cidr};
+
+       die "IP '$ip' does not exist in IPAM DB\n" if !defined($dbsubnet->{ips}->{$ip});
+       delete $dbsubnet->{ips}->{$ip};
 
-       die "IP '$ip' does not exist in IPAM DB\n" if !defined($s->{ips}->{$ip});
-       delete $s->{ips}->{$ip};
        write_db($db);
     });
     die "$@" if $@;
index 4a9e6c44f77e31674f7279d1c5f223df58007b5f..f89ef297b337d5f9e4ff3e0d01edc57ed00faf58 100644 (file)
@@ -40,7 +40,10 @@ sub options {
 sub add_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $network = $subnet->{network};
+    my $mask = $subnet->{mask};
+
     my $gateway = $subnet->{gateway};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
@@ -52,7 +55,6 @@ sub add_subnet {
 
     #create subnet
     if (!$internalid) {
-       my ($network, $mask) = split(/-/, $subnetid);
 
        my $params = { subnet => $network,
                   mask => $mask,
@@ -72,7 +74,7 @@ sub add_subnet {
 sub del_subnet {
     my ($class, $plugin_config, $subnetid, $subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $section = $plugin_config->{section};
@@ -81,7 +83,7 @@ sub del_subnet {
     my $internalid = get_internalid($url, $cidr, $headers);
     return if !$internalid;
 
-    #fixme: check that prefix is empty exluding gateway, before delete
+    return; #fixme: check that prefix is empty exluding gateway, before delete
 
     eval {
        PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/subnets/$internalid", $headers);
@@ -93,9 +95,9 @@ sub del_subnet {
 }
 
 sub add_ip {
-    my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $section = $plugin_config->{section};
@@ -120,7 +122,8 @@ sub add_ip {
 sub add_next_freeip {
     my ($class, $plugin_config, $subnetid, $subnet, $internalid, $hostname) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};  
+    my $mask = $subnet->{mask};  
     my $url = $plugin_config->{url};
     my $token = $plugin_config->{token};
     my $section = $plugin_config->{section};
@@ -140,12 +143,11 @@ sub add_next_freeip {
         die "can't find free ip in subnet $cidr: $@";
     }
 
-    my ($network, $mask) = split(/-/, $subnetid);
     return "$ip/$mask";
 }
 
 sub del_ip {
-    my ($class, $plugin_config, $subnetid, $ip) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
 
     return if !$ip;
 
index 9330ba92993375b14ef5c9753f49b0eaf8de2d75..4c68287499d56a2fed4756518f5783da89c73d2a 100644 (file)
@@ -75,16 +75,16 @@ sub del_subnet {
 }
 
 sub add_ip {
-    my ($class, $plugin_config, $subnetid, $subnet, $internalid, $ip, $hostname, $is_gateway) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
 
 }
 
 sub add_next_freeip {
-    my ($class, $plugin_config) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet) = @_;
 }
 
 sub del_ip {
-    my ($class, $plugin_config, $subnetid, $ip) = @_;
+    my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
 }
 
 sub on_update_hook {
index a5d03f6be6c825f32485c5454d7343902d86a7e7..144426229ba0259c684b01f912acffa4d606905b 100644 (file)
@@ -10,6 +10,7 @@ use PVE::Exception qw(raise raise_param_exc);
 use Net::Subnet qw(subnet_matcher);
 use PVE::Network::SDN::Vnets;
 use PVE::Network::SDN::Ipams;
+use Net::IP;
 
 PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
                                  sub { __PACKAGE__->parse_config(@_); },
@@ -25,7 +26,13 @@ PVE::JSONSchema::register_format('pve-sdn-subnet-id', \&parse_sdn_subnet_id);
 sub parse_sdn_subnet_id {
     my ($id, $noerr) = @_;
 
-    my $cidr = $id =~ s/-/\//r;
+    my $cidr = "";
+    if($id =~ /\//) {
+       $cidr = $id;
+    } else {
+       my ($zone, $ip, $mask) = split(/-/, $id);
+       $cidr = "$ip/$mask";
+    }
 
     if (!(PVE::JSONSchema::pve_verify_cidrv4($cidr, 1) ||
           PVE::JSONSchema::pve_verify_cidrv6($cidr, 1)))
@@ -91,7 +98,9 @@ sub options {
 sub on_update_hook {
     my ($class, $zone, $subnetid, $subnet, $old_subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
+    my $cidr = $subnet->{cidr};
+    my $mask = $subnet->{mask};
+
     my $subnet_matcher = subnet_matcher($cidr);
 
     my $vnetid = $subnet->{vnet};
@@ -109,9 +118,11 @@ sub on_update_hook {
        raise_param_exc({ vnet => "you can't add a subnet on a vlanaware vnet"}) if $vnet->{vlanaware};
     }
 
-    my ($ip, $mask) = split(/\//, $cidr);
+    my $pointopoint = 1 if Net::IP::ip_is_ipv4($gateway) && $mask == 32;
+
     #for /32 pointopoint, we allow gateway outside the subnet
-    raise_param_exc({ gateway => "$gateway is not in subnet $subnetid"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
+    raise_param_exc({ gateway => "$gateway is not in subnet $cidr"}) if $gateway && !$subnet_matcher->($gateway) && !$pointopoint;
+
 
     if ($ipam) {
        my $ipam_cfg = PVE::Network::SDN::Ipams::config();
@@ -119,7 +130,10 @@ sub on_update_hook {
        my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
        $plugin->add_subnet($plugin_config, $subnetid, $subnet);
 
-       #delete on removal
+       #don't register gateway for pointopoint
+       return if $pointopoint;
+
+       #delete gateway on removal
        if (!defined($gateway) && $old_gateway) {
            eval {
                PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
@@ -130,7 +144,7 @@ sub on_update_hook {
            PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway);
        }
 
-       #delete old ip after update
+       #delete old gateway after update
        if($gateway && $old_gateway && $gateway ne $old_gateway) {
            eval {
                PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
index 50130d562a89ce2f6db277fcc887d61cd3b3b889..bd1eb36dbbff24e97c0faa5ef8e6ac6277bb2b63 100644 (file)
@@ -21,6 +21,14 @@ sub sdn_subnets_config {
     my $scfg = $cfg->{ids}->{$id};
     die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
 
+    if($scfg) {
+       my ($zone, $network, $mask) = split(/-/, $id);
+       $scfg->{cidr} = "$network/$mask";
+       $scfg->{zone} = $zone;
+       $scfg->{network} = $network;
+       $scfg->{mask} = $mask;
+    }
+
     return $scfg;
 }
 
@@ -64,13 +72,15 @@ sub get_subnet {
 }
 
 sub find_ip_subnet {
-    my ($ip, $subnets) = @_;
+    my ($ip, $mask, $subnets) = @_;
 
     my $subnet = undef;
     my $subnetid = undef;
 
     foreach my $id (sort keys %{$subnets}) {
-       my $cidr = $id =~ s/-/\//r;
+
+       next if $mask ne $subnets->{$id}->{mask};
+       my $cidr = $subnets->{$id}->{cidr};
        my $subnet_matcher = subnet_matcher($cidr);
        next if !$subnet_matcher->($ip);
        $subnet = $subnets->{$id};
@@ -94,14 +104,14 @@ my $verify_dns_zone = sub {
 };
 
 my $get_reversedns_zone = sub {
-    my ($subnetid, $dns, $ip) = @_;
+    my ($subnetid, $subnet, $dns, $ip) = @_;
 
     return if !$subnetid || !$dns || !$ip;
 
     my $dns_cfg = PVE::Network::SDN::Dns::config();
     my $plugin_config = $dns_cfg->{ids}->{$dns};
     my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
-    $plugin->get_reversedns_zone($plugin_config, $subnetid, $ip);
+    $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
 };
 
 my $add_dns_record = sub {
@@ -181,7 +191,7 @@ sub next_free_ip {
     }
 
     eval {
-       my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+       my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
 
        #add dns
        &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
@@ -208,7 +218,7 @@ sub add_ip {
     my $dns = $zone->{dns};
     my $dnszone = $zone->{dnszone};
     my $reversedns = $zone->{reversedns};
-    my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+    my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
     my $dnszoneprefix = $subnet->{dnszoneprefix};
 
     #verify dns zones before ipam
@@ -220,7 +230,7 @@ sub add_ip {
        my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
        my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
        eval {
-           $plugin->add_ip($plugin_config, $subnetid, $ip);
+           $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip);
        };
        die $@ if $@;
     }
@@ -250,7 +260,7 @@ sub del_ip {
     my $dns = $zone->{dns};
     my $dnszone = $zone->{dnszone};
     my $reversedns = $zone->{reversedns};
-    my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+    my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
     my $dnszoneprefix = $subnet->{dnszoneprefix};
 
     &$verify_dns_zone($dnszone, $dns);
@@ -260,7 +270,7 @@ sub del_ip {
        my $ipam_cfg = PVE::Network::SDN::Ipams::config();
        my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
        my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
-       $plugin->del_ip($plugin_config, $subnetid, $ip);
+       $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
     }
 
     eval {
index 8481f0d16d98a3a81b52f487ab65d30d660bb25a..518d2dd0a0546ab00566a5ca5f750c1cea2886be 100644 (file)
@@ -91,29 +91,28 @@ sub on_delete_hook {
 
     #verify if subnets are associated
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
-    my @subnetlist = ();
-    foreach my $subnetid (sort keys %{$subnets}) {
-       push @subnetlist, $subnetid;
-    }
-    raise_param_exc({ vnet => "Vnet is attached to following subnets:". join(',', @subnetlist)}) if @subnetlist > 0;
+    raise_param_exc({ vnet => "Can't delete vnet if subnets exists"}) if $subnets;
 }
 
 sub on_update_hook {
-    my ($class, $vnetid, $vnet_cfg, $subnet_cfg) = @_;
+    my ($class, $vnetid, $vnet_cfg) = @_;
+
+    my $vnet = $vnet_cfg->{ids}->{$vnetid};
+    my $tag = $vnet->{tag};
+    my $vlanaware = $vnet->{vlanaware};
+
+    #don't allow vlanaware change if subnets are defined
+    if($vnet->{vlanaware}) {
+       my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+       raise_param_exc({ vlanaware => "vlanaware vnet is not compatible with subnets"}) if $subnets;
+    }
 
-    #fixme : don't allow change zone if subnets are defined
-    #fixme : don't vlanaware change if subnets are defined
-#    my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
-   
     # verify that tag is not already defined in another vnet
-    if (defined($vnet_cfg->{ids}->{$vnetid}->{tag})) {
-       my $tag = $vnet_cfg->{ids}->{$vnetid}->{tag};
+    if (defined($tag)) {
        foreach my $id (keys %{$vnet_cfg->{ids}}) {
            next if $id eq $vnetid;
-           my $vnet = $vnet_cfg->{ids}->{$id};
-           if ($vnet->{type} eq 'vnet' && defined($vnet->{tag})) {
-               raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $tag eq $vnet->{tag};
-           }
+           my $othervnettag = $vnet_cfg->{ids}->{$id}->{tag};
+           raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $othervnettag && $tag eq $othervnettag;
        }
     }
 }
index d08db51dc258576e26e6908af69a9626252efb46..6d1100392c7a8b01576fd8d5da4f57f68febcf75 100644 (file)
@@ -66,10 +66,10 @@ sub get_vnet {
 sub get_subnets {
     my ($vnetid) = @_;
 
-    my $subnets = {};
+    my $subnets = undef;
     my $subnets_cfg = PVE::Network::SDN::Subnets::config();
     foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
-       my $subnet = $subnets_cfg->{ids}->{$subnetid};
+       my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets_cfg, $subnetid);
        next if !$subnet->{vnet} || $subnet->{vnet} ne $vnetid;
        $subnets->{$subnetid} = $subnet;
     }
@@ -77,7 +77,7 @@ sub get_subnets {
 
 }
 
-sub get_next_free_ip {
+sub get_next_free_cidr {
     my ($vnetid, $hostname, $ipversion) = @_;
 
     my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
@@ -91,7 +91,7 @@ sub get_next_free_ip {
 
     foreach my $subnetid (sort keys %{$subnets}) {
         my $subnet = $subnets->{$subnetid};
-       my ($network, $mask) = split(/-/, $subnetid);
+       my $network = $subnet->{network};
 
        next if $ipversion != Net::IP::ip_get_version($network);
        $subnetcount++;
@@ -108,7 +108,7 @@ sub get_next_free_ip {
     return $ip;
 }
 
-sub add_ip {
+sub add_cidr {
     my ($vnetid, $cidr, $hostname) = @_;
 
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
@@ -117,12 +117,13 @@ sub add_ip {
     my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
 
     my ($ip, $mask) = split(/\//, $cidr);
-    my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
+    die "ip address is not in cidr format" if !$mask;
+    my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
 
     PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname);
 }
 
-sub del_ip {
+sub del_cidr {
     my ($vnetid, $cidr, $hostname) = @_;
 
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
@@ -131,7 +132,8 @@ sub del_ip {
     my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
 
     my ($ip, $mask) = split(/\//, $cidr);
-    my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
+    die "ip address is not in cidr format" if !$mask;
+    my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
 
     PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname);
 }
index 723b3cc330b060cf6fe43f76007ff72a5fc54cd3..62ab817cdaa70405794703d1302f604d0c3d6ad1 100644 (file)
@@ -86,7 +86,8 @@ sub generate_sdn_config {
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
     foreach my $subnetid (sort keys %{$subnets}) {
        my $subnet = $subnets->{$subnetid};
-       my $cidr = $subnetid =~ s/-/\//r;
+       my $cidr = $subnet->{cidr};
+
        my $gateway = $subnet->{gateway};
        if ($gateway) {
            push @iface_config, "address $gateway" if !defined($address->{$gateway});
index fe0f20f9ad5f27ba2d89611c9cdbd09bfb0a3cd9..52944859830648db1e271706632f6bce7351ec11 100644 (file)
@@ -60,14 +60,15 @@ sub generate_sdn_config {
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
     foreach my $subnetid (sort keys %{$subnets}) {
        my $subnet = $subnets->{$subnetid};
-       my $cidr = $subnetid =~ s/-/\//r; 
+       my $cidr = $subnet->{cidr};
+       my $mask = $subnet->{mask};
+
        my $gateway = $subnet->{gateway};
        if ($gateway) {
            push @iface_config, "address $gateway" if !defined($address->{$gateway});
            $address->{$gateway} = 1;
        }
        #add route for /32 pointtopoint
-       my ($ip, $mask) = split(/\//, $cidr);
        push @iface_config, "up ip route add $cidr dev $vnetid" if $mask == 32;
        if ($subnet->{snat}) {
            #find outgoing interface