]>
git.proxmox.com Git - pve-network.git/blob - src/PVE/Network/SDN/Subnets.pm
1 package PVE
::Network
::SDN
::Subnets
;
6 use Net
::Subnet
qw(subnet_matcher);
8 use NetAddr
::IP
qw(:lower);
10 use PVE
::Cluster
qw(cfs_read_file cfs_write_file cfs_lock_file);
11 use PVE
::JSONSchema
qw(parse_property_string);
12 use PVE
::Network
::SDN
::Dns
;
13 use PVE
::Network
::SDN
::Ipams
;
15 use PVE
::Network
::SDN
::SubnetPlugin
;
16 PVE
::Network
::SDN
::SubnetPlugin-
>register();
17 PVE
::Network
::SDN
::SubnetPlugin-
>init();
19 sub sdn_subnets_config
{
20 my ($cfg, $id, $noerr) = @_;
22 die "no sdn subnet ID specified\n" if !$id;
24 my $scfg = $cfg->{ids
}->{$id};
25 die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
30 my ($zone, $network, $mask) = split(/-/, $id);
31 $scfg->{cidr
} = "$network/$mask";
32 $scfg->{zone
} = $zone;
33 $scfg->{network
} = $network;
34 $scfg->{mask
} = $mask;
41 my ($subnet_config) = @_;
45 if ($subnet_config->{'dhcp-range'}) {
46 foreach my $element (@{$subnet_config->{'dhcp-range'}}) {
47 my $dhcp_range = eval { parse_property_string
('pve-sdn-dhcp-range', $element) };
49 if ($@ || !$dhcp_range) {
50 warn "Unable to parse dhcp-range string: $element\n";
55 push @dhcp_ranges, $dhcp_range;
66 my $cfg = PVE
::Network
::SDN
::running_config
();
67 return $cfg->{subnets
};
70 return cfs_read_file
("sdn/subnets.cfg");
76 cfs_write_file
("sdn/subnets.cfg", $cfg);
82 return sort keys %{$cfg->{ids
}};
85 sub complete_sdn_subnet
{
86 my ($cmdname, $pname, $cvalue) = @_;
88 my $cfg = PVE
::Network
::SDN
::Subnets
::config
();
90 return $cmdname eq 'add' ?
[] : [ PVE
::Network
::SDN
::Subnets
::sdn_subnets_ids
($cfg) ];
94 my ($subnetid, $running) = @_;
96 my $cfg = PVE
::Network
::SDN
::Subnets
::config
($running);
97 return PVE
::Network
::SDN
::Subnets
::sdn_subnets_config
($cfg, $subnetid, 1);
101 my ($ip, $subnets) = @_;
104 my $subnetid = undef;
106 foreach my $id (sort keys %{$subnets}) {
107 my $cidr = $subnets->{$id}->{cidr
};
108 my $subnet_matcher = subnet_matcher
($cidr);
109 next if !$subnet_matcher->($ip);
110 $subnet = $subnets->{$id};
114 die "can't find any subnet for ip $ip" if !$subnet;
116 return ($subnetid, $subnet);
119 sub verify_dns_zone
{
120 my ($zone, $dns) = @_;
122 return if !$zone || !$dns;
124 my $dns_cfg = PVE
::Network
::SDN
::Dns
::config
();
125 my $plugin_config = $dns_cfg->{ids
}->{$dns};
126 my $plugin = PVE
::Network
::SDN
::Dns
::Plugin-
>lookup($plugin_config->{type
});
127 $plugin->verify_zone($plugin_config, $zone);
130 sub get_reversedns_zone
{
131 my ($subnetid, $subnet, $dns, $ip) = @_;
133 return if !$subnetid || !$dns || !$ip;
135 my $dns_cfg = PVE
::Network
::SDN
::Dns
::config
();
136 my $plugin_config = $dns_cfg->{ids
}->{$dns};
137 my $plugin = PVE
::Network
::SDN
::Dns
::Plugin-
>lookup($plugin_config->{type
});
138 $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
142 my ($zone, $dns, $hostname, $ip) = @_;
143 return if !$zone || !$dns || !$hostname || !$ip;
145 my $dns_cfg = PVE
::Network
::SDN
::Dns
::config
();
146 my $plugin_config = $dns_cfg->{ids
}->{$dns};
147 my $plugin = PVE
::Network
::SDN
::Dns
::Plugin-
>lookup($plugin_config->{type
});
148 $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
152 sub add_dns_ptr_record
{
153 my ($reversezone, $zone, $dns, $hostname, $ip) = @_;
155 return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
157 $hostname .= ".$zone";
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->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
165 my ($zone, $dns, $hostname, $ip) = @_;
167 return if !$zone || !$dns || !$hostname || !$ip;
169 my $dns_cfg = PVE
::Network
::SDN
::Dns
::config
();
170 my $plugin_config = $dns_cfg->{ids
}->{$dns};
171 my $plugin = PVE
::Network
::SDN
::Dns
::Plugin-
>lookup($plugin_config->{type
});
172 $plugin->del_a_record($plugin_config, $zone, $hostname, $ip);
175 sub del_dns_ptr_record
{
176 my ($reversezone, $dns, $ip) = @_;
178 return if !$reversezone || !$dns || !$ip;
180 my $dns_cfg = PVE
::Network
::SDN
::Dns
::config
();
181 my $plugin_config = $dns_cfg->{ids
}->{$dns};
182 my $plugin = PVE
::Network
::SDN
::Dns
::Plugin-
>lookup($plugin_config->{type
});
183 $plugin->del_ptr_record($plugin_config, $reversezone, $ip);
187 my ($zone, $subnetid, $subnet) = @_;
189 my $ipam = $zone->{ipam
};
191 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
192 my $plugin_config = $ipam_cfg->{ids
}->{$ipam};
193 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
194 $plugin->add_subnet($plugin_config, $subnetid, $subnet);
198 my ($zone, $subnetid, $subnet) = @_;
200 my $ipam = $zone->{ipam
};
202 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
203 my $plugin_config = $ipam_cfg->{ids
}->{$ipam};
204 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
205 $plugin->del_subnet($plugin_config, $subnetid, $subnet);
208 sub add_next_free_ip
{
209 my ($zone, $subnetid, $subnet, $hostname, $mac, $vmid, $skipdns, $dhcprange) = @_;
214 my $ipamid = $zone->{ipam
};
215 my $dns = $zone->{dns
};
216 my $dnszone = $zone->{dnszone
};
217 my $reversedns = $zone->{reversedns
};
218 my $dnszoneprefix = $subnet->{dnszoneprefix
};
220 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
222 #verify dns zones before ipam
223 verify_dns_zone
($dnszone, $dns) if !$skipdns;
226 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
227 my $plugin_config = $ipam_cfg->{ids
}->{$ipamid};
228 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
233 hostname
=> $hostname,
237 my $dhcp_ranges = PVE
::Network
::SDN
::Subnets
::get_dhcp_ranges
($subnet);
239 foreach my $range (@$dhcp_ranges) {
240 $ip = $plugin->add_range_next_freeip($plugin_config, $subnet, $range, $data);
244 $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $vmid);
250 eval { PVE
::Network
::SDN
::Ipams
::add_cache_mac_ip
($mac, $ip); };
255 my $reversednszone = get_reversedns_zone
($subnetid, $subnet, $reversedns, $ip);
259 add_dns_record
($dnszone, $dns, $hostname, $ip);
261 add_dns_ptr_record
($reversednszone, $dnszone, $reversedns, $hostname, $ip);
268 PVE
::Network
::SDN
::Subnets
::del_ip
($zone, $subnetid, $subnet, $ip, $hostname, $mac)
276 my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $vmid, $is_gateway, $skipdns) = @_;
278 return if !$subnet || !$ip;
280 my $ipaddr = NetAddr
::IP-
>new($ip);
281 $ip = $ipaddr->canon();
283 my $ipamid = $zone->{ipam
};
284 my $dns = $zone->{dns
};
285 my $dnszone = $zone->{dnszone
};
286 my $reversedns = $zone->{reversedns
};
287 my $reversednszone = get_reversedns_zone
($subnetid, $subnet, $reversedns, $ip);
288 my $dnszoneprefix = $subnet->{dnszoneprefix
};
290 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
292 #verify dns zones before ipam
294 verify_dns_zone
($dnszone, $dns);
295 verify_dns_zone
($reversednszone, $reversedns);
300 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
301 my $plugin_config = $ipam_cfg->{ids
}->{$ipamid};
302 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
305 $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $vmid, $is_gateway);
309 eval { PVE
::Network
::SDN
::Ipams
::add_cache_mac_ip
($mac, $ip) if $mac; };
316 add_dns_record
($dnszone, $dns, $hostname, $ip);
318 add_dns_ptr_record
($reversednszone, $dnszone, $reversedns, $hostname, $ip);
325 PVE
::Network
::SDN
::Subnets
::del_ip
($zone, $subnetid, $subnet, $ip, $hostname, $mac)
332 my ($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $vmid, $skipdns) = @_;
334 return if !$subnet || !$ip;
336 my $ipaddr = NetAddr
::IP-
>new($ip);
337 $ip = $ipaddr->canon();
339 my $ipamid = $zone->{ipam
};
340 my $dns = $zone->{dns
};
341 my $dnszone = $zone->{dnszone
};
342 my $reversedns = $zone->{reversedns
};
343 my $reversednszone = get_reversedns_zone
($subnetid, $subnet, $reversedns, $ip);
344 my $dnszoneprefix = $subnet->{dnszoneprefix
};
346 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
348 #verify dns zones before ipam
350 verify_dns_zone
($dnszone, $dns);
351 verify_dns_zone
($reversednszone, $reversedns);
355 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
356 my $plugin_config = $ipam_cfg->{ids
}->{$ipamid};
357 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
359 $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $vmid);
364 return if $hostname eq $oldhostname;
369 del_dns_record
($dnszone, $dns, $oldhostname, $ip);
370 add_dns_record
($dnszone, $dns, $hostname, $ip);
372 del_dns_ptr_record
($reversednszone, $reversedns, $ip);
373 add_dns_ptr_record
($reversednszone, $dnszone, $reversedns, $hostname, $ip);
379 my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $skipdns) = @_;
381 return if !$subnet || !$ip;
383 my $ipaddr = NetAddr
::IP-
>new($ip);
384 $ip = $ipaddr->canon();
386 my $ipamid = $zone->{ipam
};
387 my $dns = $zone->{dns
};
388 my $dnszone = $zone->{dnszone
};
389 my $reversedns = $zone->{reversedns
};
390 my $reversednszone = get_reversedns_zone
($subnetid, $subnet, $reversedns, $ip);
391 my $dnszoneprefix = $subnet->{dnszoneprefix
};
392 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
395 verify_dns_zone
($dnszone, $dns);
396 verify_dns_zone
($reversednszone, $reversedns);
400 my $ipam_cfg = PVE
::Network
::SDN
::Ipams
::config
();
401 my $plugin_config = $ipam_cfg->{ids
}->{$ipamid};
402 my $plugin = PVE
::Network
::SDN
::Ipams
::Plugin-
>lookup($plugin_config->{type
});
403 $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
406 eval { PVE
::Network
::SDN
::Ipams
::del_cache_mac_ip
($mac, $ip) };
413 del_dns_record
($dnszone, $dns, $hostname, $ip);
414 del_dns_ptr_record
($reversednszone, $reversedns, $ip);