]> git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN/Subnets.pm
07ef68868a78c01ba0e40af11a86faffd61aa1d0
[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 PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
8 use Net::IP;
9
10 use PVE::Network::SDN::Ipams;
11 use PVE::Network::SDN::Dns;
12 use PVE::Network::SDN::SubnetPlugin;
13 PVE::Network::SDN::SubnetPlugin->register();
14 PVE::Network::SDN::SubnetPlugin->init();
15
16 sub 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
24 return $scfg;
25 }
26
27 sub config {
28 my $config = cfs_read_file("sdn/subnets.cfg");
29 }
30
31 sub write_config {
32 my ($cfg) = @_;
33
34 cfs_write_file("sdn/subnets.cfg", $cfg);
35 }
36
37 sub sdn_subnets_ids {
38 my ($cfg) = @_;
39
40 return keys %{$cfg->{ids}};
41 }
42
43 sub complete_sdn_subnet {
44 my ($cmdname, $pname, $cvalue) = @_;
45
46 my $cfg = PVE::Network::SDN::Subnets::config();
47
48 return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg) ];
49 }
50
51 sub get_subnet {
52 my ($subnetid) = @_;
53
54 my $cfg = PVE::Network::SDN::Subnets::config();
55 my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
56 return $subnet;
57 }
58
59 sub find_ip_subnet {
60 my ($ip, $subnetslist) = @_;
61
62 my $subnets_cfg = PVE::Network::SDN::Subnets::config();
63 my @subnets = PVE::Tools::split_list($subnetslist) if $subnetslist;
64
65 my $subnet = undef;
66 my $subnetid = undef;
67
68 foreach my $s (@subnets) {
69 my $subnet_matcher = subnet_matcher($s);
70 next if !$subnet_matcher->($ip);
71 $subnetid = $s =~ s/\//-/r;
72 $subnet = $subnets_cfg->{ids}->{$subnetid};
73 last;
74 }
75 die "can't find any subnet for ip $ip" if !$subnet;
76
77 return ($subnetid, $subnet);
78 }
79
80 my $verify_dns_zone = sub {
81 my ($zone, $dns) = @_;
82
83 return if !$zone || !$dns;
84
85 my $dns_cfg = PVE::Network::SDN::Dns::config();
86 my $plugin_config = $dns_cfg->{ids}->{$dns};
87 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
88 $plugin->verify_zone($plugin_config, $zone);
89 };
90
91 my $add_dns_record = sub {
92 my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
93 return if !$zone || !$dns || !$hostname || !$ip;
94
95 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
96
97 my $dns_cfg = PVE::Network::SDN::Dns::config();
98 my $plugin_config = $dns_cfg->{ids}->{$dns};
99 my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
100 $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
101
102 };
103
104 my $add_dns_ptr_record = sub {
105 my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
106
107 return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
108
109 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
110 $hostname .= ".$zone";
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});
114 $plugin->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
115 };
116
117 my $del_dns_record = sub {
118 my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
119
120 return if !$zone || !$dns || !$hostname || !$ip;
121
122 $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
123
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->del_a_record($plugin_config, $zone, $hostname, $ip);
128 };
129
130 my $del_dns_ptr_record = sub {
131 my ($reversezone, $dns, $ip) = @_;
132
133 return if !$reversezone || !$dns || !$ip;
134
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->del_ptr_record($plugin_config, $reversezone, $ip);
139 };
140
141 sub next_free_ip {
142 my ($subnetid, $subnet, $hostname) = @_;
143
144 my $cidr = undef;
145 my $ip = undef;
146
147 my $ipamid = $subnet->{ipam};
148 my $dns = $subnet->{dns};
149 my $dnszone = $subnet->{dnszone};
150 my $reversedns = $subnet->{reversedns};
151 my $reversednszone = $subnet->{reversednszone};
152 my $dnszoneprefix = $subnet->{dnszoneprefix};
153
154 #verify dns zones before ipam
155 &$verify_dns_zone($dnszone, $dns);
156 &$verify_dns_zone($reversednszone, $reversedns);
157
158 if($ipamid) {
159 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
160 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
161 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
162 $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
163 ($ip, undef) = split(/\//, $cidr);
164 }
165
166 eval {
167 #add dns
168 &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
169 #add reverse dns
170 &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
171 };
172 if ($@) {
173 #rollback
174 my $err = $@;
175 eval {
176 PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
177 };
178 die $err;
179 }
180 return $cidr;
181 }
182
183 sub add_ip {
184 my ($subnetid, $subnet, $ip, $hostname) = @_;
185
186 my $ipamid = $subnet->{ipam};
187 my $dns = $subnet->{dns};
188 my $dnszone = $subnet->{dnszone};
189 my $reversedns = $subnet->{reversedns};
190 my $reversednszone = $subnet->{reversednszone};
191 my $dnszoneprefix = $subnet->{dnszoneprefix};
192
193 #verify dns zones before ipam
194 &$verify_dns_zone($dnszone, $dns);
195 &$verify_dns_zone($reversednszone, $reversedns);
196
197 if ($ipamid) {
198 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
199 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
200 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
201 $plugin->add_ip($plugin_config, $subnetid, $ip);
202 }
203
204 eval {
205 #add dns
206 &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
207 #add reverse dns
208 &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
209 };
210 if ($@) {
211 #rollback
212 my $err = $@;
213 eval {
214 PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
215 };
216 die $err;
217 }
218 }
219
220 sub del_ip {
221 my ($subnetid, $subnet, $ip, $hostname) = @_;
222
223 my $ipamid = $subnet->{ipam};
224 my $dns = $subnet->{dns};
225 my $dnszone = $subnet->{dnszone};
226 my $reversedns = $subnet->{reversedns};
227 my $reversednszone = $subnet->{reversednszone};
228 my $dnszoneprefix = $subnet->{dnszoneprefix};
229
230 &$verify_dns_zone($dnszone, $dns);
231 &$verify_dns_zone($reversednszone, $reversedns);
232
233 if ($ipamid) {
234 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
235 my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
236 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
237 $plugin->del_ip($plugin_config, $subnetid, $ip);
238 }
239
240 eval {
241 &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
242 &$del_dns_ptr_record($reversednszone, $reversedns, $ip);
243 };
244 if ($@) {
245 warn $@;
246 }
247 }
248
249 1;