Signed-off-by: Alexandre Derumier <aderum...@odiso.com> --- PVE/API2/Network/SDN.pm | 1 + PVE/Network/SDN.pm | 2 + PVE/Network/SDN/EvpnPlugin.pm | 200 +++++++++++++++++++++++++++++++++ PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/VxlanPlugin.pm | 54 --------- test/documentation.txt | 4 +- 6 files changed, 206 insertions(+), 57 deletions(-) create mode 100644 PVE/Network/SDN/EvpnPlugin.pm
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index e4ed5cc..cbd393e 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -14,6 +14,7 @@ use PVE::Network::SDN::VnetPlugin; use PVE::Network::SDN::FrrPlugin; use PVE::Network::SDN::OVSFaucetPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::EvpnPlugin; use Storable qw(dclone); use PVE::JSONSchema qw(get_standard_option); diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 1946bc5..137f9f9 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -15,6 +15,7 @@ use PVE::Network::SDN::VxlanPlugin; use PVE::Network::SDN::FrrPlugin; use PVE::Network::SDN::OVSFaucetPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::EvpnPlugin; PVE::Network::SDN::VnetPlugin->register(); PVE::Network::SDN::VlanPlugin->register(); @@ -22,6 +23,7 @@ PVE::Network::SDN::VxlanPlugin->register(); PVE::Network::SDN::FrrPlugin->register(); PVE::Network::SDN::OVSFaucetPlugin->register(); PVE::Network::SDN::FaucetPlugin->register(); +PVE::Network::SDN::EvpnPlugin->register(); PVE::Network::SDN::Plugin->init(); diff --git a/PVE/Network/SDN/EvpnPlugin.pm b/PVE/Network/SDN/EvpnPlugin.pm new file mode 100644 index 0000000..f570f2f --- /dev/null +++ b/PVE/Network/SDN/EvpnPlugin.pm @@ -0,0 +1,200 @@ +package PVE::Network::SDN::EvpnPlugin; + +use strict; +use warnings; +use PVE::Network::SDN::Plugin; +use PVE::Tools qw($IPV4RE); +use PVE::INotify; + +use base('PVE::Network::SDN::VxlanPlugin'); + +sub type { + return 'evpn'; +} + +sub plugindata { + return { + role => 'transport', + }; +} + +sub properties { + return { + 'vrf' => { + description => "vrf name.", + type => 'string', #fixme: format + }, + 'vrf-vxlan' => { + type => 'integer', + description => "l3vni.", + }, + 'controller' => { + type => 'string', + description => "Frr router name", + }, + }; +} + +sub options { + + return { + 'uplink-id' => { optional => 0 }, + 'vxlan-allowed' => { optional => 1 }, + 'vrf' => { optional => 0 }, + 'vrf-vxlan' => { optional => 0 }, + 'controller' => { optional => 0 }, + }; +} + +# Plugin implementation +sub generate_sdn_config { + my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_; + + my $tag = $vnet->{tag}; + my $alias = $vnet->{alias}; + my $ipv4 = $vnet->{ipv4}; + my $ipv6 = $vnet->{ipv6}; + my $mac = $vnet->{mac}; + + my $uplink = $plugin_config->{'uplink-id'}; + my $vxlanallowed = $plugin_config->{'vxlan-allowed'}; + my $vrf = $plugin_config->{'vrf'}; + my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; + + die "missing vxlan tag" if !$tag; + my $iface = "uplink$uplink"; + my $ifaceip = ""; + + if($uplinks->{$uplink}->{name}) { + $iface = $uplinks->{$uplink}->{name}; + $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface); + } + + my $mtu = 1450; + $mtu = $uplinks->{$uplink}->{mtu} - 50 if $uplinks->{$uplink}->{mtu}; + $mtu = $vnet->{mtu} if $vnet->{mtu}; + + #vxlan interface + my @iface_config = (); + push @iface_config, "vxlan-id $tag"; + + push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip; + push @iface_config, "bridge-learning off"; + push @iface_config, "bridge-arp-nd-suppress on"; + + push @iface_config, "mtu $mtu" if $mtu; + push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"}; + + #vnet bridge + @iface_config = (); + push @iface_config, "address $ipv4" if $ipv4; + push @iface_config, "address $ipv6" if $ipv6; + push @iface_config, "hwaddress $mac" if $mac; + push @iface_config, "bridge_ports vxlan$vnetid"; + push @iface_config, "bridge_stp off"; + push @iface_config, "bridge_fd 0"; + push @iface_config, "mtu $mtu" if $mtu; + push @iface_config, "alias $alias" if $alias; + push @iface_config, "ip-forward on" if $ipv4; + push @iface_config, "ip6-forward on" if $ipv6; + push @iface_config, "arp-accept on" if $ipv4||$ipv6; + push @iface_config, "vrf $vrf" if $vrf; + push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; + + if ($vrf) { + #vrf interface + @iface_config = (); + push @iface_config, "vrf-table auto"; + push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf}; + + if ($vrfvxlan) { + #l3vni vxlan interface + my $iface_vxlan = "vxlan$vrf"; + @iface_config = (); + push @iface_config, "vxlan-id $vrfvxlan"; + push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip; + push @iface_config, "bridge-learning off"; + push @iface_config, "bridge-arp-nd-suppress on"; + push @iface_config, "mtu $mtu" if $mtu; + push(@{$config->{$iface_vxlan}}, @iface_config) if !$config->{$iface_vxlan}; + + #l3vni bridge + my $brvrf = "br$vrf"; + @iface_config = (); + push @iface_config, "bridge-ports $iface_vxlan"; + push @iface_config, "bridge_stp off"; + push @iface_config, "bridge_fd 0"; + push @iface_config, "mtu $mtu" if $mtu; + push @iface_config, "vrf $vrf"; + push(@{$config->{$brvrf}}, @iface_config) if !$config->{$brvrf}; + } + } + + return $config; +} + +sub on_update_hook { + my ($class, $transportid, $sdn_cfg) = @_; + + my $transport = $sdn_cfg->{ids}->{$transportid}; + + # verify that vxlan-allowed don't conflict with another vxlan-allowed transport + + # verify that vxlan-allowed is matching currently vnet tag in this transport + my $vxlanallowed = $transport->{'vxlan-allowed'}; + if ($vxlanallowed) { + foreach my $id (keys %{$sdn_cfg->{ids}}) { + my $sdn = $sdn_cfg->{ids}->{$id}; + if ($sdn->{type} eq 'vnet' && defined($sdn->{tag})) { + if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) { + my $tag = $sdn->{tag}; + eval { + PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag); + }; + if($@) { + die "vnet $id - vlan $tag is not allowed in transport $transportid"; + } + } + } + } + } + + # verify that router exist + if (defined($sdn_cfg->{ids}->{$transportid}->{router})) { + my $router = $sdn_cfg->{ids}->{$transportid}->{router}; + if (!defined($sdn_cfg->{ids}->{$router})) { + die "router $router don't exist"; + } else { + die "$router is not a router type" if $sdn_cfg->{ids}->{$router}->{type} ne 'frr'; + } + + #vrf && vrf-vxlan need to be defined with router + my $vrf = $sdn_cfg->{ids}->{$transportid}->{vrf}; + if (!defined($vrf)) { + die "missing vrf option"; + } else { + # verify that vrf is not already declared in another transport + foreach my $id (keys %{$sdn_cfg->{ids}}) { + next if $id eq $transportid; + die "vrf $vrf is already declared in $id" + if (defined($sdn_cfg->{ids}->{$id}->{vrf}) && $sdn_cfg->{ids}->{$id}->{vrf} eq $vrf); + } + } + + my $vrfvxlan = $sdn_cfg->{ids}->{$transportid}->{'vrf-vxlan'}; + if (!defined($vrfvxlan)) { + die "missing vrf-vxlan option"; + } else { + # verify that vrf-vxlan is not already declared in another transport + foreach my $id (keys %{$sdn_cfg->{ids}}) { + next if $id eq $transportid; + die "vrf-vxlan $vrfvxlan is already declared in $id" + if (defined($sdn_cfg->{ids}->{$id}->{'vrf-vxlan'}) && $sdn_cfg->{ids}->{$id}->{'vrf-vxlan'} eq $vrfvxlan); + } + } + } +} + +1; + + diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile index 5bb44dd..4528dcf 100644 --- a/PVE/Network/SDN/Makefile +++ b/PVE/Network/SDN/Makefile @@ -1,4 +1,4 @@ -SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanPlugin.pm FrrPlugin.pm FaucetPlugin.pm OVSFaucetPlugin.pm +SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanPlugin.pm FrrPlugin.pm FaucetPlugin.pm OVSFaucetPlugin.pm EvpnPlugin.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/PVE/Network/SDN/VxlanPlugin.pm b/PVE/Network/SDN/VxlanPlugin.pm index d39a533..5a259b0 100644 --- a/PVE/Network/SDN/VxlanPlugin.pm +++ b/PVE/Network/SDN/VxlanPlugin.pm @@ -60,18 +60,6 @@ sub properties { description => "Unicast peers address ip list.", type => 'string', format => 'ip-list' }, - 'vrf' => { - description => "vrf name.", - type => 'string', #fixme: format - }, - 'vrf-vxlan' => { - type => 'integer', - description => "l3vni.", - }, - 'controller' => { - type => 'string', - description => "Frr router name", - }, }; } @@ -82,9 +70,6 @@ sub options { 'multicast-address' => { optional => 1 }, 'unicast-address' => { optional => 1 }, 'vxlan-allowed' => { optional => 1 }, - 'vrf' => { optional => 1 }, - 'vrf-vxlan' => { optional => 1 }, - 'controller' => { optional => 1 }, }; } @@ -102,8 +87,6 @@ sub generate_sdn_config { my $uplink = $plugin_config->{'uplink-id'}; my $vxlanallowed = $plugin_config->{'vxlan-allowed'}; - my $vrf = $plugin_config->{'vrf'}; - my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; die "missing vxlan tag" if !$tag; my $iface = "uplink$uplink"; @@ -131,10 +114,6 @@ sub generate_sdn_config { next if $address eq $ifaceip; push @iface_config, "vxlan_remoteip $address"; } - } else { - push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip; - push @iface_config, "bridge-learning off"; - push @iface_config, "bridge-arp-nd-suppress on"; } push @iface_config, "mtu $mtu" if $mtu; @@ -150,41 +129,8 @@ sub generate_sdn_config { push @iface_config, "bridge_fd 0"; push @iface_config, "mtu $mtu" if $mtu; push @iface_config, "alias $alias" if $alias; - push @iface_config, "ip-forward on" if $ipv4; - push @iface_config, "ip6-forward on" if $ipv6; - push @iface_config, "arp-accept on" if $ipv4||$ipv6; - push @iface_config, "vrf $vrf" if $vrf; push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; - if ($vrf) { - #vrf intreface - @iface_config = (); - push @iface_config, "vrf-table auto"; - push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf}; - - if ($vrfvxlan) { - #l3vni vxlan interface - my $iface_vxlan = "vxlan$vrf"; - @iface_config = (); - push @iface_config, "vxlan-id $vrfvxlan"; - push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip; - push @iface_config, "bridge-learning off"; - push @iface_config, "bridge-arp-nd-suppress on"; - push @iface_config, "mtu $mtu" if $mtu; - push(@{$config->{$iface_vxlan}}, @iface_config) if !$config->{$iface_vxlan}; - - #l3vni bridge - my $brvrf = "br$vrf"; - @iface_config = (); - push @iface_config, "bridge-ports $iface_vxlan"; - push @iface_config, "bridge_stp off"; - push @iface_config, "bridge_fd 0"; - push @iface_config, "mtu $mtu" if $mtu; - push @iface_config, "vrf $vrf"; - push(@{$config->{$brvrf}}, @iface_config) if !$config->{$brvrf}; - } - } - return $config; } diff --git a/test/documentation.txt b/test/documentation.txt index 785b21c..a0d7a23 100644 --- a/test/documentation.txt +++ b/test/documentation.txt @@ -15,10 +15,10 @@ pvesh create /cluster/sdn/ --sdn vxlanunicastzone --type vxlan --uplink-id 1 --u pvesh create /cluster/sdn/ --sdn frrrouter1 --type frr --uplink-id 1 --peers 192.168.0.1,192.168.0.2,192.168.0.3 --asn 1234 --gateway-nodes pxnode1,pxnode2 --gateway-external-peers 192.168.0.253,192.168.0.254 #create a layer2 vxlan bgpevpn transportzone -pvesh create /cluster/sdn/ --sdn layer2evpnzone --type vxlan --uplink-id 1 --controller frrrouter1 +pvesh create /cluster/sdn/ --sdn layer2evpnzone --type evpn --uplink-id 1 --controller frrrouter1 #create a layer3 routable vxlan bgpevpn transportzone -pvesh create /cluster/sdn/ --sdn layer3evpnzone --type vxlan --uplink-id 1 --controller frrrouter1 --vrf vrf1 --vrf-vxlan 4000 +pvesh create /cluster/sdn/ --sdn layer3evpnzone --type evpn --uplink-id 1 --controller frrrouter1 --vrf vrf1 --vrf-vxlan 4000 #create a vnet in the transportzone -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel