]> git.proxmox.com Git - pve-network.git/blame - PVE/Network/SDN/VxlanPlugin.pm
move gateway-nodes option to frr plugin and add gateway-external-peers
[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;
3ee45e4c 6use PVE::Tools;
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
20sub type {
3ee45e4c 21 return 'vxlan';
7e720d4d
AD
22}
23
24sub properties {
25 return {
26 'vxlan-allowed' => {
6bffe819 27 type => 'string', format => 'pve-sdn-vxlanrange',
7e720d4d
AD
28 description => "Allowed vlan range",
29 },
30 'multicast-address' => {
31 description => "Multicast address.",
7d35eaf5 32 type => 'string', #fixme: format
7e720d4d 33 },
3ee45e4c
AD
34 'unicast-address' => {
35 description => "Unicast peers address ip list.",
7d35eaf5 36 type => 'string', #fixme: format
3ee45e4c 37 },
126fc68c
AD
38 'vrf' => {
39 description => "vrf name.",
7d35eaf5 40 type => 'string', #fixme: format
126fc68c
AD
41 },
42 'vrf-vxlan' => {
43 type => 'integer',
44 description => "l3vni.",
45 },
87d8b623
AD
46 'router' => {
47 type => 'string',
48 description => "Frr router name",
49 },
7e720d4d
AD
50 };
51}
52
53sub options {
54
55 return {
85533e98 56 'uplink-id' => { optional => 0 },
3ee45e4c
AD
57 'multicast-address' => { optional => 1 },
58 'unicast-address' => { optional => 1 },
7e720d4d 59 'vxlan-allowed' => { optional => 1 },
126fc68c
AD
60 'vrf' => { optional => 1 },
61 'vrf-vxlan' => { optional => 1 },
87d8b623 62 'router' => { optional => 1 },
7e720d4d
AD
63 };
64}
65
66# Plugin implementation
6bffe819 67sub generate_sdn_config {
93dea3aa 68 my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_;
7e720d4d
AD
69
70 my $tag = $vnet->{tag};
dc7e431e 71 my $alias = $vnet->{alias};
5b31292c
AD
72 my $ipv4 = $vnet->{ipv4};
73 my $ipv6 = $vnet->{ipv6};
74 my $mac = $vnet->{mac};
7e720d4d 75 my $multicastaddress = $plugin_config->{'multicast-address'};
3ee45e4c
AD
76 my @unicastaddress = split(',', $plugin_config->{'unicast-address'}) if $plugin_config->{'unicast-address'};
77
7e720d4d
AD
78 my $uplink = $plugin_config->{'uplink-id'};
79 my $vxlanallowed = $plugin_config->{'vxlan-allowed'};
126fc68c
AD
80 my $vrf = $plugin_config->{'vrf'};
81 my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
7e720d4d
AD
82
83 die "missing vxlan tag" if !$tag;
3ee45e4c
AD
84 my $iface = "uplink$uplink";
85 my $ifaceip = "";
86
87 if($uplinks->{$uplink}->{name}) {
88 $iface = $uplinks->{$uplink}->{name};
89 $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
90 }
c1ae8486
AD
91
92 my $mtu = 1450;
93 $mtu = $uplinks->{$uplink}->{mtu} - 50 if $uplinks->{$uplink}->{mtu};
94 $mtu = $vnet->{mtu} if $vnet->{mtu};
7e720d4d 95
93dea3aa
AD
96 #vxlan interface
97 my @iface_config = ();
98 push @iface_config, "vxlan-id $tag";
3ee45e4c
AD
99
100 if($multicastaddress) {
93dea3aa
AD
101 push @iface_config, "vxlan-svcnodeip $multicastaddress";
102 push @iface_config, "vxlan-physdev $iface";
3ee45e4c
AD
103 } elsif (@unicastaddress) {
104
105 foreach my $address (@unicastaddress) {
106 next if $address eq $ifaceip;
93dea3aa 107 push @iface_config, "vxlan_remoteip $address";
3ee45e4c
AD
108 }
109 } else {
93dea3aa
AD
110 push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip;
111 push @iface_config, "bridge-learning off";
112 push @iface_config, "bridge-arp-nd-suppress on";
3ee45e4c
AD
113 }
114
93dea3aa 115 push @iface_config, "mtu $mtu" if $mtu;
87d8b623 116 push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"};
93dea3aa
AD
117
118 #vnet bridge
119 @iface_config = ();
120 push @iface_config, "address $ipv4" if $ipv4;
121 push @iface_config, "address $ipv6" if $ipv6;
122 push @iface_config, "hwaddress $mac" if $mac;
123 push @iface_config, "bridge_ports vxlan$vnetid";
124 push @iface_config, "bridge_stp off";
125 push @iface_config, "bridge_fd 0";
126 push @iface_config, "mtu $mtu" if $mtu;
127 push @iface_config, "alias $alias" if $alias;
79939ff7
AD
128 push @iface_config, "ip-forward on" if $ipv4;
129 push @iface_config, "ip6-forward on" if $ipv6;
130 push @iface_config, "arp-accept on" if $ipv4||$ipv6;
93dea3aa 131 push @iface_config, "vrf $vrf" if $vrf;
87d8b623 132 push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
126fc68c
AD
133
134 if ($vrf) {
93dea3aa
AD
135 #vrf intreface
136 @iface_config = ();
137 push @iface_config, "vrf-table auto";
87d8b623 138 push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf};
126fc68c
AD
139
140 if ($vrfvxlan) {
93dea3aa
AD
141 #l3vni vxlan interface
142 my $iface_vxlan = "vxlan$vrf";
143 @iface_config = ();
144 push @iface_config, "vxlan-id $vrfvxlan";
145 push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip;
146 push @iface_config, "bridge-learning off";
147 push @iface_config, "bridge-arp-nd-suppress on";
148 push @iface_config, "mtu $mtu" if $mtu;
87d8b623 149 push(@{$config->{$iface_vxlan}}, @iface_config) if !$config->{$iface_vxlan};
93dea3aa
AD
150
151 #l3vni bridge
126fc68c 152 my $brvrf = "br$vrf";
93dea3aa
AD
153 @iface_config = ();
154 push @iface_config, "bridge-ports $iface_vxlan";
155 push @iface_config, "bridge_stp off";
156 push @iface_config, "bridge_fd 0";
157 push @iface_config, "mtu $mtu" if $mtu;
158 push @iface_config, "vrf $vrf";
87d8b623 159 push(@{$config->{$brvrf}}, @iface_config) if !$config->{$brvrf};
126fc68c
AD
160 }
161 }
7e720d4d
AD
162
163 return $config;
164}
165
87d8b623 166sub generate_frr_config {
074d270b 167 my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
87d8b623
AD
168
169 my $vrf = $plugin_config->{'vrf'};
170 my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
074d270b
AD
171 my $asn = $router->{asn};
172 my $gatewaynodes = $router->{'gateway-nodes'};
87d8b623 173
074d270b 174 return if !$vrf || !$vrfvxlan || !$asn;
87d8b623
AD
175
176 #vrf
177 my @router_config = ();
178 push @router_config, "vni $vrfvxlan";
17854295 179 push(@{$config->{vrf}->{"$vrf"}}, @router_config);
87d8b623 180
87d8b623 181 @router_config = ();
e3dca233
AD
182
183 my $is_gateway = undef;
184 my $local_node = PVE::INotify::nodename();
185
186 foreach my $gatewaynode (PVE::Tools::split_list($gatewaynodes)) {
187 $is_gateway = 1 if $gatewaynode eq $local_node;
188 }
189
190 if ($is_gateway) {
191
192 @router_config = ();
193 #import /32 routes of evpn network from vrf1 to default vrf (for packet return)
194 #frr 7.1 tag is bugged -> works fine with 7.1 stable branch(20190829-02-g6ba76bbc1)
195 #https://github.com/FRRouting/frr/issues/4905
17854295
AD
196 push @router_config, "import vrf $vrf";
197 push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
074d270b 198 push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
e3dca233
AD
199
200 @router_config = ();
6c8d2382
AD
201 #redistribute connected to be able to route to local vms on the gateway
202 push @router_config, "redistribute connected";
203 push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
074d270b 204 push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
e3dca233 205
6c8d2382 206 @router_config = ();
e3dca233 207 #add default originate to announce 0.0.0.0/0 type5 route in evpn
17854295 208 push @router_config, "default-originate ipv4";
074d270b 209 push @router_config, "default-originate ipv6";
17854295 210 push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
e3dca233 211 }
87d8b623
AD
212
213 return $config;
214}
215
fe0c6b9e 216sub on_delete_hook {
6bffe819 217 my ($class, $transportid, $sdn_cfg) = @_;
fe0c6b9e
AD
218
219 # verify that no vnet are associated to this transport
6bffe819
AD
220 foreach my $id (keys %{$sdn_cfg->{ids}}) {
221 my $sdn = $sdn_cfg->{ids}->{$id};
7d35eaf5 222 die "transport $transportid is used by vnet $id"
6bffe819 223 if ($sdn->{type} eq 'vnet' && defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid);
a8ad2789 224 }
fe0c6b9e
AD
225}
226
e8d5906e 227sub on_update_hook {
6bffe819 228 my ($class, $transportid, $sdn_cfg) = @_;
c723980e 229
6bffe819 230 my $transport = $sdn_cfg->{ids}->{$transportid};
e8d5906e
AD
231
232 # verify that vxlan-allowed don't conflict with another vxlan-allowed transport
233
7d35eaf5 234 # verify that vxlan-allowed is matching currently vnet tag in this transport
c723980e
AD
235 my $vxlanallowed = $transport->{'vxlan-allowed'};
236 if ($vxlanallowed) {
6bffe819
AD
237 foreach my $id (keys %{$sdn_cfg->{ids}}) {
238 my $sdn = $sdn_cfg->{ids}->{$id};
239 if ($sdn->{type} eq 'vnet' && defined($sdn->{tag})) {
240 if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) {
241 my $tag = $sdn->{tag};
c723980e 242 eval {
86d22462 243 PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
c723980e
AD
244 };
245 if($@) {
246 die "vnet $id - vlan $tag is not allowed in transport $transportid";
247 }
248 }
249 }
250 }
251 }
5bda8607
AD
252
253 # verify that router exist
254 if (defined($sdn_cfg->{ids}->{$transportid}->{router})) {
255 my $router = $sdn_cfg->{ids}->{$transportid}->{router};
256 if (!defined($sdn_cfg->{ids}->{$router})) {
257 die "router $router don't exist";
258 } else {
259 die "$router is not a router type" if $sdn_cfg->{ids}->{$router}->{type} ne 'frr';
260 }
261
262 #vrf && vrf-vxlan need to be defined with router
263 my $vrf = $sdn_cfg->{ids}->{$transportid}->{vrf};
264 if (!defined($vrf)) {
265 die "missing vrf option";
266 } else {
267 # verify that vrf is not already declared in another transport
268 foreach my $id (keys %{$sdn_cfg->{ids}}) {
269 next if $id eq $transportid;
270 die "vrf $vrf is already declared in $id"
271 if (defined($sdn_cfg->{ids}->{$id}->{vrf}) && $sdn_cfg->{ids}->{$id}->{vrf} eq $vrf);
272 }
273 }
274
275 my $vrfvxlan = $sdn_cfg->{ids}->{$transportid}->{'vrf-vxlan'};
276 if (!defined($vrfvxlan)) {
277 die "missing vrf-vxlan option";
278 } else {
279 # verify that vrf-vxlan is not already declared in another transport
280 foreach my $id (keys %{$sdn_cfg->{ids}}) {
281 next if $id eq $transportid;
282 die "vrf-vxlan $vrfvxlan is already declared in $id"
283 if (defined($sdn_cfg->{ids}->{$id}->{'vrf-vxlan'}) && $sdn_cfg->{ids}->{$id}->{'vrf-vxlan'} eq $vrfvxlan);
284 }
285 }
7d35eaf5 286 }
e8d5906e
AD
287}
288
7e720d4d
AD
2891;
290
291