]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/Subnets.pm
api: generate 'running-config' state instead of version increase on apply
[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
24 return $scfg;
25}
26
27sub config {
28 my $config = cfs_read_file("sdn/subnets.cfg");
29}
30
31sub write_config {
32 my ($cfg) = @_;
33
34 cfs_write_file("sdn/subnets.cfg", $cfg);
35}
36
37sub sdn_subnets_ids {
38 my ($cfg) = @_;
39
40 return keys %{$cfg->{ids}};
41}
42
43sub 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
51sub 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 66sub 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
85my $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
96my $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
109my $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
122my $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
135my $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 146sub 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
191sub 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
233sub 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 2641;