]> git.proxmox.com Git - pve-network.git/blobdiff - PVE/Network/SDN/SubnetPlugin.pm
controllers: evpn : use frr restart if reload fail
[pve-network.git] / PVE / Network / SDN / SubnetPlugin.pm
index 44751e93bcff2fa47addd1d8b22dbf4e206398c7..15b370fb91ce80e9cab368aad42c75dbf314eea7 100644 (file)
@@ -3,11 +3,16 @@ package PVE::Network::SDN::SubnetPlugin;
 use strict;
 use warnings;
 
+use Net::IP;
+use Net::Subnet qw(subnet_matcher);
+
 use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
-use base qw(PVE::SectionConfig);
-use PVE::JSONSchema qw(get_standard_option);
 use PVE::Exception qw(raise raise_param_exc);
-use Net::Subnet qw(subnet_matcher);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Vnets;
+
+use base qw(PVE::SectionConfig);
 
 PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
                                  sub { __PACKAGE__->parse_config(@_); },
@@ -23,7 +28,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)))
@@ -52,6 +63,10 @@ sub private {
 
 sub properties {
     return {
+        vnet => {
+            type => 'string',
+            description => "associated vnet",
+        },
         gateway => {
             type => 'string', format => 'ip',
             description => "Subnet Gateway: Will be assign on vnet for layer3 zones",
@@ -65,30 +80,10 @@ sub properties {
 #            type => 'string',
 #            description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
 #        },
-        dns => {
-            type => 'string',
-            description => "dns api server",
-        },
-        reversedns => {
-            type => 'string',
-            description => "reverse dns api server",
-        },
-        dnszone => {
-            type => 'string', format => 'dns-name',
-            description => "dns domain zone  ex: mydomain.com",
-        },
-        reversednszone => {
-            type => 'string', format => 'dns-name',
-            description => "reverse dns zone ex: 0.168.192.in-addr.arpa",
-        },
         dnszoneprefix => {
             type => 'string', format => 'dns-name',
             description => "dns domain zone prefix  ex: 'adm' -> <hostname>.adm.mydomain.com",
         },
-        ipam => {
-            type => 'string',
-            description => "use a specific ipam",
-        },
     };
 }
 
@@ -98,52 +93,72 @@ sub options {
        gateway => { optional => 1 },
 #      routes => { optional => 1 },
        snat => { optional => 1 },
-       dns => { optional => 1 },
-       reversedns => { optional => 1 },
-       dnszone => { optional => 1 },
-       reversednszone => { optional => 1 },
        dnszoneprefix => { optional => 1 },
-       ipam => { optional => 1 },
     };
 }
 
 sub on_update_hook {
-    my ($class, $subnetid, $subnet_cfg) = @_;
+    my ($class, $zone, $subnetid, $subnet, $old_subnet) = @_;
 
-    my $cidr = $subnetid =~ s/-/\//r;
-    my $subnet_matcher = subnet_matcher($cidr);
+    my $cidr = $subnet->{cidr};
+    my $mask = $subnet->{mask};
 
-    my $subnet = $subnet_cfg->{ids}->{$subnetid};
+    my $subnet_matcher = subnet_matcher($cidr);
 
+    my $vnetid = $subnet->{vnet};
     my $gateway = $subnet->{gateway};
-    my $dns = $subnet->{dns};
-    my $dnszone = $subnet->{dnszone};
-    my $reversedns = $subnet->{reversedns};
-    my $reversednszone = $subnet->{reversednszone};
+    my $ipam = $zone->{ipam};
+    my $dns = $zone->{dns};
+    my $dnszone = $zone->{dnszone};
+    my $reversedns = $zone->{reversedns};
+
+    my $old_gateway = $old_subnet->{gateway} if $old_subnet;
+    my $mac = undef;
+
+    if($vnetid) {
+       my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+       raise_param_exc({ vnet => "$vnetid don't exist"}) if !$vnet;
+       raise_param_exc({ vnet => "you can't add a subnet on a vlanaware vnet"}) if $vnet->{vlanaware};
+       $mac = $vnet->{mac};
+    }
 
-    #to: for /32 pointotoping, allow gateway outside the subnet
-    raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+    my $pointopoint = 1 if Net::IP::ip_is_ipv4($gateway) && $mask == 32;
 
-    raise_param_exc({ dns => "missing dns provider"}) if $dnszone && !$dns;
-    raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
-    raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
-    raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
-    raise_param_exc({ reversedns => "missing forward dns zone"}) if $reversednszone && !$dnszone;
+    #for /32 pointopoint, we allow gateway outside the subnet
+    raise_param_exc({ gateway => "$gateway is not in subnet $cidr"}) if $gateway && !$subnet_matcher->($gateway) && !$pointopoint;
 
-}
 
-sub on_delete_hook {
-    my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
+    if ($ipam) {
+       PVE::Network::SDN::Subnets::add_subnet($zone, $subnetid, $subnet);
 
-    #verify if vnets have subnet
-    foreach my $vnetid (keys %{$vnet_cfg->{ids}}) {
-       my $vnet = $vnet_cfg->{ids}->{$vnetid};
-       my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
-       foreach my $subnet (@subnets) {
-           my $id = $subnet =~ s/\//-/r;
-           raise_param_exc({ subnet => "$subnet is attached to vnet $vnetid"}) if $id eq $subnetid;
+       #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);
+           };
+           warn if $@;
+       }
+        if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
+           my $hostname = "$vnetid-gw";
+           my $description = "gateway";
+           PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway, $hostname, $mac, $description, 1);
+       }
+
+       #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);
+           };
+           warn if $@;
        }
     }
+}
+
+sub on_delete_hook {
+    my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
 
     return;
 }