]> git.proxmox.com Git - pve-network.git/blobdiff - PVE/Network/SDN/Subnets.pm
controllers: evpn : use frr restart if reload fail
[pve-network.git] / PVE / Network / SDN / Subnets.pm
index 626b71dd5a7c5b4c74069844077d54c75f99994a..6bb42e5b3f0563f0ca9a48735ce87505b67ab81f 100644 (file)
@@ -4,11 +4,13 @@ use strict;
 use warnings;
 
 use Net::Subnet qw(subnet_matcher);
-use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
 use Net::IP;
+use NetAddr::IP qw(:lower);
 
-use PVE::Network::SDN::Ipams;
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
 use PVE::Network::SDN::Dns;
+use PVE::Network::SDN::Ipams;
+
 use PVE::Network::SDN::SubnetPlugin;
 PVE::Network::SDN::SubnetPlugin->register();
 PVE::Network::SDN::SubnetPlugin->init();
@@ -21,6 +23,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;
 }
 
@@ -37,7 +47,7 @@ sub write_config {
 sub sdn_subnets_ids {
     my ($cfg) = @_;
 
-    return keys %{$cfg->{ids}};
+    return sort keys %{$cfg->{ids}};
 }
 
 sub complete_sdn_subnet {
@@ -49,21 +59,30 @@ sub complete_sdn_subnet {
 }
 
 sub get_subnet {
-    my ($subnetid) = @_;
+    my ($subnetid, $running) = @_;
+
+    my $cfg = {};
+    if($running) {
+       my $cfg = PVE::Network::SDN::running_config();
+       $cfg = $cfg->{subnets};
+    } else {
+       $cfg = PVE::Network::SDN::Subnets::config();
+    }
 
-    my $cfg = PVE::Network::SDN::Subnets::config();
     my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
     return $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};
@@ -75,7 +94,7 @@ sub find_ip_subnet {
     return ($subnetid, $subnet);
 }
 
-my $verify_dns_zone = sub {
+sub verify_dns_zone {
     my ($zone, $dns) = @_;
 
     return if !$zone || !$dns;
@@ -84,48 +103,54 @@ my $verify_dns_zone = sub {
     my $plugin_config = $dns_cfg->{ids}->{$dns};
     my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
     $plugin->verify_zone($plugin_config, $zone);
-};
+}
 
-my $add_dns_record = sub {
-    my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
-    return if !$zone || !$dns || !$hostname || !$ip;
+sub get_reversedns_zone {
+    my ($subnetid, $subnet, $dns, $ip) = @_;
 
-    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+    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, $subnet, $ip);
+}
+
+sub add_dns_record {
+    my ($zone, $dns, $hostname, $ip) = @_;
+    return if !$zone || !$dns || !$hostname || !$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->add_a_record($plugin_config, $zone, $hostname, $ip);
 
-};
+}
 
-my $add_dns_ptr_record = sub {
-    my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+sub add_dns_ptr_record {
+    my ($reversezone, $zone, $dns, $hostname, $ip) = @_;
 
     return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
 
-    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
     $hostname .= ".$zone";
     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->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
-};
+}
 
-my $del_dns_record = sub {
-    my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+sub del_dns_record {
+    my ($zone, $dns, $hostname, $ip) = @_;
 
     return if !$zone || !$dns || !$hostname || !$ip;
 
-    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
-
     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->del_a_record($plugin_config, $zone, $hostname, $ip);
-};
+}
 
-my $del_dns_ptr_record = sub {
+sub del_dns_ptr_record {
     my ($reversezone, $dns, $ip) = @_;
 
     return if !$reversezone || !$dns || !$ip;
@@ -134,47 +159,74 @@ my $del_dns_ptr_record = sub {
     my $plugin_config = $dns_cfg->{ids}->{$dns};
     my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
     $plugin->del_ptr_record($plugin_config, $reversezone, $ip);
-};
+}
+
+sub add_subnet {
+    my ($zone, $subnetid, $subnet) = @_;
+
+    my $ipam = $zone->{ipam};
+    return if !$ipam;
+    my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+    my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+    my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+    $plugin->add_subnet($plugin_config, $subnetid, $subnet);
+}
+
+sub del_subnet {
+    my ($zone, $subnetid, $subnet) = @_;
+
+    my $ipam = $zone->{ipam};
+    return if !$ipam;
+    my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+    my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+    my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+    $plugin->del_subnet($plugin_config, $subnetid, $subnet);
+}
 
 sub next_free_ip {
-    my ($subnetid, $subnet, $hostname) = @_;
+    my ($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns) = @_;
 
     my $cidr = undef;
     my $ip = undef;
+    $description = '' if !$description;
 
-    my $ipamid = $subnet->{ipam};
-    my $dns = $subnet->{dns};
-    my $dnszone = $subnet->{dnszone};
-    my $reversedns = $subnet->{reversedns};
-    my $reversednszone = $subnet->{reversednszone};
+    my $ipamid = $zone->{ipam};
+    my $dns = $zone->{dns};
+    my $dnszone = $zone->{dnszone};
+    my $reversedns = $zone->{reversedns};
     my $dnszoneprefix = $subnet->{dnszoneprefix};
 
+    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
     #verify dns zones before ipam
-    &$verify_dns_zone($dnszone, $dns);
-    &$verify_dns_zone($reversednszone, $reversedns);
+    verify_dns_zone($dnszone, $dns) if !$skipdns;
 
     if($ipamid) {
        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});
        eval {
-           $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+           $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $description);
            ($ip, undef) = split(/\//, $cidr);
        };
        die $@ if $@;
     }
 
     eval {
-       #add dns
-       &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
-       #add reverse dns
-       &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
+       my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
+
+       if(!$skipdns) {
+           #add dns
+           add_dns_record($dnszone, $dns, $hostname, $ip);
+           #add reverse dns
+           add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
+       }
     };
     if ($@) {
        #rollback
        my $err = $@;
        eval {
-           PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
+           PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
        };
        die $err;
     }
@@ -182,72 +234,138 @@ sub next_free_ip {
 }
 
 sub add_ip {
-    my ($subnetid, $subnet, $ip, $hostname) = @_;
+    my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, $skipdns) = @_;
+
+    return if !$subnet || !$ip; 
 
-    return if !$subnet;
+    my $ipaddr = NetAddr::IP->new($ip);
+    $ip = $ipaddr->canon();
 
-    my $ipamid = $subnet->{ipam};
-    my $dns = $subnet->{dns};
-    my $dnszone = $subnet->{dnszone};
-    my $reversedns = $subnet->{reversedns};
-    my $reversednszone = $subnet->{reversednszone};
+    my $ipamid = $zone->{ipam};
+    my $dns = $zone->{dns};
+    my $dnszone = $zone->{dnszone};
+    my $reversedns = $zone->{reversedns};
+    my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
     my $dnszoneprefix = $subnet->{dnszoneprefix};
 
+    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
     #verify dns zones before ipam
-    &$verify_dns_zone($dnszone, $dns);
-    &$verify_dns_zone($reversednszone, $reversedns);
+    if(!$skipdns) {
+       verify_dns_zone($dnszone, $dns);
+       verify_dns_zone($reversednszone, $reversedns);
+    }
 
     if ($ipamid) {
+
        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});
+
        eval {
-           $plugin->add_ip($plugin_config, $subnetid, $ip);
+           $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway);
        };
        die $@ if $@;
     }
 
     eval {
-       #add dns
-       &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
-       #add reverse dns
-       &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
+       if(!$skipdns) {
+           #add dns
+           add_dns_record($dnszone, $dns, $hostname, $ip);
+           #add reverse dns
+           add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
+       }
     };
     if ($@) {
        #rollback
        my $err = $@;
        eval {
-           PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
+           PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
        };
        die $err;
     }
 }
 
+sub update_ip {
+    my ($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $description, $skipdns) = @_;
+
+    return if !$subnet || !$ip; 
+
+    my $ipaddr = NetAddr::IP->new($ip);
+    $ip = $ipaddr->canon();
+
+    my $ipamid = $zone->{ipam};
+    my $dns = $zone->{dns};
+    my $dnszone = $zone->{dnszone};
+    my $reversedns = $zone->{reversedns};
+    my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
+    my $dnszoneprefix = $subnet->{dnszoneprefix};
+
+    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
+    #verify dns zones before ipam
+    if(!$skipdns) {
+       verify_dns_zone($dnszone, $dns);
+       verify_dns_zone($reversednszone, $reversedns);
+    }
+
+    if ($ipamid) {
+       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});
+       eval {
+           $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description);
+       };
+       die $@ if $@;
+    }
+
+    return if $hostname eq $oldhostname;
+
+    eval {
+       if(!$skipdns) {
+           #add dns
+           del_dns_record($dnszone, $dns, $oldhostname, $ip);
+           add_dns_record($dnszone, $dns, $hostname, $ip);
+           #add reverse dns
+           del_dns_ptr_record($reversednszone, $reversedns, $ip);
+           add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
+       }
+    };
+}
+
 sub del_ip {
-    my ($subnetid, $subnet, $ip, $hostname) = @_;
+    my ($zone, $subnetid, $subnet, $ip, $hostname, $skipdns) = @_;
+
+    return if !$subnet || !$ip;
 
-    return if !$subnet;
+    my $ipaddr = NetAddr::IP->new($ip);
+    $ip = $ipaddr->canon();
 
-    my $ipamid = $subnet->{ipam};
-    my $dns = $subnet->{dns};
-    my $dnszone = $subnet->{dnszone};
-    my $reversedns = $subnet->{reversedns};
-    my $reversednszone = $subnet->{reversednszone};
+    my $ipamid = $zone->{ipam};
+    my $dns = $zone->{dns};
+    my $dnszone = $zone->{dnszone};
+    my $reversedns = $zone->{reversedns};
+    my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
     my $dnszoneprefix = $subnet->{dnszoneprefix};
+    $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
 
-    &$verify_dns_zone($dnszone, $dns);
-    &$verify_dns_zone($reversednszone, $reversedns);
+    if(!$skipdns) {
+       verify_dns_zone($dnszone, $dns);
+       verify_dns_zone($reversednszone, $reversedns);
+    }
 
     if ($ipamid) {
        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 {
-       &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
-       &$del_dns_ptr_record($reversednszone, $reversedns, $ip);
+       if(!$skipdns) {
+           del_dns_record($dnszone, $dns, $hostname, $ip);
+           del_dns_ptr_record($reversednszone, $reversedns, $ip);
+       }
     };
     if ($@) {
        warn $@;