From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 13FDD63D40 for ; Mon, 5 Oct 2020 17:09:58 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0390A1CF99 for ; Mon, 5 Oct 2020 17:09:53 +0200 (CEST) Received: from kvmformation1.odiso.net (globalOdiso.M6Lille.odiso.net [89.248.211.242]) by firstgate.proxmox.com (Proxmox) with ESMTP id 658031C76F for ; Mon, 5 Oct 2020 17:09:14 +0200 (CEST) Received: by kvmformation1.odiso.net (Postfix, from userid 0) id EAC7EE89A7; Mon, 5 Oct 2020 17:09:13 +0200 (CEST) From: Alexandre Derumier To: pve-devel@lists.proxmox.com Date: Mon, 5 Oct 2020 17:08:48 +0200 Message-Id: <20201005150912.463000-12-aderumier@odiso.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201005150912.463000-1-aderumier@odiso.com> References: <20201005150912.463000-1-aderumier@odiso.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.393 Adjusted score from AWL reputation of From: address HEADER_FROM_DIFFERENT_DOMAINS 0.248 From and EnvelopeFrom 2nd level mail domains are different KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods KHOP_HELO_FCRDNS 0.398 Relay HELO differs from its IP's reverse DNS NO_DNS_FOR_FROM 0.379 Envelope sender has no MX or A DNS records SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pve-devel] [PATCH v10 pve-network 11/35] add pve internal ipam plugin X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Oct 2020 15:09:58 -0000 Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN/Ipams.pm | 1 + PVE/API2/Network/SDN/Subnets.pm | 4 +- PVE/Network/SDN/Ipams.pm | 2 + PVE/Network/SDN/Ipams/Makefile | 2 +- PVE/Network/SDN/Ipams/NetboxPlugin.pm | 4 +- PVE/Network/SDN/Ipams/PVEPlugin.pm | 166 +++++++++++++++++++++++++ PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 2 +- PVE/Network/SDN/Ipams/Plugin.pm | 2 +- debian/control | 1 + 9 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 PVE/Network/SDN/Ipams/PVEPlugin.pm diff --git a/PVE/API2/Network/SDN/Ipams.pm b/PVE/API2/Network/SDN/Ipams.pm index f8665a1..0d567c8 100644 --- a/PVE/API2/Network/SDN/Ipams.pm +++ b/PVE/API2/Network/SDN/Ipams.pm @@ -9,6 +9,7 @@ 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::PVEPlugin; use PVE::Network::SDN::Ipams::PhpIpamPlugin; use PVE::Network::SDN::Ipams::NetboxPlugin; diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm index b60db3d..094401c 100644 --- a/PVE/API2/Network/SDN/Subnets.pm +++ b/PVE/API2/Network/SDN/Subnets.pm @@ -193,10 +193,10 @@ __PACKAGE__->register_method ({ $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}); + $plugin->del_ip($plugin_config, $id, $scfg->{gateway}); } if (!defined($opts->{gateway}) && $scfg->{gateway}) { - $plugin->del_ip($plugin_config, $scfg->{gateway}); + $plugin->del_ip($plugin_config, $id, $scfg->{gateway}); } $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway}; } diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm index 3d33632..b634020 100644 --- a/PVE/Network/SDN/Ipams.pm +++ b/PVE/Network/SDN/Ipams.pm @@ -10,10 +10,12 @@ 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::PVEPlugin; use PVE::Network::SDN::Ipams::NetboxPlugin; use PVE::Network::SDN::Ipams::PhpIpamPlugin; use PVE::Network::SDN::Ipams::Plugin; +PVE::Network::SDN::Ipams::PVEPlugin->register(); PVE::Network::SDN::Ipams::NetboxPlugin->register(); PVE::Network::SDN::Ipams::PhpIpamPlugin->register(); PVE::Network::SDN::Ipams::Plugin->init(); diff --git a/PVE/Network/SDN/Ipams/Makefile b/PVE/Network/SDN/Ipams/Makefile index 884c47a..4e7d65f 100644 --- a/PVE/Network/SDN/Ipams/Makefile +++ b/PVE/Network/SDN/Ipams/Makefile @@ -1,4 +1,4 @@ -SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm +SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm index ccc1184..c25f451 100644 --- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm +++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm @@ -68,7 +68,7 @@ sub del_subnet { 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; + PVE::Network::SDN::Ipams::NetboxPlugin::del_ip($class, $plugin_config, $subnetid, $gateway) if $gateway; eval { PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers); @@ -125,7 +125,7 @@ sub add_next_freeip { } sub del_ip { - my ($class, $plugin_config, $ip) = @_; + my ($class, $plugin_config, $subnetid, $ip) = @_; return if !$ip; diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm new file mode 100644 index 0000000..0dfc8a4 --- /dev/null +++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm @@ -0,0 +1,166 @@ +package PVE::Network::SDN::Ipams::PVEPlugin; + +use strict; +use warnings; +use PVE::INotify; +use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file); +use PVE::Tools; +use JSON; +use Net::IP; +use Digest::SHA; + +use base('PVE::Network::SDN::Ipams::Plugin'); + + +my $ipamdb_file = "priv/ipam.db"; + +PVE::Cluster::cfs_register_file($ipamdb_file, + sub { PVE::Network::SDN::Ipams::PVEPlugin->parse_config(@_); }, + sub { PVE::Network::SDN::Ipams::PVEPlugin->write_config(@_); }); + +sub type { + return 'pve'; +} + +sub properties { +} + +sub options { +} + +# Plugin implementation + +sub add_subnet { + my ($class, $plugin_config, $subnetid, $subnet) = @_; + + my $cidr = $subnetid =~ s/-/\//r; + my $gateway = $subnet->{gateway}; + + cfs_lock_file($ipamdb_file, undef, sub { + my $config = read_db(); + #create subnet + if (!defined($config->{subnets}->{$cidr})) { + $config->{subnets}->{$cidr}->{ips} = {}; + write_db($config); + } + }); + die "$@" if $@; +} + +sub del_subnet { + my ($class, $plugin_config, $subnetid, $subnet) = @_; + + my $cidr = $subnetid =~ s/-/\//r; + + cfs_lock_file($ipamdb_file, undef, sub { + + my $db = read_db(); + my $ips = $db->{subnets}->{$cidr}->{ips}; + die "can't delete subnet, not empty" if keys %{$ips} > 0; + delete $db->{subnets}->{$cidr}; + write_db($db); + }); + die "$@" if $@; + +} + +sub add_ip { + my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_; + + my $cidr = $subnetid =~ s/-/\//r; + + cfs_lock_file($ipamdb_file, undef, sub { + + my $db = read_db(); + my $s = $db->{subnets}->{$cidr}; + + die "ip already exist" if defined($s->{ips}->{$ip}); + + #verify that ip is valid for this subnet + $s->{ips}->{$ip} = 1; + write_db($db); + }); + die "$@" if $@; +} + +sub add_next_freeip { + my ($class, $plugin_config, $subnetid, $subnet) = @_; + + my $cidr = $subnetid =~ s/-/\//r; + my $freeip = undef; + + cfs_lock_file($ipamdb_file, undef, sub { + + my $db = read_db(); + my $s = $db->{subnets}->{$cidr}; + + my $iplist = new Net::IP($cidr); + + while(1) { + my $ip = $iplist->ip(); + ++$iplist; + print "nextip: $ip\n"; + next if defined($s->{ips}->{$ip}); + $freeip = $ip; + last; + } + + die "can't find free ip in subnet $cidr" if !$freeip; + + $s->{ips}->{$freeip} = 1; + write_db($db); + }); + die "$@" if $@; + + my ($network, $mask) = split(/-/, $subnetid); + return "$freeip/$mask"; +} + +sub del_ip { + my ($class, $plugin_config, $subnetid, $ip) = @_; + + my $cidr = $subnetid =~ s/-/\//r; + + cfs_lock_file($ipamdb_file, undef, sub { + + my $db = read_db(); + my $s = $db->{subnets}->{$cidr}; + return if !$ip; + + die "ip does not exist in pam" if !defined($s->{ips}->{$ip}); + delete $s->{ips}->{$ip}; + write_db($db); + }); + die "$@" if $@; +} + +#helpers + +sub read_db { + my $db = cfs_read_file($ipamdb_file); + return $db; +} + +sub write_db { + my ($cfg) = @_; + + my $json = to_json($cfg); + cfs_write_file($ipamdb_file, $json); +} + +sub write_config { + my ($class, $filename, $cfg) = @_; + + return $cfg; +} + +sub parse_config { + my ($class, $filename, $raw) = @_; + + $raw = '{}' if !defined($raw) ||$raw eq ''; + my $cfg = from_json($raw); + + return $cfg; +} + +1; diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm index 7380bf3..d7ba3ed 100644 --- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm +++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm @@ -145,7 +145,7 @@ sub add_next_freeip { } sub del_ip { - my ($class, $plugin_config, $ip) = @_; + my ($class, $plugin_config, $subnetid, $ip) = @_; return if !$ip; diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm index 8a44090..fc736b8 100644 --- a/PVE/Network/SDN/Ipams/Plugin.pm +++ b/PVE/Network/SDN/Ipams/Plugin.pm @@ -84,7 +84,7 @@ sub add_next_freeip { } sub del_ip { - my ($class, $plugin_config, $ip) = @_; + my ($class, $plugin_config, $subnetid, $ip) = @_; } diff --git a/debian/control b/debian/control index 8b67d74..c54f8bc 100644 --- a/debian/control +++ b/debian/control @@ -17,6 +17,7 @@ Depends: libpve-common-perl (>= 5.0-45), perl (>= 5.6.0-16), pve-cluster (>= 5.0-32), libnet-subnet-perl, + libnet-ip-perl, ${misc:Depends}, ${perl:Depends}, Recommends: frr-pythontools, ifupdown2 -- 2.20.1