]> git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN/Subnets.pm
fix coding style NetAddr::IP->new
[pve-network.git] / PVE / Network / SDN / Subnets.pm
1 package PVE::Network::SDN::Subnets;
2
3 use strict;
4 use warnings;
5
6 use Net::Subnet qw(subnet_matcher);
7 use Net::IP;
8 use NetAddr::IP qw(:lower);
9
10 use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
11 use PVE::Network::SDN::Dns;
12 use PVE::Network::SDN::Ipams;
13
14 use PVE::Network::SDN::SubnetPlugin;
15 PVE::Network::SDN::SubnetPlugin->register();
16 PVE::Network::SDN::SubnetPlugin->init();
17
18 sub 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
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
34 return $scfg;
35 }
36
37 sub config {
38 my $config = cfs_read_file("sdn/subnets.cfg");
39 }
40
41 sub write_config {
42 my ($cfg) = @_;
43
44 cfs_write_file("sdn/subnets.cfg", $cfg);
45 }
46
47 sub sdn_subnets_ids {
48 my ($cfg) = @_;
49
50 return sort keys %{$cfg->{ids}};
51 }
52
53 sub 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
61 sub get_subnet {
62 my ($subnetid, $running) = @_;
63
64 my $cfg = {};
65 if($running) {
66 my $cfg = PVE::Network::SDN::config();
67 $cfg = $cfg->{subnets};
68 } else {
69 $cfg = PVE::Network::SDN::Subnets::config();
70 }
71
72 my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
73 return $subnet;
74 }
75
76 sub find_ip_subnet {
77 my ($ip, $mask, $subnets) = @_;
78
79 my $subnet = undef;
80 my $subnetid = undef;
81
82 foreach my $id (sort keys %{$subnets}) {
83
84 next if $mask ne $subnets->{$id}->{mask};
85 my $cidr = $subnets->{$id}->{cidr};
86 my $subnet_matcher = subnet_matcher($cidr);
87 next if !$subnet_matcher->($ip);
88 $subnet = $subnets->{$id};
89 $subnetid = $id;
90 last;
91 }
92 die "can't find any subnet for ip $ip" if !$subnet;
93
94 return ($subnetid, $subnet);
95 }
96
97 sub verify_dns_zone {
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);
106 }
107
108 sub get_reversedns_zone {
109 my ($subnetid, $subnet, $dns, $ip) = @_;
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});
116 $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
117 }
118
119 sub add_dns_record {
120 my ($zone, $dns, $hostname, $ip) = @_;
121 return if !$zone || !$dns || !$hostname || !$ip;
122
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
128 }
129
130 sub add_dns_ptr_record {
131 my ($reversezone, $zone, $dns, $hostname, $ip) = @_;
132
133 return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
134
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);
140 }
141
142 sub del_dns_record {
143 my ($zone, $dns, $hostname, $ip) = @_;
144
145 return if !$zone || !$dns || !$hostname || !$ip;
146
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);
151 }
152
153 sub del_dns_ptr_record {
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);
162 }
163
164 sub add_subnet {
165 my ($zone, $subnetid, $subnet) = @_;
166
167 my $ipam = $zone->{ipam};
168 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
169 my $plugin_config = $ipam_cfg->{ids}->{$ipam};
170 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
171 $plugin->add_subnet($plugin_config, $subnetid, $subnet);
172 }
173
174 sub del_subnet {
175 my ($zone, $subnetid, $subnet) = @_;
176
177 my $ipam = $zone->{ipam};
178 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
179 my $plugin_config = $ipam_cfg->{ids}->{$ipam};
180 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
181 $plugin->del_subnet($plugin_config, $subnetid, $subnet);
182 }
183
184 sub next_free_ip {
185 my ($zone, $subnetid, $subnet, $hostname, $mac, $description) = @_;
186
187 my $cidr = undef;
188 my $ip = undef;
189 $description = '' if !$description;
190
191 my $ipamid = $zone->{ipam};
192 my $dns = $zone->{dns};
193 my $dnszone = $zone->{dnszone};
194 my $reversedns = $zone->{reversedns};
195 my $dnszoneprefix = $subnet->{dnszoneprefix};
196
197 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
198
199 #verify dns zones before ipam
200 verify_dns_zone($dnszone, $dns);
201
202 if($ipamid) {
203 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
204 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
205 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
206 eval {
207 $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $description);
208 ($ip, undef) = split(/\//, $cidr);
209 };
210 die $@ if $@;
211 }
212
213 eval {
214 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
215
216 #add dns
217 add_dns_record($dnszone, $dns, $hostname, $ip);
218 #add reverse dns
219 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
220 };
221 if ($@) {
222 #rollback
223 my $err = $@;
224 eval {
225 PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
226 };
227 die $err;
228 }
229 return $cidr;
230 }
231
232 sub add_ip {
233 my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description) = @_;
234
235 return if !$subnet || !$ip;
236
237 my $ipaddr = NetAddr::IP->new($ip);
238 $ip = $ipaddr->canon();
239
240 my $ipamid = $zone->{ipam};
241 my $dns = $zone->{dns};
242 my $dnszone = $zone->{dnszone};
243 my $reversedns = $zone->{reversedns};
244 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
245 my $dnszoneprefix = $subnet->{dnszoneprefix};
246
247 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
248
249 #verify dns zones before ipam
250 verify_dns_zone($dnszone, $dns);
251 verify_dns_zone($reversednszone, $reversedns);
252
253 if ($ipamid) {
254 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
255 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
256 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
257 eval {
258 $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description);
259 };
260 die $@ if $@;
261 }
262
263 eval {
264 #add dns
265 add_dns_record($dnszone, $dns, $hostname, $ip);
266 #add reverse dns
267 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
268 };
269 if ($@) {
270 #rollback
271 my $err = $@;
272 eval {
273 PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
274 };
275 die $err;
276 }
277 }
278
279 sub update_ip {
280 my ($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $description) = @_;
281
282 return if !$subnet || !$ip;
283
284 my $ipaddr = NetAddr::IP->new($ip);
285 $ip = $ipaddr->canon();
286
287 my $ipamid = $zone->{ipam};
288 my $dns = $zone->{dns};
289 my $dnszone = $zone->{dnszone};
290 my $reversedns = $zone->{reversedns};
291 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
292 my $dnszoneprefix = $subnet->{dnszoneprefix};
293
294 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
295
296 #verify dns zones before ipam
297 verify_dns_zone($dnszone, $dns);
298 verify_dns_zone($reversednszone, $reversedns);
299
300 if ($ipamid) {
301 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
302 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
303 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
304 eval {
305 $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description);
306 };
307 die $@ if $@;
308 }
309
310 return if $hostname eq $oldhostname;
311
312 eval {
313 #add dns
314
315 del_dns_record($dnszone, $dns, $oldhostname, $ip);
316 add_dns_record($dnszone, $dns, $hostname, $ip);
317 #add reverse dns
318 del_dns_ptr_record($reversednszone, $reversedns, $ip);
319 add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
320 };
321 }
322
323 sub del_ip {
324 my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
325
326 return if !$subnet || !$ip;
327
328 my $ipaddr = NetAddr::IP->new($ip);
329 $ip = $ipaddr->canon();
330
331 my $ipamid = $zone->{ipam};
332 my $dns = $zone->{dns};
333 my $dnszone = $zone->{dnszone};
334 my $reversedns = $zone->{reversedns};
335 my $reversednszone = get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
336 my $dnszoneprefix = $subnet->{dnszoneprefix};
337 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
338
339
340 verify_dns_zone($dnszone, $dns);
341 verify_dns_zone($reversednszone, $reversedns);
342
343 if ($ipamid) {
344 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
345 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
346 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
347 $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
348 }
349
350 eval {
351 del_dns_record($dnszone, $dns, $hostname, $ip);
352 del_dns_ptr_record($reversednszone, $reversedns, $ip);
353 };
354 if ($@) {
355 warn $@;
356 }
357 }
358
359 1;