]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/VxlanPlugin.pm
add evpnplugin (splitted from vxlanplugin)
[pve-network.git] / PVE / Network / SDN / VxlanPlugin.pm
CommitLineData
3ee45e4c 1package PVE::Network::SDN::VxlanPlugin;
7e720d4d
AD
2
3use strict;
4use warnings;
86d22462 5use PVE::Network::SDN::Plugin;
c692cbfa 6use PVE::Tools qw($IPV4RE);
e3dca233 7use PVE::INotify;
7e720d4d 8
86d22462 9use base('PVE::Network::SDN::Plugin');
7e720d4d 10
6bffe819
AD
11PVE::JSONSchema::register_format('pve-sdn-vxlanrange', \&pve_verify_sdn_vxlanrange);
12sub pve_verify_sdn_vxlanrange {
7e720d4d
AD
13 my ($vxlanstr) = @_;
14
86d22462 15 PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanstr, '16777216');
7e720d4d
AD
16
17 return $vxlanstr;
18}
19
c692cbfa
AD
20PVE::JSONSchema::register_format('ipv4-multicast', \&parse_ipv4_multicast);
21sub parse_ipv4_multicast {
22 my ($ipv4, $noerr) = @_;
23
24 if ($ipv4 !~ m/^(?:$IPV4RE)$/) {
25 return undef if $noerr;
26 die "value does not look like a valid multicast IPv4 address\n";
27 }
28
29 if ($ipv4 =~ m/^(\d+)\.\d+.\d+.\d+/) {
30 if($1 < 224 || $1 > 239) {
31 return undef if $noerr;
32 die "value does not look like a valid multicast IPv4 address\n";
33 }
34 }
35
36 return $ipv4;
37}
38
7e720d4d 39sub type {
3ee45e4c 40 return 'vxlan';
7e720d4d
AD
41}
42
8fb1ee7f
AD
43sub plugindata {
44 return {
45 role => 'transport',
46 };
47}
48
7e720d4d
AD
49sub properties {
50 return {
51 'vxlan-allowed' => {
6bffe819 52 type => 'string', format => 'pve-sdn-vxlanrange',
7e720d4d
AD
53 description => "Allowed vlan range",
54 },
55 'multicast-address' => {
56 description => "Multicast address.",
c692cbfa 57 type => 'string', format => 'ipv4-multicast'
7e720d4d 58 },
3ee45e4c
AD
59 'unicast-address' => {
60 description => "Unicast peers address ip list.",
fcfca9ef 61 type => 'string', format => 'ip-list'
3ee45e4c 62 },
7e720d4d
AD
63 };
64}
65
66sub options {
67
68 return {
85533e98 69 'uplink-id' => { optional => 0 },
3ee45e4c
AD
70 'multicast-address' => { optional => 1 },
71 'unicast-address' => { optional => 1 },
7e720d4d
AD
72 'vxlan-allowed' => { optional => 1 },
73 };
74}
75
76# Plugin implementation
6bffe819 77sub generate_sdn_config {
93dea3aa 78 my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_;
7e720d4d
AD
79
80 my $tag = $vnet->{tag};
dc7e431e 81 my $alias = $vnet->{alias};
5b31292c
AD
82 my $ipv4 = $vnet->{ipv4};
83 my $ipv6 = $vnet->{ipv6};
84 my $mac = $vnet->{mac};
7e720d4d 85 my $multicastaddress = $plugin_config->{'multicast-address'};
3ee45e4c
AD
86 my @unicastaddress = split(',', $plugin_config->{'unicast-address'}) if $plugin_config->{'unicast-address'};
87
7e720d4d
AD
88 my $uplink = $plugin_config->{'uplink-id'};
89 my $vxlanallowed = $plugin_config->{'vxlan-allowed'};
90
91 die "missing vxlan tag" if !$tag;
3ee45e4c
AD
92 my $iface = "uplink$uplink";
93 my $ifaceip = "";
94
95 if($uplinks->{$uplink}->{name}) {
96 $iface = $uplinks->{$uplink}->{name};
97 $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
98 }
c1ae8486
AD
99
100 my $mtu = 1450;
101 $mtu = $uplinks->{$uplink}->{mtu} - 50 if $uplinks->{$uplink}->{mtu};
102 $mtu = $vnet->{mtu} if $vnet->{mtu};
7e720d4d 103
93dea3aa
AD
104 #vxlan interface
105 my @iface_config = ();
106 push @iface_config, "vxlan-id $tag";
3ee45e4c
AD
107
108 if($multicastaddress) {
93dea3aa
AD
109 push @iface_config, "vxlan-svcnodeip $multicastaddress";
110 push @iface_config, "vxlan-physdev $iface";
3ee45e4c
AD
111 } elsif (@unicastaddress) {
112
113 foreach my $address (@unicastaddress) {
114 next if $address eq $ifaceip;
93dea3aa 115 push @iface_config, "vxlan_remoteip $address";
3ee45e4c 116 }
3ee45e4c
AD
117 }
118
93dea3aa 119 push @iface_config, "mtu $mtu" if $mtu;
87d8b623 120 push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"};
93dea3aa
AD
121
122 #vnet bridge
123 @iface_config = ();
124 push @iface_config, "address $ipv4" if $ipv4;
125 push @iface_config, "address $ipv6" if $ipv6;
126 push @iface_config, "hwaddress $mac" if $mac;
127 push @iface_config, "bridge_ports vxlan$vnetid";
128 push @iface_config, "bridge_stp off";
129 push @iface_config, "bridge_fd 0";
130 push @iface_config, "mtu $mtu" if $mtu;
131 push @iface_config, "alias $alias" if $alias;
87d8b623 132 push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
126fc68c 133
7e720d4d
AD
134 return $config;
135}
136
fe0c6b9e 137sub on_delete_hook {
6bffe819 138 my ($class, $transportid, $sdn_cfg) = @_;
fe0c6b9e
AD
139
140 # verify that no vnet are associated to this transport
6bffe819
AD
141 foreach my $id (keys %{$sdn_cfg->{ids}}) {
142 my $sdn = $sdn_cfg->{ids}->{$id};
7d35eaf5 143 die "transport $transportid is used by vnet $id"
6bffe819 144 if ($sdn->{type} eq 'vnet' && defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid);
a8ad2789 145 }
fe0c6b9e
AD
146}
147
e8d5906e 148sub on_update_hook {
6bffe819 149 my ($class, $transportid, $sdn_cfg) = @_;
c723980e 150
6bffe819 151 my $transport = $sdn_cfg->{ids}->{$transportid};
e8d5906e
AD
152
153 # verify that vxlan-allowed don't conflict with another vxlan-allowed transport
154
7d35eaf5 155 # verify that vxlan-allowed is matching currently vnet tag in this transport
c723980e
AD
156 my $vxlanallowed = $transport->{'vxlan-allowed'};
157 if ($vxlanallowed) {
6bffe819
AD
158 foreach my $id (keys %{$sdn_cfg->{ids}}) {
159 my $sdn = $sdn_cfg->{ids}->{$id};
160 if ($sdn->{type} eq 'vnet' && defined($sdn->{tag})) {
161 if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) {
162 my $tag = $sdn->{tag};
c723980e 163 eval {
86d22462 164 PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
c723980e
AD
165 };
166 if($@) {
167 die "vnet $id - vlan $tag is not allowed in transport $transportid";
168 }
169 }
170 }
171 }
172 }
5bda8607
AD
173
174 # verify that router exist
175 if (defined($sdn_cfg->{ids}->{$transportid}->{router})) {
176 my $router = $sdn_cfg->{ids}->{$transportid}->{router};
177 if (!defined($sdn_cfg->{ids}->{$router})) {
178 die "router $router don't exist";
179 } else {
180 die "$router is not a router type" if $sdn_cfg->{ids}->{$router}->{type} ne 'frr';
181 }
182
183 #vrf && vrf-vxlan need to be defined with router
184 my $vrf = $sdn_cfg->{ids}->{$transportid}->{vrf};
185 if (!defined($vrf)) {
186 die "missing vrf option";
187 } else {
188 # verify that vrf is not already declared in another transport
189 foreach my $id (keys %{$sdn_cfg->{ids}}) {
190 next if $id eq $transportid;
191 die "vrf $vrf is already declared in $id"
192 if (defined($sdn_cfg->{ids}->{$id}->{vrf}) && $sdn_cfg->{ids}->{$id}->{vrf} eq $vrf);
193 }
194 }
195
196 my $vrfvxlan = $sdn_cfg->{ids}->{$transportid}->{'vrf-vxlan'};
197 if (!defined($vrfvxlan)) {
198 die "missing vrf-vxlan option";
199 } else {
200 # verify that vrf-vxlan is not already declared in another transport
201 foreach my $id (keys %{$sdn_cfg->{ids}}) {
202 next if $id eq $transportid;
203 die "vrf-vxlan $vrfvxlan is already declared in $id"
204 if (defined($sdn_cfg->{ids}->{$id}->{'vrf-vxlan'}) && $sdn_cfg->{ids}->{$id}->{'vrf-vxlan'} eq $vrfvxlan);
205 }
206 }
7d35eaf5 207 }
e8d5906e
AD
208}
209
7e720d4d
AD
2101;
211
212