1 package PVE
::Network
::SDN
::VxlanPlugin
;
5 use PVE
::Network
::SDN
::Plugin
;
9 use base
('PVE::Network::SDN::Plugin');
11 PVE
::JSONSchema
::register_format
('pve-sdn-vxlanrange', \
&pve_verify_sdn_vxlanrange
);
12 sub pve_verify_sdn_vxlanrange
{
15 PVE
::Network
::SDN
::Plugin
::parse_tag_number_or_range
($vxlanstr, '16777216');
27 type
=> 'string', format
=> 'pve-sdn-vxlanrange',
28 description
=> "Allowed vlan range",
30 'multicast-address' => {
31 description
=> "Multicast address.",
32 type
=> 'string', #fixme: format
34 'unicast-address' => {
35 description
=> "Unicast peers address ip list.",
36 type
=> 'string', #fixme: format
39 description
=> "vrf name.",
40 type
=> 'string', #fixme: format
44 description
=> "l3vni.",
48 description
=> "Frr router name",
56 'uplink-id' => { optional
=> 0 },
57 'multicast-address' => { optional
=> 1 },
58 'unicast-address' => { optional
=> 1 },
59 'vxlan-allowed' => { optional
=> 1 },
60 'vrf' => { optional
=> 1 },
61 'vrf-vxlan' => { optional
=> 1 },
62 'router' => { optional
=> 1 },
66 # Plugin implementation
67 sub generate_sdn_config
{
68 my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_;
70 my $tag = $vnet->{tag
};
71 my $alias = $vnet->{alias
};
72 my $ipv4 = $vnet->{ipv4
};
73 my $ipv6 = $vnet->{ipv6
};
74 my $mac = $vnet->{mac
};
75 my $multicastaddress = $plugin_config->{'multicast-address'};
76 my @unicastaddress = split(',', $plugin_config->{'unicast-address'}) if $plugin_config->{'unicast-address'};
78 my $uplink = $plugin_config->{'uplink-id'};
79 my $vxlanallowed = $plugin_config->{'vxlan-allowed'};
80 my $vrf = $plugin_config->{'vrf'};
81 my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
83 die "missing vxlan tag" if !$tag;
84 my $iface = "uplink$uplink";
87 if($uplinks->{$uplink}->{name
}) {
88 $iface = $uplinks->{$uplink}->{name
};
89 $ifaceip = PVE
::Network
::SDN
::Plugin
::get_first_local_ipv4_from_interface
($iface);
93 $mtu = $uplinks->{$uplink}->{mtu
} - 50 if $uplinks->{$uplink}->{mtu
};
94 $mtu = $vnet->{mtu
} if $vnet->{mtu
};
97 my @iface_config = ();
98 push @iface_config, "vxlan-id $tag";
100 if($multicastaddress) {
101 push @iface_config, "vxlan-svcnodeip $multicastaddress";
102 push @iface_config, "vxlan-physdev $iface";
103 } elsif (@unicastaddress) {
105 foreach my $address (@unicastaddress) {
106 next if $address eq $ifaceip;
107 push @iface_config, "vxlan_remoteip $address";
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";
115 push @iface_config, "mtu $mtu" if $mtu;
116 push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"};
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;
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;
131 push @iface_config, "vrf $vrf" if $vrf;
132 push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
137 push @iface_config, "vrf-table auto";
138 push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf};
141 #l3vni vxlan interface
142 my $iface_vxlan = "vxlan$vrf";
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;
149 push(@{$config->{$iface_vxlan}}, @iface_config) if !$config->{$iface_vxlan};
152 my $brvrf = "br$vrf";
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";
159 push(@{$config->{$brvrf}}, @iface_config) if !$config->{$brvrf};
166 sub generate_frr_config
{
167 my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
169 my $vrf = $plugin_config->{'vrf'};
170 my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
171 my $asn = $router->{asn
};
172 my $gatewaynodes = $router->{'gateway-nodes'};
174 return if !$vrf || !$vrfvxlan || !$asn;
177 my @router_config = ();
178 push @router_config, "vni $vrfvxlan";
179 push(@{$config->{vrf
}->{"$vrf"}}, @router_config);
183 my $is_gateway = undef;
184 my $local_node = PVE
::INotify
::nodename
();
186 foreach my $gatewaynode (PVE
::Tools
::split_list
($gatewaynodes)) {
187 $is_gateway = 1 if $gatewaynode eq $local_node;
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
196 push @router_config, "import vrf $vrf";
197 push(@{$config->{router
}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
198 push(@{$config->{router
}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
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);
204 push(@{$config->{router
}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
207 #add default originate to announce 0.0.0.0/0 type5 route in evpn
208 push @router_config, "default-originate ipv4";
209 push @router_config, "default-originate ipv6";
210 push(@{$config->{router
}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
217 my ($class, $transportid, $sdn_cfg) = @_;
219 # verify that no vnet are associated to this transport
220 foreach my $id (keys %{$sdn_cfg->{ids
}}) {
221 my $sdn = $sdn_cfg->{ids
}->{$id};
222 die "transport $transportid is used by vnet $id"
223 if ($sdn->{type
} eq 'vnet' && defined($sdn->{transportzone
}) && $sdn->{transportzone
} eq $transportid);
228 my ($class, $transportid, $sdn_cfg) = @_;
230 my $transport = $sdn_cfg->{ids
}->{$transportid};
232 # verify that vxlan-allowed don't conflict with another vxlan-allowed transport
234 # verify that vxlan-allowed is matching currently vnet tag in this transport
235 my $vxlanallowed = $transport->{'vxlan-allowed'};
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
};
243 PVE
::Network
::SDN
::Plugin
::parse_tag_number_or_range
($vxlanallowed, '16777216', $tag);
246 die "vnet $id - vlan $tag is not allowed in transport $transportid";
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";
259 die "$router is not a router type" if $sdn_cfg->{ids
}->{$router}->{type
} ne 'frr';
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";
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);
275 my $vrfvxlan = $sdn_cfg->{ids
}->{$transportid}->{'vrf-vxlan'};
276 if (!defined($vrfvxlan)) {
277 die "missing vrf-vxlan option";
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);