]> git.proxmox.com Git - pve-network.git/blob - src/PVE/Network/SDN/Vnets.pm
subnet: vnet: refactor IPAM related methods
[pve-network.git] / src / PVE / Network / SDN / Vnets.pm
1 package PVE::Network::SDN::Vnets;
2
3 use strict;
4 use warnings;
5
6 use Net::IP;
7
8 use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
9 use PVE::Network::SDN;
10 use PVE::Network::SDN::Subnets;
11 use PVE::Network::SDN::Zones;
12
13 use PVE::Network::SDN::VnetPlugin;
14 PVE::Network::SDN::VnetPlugin->register();
15 PVE::Network::SDN::VnetPlugin->init();
16
17 sub sdn_vnets_config {
18 my ($cfg, $id, $noerr) = @_;
19
20 die "no sdn vnet ID specified\n" if !$id;
21
22 my $scfg = $cfg->{ids}->{$id};
23 die "sdn vnet '$id' does not exist\n" if (!$noerr && !$scfg);
24
25 return $scfg;
26 }
27
28 sub config {
29 my ($running) = @_;
30
31 if ($running) {
32 my $cfg = PVE::Network::SDN::running_config();
33 return $cfg->{vnets};
34 }
35
36 return cfs_read_file("sdn/vnets.cfg");
37 }
38
39 sub write_config {
40 my ($cfg) = @_;
41
42 cfs_write_file("sdn/vnets.cfg", $cfg);
43 }
44
45 sub sdn_vnets_ids {
46 my ($cfg) = @_;
47
48 return sort keys %{$cfg->{ids}};
49 }
50
51 sub complete_sdn_vnet {
52 my ($cmdname, $pname, $cvalue) = @_;
53
54 my $cfg = PVE::Network::SDN::Vnets::config();
55
56 return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_vnet_ids($cfg) ];
57 }
58
59 sub get_vnet {
60 my ($vnetid, $running) = @_;
61
62 return if !$vnetid;
63
64 my $cfg = PVE::Network::SDN::Vnets::config($running);
65 return PVE::Network::SDN::Vnets::sdn_vnets_config($cfg, $vnetid, 1);
66 }
67
68 sub get_subnets {
69 my ($vnetid, $running) = @_;
70
71 my $subnets = undef;
72 my $subnets_cfg = PVE::Network::SDN::Subnets::config($running);
73
74 foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
75 my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets_cfg, $subnetid);
76 next if !$subnet->{vnet} || ($vnetid && $subnet->{vnet} ne $vnetid);
77 $subnets->{$subnetid} = $subnet;
78 }
79
80 return $subnets;
81 }
82
83 sub get_subnet_from_vnet_ip {
84 my ($vnetid, $ip) = @_;
85
86 my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
87 my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
88 my $zoneid = $vnet->{zone};
89 my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
90
91 my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
92
93 return ($zone, $subnetid, $subnet, $ip);
94 }
95
96 sub add_next_free_cidr {
97 my ($vnetid, $hostname, $mac, $vmid, $skipdns, $dhcprange) = @_;
98
99 my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
100 return if !$vnet;
101
102 my $zoneid = $vnet->{zone};
103 my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
104
105 return if !$zone->{ipam} || !$zone->{dhcp};
106
107 my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
108
109 my $ips = {};
110
111 my @ipversions = qw/ 4 6 /;
112 for my $ipversion (@ipversions) {
113 my $ip = undef;
114 my $subnetcount = 0;
115 foreach my $subnetid (sort keys %{$subnets}) {
116 my $subnet = $subnets->{$subnetid};
117 my $network = $subnet->{network};
118
119 next if Net::IP::ip_get_version($network) != $ipversion || $ips->{$ipversion};
120 $subnetcount++;
121
122 eval {
123 $ip = PVE::Network::SDN::Subnets::add_next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $vmid, $skipdns, $dhcprange);
124 };
125 die $@ if $@;
126
127 if ($ip) {
128 $ips->{$ipversion} = $ip;
129 last;
130 }
131 }
132 die "can't find any free ip" if !$ip && $subnetcount > 0;
133 }
134 }
135
136 sub add_ip {
137 my ($vnetid, $ip, $hostname, $mac, $vmid, $skipdns) = @_;
138
139 return if !$vnetid;
140
141 my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
142 PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $vmid, undef, $skipdns);
143 }
144
145 sub update_ip {
146 my ($vnetid, $ip, $hostname, $oldhostname, $mac, $vmid, $skipdns) = @_;
147
148 return if !$vnetid;
149
150 my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
151 PVE::Network::SDN::Subnets::update_ip($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $vmid, $skipdns);
152 }
153
154 sub del_ip {
155 my ($vnetid, $ip, $hostname, $mac, $skipdns) = @_;
156
157 return if !$vnetid;
158
159 my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
160 PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $skipdns);
161 }
162
163 sub get_ips_from_mac {
164 my ($vnetid, $mac) = @_;
165
166 my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
167 return if !$vnet;
168
169 my $zoneid = $vnet->{zone};
170 my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
171
172 return if !$zone->{ipam} || !$zone->{dhcp};
173
174 return PVE::Network::SDN::Ipams::get_ips_from_mac($mac, $zoneid, $zone);
175 }
176
177 sub del_ips_from_mac {
178 my ($vnetid, $mac, $hostname) = @_;
179
180 my ($ip4, $ip6) = PVE::Network::SDN::Vnets::get_ips_from_mac($vnetid, $mac);
181 PVE::Network::SDN::Vnets::del_ip($vnetid, $ip4, $hostname, $mac) if $ip4;
182 PVE::Network::SDN::Vnets::del_ip($vnetid, $ip6, $hostname, $mac) if $ip6;
183
184 return ($ip4, $ip6);
185 }
186
187 1;