]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/SubnetPlugin.pm
Fix vnet gateway for routed setup + /32 pointopoint subnet
[pve-network.git] / PVE / Network / SDN / SubnetPlugin.pm
CommitLineData
c33dd818
AD
1package PVE::Network::SDN::SubnetPlugin;
2
3use strict;
4use warnings;
5
6use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
7use base qw(PVE::SectionConfig);
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::Exception qw(raise raise_param_exc);
10use Net::Subnet qw(subnet_matcher);
e612faf6
AD
11use PVE::Network::SDN::Vnets;
12use PVE::Network::SDN::Ipams;
c33dd818
AD
13
14PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
15 sub { __PACKAGE__->parse_config(@_); },
16 sub { __PACKAGE__->write_config(@_); });
17
18PVE::JSONSchema::register_standard_option('pve-sdn-subnet-id', {
19 description => "The SDN subnet object identifier.",
20 type => 'string', format => 'pve-sdn-subnet-id',
21 type => 'string'
22});
23
24PVE::JSONSchema::register_format('pve-sdn-subnet-id', \&parse_sdn_subnet_id);
25sub parse_sdn_subnet_id {
26 my ($id, $noerr) = @_;
27
28 my $cidr = $id =~ s/-/\//r;
29
30 if (!(PVE::JSONSchema::pve_verify_cidrv4($cidr, 1) ||
31 PVE::JSONSchema::pve_verify_cidrv6($cidr, 1)))
32 {
33 return undef if $noerr;
34 die "value does not look like a valid CIDR network\n";
35 }
36 return $id;
37}
38
39my $defaultData = {
40
41 propertyList => {
42 subnet => get_standard_option('pve-sdn-subnet-id',
43 { completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnet }),
44 },
45};
46
47sub type {
48 return 'subnet';
49}
50
51sub private {
52 return $defaultData;
53}
54
55sub properties {
56 return {
e612faf6
AD
57 vnet => {
58 type => 'string',
59 description => "associated vnet",
60 },
c33dd818
AD
61 gateway => {
62 type => 'string', format => 'ip',
63 description => "Subnet Gateway: Will be assign on vnet for layer3 zones",
64 },
65 snat => {
66 type => 'boolean',
67 description => "enable masquerade for this subnet if pve-firewall",
68 },
f6f2aa16
AD
69# #cloudinit, dhcp options
70# routes => {
71# type => 'string',
72# description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
73# },
ee4f339e
AD
74 dns => {
75 type => 'string',
76 description => "dns api server",
c33dd818 77 },
ee4f339e 78 reversedns => {
c33dd818 79 type => 'string',
ee4f339e 80 description => "reverse dns api server",
c33dd818 81 },
ee4f339e 82 dnszone => {
f6f2aa16 83 type => 'string', format => 'dns-name',
ee4f339e 84 description => "dns domain zone ex: mydomain.com",
c33dd818 85 },
ee4f339e 86 reversednszone => {
f6f2aa16 87 type => 'string', format => 'dns-name',
ee4f339e
AD
88 description => "reverse dns zone ex: 0.168.192.in-addr.arpa",
89 },
90 dnszoneprefix => {
f6f2aa16 91 type => 'string', format => 'dns-name',
ee4f339e 92 description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
c33dd818 93 },
70b03506 94 ipam => {
c33dd818
AD
95 type => 'string',
96 description => "use a specific ipam",
97 },
98 };
99}
100
101sub options {
102 return {
3926d9a7 103 vnet => { optional => 0 },
c33dd818 104 gateway => { optional => 1 },
f6f2aa16 105# routes => { optional => 1 },
c33dd818 106 snat => { optional => 1 },
ee4f339e
AD
107 dns => { optional => 1 },
108 reversedns => { optional => 1 },
109 dnszone => { optional => 1 },
110 reversednszone => { optional => 1 },
111 dnszoneprefix => { optional => 1 },
70b03506 112 ipam => { optional => 1 },
c33dd818
AD
113 };
114}
115
116sub on_update_hook {
e612faf6 117 my ($class, $subnetid, $subnet, $old_subnet) = @_;
c33dd818 118
ee4f339e
AD
119 my $cidr = $subnetid =~ s/-/\//r;
120 my $subnet_matcher = subnet_matcher($cidr);
121
e612faf6 122 my $vnetid = $subnet->{vnet};
ee4f339e 123 my $gateway = $subnet->{gateway};
e612faf6 124 my $ipam = $subnet->{ipam};
ee4f339e
AD
125 my $dns = $subnet->{dns};
126 my $dnszone = $subnet->{dnszone};
127 my $reversedns = $subnet->{reversedns};
128 my $reversednszone = $subnet->{reversednszone};
129
e612faf6
AD
130 my $old_gateway = $old_subnet->{gateway} if $old_subnet;
131
132 if($vnetid) {
133 my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
134 raise_param_exc({ vnet => "$vnetid don't exist"}) if !$vnet;
135 }
136
137 my ($ip, $mask) = split(/\//, $cidr);
138 #for /32 pointopoint, we allow gateway outside the subnet
139 raise_param_exc({ gateway => "$gateway is not in subnet $subnetid"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
70b03506 140
ee4f339e
AD
141 raise_param_exc({ dns => "missing dns provider"}) if $dnszone && !$dns;
142 raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
143 raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
144 raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
145 raise_param_exc({ reversedns => "missing forward dns zone"}) if $reversednszone && !$dnszone;
146
e612faf6
AD
147 if ($ipam) {
148 my $ipam_cfg = PVE::Network::SDN::Ipams::config();
149 my $plugin_config = $ipam_cfg->{ids}->{$ipam};
150 raise_param_exc({ ipam => "$ipam not existing"}) if !$plugin_config;
151 my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
152 $plugin->add_subnet($plugin_config, $subnetid, $subnet);
153
154 #delete on removal
155 if (!defined($gateway) && $old_gateway) {
156 eval {
157 PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
158 };
159 warn if $@;
160 }
161 if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
162 PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $gateway);
163 }
164
165 #delete old ip after update
166 if($gateway && $old_gateway && $gateway ne $old_gateway) {
167 eval {
168 PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
169 };
170 warn if $@;
171 }
172 }
c33dd818
AD
173}
174
58a7773a
AD
175sub on_delete_hook {
176 my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
177
58a7773a
AD
178 return;
179}
180
c33dd818 1811;