]>
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 | ||
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 { | |
5d3e0248 AD |
52 | my ($subnetid, $running) = @_; |
53 | ||
54 | my $cfg = {}; | |
55 | if($running) { | |
56 | my $cfg = PVE::Network::SDN::config(); | |
57 | $cfg = $cfg->{subnets}; | |
58 | } else { | |
59 | $cfg = PVE::Network::SDN::Subnets::config(); | |
60 | } | |
c33dd818 | 61 | |
c33dd818 AD |
62 | my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1); |
63 | return $subnet; | |
64 | } | |
65 | ||
70b03506 | 66 | sub find_ip_subnet { |
e612faf6 | 67 | my ($ip, $subnets) = @_; |
70b03506 AD |
68 | |
69 | my $subnet = undef; | |
70 | my $subnetid = undef; | |
71 | ||
e612faf6 AD |
72 | foreach my $id (sort keys %{$subnets}) { |
73 | my $cidr = $id =~ s/-/\//r; | |
74 | my $subnet_matcher = subnet_matcher($cidr); | |
75 | next if !$subnet_matcher->($ip); | |
76 | $subnet = $subnets->{$id}; | |
77 | $subnetid = $id; | |
78 | last; | |
70b03506 AD |
79 | } |
80 | die "can't find any subnet for ip $ip" if !$subnet; | |
81 | ||
82 | return ($subnetid, $subnet); | |
83 | } | |
84 | ||
ee4f339e AD |
85 | my $verify_dns_zone = sub { |
86 | my ($zone, $dns) = @_; | |
87 | ||
88 | return if !$zone || !$dns; | |
89 | ||
90 | my $dns_cfg = PVE::Network::SDN::Dns::config(); | |
91 | my $plugin_config = $dns_cfg->{ids}->{$dns}; | |
92 | my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type}); | |
93 | $plugin->verify_zone($plugin_config, $zone); | |
94 | }; | |
95 | ||
96 | my $add_dns_record = sub { | |
97 | my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_; | |
98 | return if !$zone || !$dns || !$hostname || !$ip; | |
99 | ||
100 | $hostname .= ".$dnszoneprefix" if $dnszoneprefix; | |
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->add_a_record($plugin_config, $zone, $hostname, $ip); | |
106 | ||
107 | }; | |
108 | ||
109 | my $add_dns_ptr_record = sub { | |
110 | my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_; | |
111 | ||
112 | return if !$zone || !$reversezone || !$dns || !$hostname || !$ip; | |
113 | ||
114 | $hostname .= ".$dnszoneprefix" if $dnszoneprefix; | |
115 | $hostname .= ".$zone"; | |
116 | my $dns_cfg = PVE::Network::SDN::Dns::config(); | |
117 | my $plugin_config = $dns_cfg->{ids}->{$dns}; | |
118 | my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type}); | |
119 | $plugin->add_ptr_record($plugin_config, $reversezone, $hostname, $ip); | |
120 | }; | |
121 | ||
122 | my $del_dns_record = sub { | |
123 | my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_; | |
124 | ||
125 | return if !$zone || !$dns || !$hostname || !$ip; | |
126 | ||
127 | $hostname .= ".$dnszoneprefix" if $dnszoneprefix; | |
128 | ||
129 | my $dns_cfg = PVE::Network::SDN::Dns::config(); | |
130 | my $plugin_config = $dns_cfg->{ids}->{$dns}; | |
131 | my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type}); | |
132 | $plugin->del_a_record($plugin_config, $zone, $hostname, $ip); | |
133 | }; | |
134 | ||
135 | my $del_dns_ptr_record = sub { | |
136 | my ($reversezone, $dns, $ip) = @_; | |
137 | ||
138 | return if !$reversezone || !$dns || !$ip; | |
139 | ||
140 | my $dns_cfg = PVE::Network::SDN::Dns::config(); | |
141 | my $plugin_config = $dns_cfg->{ids}->{$dns}; | |
142 | my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type}); | |
143 | $plugin->del_ptr_record($plugin_config, $reversezone, $ip); | |
144 | }; | |
145 | ||
70b03506 | 146 | sub next_free_ip { |
ee4f339e AD |
147 | my ($subnetid, $subnet, $hostname) = @_; |
148 | ||
149 | my $cidr = undef; | |
150 | my $ip = undef; | |
70b03506 AD |
151 | |
152 | my $ipamid = $subnet->{ipam}; | |
ee4f339e AD |
153 | my $dns = $subnet->{dns}; |
154 | my $dnszone = $subnet->{dnszone}; | |
155 | my $reversedns = $subnet->{reversedns}; | |
156 | my $reversednszone = $subnet->{reversednszone}; | |
157 | my $dnszoneprefix = $subnet->{dnszoneprefix}; | |
158 | ||
159 | #verify dns zones before ipam | |
160 | &$verify_dns_zone($dnszone, $dns); | |
161 | &$verify_dns_zone($reversednszone, $reversedns); | |
162 | ||
163 | if($ipamid) { | |
164 | my $ipam_cfg = PVE::Network::SDN::Ipams::config(); | |
165 | my $plugin_config = $ipam_cfg->{ids}->{$ipamid}; | |
166 | my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); | |
e612faf6 AD |
167 | eval { |
168 | $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet); | |
169 | ($ip, undef) = split(/\//, $cidr); | |
170 | }; | |
171 | die $@ if $@; | |
ee4f339e | 172 | } |
70b03506 | 173 | |
ee4f339e AD |
174 | eval { |
175 | #add dns | |
176 | &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip); | |
177 | #add reverse dns | |
178 | &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip); | |
179 | }; | |
180 | if ($@) { | |
181 | #rollback | |
182 | my $err = $@; | |
183 | eval { | |
184 | PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname) | |
185 | }; | |
186 | die $err; | |
187 | } | |
188 | return $cidr; | |
70b03506 AD |
189 | } |
190 | ||
191 | sub add_ip { | |
ee4f339e | 192 | my ($subnetid, $subnet, $ip, $hostname) = @_; |
70b03506 | 193 | |
e612faf6 AD |
194 | return if !$subnet; |
195 | ||
70b03506 | 196 | my $ipamid = $subnet->{ipam}; |
ee4f339e AD |
197 | my $dns = $subnet->{dns}; |
198 | my $dnszone = $subnet->{dnszone}; | |
199 | my $reversedns = $subnet->{reversedns}; | |
200 | my $reversednszone = $subnet->{reversednszone}; | |
201 | my $dnszoneprefix = $subnet->{dnszoneprefix}; | |
202 | ||
203 | #verify dns zones before ipam | |
204 | &$verify_dns_zone($dnszone, $dns); | |
205 | &$verify_dns_zone($reversednszone, $reversedns); | |
206 | ||
207 | if ($ipamid) { | |
208 | my $ipam_cfg = PVE::Network::SDN::Ipams::config(); | |
209 | my $plugin_config = $ipam_cfg->{ids}->{$ipamid}; | |
210 | my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); | |
e612faf6 AD |
211 | eval { |
212 | $plugin->add_ip($plugin_config, $subnetid, $ip); | |
213 | }; | |
214 | die $@ if $@; | |
ee4f339e | 215 | } |
70b03506 | 216 | |
ee4f339e AD |
217 | eval { |
218 | #add dns | |
219 | &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip); | |
220 | #add reverse dns | |
221 | &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip); | |
222 | }; | |
223 | if ($@) { | |
224 | #rollback | |
225 | my $err = $@; | |
226 | eval { | |
227 | PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname) | |
228 | }; | |
229 | die $err; | |
230 | } | |
70b03506 AD |
231 | } |
232 | ||
233 | sub del_ip { | |
ee4f339e | 234 | my ($subnetid, $subnet, $ip, $hostname) = @_; |
70b03506 | 235 | |
e612faf6 AD |
236 | return if !$subnet; |
237 | ||
70b03506 | 238 | my $ipamid = $subnet->{ipam}; |
ee4f339e AD |
239 | my $dns = $subnet->{dns}; |
240 | my $dnszone = $subnet->{dnszone}; | |
241 | my $reversedns = $subnet->{reversedns}; | |
242 | my $reversednszone = $subnet->{reversednszone}; | |
243 | my $dnszoneprefix = $subnet->{dnszoneprefix}; | |
244 | ||
245 | &$verify_dns_zone($dnszone, $dns); | |
246 | &$verify_dns_zone($reversednszone, $reversedns); | |
247 | ||
248 | if ($ipamid) { | |
249 | my $ipam_cfg = PVE::Network::SDN::Ipams::config(); | |
250 | my $plugin_config = $ipam_cfg->{ids}->{$ipamid}; | |
251 | my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); | |
252 | $plugin->del_ip($plugin_config, $subnetid, $ip); | |
253 | } | |
70b03506 | 254 | |
ee4f339e AD |
255 | eval { |
256 | &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip); | |
257 | &$del_dns_ptr_record($reversednszone, $reversedns, $ip); | |
258 | }; | |
259 | if ($@) { | |
260 | warn $@; | |
261 | } | |
70b03506 AD |
262 | } |
263 | ||
c33dd818 | 264 | 1; |