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