]>
Commit | Line | Data |
---|---|---|
c33dd818 AD |
1 | package PVE::Network::SDN::Subnets; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
70b03506 | 6 | use Net::Subnet qw(subnet_matcher); |
c33dd818 | 7 | use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); |
ee4f339e | 8 | use Net::IP; |
c33dd818 | 9 | |
70b03506 | 10 | use PVE::Network::SDN::Ipams; |
ee4f339e | 11 | use PVE::Network::SDN::Dns; |
c33dd818 AD |
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 | ||
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 | ||
35 | sub config { | |
36 | my $config = cfs_read_file("sdn/subnets.cfg"); | |
37 | } | |
38 | ||
39 | sub write_config { | |
40 | my ($cfg) = @_; | |
41 | ||
42 | cfs_write_file("sdn/subnets.cfg", $cfg); | |
43 | } | |
44 | ||
45 | sub sdn_subnets_ids { | |
46 | my ($cfg) = @_; | |
47 | ||
b184ebc3 | 48 | return sort keys %{$cfg->{ids}}; |
c33dd818 AD |
49 | } |
50 | ||
51 | sub 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 | ||
59 | sub 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 | 74 | sub 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 |
95 | my $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 | 106 | my $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 |
117 | my $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 | ||
130 | my $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 | ||
143 | my $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 | ||
156 | my $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 | 167 | sub 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 | ||
212 | sub 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 | ||
254 | sub 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 | 285 | 1; |