]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/Subnets.pm
vnet/subnet : add skipdns option
[pve-network.git] / PVE / Network / SDN / Subnets.pm
CommitLineData
c33dd818
AD
1package PVE::Network::SDN::Subnets;
2
3use strict;
4use warnings;
5
70b03506 6use Net::Subnet qw(subnet_matcher);
ee4f339e 7use Net::IP;
aba0731c 8use NetAddr::IP qw(:lower);
c33dd818 9
d1ab9bdb 10use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
ee4f339e 11use PVE::Network::SDN::Dns;
d1ab9bdb
TL
12use PVE::Network::SDN::Ipams;
13
c33dd818
AD
14use PVE::Network::SDN::SubnetPlugin;
15PVE::Network::SDN::SubnetPlugin->register();
16PVE::Network::SDN::SubnetPlugin->init();
17
18sub sdn_subnets_config {
19 my ($cfg, $id, $noerr) = @_;
20
21 die "no sdn subnet ID specified\n" if !$id;
22
23 my $scfg = $cfg->{ids}->{$id};
24 die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
25
e8736dac
AD
26 if($scfg) {
27 my ($zone, $network, $mask) = split(/-/, $id);
28 $scfg->{cidr} = "$network/$mask";
29 $scfg->{zone} = $zone;
30 $scfg->{network} = $network;
31 $scfg->{mask} = $mask;
32 }
33
c33dd818
AD
34 return $scfg;
35}
36
37sub config {
38 my $config = cfs_read_file("sdn/subnets.cfg");
39}
40
41sub write_config {
42 my ($cfg) = @_;
43
44 cfs_write_file("sdn/subnets.cfg", $cfg);
45}
46
47sub sdn_subnets_ids {
48 my ($cfg) = @_;
49
b184ebc3 50 return sort keys %{$cfg->{ids}};
c33dd818
AD
51}
52
53sub complete_sdn_subnet {
54 my ($cmdname, $pname, $cvalue) = @_;
55
56 my $cfg = PVE::Network::SDN::Subnets::config();
57
58 return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg) ];
59}
60
61sub get_subnet {
5d3e0248
AD
62 my ($subnetid, $running) = @_;
63
64 my $cfg = {};
65 if($running) {
d73c7c36 66 my $cfg = PVE::Network::SDN::running_config();
5d3e0248
AD
67 $cfg = $cfg->{subnets};
68 } else {
69 $cfg = PVE::Network::SDN::Subnets::config();
70 }
c33dd818 71
c33dd818
AD
72 my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
73 return $subnet;
74}
75
70b03506 76sub find_ip_subnet {
e8736dac 77 my ($ip, $mask, $subnets) = @_;
70b03506
AD
78
79 my $subnet = undef;
80 my $subnetid = undef;
81
e612faf6 82 foreach my $id (sort keys %{$subnets}) {
e8736dac
AD
83
84 next if $mask ne $subnets->{$id}->{mask};
85 my $cidr = $subnets->{$id}->{cidr};
e612faf6
AD
86 my $subnet_matcher = subnet_matcher($cidr);
87 next if !$subnet_matcher->($ip);
88 $subnet = $subnets->{$id};
89 $subnetid = $id;
90 last;
70b03506
AD
91 }
92 die "can't find any subnet for ip $ip" if !$subnet;
93
94 return ($subnetid, $subnet);
95}
96
b61e93a5 97sub verify_dns_zone {
ee4f339e
AD
98 my ($zone, $dns) = @_;
99
100 return if !$zone || !$dns;
101
102 my $dns_cfg = PVE::Network::SDN::Dns::config();
103 my $plugin_config = $dns_cfg->{ids}->{$dns};
104 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
105 $plugin->verify_zone($plugin_config, $zone);
b61e93a5 106}
ee4f339e 107
b61e93a5 108sub get_reversedns_zone {
e8736dac 109 my ($subnetid, $subnet, $dns, $ip) = @_;
4ad78442
AD
110
111 return if !$subnetid || !$dns || !$ip;
112
113 my $dns_cfg = PVE::Network::SDN::Dns::config();
114 my $plugin_config = $dns_cfg->{ids}->{$dns};
115 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
e8736dac 116 $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
b61e93a5 117}
4ad78442 118
b61e93a5 119sub add_dns_record {
ceb972a9 120 my ($zone, $dns, $hostname, $ip) = @_;
ee4f339e
AD
121 return if !$zone || !$dns || !$hostname || !$ip;
122
ee4f339e
AD
123 my $dns_cfg = PVE::Network::SDN::Dns::config();
124 my $plugin_config = $dns_cfg->{ids}->{$dns};
125 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
126 $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
127
b61e93a5 128}
ee4f339e 129
b61e93a5 130sub add_dns_ptr_record {
ceb972a9 131 my ($reversezone, $zone, $dns, $hostname, $ip) = @_;
ee4f339e
AD
132
133 return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
134
ee4f339e
AD
135 $hostname .= ".$zone";
136 my $dns_cfg = PVE::Network::SDN::Dns::config();
137 my $plugin_config = $dns_cfg->{ids}->{$dns};
138 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
139 $plugin->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
b61e93a5 140}
ee4f339e 141
b61e93a5 142sub del_dns_record {
ceb972a9 143 my ($zone, $dns, $hostname, $ip) = @_;
ee4f339e
AD
144
145 return if !$zone || !$dns || !$hostname || !$ip;
146
ee4f339e
AD
147 my $dns_cfg = PVE::Network::SDN::Dns::config();
148 my $plugin_config = $dns_cfg->{ids}->{$dns};
149 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
150 $plugin->del_a_record($plugin_config, $zone, $hostname, $ip);
b61e93a5 151}
ee4f339e 152
b61e93a5 153sub del_dns_ptr_record {
ee4f339e
AD
154 my ($reversezone, $dns, $ip) = @_;
155
156 return if !$reversezone || !$dns || !$ip;
157
158 my $dns_cfg = PVE::Network::SDN::Dns::config();
159 my $plugin_config = $dns_cfg->{ids}->{$dns};
160 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
161 $plugin->del_ptr_record($plugin_config, $reversezone, $ip);
b61e93a5 162}
ee4f339e 163
77ec7eb2
AD
164sub add_subnet {
165 my ($zone, $subnetid, $subnet) = @_;
166
167 my $ipam = $zone->{ipam};
d6557a2d 168 return if !$ipam;
77ec7eb2
AD
169 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
170 my $plugin_config = $ipam_cfg->{ids}->{$ipam};
171 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
172 $plugin->add_subnet($plugin_config, $subnetid, $subnet);
173}
174
175sub del_subnet {
176 my ($zone, $subnetid, $subnet) = @_;
177
178 my $ipam = $zone->{ipam};
d6557a2d 179 return if !$ipam;
77ec7eb2
AD
180 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
181 my $plugin_config = $ipam_cfg->{ids}->{$ipam};
182 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
183 $plugin->del_subnet($plugin_config, $subnetid, $subnet);
184}
185
70b03506 186sub next_free_ip {
83dcfd57 187 my ($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns) = @_;
ee4f339e
AD
188
189 my $cidr = undef;
190 my $ip = undef;
ceb972a9 191 $description = '' if !$description;
70b03506 192
331e2330 193 my $ipamid = $zone->{ipam};
4ad78442
AD
194 my $dns = $zone->{dns};
195 my $dnszone = $zone->{dnszone};
196 my $reversedns = $zone->{reversedns};
ee4f339e
AD
197 my $dnszoneprefix = $subnet->{dnszoneprefix};
198
ceb972a9
AD
199 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
200
ee4f339e 201 #verify dns zones before ipam
83dcfd57 202 verify_dns_zone($dnszone, $dns) if !$skipdns;
ee4f339e
AD
203
204 if($ipamid) {
205 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
206 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
207 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
e612faf6 208 eval {
e9365ab0 209 $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $description);
e612faf6
AD
210 ($ip, undef) = split(/\//, $cidr);
211 };
212 die $@ if $@;
ee4f339e 213 }
70b03506 214
ee4f339e 215 eval {
b61e93a5 216 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
4ad78442 217
83dcfd57
AD
218 if(!$skipdns) {
219 #add dns
220 add_dns_record($dnszone, $dns, $hostname, $ip);
221 #add reverse dns
222 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
223 }
ee4f339e
AD
224 };
225 if ($@) {
226 #rollback
227 my $err = $@;
228 eval {
0720c17e 229 PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
ee4f339e
AD
230 };
231 die $err;
232 }
233 return $cidr;
70b03506
AD
234}
235
236sub add_ip {
83dcfd57 237 my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, $skipdns) = @_;
70b03506 238
b184ebc3 239 return if !$subnet || !$ip;
e612faf6 240
533eb3d4 241 my $ipaddr = NetAddr::IP->new($ip);
aba0731c
AD
242 $ip = $ipaddr->canon();
243
331e2330 244 my $ipamid = $zone->{ipam};
4ad78442
AD
245 my $dns = $zone->{dns};
246 my $dnszone = $zone->{dnszone};
247 my $reversedns = $zone->{reversedns};
b61e93a5 248 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
ee4f339e
AD
249 my $dnszoneprefix = $subnet->{dnszoneprefix};
250
ceb972a9
AD
251 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
252
ee4f339e 253 #verify dns zones before ipam
83dcfd57
AD
254 if(!$skipdns) {
255 verify_dns_zone($dnszone, $dns);
256 verify_dns_zone($reversednszone, $reversedns);
257 }
ee4f339e
AD
258
259 if ($ipamid) {
5221635a 260
ee4f339e
AD
261 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
262 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
263 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
5221635a 264
e612faf6 265 eval {
34c4c6d7 266 $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway);
e612faf6
AD
267 };
268 die $@ if $@;
ee4f339e 269 }
70b03506 270
ee4f339e 271 eval {
83dcfd57
AD
272 if(!$skipdns) {
273 #add dns
274 add_dns_record($dnszone, $dns, $hostname, $ip);
275 #add reverse dns
276 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
277 }
ee4f339e
AD
278 };
279 if ($@) {
280 #rollback
281 my $err = $@;
282 eval {
0720c17e 283 PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
ee4f339e
AD
284 };
285 die $err;
286 }
70b03506
AD
287}
288
dd54b5a3 289sub update_ip {
83dcfd57 290 my ($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $description, $skipdns) = @_;
dd54b5a3
AD
291
292 return if !$subnet || !$ip;
293
533eb3d4 294 my $ipaddr = NetAddr::IP->new($ip);
dd54b5a3
AD
295 $ip = $ipaddr->canon();
296
297 my $ipamid = $zone->{ipam};
298 my $dns = $zone->{dns};
299 my $dnszone = $zone->{dnszone};
300 my $reversedns = $zone->{reversedns};
b61e93a5 301 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
dd54b5a3
AD
302 my $dnszoneprefix = $subnet->{dnszoneprefix};
303
304 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
305
306 #verify dns zones before ipam
83dcfd57
AD
307 if(!$skipdns) {
308 verify_dns_zone($dnszone, $dns);
309 verify_dns_zone($reversednszone, $reversedns);
310 }
dd54b5a3
AD
311
312 if ($ipamid) {
313 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
314 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
315 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
316 eval {
317 $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description);
318 };
319 die $@ if $@;
320 }
321
0d2396b0
AD
322 return if $hostname eq $oldhostname;
323
dd54b5a3 324 eval {
83dcfd57
AD
325 if(!$skipdns) {
326 #add dns
327 del_dns_record($dnszone, $dns, $oldhostname, $ip);
328 add_dns_record($dnszone, $dns, $hostname, $ip);
329 #add reverse dns
330 del_dns_ptr_record($reversednszone, $reversedns, $ip);
331 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
332 }
dd54b5a3
AD
333 };
334}
335
70b03506 336sub del_ip {
83dcfd57 337 my ($zone, $subnetid, $subnet, $ip, $hostname, $skipdns) = @_;
70b03506 338
aba0731c
AD
339 return if !$subnet || !$ip;
340
533eb3d4 341 my $ipaddr = NetAddr::IP->new($ip);
aba0731c 342 $ip = $ipaddr->canon();
e612faf6 343
331e2330 344 my $ipamid = $zone->{ipam};
4ad78442
AD
345 my $dns = $zone->{dns};
346 my $dnszone = $zone->{dnszone};
347 my $reversedns = $zone->{reversedns};
b61e93a5 348 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
ee4f339e 349 my $dnszoneprefix = $subnet->{dnszoneprefix};
ceb972a9
AD
350 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
351
83dcfd57
AD
352 if(!$skipdns) {
353 verify_dns_zone($dnszone, $dns);
354 verify_dns_zone($reversednszone, $reversedns);
355 }
ee4f339e
AD
356
357 if ($ipamid) {
358 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
359 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
360 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
e8736dac 361 $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
ee4f339e 362 }
70b03506 363
ee4f339e 364 eval {
83dcfd57
AD
365 if(!$skipdns) {
366 del_dns_record($dnszone, $dns, $hostname, $ip);
367 del_dns_ptr_record($reversednszone, $reversedns, $ip);
368 }
ee4f339e
AD
369 };
370 if ($@) {
371 warn $@;
372 }
70b03506
AD
373}
374
c33dd818 3751;