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