From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <aderumier@odiso.com>
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) server-digest SHA256)
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 227D963373
 for <pve-devel@lists.proxmox.com>; Mon, 24 Aug 2020 18:50:04 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id E04511F87E
 for <pve-devel@lists.proxmox.com>; Mon, 24 Aug 2020 18:49:33 +0200 (CEST)
Received: from mailpro.odiso.net (mailpro.odiso.net [89.248.211.110])
 (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS id E0B731F7B9
 for <pve-devel@lists.proxmox.com>; Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
Received: from localhost (localhost [127.0.0.1])
 by mailpro.odiso.net (Postfix) with ESMTP id C26E715A51B9;
 Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
Received: from mailpro.odiso.net ([127.0.0.1])
 by localhost (mailpro.odiso.net [127.0.0.1]) (amavisd-new, port 10032)
 with ESMTP id vb8-Gi3v-TFP; Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
Received: from localhost (localhost [127.0.0.1])
 by mailpro.odiso.net (Postfix) with ESMTP id A735A15A51BD;
 Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
X-Virus-Scanned: amavisd-new at mailpro.odiso.com
Received: from mailpro.odiso.net ([127.0.0.1])
 by localhost (mailpro.odiso.net [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id 0tmvs5kiYWnv; Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
Received: from pve.fritz.box (unknown [213.211.148.86])
 by mailpro.odiso.net (Postfix) with ESMTPSA id 7593815A51B9;
 Mon, 24 Aug 2020 18:49:31 +0200 (CEST)
From: Alexandre Derumier <aderumier@odiso.com>
To: pve-devel@lists.proxmox.com
Date: Mon, 24 Aug 2020 18:49:23 +0200
Message-Id: <20200824164923.12652-1-aderumier@odiso.com>
X-Mailer: git-send-email 2.20.1
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
X-SPAM-LEVEL: Spam detection results:  0
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 RCVD_IN_DNSWL_NONE     -0.0001 Sender listed at https://www.dnswl.org/,
 no trust
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [config.pm]
Subject: [pve-devel] [PATCH v2 pve-container] POC : add/del/update ip from
 vnet-subnet-ipam
X-BeenThere: pve-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
List-Post: <mailto:pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Mon, 24 Aug 2020 16:50:04 -0000

This is a POC to call ip to retreive ip address from ipam.

(it's really just a poc && buggt , it need to be improve for vnet changes=
, pending config apply/revert,...)
---
 src/PVE/LXC/Config.pm | 107 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 106 insertions(+), 1 deletion(-)

diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
index 5bf12d5..05498e2 100644
--- a/src/PVE/LXC/Config.pm
+++ b/src/PVE/LXC/Config.pm
@@ -11,6 +11,14 @@ use PVE::INotify;
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Tools;
=20
+my $have_sdn;
+eval {
+    require PVE::Network::SDN::Vnets;
+    require PVE::Network::SDN::Subnets;
+    $have_sdn =3D 1;
+};
+
+
 use base qw(PVE::AbstractConfig);
=20
 my $nodename =3D PVE::INotify::nodename();
@@ -1145,7 +1153,6 @@ sub parse_lxc_network {
 	my $dc =3D PVE::Cluster::cfs_read_file('datacenter.cfg');
 	$res->{hwaddr} =3D PVE::Tools::random_ether_addr($dc->{mac_prefix});
     }
-
     return $res;
 }
=20
@@ -1225,6 +1232,8 @@ sub vmconfig_hotplug_pending {
 		$cgroup->change_cpu_shares(undef, $confdesc->{cpuunits}->{default});
 	    } elsif ($opt =3D~ m/^net(\d)$/) {
 		my $netid =3D $1;
+		my $net =3D $class->parse_lxc_network($conf->{$opt});
+		delete_net_ip($conf->{hostname}, $net);
 		PVE::Network::veth_delete("veth${vmid}i$netid");
 	    } else {
 		die "skip\n"; # skip non-hotpluggable opts
@@ -1251,6 +1260,7 @@ sub vmconfig_hotplug_pending {
 	    } elsif ($opt =3D~ m/^net(\d+)$/) {
 		my $netid =3D $1;
 		my $net =3D $class->parse_lxc_network($value);
+		update_net_ip($conf->{hostname}, $net);
 		$value =3D $class->print_lxc_network($net);
 		PVE::LXC::update_net($vmid, $conf, $opt, $net, $netid, $rootdir);
 	    } elsif ($opt eq 'memory' || $opt eq 'swap') {
@@ -1327,6 +1337,8 @@ sub vmconfig_apply_pending {
 	    } elsif ($opt =3D~ m/^net(\d+)$/) {
 		my $netid =3D $1;
 		my $net =3D $class->parse_lxc_network($conf->{pending}->{$opt});
+		my $oldnet =3D $class->parse_lxc_network($conf->{$opt});
+		update_net_ip($conf->{hostname}, $net, $oldnet);
 		$conf->{pending}->{$opt} =3D $class->print_lxc_network($net);
 	    }
 	};
@@ -1590,4 +1602,97 @@ sub get_backup_volumes {
     return $return_volumes;
 }
=20
+sub update_net_ip {
+    my ($hostname, $net, $oldnet) =3D @_;
+
+    return if !$have_sdn;
+
+    my $oldbridge =3D $oldnet->{bridge};
+    my $bridge =3D $net->{bridge};
+
+    my $subnets =3D PVE::Network::SDN::Vnets::get_subnets($bridge);
+
+    return if !keys %{$subnets};
+
+    eval {
+	if (!$net->{ip}) {
+	    $net->{ip} =3D PVE::Network::SDN::Vnets::get_next_free_ip($bridge, =
$hostname);
+	    #writeconfig ?
+	} elsif ($net->{ip} ne 'dhcp' && $net->{ip} ne 'manual') {
+	    PVE::Network::SDN::Vnets::add_ip($bridge, $net->{ip}, $hostname) if=
 $net->{ip} ne $oldnet->{ip};
+	    #writeconfig ?
+	}
+    };
+    if ($@) {
+	#keep old config if error
+	$net->{ip} =3D $oldnet->{ip};
+	die $@;
+    }
+
+    #delete old ip after adding new
+    if ($oldnet->{ip} && $oldnet->{ip} ne 'dhcp' && $oldnet->{ip} ne 'ma=
nual') {
+	my $deletebridge =3D $oldbridge ne $bridge ? $oldbridge : $bridge;
+	eval {
+	    PVE::Network::SDN::Vnets::del_ip($deletebridge, $oldnet->{ip}, $hos=
tname) if !$net->{ip} || $net->{ip} ne $oldnet->{ip};
+	    #writeconfig ?
+	};
+	warn $@ if $@;
+    }
+
+
+    eval {
+	if (!$net->{ip6}) {
+	    $net->{ip6} =3D PVE::Network::SDN::Vnets::get_next_free_ip($bridge,=
 $hostname, 6);
+	    #writeconfig ?
+	} elsif ($net->{ip6} ne 'dhcp' && $net->{ip6} ne 'manual' && $net->{ip6=
} ne 'auto') {
+	    PVE::Network::SDN::Vnets::add_ip($bridge, $net->{ip6}, $hostname) i=
f $net->{ip6} ne $oldnet->{ip6};
+	    #writeconfig ?
+	}
+    };
+    if ($@) {
+	#keep old config if error
+	$net->{ip6} =3D $oldnet->{ip6};
+	die $@;
+    }
+
+    #delete old ip after adding new
+    if ($oldnet->{ip6} && $oldnet->{ip6} ne 'dhcp' && $oldnet->{ip6} ne =
'manual' && $net->{ip6} ne 'auto') {
+	my $deletebridge =3D $oldbridge ne $bridge ? $oldbridge : $bridge;
+	eval {
+	    PVE::Network::SDN::Vnets::del_ip($deletebridge, $oldnet->{ip6}, $ho=
stname) if !$net->{ip6} || $net->{ip6} ne $oldnet->{ip6};
+	    #writeconfig ?
+	};
+	warn $@ if $@;
+    }
+
+    if ($net->{ip}) {
+	my ($ip, undef) =3D split(/\//, $net->{ip});
+	my ($subnetidv4, $subnetv4) =3D PVE::Network::SDN::Subnets::find_ip_sub=
net($ip, $subnets);
+	$net->{gw} =3D $subnetv4->{gateway};
+    }
+
+    if ($net->{ip6}) {
+	my ($ip6, undef) =3D split(/\//, $net->{ip6});
+	my ($subnetidv6, $subnetv6) =3D PVE::Network::SDN::Subnets::find_ip_sub=
net($ip6, $subnets);
+	$net->{gw6} =3D $subnetv6->{gateway} if !$net->{gw6};
+    }
+
+}
+
+sub delete_net_ip {
+    my ($hostname, $net) =3D @_;
+
+    return if !$have_sdn;
+
+    my $bridge =3D $net->{bridge};
+    my $subnets =3D PVE::Network::SDN::Vnets::get_subnets($bridge);
+    return if !keys %{$subnets};
+
+    if ($net->{ip6} && ($net->{ip6} eq 'auto' || $net->{ip6} eq 'manual'=
 || $net->{ip6} eq 'dhcp')) {
+	PVE::Network::SDN::Vnets::del_ip($hostname, $bridge, $net->{ip6});
+    } elsif ($net->{ip} && $net->{ip} ne 'dhcp' && $net->{ip} ne 'manual=
') {
+	PVE::Network::SDN::Vnets::del_ip($hostname, $bridge, $net->{ip});
+    }
+}
+
 1;
--=20
2.20.1