]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/Subnets.pm
subnets/ipam: allow same subnet on different zones
[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);
c33dd818 7use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
ee4f339e 8use Net::IP;
c33dd818 9
70b03506 10use PVE::Network::SDN::Ipams;
ee4f339e 11use PVE::Network::SDN::Dns;
c33dd818
AD
12use PVE::Network::SDN::SubnetPlugin;
13PVE::Network::SDN::SubnetPlugin->register();
14PVE::Network::SDN::SubnetPlugin->init();
15
16sub sdn_subnets_config {
17 my ($cfg, $id, $noerr) = @_;
18
19 die "no sdn subnet ID specified\n" if !$id;
20
21 my $scfg = $cfg->{ids}->{$id};
22 die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
23
e8736dac
AD
24 if($scfg) {
25 my ($zone, $network, $mask) = split(/-/, $id);
26 $scfg->{cidr} = "$network/$mask";
27 $scfg->{zone} = $zone;
28 $scfg->{network} = $network;
29 $scfg->{mask} = $mask;
30 }
31
c33dd818
AD
32 return $scfg;
33}
34
35sub config {
36 my $config = cfs_read_file("sdn/subnets.cfg");
37}
38
39sub write_config {
40 my ($cfg) = @_;
41
42 cfs_write_file("sdn/subnets.cfg", $cfg);
43}
44
45sub sdn_subnets_ids {
46 my ($cfg) = @_;
47
b184ebc3 48 return sort keys %{$cfg->{ids}};
c33dd818
AD
49}
50
51sub complete_sdn_subnet {
52 my ($cmdname, $pname, $cvalue) = @_;
53
54 my $cfg = PVE::Network::SDN::Subnets::config();
55
56 return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg) ];
57}
58
59sub get_subnet {
5d3e0248
AD
60 my ($subnetid, $running) = @_;
61
62 my $cfg = {};
63 if($running) {
64 my $cfg = PVE::Network::SDN::config();
65 $cfg = $cfg->{subnets};
66 } else {
67 $cfg = PVE::Network::SDN::Subnets::config();
68 }
c33dd818 69
c33dd818
AD
70 my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
71 return $subnet;
72}
73
70b03506 74sub find_ip_subnet {
e8736dac 75 my ($ip, $mask, $subnets) = @_;
70b03506
AD
76
77 my $subnet = undef;
78 my $subnetid = undef;
79
e612faf6 80 foreach my $id (sort keys %{$subnets}) {
e8736dac
AD
81
82 next if $mask ne $subnets->{$id}->{mask};
83 my $cidr = $subnets->{$id}->{cidr};
e612faf6
AD
84 my $subnet_matcher = subnet_matcher($cidr);
85 next if !$subnet_matcher->($ip);
86 $subnet = $subnets->{$id};
87 $subnetid = $id;
88 last;
70b03506
AD
89 }
90 die "can't find any subnet for ip $ip" if !$subnet;
91
92 return ($subnetid, $subnet);
93}
94
ee4f339e
AD
95my $verify_dns_zone = sub {
96 my ($zone, $dns) = @_;
97
98 return if !$zone || !$dns;
99
100 my $dns_cfg = PVE::Network::SDN::Dns::config();
101 my $plugin_config = $dns_cfg->{ids}->{$dns};
102 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
103 $plugin->verify_zone($plugin_config, $zone);
104};
105
4ad78442 106my $get_reversedns_zone = sub {
e8736dac 107 my ($subnetid, $subnet, $dns, $ip) = @_;
4ad78442
AD
108
109 return if !$subnetid || !$dns || !$ip;
110
111 my $dns_cfg = PVE::Network::SDN::Dns::config();
112 my $plugin_config = $dns_cfg->{ids}->{$dns};
113 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
e8736dac 114 $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
4ad78442
AD
115};
116
ee4f339e
AD
117my $add_dns_record = sub {
118 my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
119 return if !$zone || !$dns || !$hostname || !$ip;
120
121 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
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
130my $add_dns_ptr_record = sub {
131 my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
132
133 return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
134
135 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
136 $hostname .= ".$zone";
137 my $dns_cfg = PVE::Network::SDN::Dns::config();
138 my $plugin_config = $dns_cfg->{ids}->{$dns};
139 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
140 $plugin->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
141};
142
143my $del_dns_record = sub {
144 my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
145
146 return if !$zone || !$dns || !$hostname || !$ip;
147
148 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
149
150 my $dns_cfg = PVE::Network::SDN::Dns::config();
151 my $plugin_config = $dns_cfg->{ids}->{$dns};
152 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
153 $plugin->del_a_record($plugin_config, $zone, $hostname, $ip);
154};
155
156my $del_dns_ptr_record = sub {
157 my ($reversezone, $dns, $ip) = @_;
158
159 return if !$reversezone || !$dns || !$ip;
160
161 my $dns_cfg = PVE::Network::SDN::Dns::config();
162 my $plugin_config = $dns_cfg->{ids}->{$dns};
163 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
164 $plugin->del_ptr_record($plugin_config, $reversezone, $ip);
165};
166
70b03506 167sub next_free_ip {
4ad78442 168 my ($zone, $subnetid, $subnet, $hostname) = @_;
ee4f339e
AD
169
170 my $cidr = undef;
171 my $ip = undef;
70b03506 172
331e2330 173 my $ipamid = $zone->{ipam};
4ad78442
AD
174 my $dns = $zone->{dns};
175 my $dnszone = $zone->{dnszone};
176 my $reversedns = $zone->{reversedns};
ee4f339e
AD
177 my $dnszoneprefix = $subnet->{dnszoneprefix};
178
179 #verify dns zones before ipam
180 &$verify_dns_zone($dnszone, $dns);
ee4f339e
AD
181
182 if($ipamid) {
183 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
184 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
185 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
e612faf6
AD
186 eval {
187 $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
188 ($ip, undef) = split(/\//, $cidr);
189 };
190 die $@ if $@;
ee4f339e 191 }
70b03506 192
ee4f339e 193 eval {
e8736dac 194 my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
4ad78442 195
ee4f339e
AD
196 #add dns
197 &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
198 #add reverse dns
199 &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
200 };
201 if ($@) {
202 #rollback
203 my $err = $@;
204 eval {
205 PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
206 };
207 die $err;
208 }
209 return $cidr;
70b03506
AD
210}
211
212sub add_ip {
4ad78442 213 my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
70b03506 214
b184ebc3 215 return if !$subnet || !$ip;
e612faf6 216
331e2330 217 my $ipamid = $zone->{ipam};
4ad78442
AD
218 my $dns = $zone->{dns};
219 my $dnszone = $zone->{dnszone};
220 my $reversedns = $zone->{reversedns};
e8736dac 221 my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
ee4f339e
AD
222 my $dnszoneprefix = $subnet->{dnszoneprefix};
223
224 #verify dns zones before ipam
225 &$verify_dns_zone($dnszone, $dns);
226 &$verify_dns_zone($reversednszone, $reversedns);
227
228 if ($ipamid) {
229 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
230 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
231 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
e612faf6 232 eval {
e8736dac 233 $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip);
e612faf6
AD
234 };
235 die $@ if $@;
ee4f339e 236 }
70b03506 237
ee4f339e
AD
238 eval {
239 #add dns
240 &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
241 #add reverse dns
242 &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
243 };
244 if ($@) {
245 #rollback
246 my $err = $@;
247 eval {
248 PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
249 };
250 die $err;
251 }
70b03506
AD
252}
253
254sub del_ip {
4ad78442 255 my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
70b03506 256
e612faf6
AD
257 return if !$subnet;
258
331e2330 259 my $ipamid = $zone->{ipam};
4ad78442
AD
260 my $dns = $zone->{dns};
261 my $dnszone = $zone->{dnszone};
262 my $reversedns = $zone->{reversedns};
e8736dac 263 my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
ee4f339e
AD
264 my $dnszoneprefix = $subnet->{dnszoneprefix};
265
266 &$verify_dns_zone($dnszone, $dns);
267 &$verify_dns_zone($reversednszone, $reversedns);
268
269 if ($ipamid) {
270 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
271 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
272 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
e8736dac 273 $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
ee4f339e 274 }
70b03506 275
ee4f339e
AD
276 eval {
277 &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
278 &$del_dns_ptr_record($reversednszone, $reversedns, $ip);
279 };
280 if ($@) {
281 warn $@;
282 }
70b03506
AD
283}
284
c33dd818 2851;