* [pve-devel] [PATCH v2 pve-network 01/10] add subnet plugin
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 02/10] vnets: add subnets Alexandre Derumier
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN.pm | 7 +
PVE/API2/Network/SDN/Makefile | 2 +-
PVE/API2/Network/SDN/Subnets.pm | 219 ++++++++++++++++++++++++++++++++
PVE/Network/SDN/Makefile | 2 +-
PVE/Network/SDN/SubnetPlugin.pm | 115 +++++++++++++++++
PVE/Network/SDN/Subnets.pm | 55 ++++++++
debian/control | 1 +
7 files changed, 399 insertions(+), 2 deletions(-)
create mode 100644 PVE/API2/Network/SDN/Subnets.pm
create mode 100644 PVE/Network/SDN/SubnetPlugin.pm
create mode 100644 PVE/Network/SDN/Subnets.pm
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 3f497fc..38af746 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -14,6 +14,7 @@ use PVE::Tools qw(run_command);
use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
use PVE::API2::Network::SDN::Zones;
+use PVE::API2::Network::SDN::Subnets;
use base qw(PVE::RESTHandler);
@@ -32,6 +33,11 @@ __PACKAGE__->register_method ({
path => 'controllers',
});
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Network::SDN::Subnets",
+ path => 'subnets',
+});
+
__PACKAGE__->register_method({
name => 'index',
path => '',
@@ -61,6 +67,7 @@ __PACKAGE__->register_method({
{ id => 'vnets' },
{ id => 'zones' },
{ id => 'controllers' },
+ { id => 'subnets' },
];
return $res;
diff --git a/PVE/API2/Network/SDN/Makefile b/PVE/API2/Network/SDN/Makefile
index 6f20d4a..59626fa 100644
--- a/PVE/API2/Network/SDN/Makefile
+++ b/PVE/API2/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm Zones.pm Controllers.pm
+SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
new file mode 100644
index 0000000..26b2aa5
--- /dev/null
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -0,0 +1,219 @@
+package PVE::API2::Network::SDN::Subnets;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::Tools qw(extract_param);
+use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Network::SDN;
+use PVE::Network::SDN::Subnets;
+use PVE::Network::SDN::SubnetPlugin;
+
+use Storable qw(dclone);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::RPCEnvironment;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my $api_sdn_subnets_config = sub {
+ my ($cfg, $id) = @_;
+
+ my $scfg = dclone(PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id));
+ $scfg->{subnet} = $id;
+ $scfg->{digest} = $cfg->{digest};
+
+ return $scfg;
+};
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => "SDN subnets index.",
+ permissions => {
+ description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/subnets/<subnet>'",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => {},
+ },
+ links => [ { rel => 'child', href => "{subnet}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+
+ my @sids = PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg);
+ my $res = [];
+ foreach my $id (@sids) {
+ my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
+ next if !$rpcenv->check_any($authuser, "/sdn/subnets/$id", $privs, 1);
+
+ my $scfg = &$api_sdn_subnets_config($cfg, $id);
+ push @$res, $scfg;
+ }
+
+ return $res;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'read',
+ path => '{subnet}',
+ method => 'GET',
+ description => "Read sdn subnet configuration.",
+ permissions => {
+ check => ['perm', '/sdn/subnets/{subnet}', ['SDN.Allocate']],
+ },
+
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ subnet => get_standard_option('pve-sdn-subnet-id', {
+ completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets,
+ }),
+ },
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+
+ return &$api_sdn_subnets_config($cfg, $param->{subnet});
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ path => '',
+ method => 'POST',
+ description => "Create a new sdn subnet object.",
+ permissions => {
+ check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::SubnetPlugin->createSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $type = extract_param($param, 'type');
+ my $id = extract_param($param, 'subnet');
+
+ # create /etc/pve/sdn directory
+ PVE::Cluster::check_cfs_quorum();
+ mkdir("/etc/pve/sdn");
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+ my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 1, 1);
+
+ my $scfg = undef;
+ if ($scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id, 1)) {
+ die "sdn subnet object ID '$id' already defined\n";
+ }
+
+ $cfg->{ids}->{$id} = $opts;
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+ PVE::Network::SDN::Subnets::write_config($cfg);
+ PVE::Network::SDN::increase_version();
+
+ }, "create sdn subnet object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ path => '{subnet}',
+ method => 'PUT',
+ description => "Update sdn subnet object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::SubnetPlugin->updateSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'subnet');
+ my $digest = extract_param($param, 'digest');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+
+ PVE::SectionConfig::assert_if_modified($cfg, $digest);
+
+ my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 0, 1);
+ $cfg->{ids}->{$id} = $opts;
+
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+ PVE::Network::SDN::Subnets::write_config($cfg);
+ PVE::Network::SDN::increase_version();
+
+ }, "update sdn subnet object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{subnet}',
+ method => 'DELETE',
+ description => "Delete sdn subnet object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ subnet => get_standard_option('pve-sdn-subnet-id', {
+ completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets,
+ }),
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'subnet');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+
+ my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
+
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+
+ delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::Subnets::write_config($cfg);
+ PVE::Network::SDN::increase_version();
+
+ }, "delete sdn subnet object failed");
+
+
+ return undef;
+ }});
+
+1;
diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile
index 7622255..59f8c34 100644
--- a/PVE/Network/SDN/Makefile
+++ b/PVE/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm
+SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
new file mode 100644
index 0000000..8900681
--- /dev/null
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -0,0 +1,115 @@
+package PVE::Network::SDN::SubnetPlugin;
+
+use strict;
+use warnings;
+
+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);
+
+PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
+ sub { __PACKAGE__->parse_config(@_); },
+ sub { __PACKAGE__->write_config(@_); });
+
+PVE::JSONSchema::register_standard_option('pve-sdn-subnet-id', {
+ description => "The SDN subnet object identifier.",
+ type => 'string', format => 'pve-sdn-subnet-id',
+ type => 'string'
+});
+
+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;
+
+ if (!(PVE::JSONSchema::pve_verify_cidrv4($cidr, 1) ||
+ PVE::JSONSchema::pve_verify_cidrv6($cidr, 1)))
+ {
+ return undef if $noerr;
+ die "value does not look like a valid CIDR network\n";
+ }
+ return $id;
+}
+
+my $defaultData = {
+
+ propertyList => {
+ subnet => get_standard_option('pve-sdn-subnet-id',
+ { completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnet }),
+ },
+};
+
+sub type {
+ return 'subnet';
+}
+
+sub private {
+ return $defaultData;
+}
+
+sub properties {
+ return {
+ gateway => {
+ type => 'string', format => 'ip',
+ description => "Subnet Gateway: Will be assign on vnet for layer3 zones",
+ },
+ snat => {
+ 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_driver => {
+ type => 'string',
+ description => "use a specific ipam",
+ },
+ };
+}
+
+sub options {
+ return {
+ gateway => { optional => 1 },
+ routes => { optional => 1 },
+ nameservers => { optional => 1 },
+ searchdomain => { optional => 1 },
+ snat => { optional => 1 },
+ dhcp => { optional => 1 },
+ dns_driver => { optional => 1 },
+ ipam_driver => { optional => 1 },
+ };
+}
+
+sub on_update_hook {
+ my ($class, $subnetid, $subnet_cfg) = @_;
+
+ my $subnet = $subnetid =~ s/-/\//r;
+ my $subnet_matcher = subnet_matcher($subnet);
+
+ my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
+ raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+}
+
+1;
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
new file mode 100644
index 0000000..454a9cf
--- /dev/null
+++ b/PVE/Network/SDN/Subnets.pm
@@ -0,0 +1,55 @@
+package PVE::Network::SDN::Subnets;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+
+use PVE::Network::SDN::SubnetPlugin;
+PVE::Network::SDN::SubnetPlugin->register();
+PVE::Network::SDN::SubnetPlugin->init();
+
+sub sdn_subnets_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn subnet ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/subnets.cfg");
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/subnets.cfg", $cfg);
+}
+
+sub sdn_subnets_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_subnet {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg) ];
+}
+
+sub get_subnet {
+ my ($subnetid) = @_;
+
+ my $cfg = PVE::Network::SDN::Subnets::config();
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
+ return $subnet;
+}
+
+1;
diff --git a/debian/control b/debian/control
index afdf573..8b67d74 100644
--- a/debian/control
+++ b/debian/control
@@ -16,6 +16,7 @@ Breaks: pve-manager (<< 5.2-12)
Depends: libpve-common-perl (>= 5.0-45),
perl (>= 5.6.0-16),
pve-cluster (>= 5.0-32),
+ libnet-subnet-perl,
${misc:Depends},
${perl:Depends},
Recommends: frr-pythontools, ifupdown2
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 02/10] vnets: add subnets
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 01/10] add subnet plugin Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 03/10] add subnets verifications hooks Alexandre Derumier
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/Network/SDN/VnetPlugin.pm | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 384358c..47ca50b 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -68,16 +68,11 @@ sub properties {
description => "alias name of the vnet",
optional => 1,
},
- ipv4 => {
- description => "Anycast router ipv4 address.",
- type => 'string', format => 'CIDRv4',
- optional => 1,
- },
- ipv6 => {
- description => "Anycast router ipv6 address.",
- type => 'string', format => 'CIDRv6',
+ subnets => {
+ type => 'string',
+ description => "Subnets list",
optional => 1,
- },
+ },
mac => {
type => 'string',
description => "Anycast router mac address",
@@ -91,8 +86,7 @@ sub options {
zone => { optional => 0},
tag => { optional => 1},
alias => { optional => 1 },
- ipv4 => { optional => 1 },
- ipv6 => { optional => 1 },
+ subnets => { optional => 1 },
mac => { optional => 1 },
vlanaware => { optional => 1 },
};
@@ -105,7 +99,7 @@ sub on_delete_hook {
}
sub on_update_hook {
- my ($class, $vnetid, $vnet_cfg) = @_;
+ my ($class, $vnetid, $vnet_cfg, $subnet_cfg) = @_;
# verify that tag is not already defined in another vnet
if (defined($vnet_cfg->{ids}->{$vnetid}->{tag})) {
my $tag = $vnet_cfg->{ids}->{$vnetid}->{tag};
@@ -117,6 +111,10 @@ sub on_update_hook {
}
}
}
+ #verify subnet
+ my $subnets = $vnet_cfg->{ids}->{$vnetid}->{subnets};
+ my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $plugin_config->{'peers'};
+
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 03/10] add subnets verifications hooks
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 01/10] add subnet plugin Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 02/10] vnets: add subnets Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 04/10] zones: simple|evpn: add gateway ip from subnets to vnet Alexandre Derumier
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN/Subnets.pm | 5 ++++-
PVE/API2/Network/SDN/Vnets.pm | 9 +++++++--
PVE/Network/SDN/SubnetPlugin.pm | 15 +++++++++++++++
PVE/Network/SDN/VnetPlugin.pm | 8 +++++---
4 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 26b2aa5..3ef1d11 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -9,6 +9,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file);
use PVE::Network::SDN;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::SubnetPlugin;
+use PVE::Network::SDN::Vnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -204,9 +205,11 @@ __PACKAGE__->register_method ({
my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
- my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
PVE::Network::SDN::increase_version();
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index c5860c8..23bc8bb 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -11,6 +11,7 @@ use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::VnetPlugin;
+use PVE::Network::SDN::Subnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -132,7 +133,9 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->verify_tag($opts->{tag});
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
PVE::Network::SDN::increase_version();
@@ -173,7 +176,9 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->verify_tag($opts->{tag});
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
PVE::Network::SDN::increase_version();
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 8900681..1b790a6 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -112,4 +112,19 @@ sub on_update_hook {
raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
}
+sub on_delete_hook {
+ my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
+
+ #verify if vnets have subnet
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ my $vnet = $vnet_cfg->{ids}->{$id};
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $subnet eq $subnetid;
+ }
+ }
+
+ return;
+}
+
1;
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 47ca50b..430b3bf 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -111,10 +111,12 @@ sub on_update_hook {
}
}
}
- #verify subnet
- my $subnets = $vnet_cfg->{ids}->{$vnetid}->{subnets};
- my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $plugin_config->{'peers'};
+ #verify subnet
+ my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $vnet_cfg->{ids}->{$vnetid}->{subnets};
+ foreach my $subnet (@subnets) {
+ raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$subnet};
+ }
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 04/10] zones: simple|evpn: add gateway ip from subnets to vnet
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (2 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 03/10] add subnets verifications hooks Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 05/10] zone: add vnet_update_hook Alexandre Derumier
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/Network/SDN/Zones.pm | 4 +++-
PVE/Network/SDN/Zones/EvpnPlugin.pm | 11 ++++++++---
PVE/Network/SDN/Zones/Plugin.pm | 2 +-
PVE/Network/SDN/Zones/QinQPlugin.pm | 2 +-
PVE/Network/SDN/Zones/SimplePlugin.pm | 11 ++++++++---
PVE/Network/SDN/Zones/VlanPlugin.pm | 2 +-
PVE/Network/SDN/Zones/VxlanPlugin.pm | 8 +-------
7 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index 143d6e5..25af088 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -11,6 +11,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Network;
use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Zones::VlanPlugin;
use PVE::Network::SDN::Zones::QinQPlugin;
use PVE::Network::SDN::Zones::VxlanPlugin;
@@ -78,6 +79,7 @@ sub generate_etc_network_config {
my $version = PVE::Cluster::cfs_read_file('sdn/.version');
my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
my $zone_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
return if !$vnet_cfg && !$zone_cfg;
@@ -112,7 +114,7 @@ sub generate_etc_network_config {
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
eval {
- $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $controller, $interfaces_config, $config);
+ $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $controller, $subnet_cfg, $interfaces_config, $config);
};
if (my $err = $@) {
warn "zone $zone : vnet $id : $err\n";
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index a916579..83ceb3a 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -38,7 +38,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $tag = $vnet->{tag};
my $alias = $vnet->{alias};
@@ -72,8 +72,13 @@ sub generate_sdn_config {
#vnet bridge
@iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
+
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ next if !defined($subnet_cfg->{ids}->{$subnet});
+ push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ }
+
push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports $vxlan_iface";
push @iface_config, "bridge_stp off";
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index d96e069..451699f 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -94,7 +94,7 @@ sub parse_section_header {
}
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
die "please implement inside plugin";
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index b39732a..5fffd15 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -45,7 +45,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $stag = $plugin_config->{tag};
my $mtu = $plugin_config->{mtu};
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 6137062..312dcbf 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -20,7 +20,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
return $config if$config->{$vnetid}; # nothing to do
@@ -32,8 +32,13 @@ sub generate_sdn_config {
# vnet bridge
my @iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
+
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ next if !defined($subnet_cfg->{ids}->{$subnet});
+ push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ }
+
push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports none";
push @iface_config, "bridge_stp off";
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index db719a0..8485ae1 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -39,7 +39,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $bridge = $plugin_config->{bridge};
die "can't find bridge $bridge" if !-d "/sys/class/net/$bridge";
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index a256268..8386c43 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -43,13 +43,10 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $tag = $vnet->{tag};
my $alias = $vnet->{alias};
- my $ipv4 = $vnet->{ipv4};
- my $ipv6 = $vnet->{ipv6};
- my $mac = $vnet->{mac};
my $multicastaddress = $plugin_config->{'multicast-address'};
my @peers;
@peers = PVE::Tools::split_list($plugin_config->{'peers'}) if $plugin_config->{'peers'};
@@ -78,9 +75,6 @@ sub generate_sdn_config {
#vnet bridge
@iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
- push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports $vxlan_iface";
push @iface_config, "bridge_stp off";
push @iface_config, "bridge_fd 0";
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 05/10] zone: add vnet_update_hook
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (3 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 04/10] zones: simple|evpn: add gateway ip from subnets to vnet Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 06/10] vnets: subnets: use cidr Alexandre Derumier
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
move verify_tag code in this hook
add mac address generation for simple && evpn plugin
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN/Vnets.pm | 4 ++--
PVE/Network/SDN/Zones/EvpnPlugin.pm | 19 +++++++++++++++----
PVE/Network/SDN/Zones/Plugin.pm | 5 +++--
PVE/Network/SDN/Zones/QinQPlugin.pm | 8 ++++----
PVE/Network/SDN/Zones/SimplePlugin.pm | 14 +++++++++++---
PVE/Network/SDN/Zones/VlanPlugin.pm | 8 ++++----
PVE/Network/SDN/Zones/VxlanPlugin.pm | 8 ++++----
7 files changed, 43 insertions(+), 23 deletions(-)
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 23bc8bb..58ec21f 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -131,7 +131,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->verify_tag($opts->{tag});
+ $plugin->vnet_update_hook($cfg->{ids}->{$id});
my $subnet_cfg = PVE::Network::SDN::Subnets::config();
@@ -174,7 +174,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->verify_tag($opts->{tag});
+ $plugin->vnet_update_hook($cfg->{ids}->{$id});
my $subnet_cfg = PVE::Network::SDN::Subnets::config();
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 83ceb3a..0ebe13e 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -5,6 +5,9 @@ use warnings;
use PVE::Network::SDN::Zones::VxlanPlugin;
use PVE::Tools qw($IPV4RE);
use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
use PVE::Network::SDN::Controllers::EvpnPlugin;
use base('PVE::Network::SDN::Zones::VxlanPlugin');
@@ -143,15 +146,23 @@ sub on_update_hook {
die "vrf-vxlan $vrfvxlan is already declared in $id"
if (defined($zone_cfg->{ids}->{$id}->{'vrf-vxlan'}) && $zone_cfg->{ids}->{$id}->{'vrf-vxlan'} eq $vrfvxlan);
}
+
}
-sub verify_tag {
- my ($class, $tag) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
+
+ if (!defined($vnet->{mac})) {
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $vnet->{mac} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ }
}
+
1;
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index 451699f..7f6db0e 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -139,8 +139,9 @@ sub on_update_hook {
# do nothing by default
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
# do nothing by default
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index 5fffd15..c828af4 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -211,11 +211,11 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vlan tag max value is 4096"}) if $tag > 4096;
+ raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
}
1;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 312dcbf..7006b13 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -4,6 +4,8 @@ use strict;
use warnings;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Exception qw(raise raise_param_exc);
+use PVE::Cluster;
+use PVE::Tools;
use base('PVE::Network::SDN::Zones::Plugin');
@@ -71,10 +73,16 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
- raise_param_exc({ tag => "vlan tag is not allowed on simple bridge"}) if defined($tag);
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
+ raise_param_exc({ tag => "vlan tag is not allowed on simple bridge"}) if defined($vnet->{tag});
+
+ if (!defined($vnet->{mac})) {
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $vnet->{mac} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ }
}
1;
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index 8485ae1..7f90d31 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -170,11 +170,11 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vlan tag max value is 4096"}) if $tag > 4096;
+ raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
}
1;
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 8386c43..79af054 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -89,11 +89,11 @@ sub generate_sdn_config {
return $config;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 06/10] vnets: subnets: use cidr
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (4 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 05/10] zone: add vnet_update_hook Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 07/10] subnet: fix on_delete_hook Alexandre Derumier
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/Network/SDN/SubnetPlugin.pm | 3 ++-
PVE/Network/SDN/VnetPlugin.pm | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 1b790a6..c555314 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -120,7 +120,8 @@ sub on_delete_hook {
my $vnet = $vnet_cfg->{ids}->{$id};
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
foreach my $subnet (@subnets) {
- raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $subnet eq $subnetid;
+ my $id = $subnet =~ s/\//-/r;
+ raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $id eq $subnetid;
}
}
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 430b3bf..6b2bcc8 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -115,7 +115,8 @@ sub on_update_hook {
#verify subnet
my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $vnet_cfg->{ids}->{$vnetid}->{subnets};
foreach my $subnet (@subnets) {
- raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$subnet};
+ my $id = $subnet =~ s/\//-/r;
+ raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$id};
}
}
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 07/10] subnet: fix on_delete_hook
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (5 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 06/10] vnets: subnets: use cidr Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 08/10] api2: subnet create: convert cidr to subnetid Alexandre Derumier
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/Network/SDN/SubnetPlugin.pm | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index c555314..ea47684 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -116,12 +116,12 @@ sub on_delete_hook {
my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
#verify if vnets have subnet
- foreach my $id (keys %{$vnet_cfg->{ids}}) {
- my $vnet = $vnet_cfg->{ids}->{$id};
+ 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 $id"}) if $id eq $subnetid;
+ raise_param_exc({ subnet => "$subnet is attached to vnet $vnetid"}) if $id eq $subnetid;
}
}
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 08/10] api2: subnet create: convert cidr to subnetid
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (6 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 07/10] subnet: fix on_delete_hook Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 09/10] api2: increase version on apply/reload only Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 10/10] add ipams plugins Alexandre Derumier
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN/Subnets.pm | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 3ef1d11..d18cf90 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -24,6 +24,7 @@ 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;
@@ -112,7 +113,8 @@ __PACKAGE__->register_method ({
my ($param) = @_;
my $type = extract_param($param, 'type');
- my $id = extract_param($param, 'subnet');
+ my $cidr = extract_param($param, 'subnet');
+ my $id = $cidr =~ s/\//-/r;
# create /etc/pve/sdn directory
PVE::Cluster::check_cfs_quorum();
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 09/10] api2: increase version on apply/reload only
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (7 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 08/10] api2: subnet create: convert cidr to subnetid Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 10/10] add ipams plugins Alexandre Derumier
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN.pm | 3 +++
PVE/API2/Network/SDN/Controllers.pm | 6 ------
PVE/API2/Network/SDN/Subnets.pm | 3 ---
PVE/API2/Network/SDN/Vnets.pm | 3 ---
PVE/API2/Network/SDN/Zones.pm | 6 ------
5 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 38af746..175f76f 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -10,6 +10,7 @@ use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::SafeSyslog;
use PVE::Tools qw(run_command);
+use PVE::Network::SDN;
use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
@@ -111,6 +112,8 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
+ PVE::Network::SDN::increase_version();
+
my $code = sub {
$rpcenv->{type} = 'priv'; # to start tasks in background
PVE::Cluster::check_cfs_quorum();
diff --git a/PVE/API2/Network/SDN/Controllers.pm b/PVE/API2/Network/SDN/Controllers.pm
index 9bc3075..919d343 100644
--- a/PVE/API2/Network/SDN/Controllers.pm
+++ b/PVE/API2/Network/SDN/Controllers.pm
@@ -152,8 +152,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Controllers::write_config($controller_cfg);
- PVE::Network::SDN::increase_version();
-
}, "create sdn controller object failed");
return undef;
@@ -196,8 +194,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Controllers::write_config($controller_cfg);
- PVE::Network::SDN::increase_version();
-
}, "update sdn controller object failed");
@@ -243,8 +239,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Controllers::write_config($cfg);
- PVE::Network::SDN::increase_version();
-
}, "delete sdn controller object failed");
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index d18cf90..d9cb9e9 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -134,7 +134,6 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "create sdn subnet object failed");
@@ -170,7 +169,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "update sdn subnet object failed");
@@ -213,7 +211,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "delete sdn subnet object failed");
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 58ec21f..b585c9c 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -138,7 +138,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "create sdn vnet object failed");
@@ -181,7 +180,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "update sdn vnet object failed");
@@ -221,7 +219,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "delete sdn vnet object failed");
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index f629f43..a37df3d 100644
--- a/PVE/API2/Network/SDN/Zones.pm
+++ b/PVE/API2/Network/SDN/Zones.pm
@@ -161,8 +161,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Zones::write_config($zone_cfg);
- PVE::Network::SDN::increase_version();
-
}, "create sdn zone object failed");
return undef;
@@ -206,8 +204,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Zones::write_config($zone_cfg);
- PVE::Network::SDN::increase_version();
-
}, "update sdn zone object failed");
return undef;
@@ -252,8 +248,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Zones::write_config($cfg);
- PVE::Network::SDN::increase_version();
-
}, "delete sdn zone object failed");
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [pve-devel] [PATCH v2 pve-network 10/10] add ipams plugins
2020-07-15 13:02 [pve-devel] [PATCH v2 pve-network 00/10] sdn : add subnets management Alexandre Derumier
` (8 preceding siblings ...)
2020-07-15 13:02 ` [pve-devel] [PATCH v2 pve-network 09/10] api2: increase version on apply/reload only Alexandre Derumier
@ 2020-07-15 13:02 ` Alexandre Derumier
9 siblings, 0 replies; 11+ messages in thread
From: Alexandre Derumier @ 2020-07-15 13:02 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Network/SDN.pm | 7 +
PVE/API2/Network/SDN/Ipams.pm | 241 +++++++++++++++++++++++++
PVE/API2/Network/SDN/Makefile | 2 +-
PVE/API2/Network/SDN/Subnets.pm | 47 ++++-
PVE/Network/SDN/Ipams.pm | 78 ++++++++
PVE/Network/SDN/Ipams/Makefile | 8 +
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 169 +++++++++++++++++
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 189 +++++++++++++++++++
PVE/Network/SDN/Ipams/Plugin.pm | 127 +++++++++++++
PVE/Network/SDN/Makefile | 3 +-
PVE/Network/SDN/SubnetPlugin.pm | 5 +-
PVE/Network/SDN/Vnets.pm | 25 +++
12 files changed, 895 insertions(+), 6 deletions(-)
create mode 100644 PVE/API2/Network/SDN/Ipams.pm
create mode 100644 PVE/Network/SDN/Ipams.pm
create mode 100644 PVE/Network/SDN/Ipams/Makefile
create mode 100644 PVE/Network/SDN/Ipams/NetboxPlugin.pm
create mode 100644 PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
create mode 100644 PVE/Network/SDN/Ipams/Plugin.pm
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 175f76f..6055fe5 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -16,6 +16,7 @@ use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
use PVE::API2::Network::SDN::Zones;
use PVE::API2::Network::SDN::Subnets;
+use PVE::API2::Network::SDN::Ipams;
use base qw(PVE::RESTHandler);
@@ -39,6 +40,11 @@ __PACKAGE__->register_method ({
path => 'subnets',
});
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Network::SDN::Ipams",
+ path => 'ipams',
+});
+
__PACKAGE__->register_method({
name => 'index',
path => '',
@@ -69,6 +75,7 @@ __PACKAGE__->register_method({
{ id => 'zones' },
{ id => 'controllers' },
{ id => 'subnets' },
+ { id => 'ipams' },
];
return $res;
diff --git a/PVE/API2/Network/SDN/Ipams.pm b/PVE/API2/Network/SDN/Ipams.pm
new file mode 100644
index 0000000..f8665a1
--- /dev/null
+++ b/PVE/API2/Network/SDN/Ipams.pm
@@ -0,0 +1,241 @@
+package PVE::API2::Network::SDN::Ipams;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::Tools qw(extract_param);
+use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Network::SDN;
+use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Ipams::Plugin;
+use PVE::Network::SDN::Ipams::PhpIpamPlugin;
+use PVE::Network::SDN::Ipams::NetboxPlugin;
+
+use Storable qw(dclone);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::RPCEnvironment;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my $sdn_ipams_type_enum = PVE::Network::SDN::Ipams::Plugin->lookup_types();
+
+my $api_sdn_ipams_config = sub {
+ my ($cfg, $id) = @_;
+
+ my $scfg = dclone(PVE::Network::SDN::Ipams::sdn_ipams_config($cfg, $id));
+ $scfg->{ipam} = $id;
+ $scfg->{digest} = $cfg->{digest};
+
+ return $scfg;
+};
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => "SDN ipams index.",
+ permissions => {
+ description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/ipams/<ipam>'",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ type => {
+ description => "Only list sdn ipams of specific type",
+ type => 'string',
+ enum => $sdn_ipams_type_enum,
+ optional => 1,
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => { ipam => { type => 'string'},
+ type => { type => 'string'},
+ },
+ },
+ links => [ { rel => 'child', href => "{ipam}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ my @sids = PVE::Network::SDN::Ipams::sdn_ipams_ids($cfg);
+ my $res = [];
+ foreach my $id (@sids) {
+ my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
+ next if !$rpcenv->check_any($authuser, "/sdn/ipams/$id", $privs, 1);
+
+ my $scfg = &$api_sdn_ipams_config($cfg, $id);
+ next if $param->{type} && $param->{type} ne $scfg->{type};
+
+ my $plugin_config = $cfg->{ids}->{$id};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ push @$res, $scfg;
+ }
+
+ return $res;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'read',
+ path => '{ipam}',
+ method => 'GET',
+ description => "Read sdn ipam configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams/{ipam}', ['SDN.Allocate']],
+ },
+
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ ipam => get_standard_option('pve-sdn-ipam-id'),
+ },
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ return &$api_sdn_ipams_config($cfg, $param->{ipam});
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ path => '',
+ method => 'POST',
+ description => "Create a new sdn ipam object.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Ipams::Plugin->createSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $type = extract_param($param, 'type');
+ my $id = extract_param($param, 'ipam');
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($type);
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ # create /etc/pve/sdn directory
+ PVE::Cluster::check_cfs_quorum();
+ mkdir("/etc/pve/sdn");
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $controller_cfg = PVE::Network::SDN::Controllers::config();
+
+ my $scfg = undef;
+ if ($scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($ipam_cfg, $id, 1)) {
+ die "sdn ipam object ID '$id' already defined\n";
+ }
+
+ $ipam_cfg->{ids}->{$id} = $opts;
+
+ PVE::Network::SDN::Ipams::write_config($ipam_cfg);
+
+ }, "create sdn ipam object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ path => '{ipam}',
+ method => 'PUT',
+ description => "Update sdn ipam object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Ipams::Plugin->updateSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'ipam');
+ my $digest = extract_param($param, 'digest');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+
+ PVE::SectionConfig::assert_if_modified($ipam_cfg, $digest);
+
+ my $scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($ipam_cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($scfg->{type});
+ my $opts = $plugin->check_config($id, $param, 0, 1);
+
+ foreach my $k (%$opts) {
+ $scfg->{$k} = $opts->{$k};
+ }
+
+ PVE::Network::SDN::Ipams::write_config($ipam_cfg);
+
+ }, "update sdn ipam object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{ipam}',
+ method => 'DELETE',
+ description => "Delete sdn ipam object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ ipam => get_standard_option('pve-sdn-ipam-id', {
+ completion => \&PVE::Network::SDN::Ipams::complete_sdn_ipams,
+ }),
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'ipam');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ my $scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($scfg->{type});
+
+ my $vnet_cfg = PVE::Network::SDN::Vnets::config();
+
+ delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::Ipams::write_config($cfg);
+
+ }, "delete sdn zone object failed");
+
+ return undef;
+ }});
+
+1;
diff --git a/PVE/API2/Network/SDN/Makefile b/PVE/API2/Network/SDN/Makefile
index 59626fa..1117dfa 100644
--- a/PVE/API2/Network/SDN/Makefile
+++ b/PVE/API2/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm
+SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index d9cb9e9..b60db3d 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -6,10 +6,13 @@ use warnings;
use PVE::SafeSyslog;
use PVE::Tools qw(extract_param);
use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Exception qw(raise raise_param_exc);
use PVE::Network::SDN;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::SubnetPlugin;
use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Ipams::Plugin;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -133,6 +136,17 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
+ $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
+ }
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "create sdn subnet object failed");
@@ -161,6 +175,7 @@ __PACKAGE__->register_method ({
sub {
my $cfg = PVE::Network::SDN::Subnets::config();
+ my $scfg = &$api_sdn_subnets_config($cfg, $id);
PVE::SectionConfig::assert_if_modified($cfg, $digest);
@@ -168,6 +183,24 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
+
+ if($opts->{gateway} && $scfg->{gateway} && $opts->{gateway} ne $scfg->{gateway}) {
+ $plugin->del_ip($plugin_config, $scfg->{gateway});
+ }
+ if (!defined($opts->{gateway}) && $scfg->{gateway}) {
+ $plugin->del_ip($plugin_config, $scfg->{gateway});
+ }
+ $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
+ }
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "update sdn subnet object failed");
@@ -200,7 +233,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::lock_sdn_config(
sub {
-
my $cfg = PVE::Network::SDN::Subnets::config();
my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
@@ -208,8 +240,19 @@ __PACKAGE__->register_method ({
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
my $vnets_cfg = PVE::Network::SDN::Vnets::config();
- delete $cfg->{ids}->{$id};
PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->del_subnet($plugin_config, $id, $scfg);
+ }
+
+ delete $cfg->{ids}->{$id};
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "delete sdn subnet object failed");
diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm
new file mode 100644
index 0000000..3d33632
--- /dev/null
+++ b/PVE/Network/SDN/Ipams.pm
@@ -0,0 +1,78 @@
+package PVE::Network::SDN::Ipams;
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use JSON;
+
+use PVE::Tools qw(extract_param dir_glob_regex run_command);
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network;
+
+use PVE::Network::SDN::Ipams::NetboxPlugin;
+use PVE::Network::SDN::Ipams::PhpIpamPlugin;
+use PVE::Network::SDN::Ipams::Plugin;
+
+PVE::Network::SDN::Ipams::NetboxPlugin->register();
+PVE::Network::SDN::Ipams::PhpIpamPlugin->register();
+PVE::Network::SDN::Ipams::Plugin->init();
+
+
+sub sdn_ipams_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn ipam ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn '$id' does not exist\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/ipams.cfg");
+ return $config;
+}
+
+sub get_plugin_config {
+ my ($vnet) = @_;
+ my $ipamid = $vnet->{ipam};
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ return $ipam_cfg->{ids}->{$ipamid};
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/ipams.cfg", $cfg);
+}
+
+sub sdn_ipams_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_vnet {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_ipams_ids($cfg) ];
+}
+
+sub next_free_ip {
+ my ($subnetid, $subnet) = @_;
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipamid = $subnet->{ipam};
+ return if !$ipamid;
+
+ my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ my $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ return $ip;
+}
+1;
+
diff --git a/PVE/Network/SDN/Ipams/Makefile b/PVE/Network/SDN/Ipams/Makefile
new file mode 100644
index 0000000..884c47a
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/Makefile
@@ -0,0 +1,8 @@
+SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm
+
+
+PERL5DIR=${DESTDIR}/usr/share/perl5
+
+.PHONY: install
+install:
+ for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/Ipams/$$i; done
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
new file mode 100644
index 0000000..ccc1184
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -0,0 +1,169 @@
+package PVE::Network::SDN::Ipams::NetboxPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
+use base('PVE::Network::SDN::Ipams::Plugin');
+
+sub type {
+ return 'netbox';
+}
+
+sub properties {
+ return {
+ };
+}
+
+sub options {
+
+ return {
+ url => { optional => 0},
+ token => { optional => 0 },
+ };
+}
+
+# Plugin implementation
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $gateway = $subnet->{gateway};
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $internalid = get_prefix_id($url, $cidr, $headers);
+
+ #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: $@";
+ }
+ }
+
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $gateway = $subnet->{gateway};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ 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, $gateway) if $gateway;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers);
+ };
+ if ($@) {
+ die "error deleting subnet from ipam: $@";
+ }
+
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+
+ my ($network, $mask) = split(/-/, $subnetid);
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $params = { address => "$ip/$mask" };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/ip-addresses/", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add subnet ip to ipam: ip already exist: $@";
+ }
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $internalid = get_prefix_id($url, $cidr, $headers);
+
+ my $params = {};
+
+ my $ip = undef;
+ eval {
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/prefixes/$internalid/available-ips/", $headers, $params);
+ $ip = $result->{address};
+ };
+
+ if ($@) {
+ die "can't find free ip in subnet $cidr: $@";
+ }
+
+ return $ip;
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+
+ return if !$ip;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $ip_id = get_ip_id($url, $ip, $headers);
+ die "can't find ip $ip in ipam" if !$ip_id;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers);
+ };
+ if ($@) {
+ die "error delete ip $ip";
+ }
+}
+
+#helpers
+
+sub get_prefix_id {
+ my ($url, $cidr, $headers) = @_;
+
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/ipam/prefixes/?q=$cidr", $headers);
+ my $data = @{$result->{results}}[0];
+ my $internalid = $data->{id};
+ return $internalid;
+}
+
+sub get_ip_id {
+ my ($url, $ip, $headers) = @_;
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers);
+ my $data = @{$result->{results}}[0];
+ my $ip_id = $data->{id};
+ return $ip_id;
+}
+
+
+1;
+
+
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
new file mode 100644
index 0000000..7380bf3
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -0,0 +1,189 @@
+package PVE::Network::SDN::Ipams::PhpIpamPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
+use base('PVE::Network::SDN::Ipams::Plugin');
+
+sub type {
+ return 'phpipam';
+}
+
+sub properties {
+ return {
+ url => {
+ type => 'string',
+ },
+ token => {
+ type => 'string',
+ },
+ section => {
+ type => 'integer',
+ },
+ };
+}
+
+sub options {
+
+ return {
+ url => { optional => 0},
+ token => { optional => 0 },
+ section => { optional => 0 },
+ };
+}
+
+# Plugin implementation
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $gateway = $subnet->{gateway};
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ #search subnet
+ my $internalid = get_internalid($url, $cidr, $headers);
+
+ #create subnet
+ if (!$internalid) {
+ my ($network, $mask) = split(/-/, $subnetid);
+
+ my $params = { subnet => $network,
+ mask => $mask,
+ sectionId => $section,
+ };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/subnets/", $headers, $params);
+ };
+ if ($@) {
+ die "error add subnet to ipam: $@";
+ }
+ }
+
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $internalid = get_internalid($url, $cidr, $headers);
+ return if !$internalid;
+
+ #fixme: check that prefix is empty exluding gateway, before delete
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/subnets/$internalid", $headers);
+ };
+ if ($@) {
+ die "error deleting subnet from ipam: $@";
+ }
+
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $internalid = get_internalid($url, $cidr, $headers);
+
+ my $params = { ip => $ip,
+ subnetId => $internalid,
+ is_gateway => $is_gateway,
+ };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/addresses/", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add subnet ip to ipam: ip $ip already exist: $@";
+ }
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config, $subnetid, $subnet, $internalid, $hostname) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ $internalid = get_internalid($url, $cidr, $headers) if !$internalid;
+
+ my $params = {};
+
+ my $ip = undef;
+ eval {
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/addresses/first_free/$internalid/", $headers, $params);
+ $ip = $result->{data};
+ };
+
+ if ($@) {
+ die "can't find free ip in subnet $cidr: $@";
+ }
+
+ my ($network, $mask) = split(/-/, $subnetid);
+ return "$ip/$mask";
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+
+ return if !$ip;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $ip_id = get_ip_id($url, $ip, $headers);
+ return if !$ip_id;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/addresses/$ip_id", $headers);
+ };
+ if ($@) {
+ die "error delete ip $ip";
+ }
+}
+
+
+#helpers
+
+sub get_internalid {
+ my ($url, $cidr, $headers) = @_;
+
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/subnets/cidr/$cidr", $headers);
+ my $data = @{$result->{data}}[0];
+ my $internalid = $data->{id};
+ return $internalid;
+}
+
+sub get_ip_id {
+ my ($url, $ip, $headers) = @_;
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/addresses/search/$ip", $headers);
+ my $data = @{$result->{data}}[0];
+ my $ip_id = $data->{id};
+ return $ip_id;
+}
+
+1;
+
+
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
new file mode 100644
index 0000000..8a44090
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -0,0 +1,127 @@
+package PVE::Network::SDN::Ipams::Plugin;
+
+use strict;
+use warnings;
+
+use PVE::Tools qw(run_command);
+use PVE::JSONSchema;
+use PVE::Cluster;
+use HTTP::Request;
+use LWP::UserAgent;
+use JSON;
+
+use Data::Dumper;
+use PVE::JSONSchema qw(get_standard_option);
+use base qw(PVE::SectionConfig);
+
+PVE::Cluster::cfs_register_file('sdn/ipams.cfg',
+ sub { __PACKAGE__->parse_config(@_); },
+ sub { __PACKAGE__->write_config(@_); });
+
+PVE::JSONSchema::register_standard_option('pve-sdn-ipam-id', {
+ description => "The SDN ipam object identifier.",
+ type => 'string', format => 'pve-sdn-ipam-id',
+});
+
+PVE::JSONSchema::register_format('pve-sdn-ipam-id', \&parse_sdn_ipam_id);
+sub parse_sdn_ipam_id {
+ my ($id, $noerr) = @_;
+
+ if ($id !~ m/^[a-z][a-z0-9]*[a-z0-9]$/i) {
+ return undef if $noerr;
+ die "ipam ID '$id' contains illegal characters\n";
+ }
+ return $id;
+}
+
+my $defaultData = {
+
+ propertyList => {
+ type => {
+ description => "Plugin type.",
+ type => 'string', format => 'pve-configid',
+ type => 'string',
+ },
+ ipam => get_standard_option('pve-sdn-ipam-id',
+ { completion => \&PVE::Network::SDN::Ipams::complete_sdn_ipam }),
+ },
+};
+
+sub private {
+ return $defaultData;
+}
+
+sub parse_section_header {
+ my ($class, $line) = @_;
+
+ if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+ my ($type, $id) = (lc($1), $2);
+ my $errmsg = undef; # set if you want to skip whole section
+ eval { PVE::JSONSchema::pve_verify_configid($type); };
+ $errmsg = $@ if $@;
+ my $config = {}; # to return additional attributes
+ return ($type, $id, $errmsg, $config);
+ }
+ return undef;
+}
+
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $subnet, $internalid, $ip, $hostname, $is_gateway) = @_;
+
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config) = @_;
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+}
+
+
+#helpers
+sub api_request {
+ my ($method, $url, $headers, $data) = @_;
+
+ my $encoded_data = to_json($data) if $data;
+
+ my $req = HTTP::Request->new($method,$url, $headers, $encoded_data);
+
+ my $ua = LWP::UserAgent->new(protocols_allowed => ['http', 'https'], timeout => 30);
+ my $proxy = undef;
+
+ if ($proxy) {
+ $ua->proxy(['http', 'https'], $proxy);
+ } else {
+ $ua->env_proxy;
+ }
+
+ $ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00);
+
+ my $response = $ua->request($req);
+ my $code = $response->code;
+
+ if ($code !~ /2(\d+)$/) {
+ my $msg = $response->message || 'unknown';
+ die "Invalid response from server: $code $msg\n";
+ }
+
+ my $raw = '';
+ if (defined($response->decoded_content)) {
+ $raw = $response->decoded_content;
+ } else {
+ $raw = $response->content;
+ }
+ return from_json($raw) if $raw ne '';
+}
+
+1;
diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile
index 59f8c34..fb68856 100644
--- a/PVE/Network/SDN/Makefile
+++ b/PVE/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm
+SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
@@ -8,4 +8,5 @@ install:
for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/$$i; done
make -C Controllers install
make -C Zones install
+ make -C Ipams install
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index ea47684..6224065 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -82,7 +82,7 @@ sub properties {
type => 'string',
description => "Develop some dns registrations plugins (powerdns,...)",
},
- ipam_driver => {
+ ipam => {
type => 'string',
description => "use a specific ipam",
},
@@ -98,7 +98,7 @@ sub options {
snat => { optional => 1 },
dhcp => { optional => 1 },
dns_driver => { optional => 1 },
- ipam_driver => { optional => 1 },
+ ipam => { optional => 1 },
};
}
@@ -110,6 +110,7 @@ sub on_update_hook {
my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+
}
sub on_delete_hook {
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 073ab80..d474037 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -4,6 +4,8 @@ use strict;
use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network::SDN::Subnets;
+use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::VnetPlugin;
PVE::Network::SDN::VnetPlugin->register();
@@ -52,4 +54,27 @@ sub get_vnet {
return $vnet;
}
+sub get_next_free_ip {
+ my ($vnetid) = @_;
+
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my $vnet = $vnets_cfg->{ids}->{$vnetid};
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $ip = undef;
+ foreach my $s (@subnets) {
+ my $subnetid = $s =~ s/\//-/r;
+ my $subnet = $subnets_cfg->{ids}->{$subnetid};
+ if ($subnet && $subnet->{ipam}) {
+ eval {
+ $ip = PVE::Network::SDN::Ipams::next_free_ip($subnetid, $subnet);
+ };
+ warn $@ if $@;
+ }
+ last if $ip;
+ }
+ die "can't find any ip" if !$ip;
+ return $ip;
+}
+
1;
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread