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(@_); },
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)))
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",
type => 'boolean',
description => "enable masquerade for this subnet if pve-firewall",
},
- #cloudinit, dhcp options
- routes => {
- type => 'string',
- description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
- },
- #cloudinit, dhcp options
- nameservers => {
- type => 'string', format => 'address-list',
- description => " dns nameserver",
- },
- #cloudinit, dhcp options
- searchdomain => {
- type => 'string',
- },
- dhcp => {
- type => 'boolean',
- description => "enable dhcp for this subnet",
- },
- dns_driver => {
- type => 'string',
- description => "Develop some dns registrations plugins (powerdns,...)",
- },
- ipam => {
- type => 'string',
- description => "use a specific ipam",
+# #cloudinit, dhcp options
+# routes => {
+# type => 'string',
+# description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
+# },
+ dnszoneprefix => {
+ type => 'string', format => 'dns-name',
+ description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
},
};
}
sub options {
return {
+ vnet => { optional => 0 },
gateway => { optional => 1 },
- routes => { optional => 1 },
- nameservers => { optional => 1 },
- searchdomain => { optional => 1 },
+# routes => { optional => 1 },
snat => { optional => 1 },
- dhcp => { optional => 1 },
- dns_driver => { optional => 1 },
- ipam => { optional => 1 },
+ dnszoneprefix => { optional => 1 },
};
}
sub on_update_hook {
- my ($class, $subnetid, $subnet_cfg) = @_;
+ my ($class, $zone, $subnetid, $subnet, $old_subnet) = @_;
- my $subnet = $subnetid =~ s/-/\//r;
- my $subnet_matcher = subnet_matcher($subnet);
+ my $cidr = $subnet->{cidr};
+ my $mask = $subnet->{mask};
- my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
- raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+ my $subnet_matcher = subnet_matcher($cidr);
-}
+ my $vnetid = $subnet->{vnet};
+ my $gateway = $subnet->{gateway};
+ 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};
+ }
+
+ 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 $cidr"}) if $gateway && !$subnet_matcher->($gateway) && !$pointopoint;
-sub on_delete_hook {
- my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
- #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;
+ if ($ipam) {
+ PVE::Network::SDN::Subnets::add_subnet($zone, $subnetid, $subnet);
+
+ #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;
}