Always create a vnet bridge for each vnet, and avoid to tag vm port directly.
As we don't manage tap|veth vlan tag in /etc/network/interfaces, this could break on reload if user change vlan value on a vnet. ovs --- eth0--->ovsintport(dot1q-tunnel tag)------->vlanawarebrige-----(tag)--->vnet--->vm vlanawarebridge --------------- eth0----vlanawarebrige-(tag)----->vlanwarebridge-(tag)----->vnet--->vm non-vlanaware bridge -------------------- eth0--->eth0.x(svlan)--->eth0.x.y(cvlan)---->vnet---->vm Signed-off-by: Alexandre Derumier <aderum...@odiso.com> --- PVE/Network/SDN/Zones/QinQPlugin.pm | 133 ++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 28 deletions(-) diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm index 3f0697f..fe43d42 100644 --- a/PVE/Network/SDN/Zones/QinQPlugin.pm +++ b/PVE/Network/SDN/Zones/QinQPlugin.pm @@ -2,9 +2,9 @@ package PVE::Network::SDN::Zones::QinQPlugin; use strict; use warnings; -use PVE::Network::SDN::Zones::VlanPlugin; +use PVE::Network::SDN::Zones::Plugin; -use base('PVE::Network::SDN::Zones::VlanPlugin'); +use base('PVE::Network::SDN::Zones::Plugin'); sub type { return 'qinq'; @@ -21,6 +21,12 @@ sub properties { description => "mtu", optional => 1, }, + 'vlan-protocol' => { + type => 'string', + enum => ['802.1q', '802.1ad'], + default => '802.1q', + optional => 1, + } }; } @@ -31,6 +37,7 @@ sub options { 'tag' => { optional => 0 }, 'bridge' => { optional => 0 }, 'mtu' => { optional => 1 }, + 'vlan-protocol' => { optional => 1 }, }; } @@ -38,28 +45,113 @@ sub options { sub generate_sdn_config { my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_; - my $tag = $plugin_config->{tag}; + my $stag = $plugin_config->{tag}; my $mtu = $plugin_config->{mtu}; my $bridge = $plugin_config->{'bridge'}; + my $vlanprotocol = $plugin_config->{'vlan-protocol'}; + my $ctag = $vnet->{tag}; + my $alias = $vnet->{alias}; - die "missing vlan tag" if !$tag; + my $vlan_aware = PVE::Tools::file_read_firstline("/sys/class/net/$bridge/bridge/vlan_filtering"); + my $is_ovs = 1 if !-d "/sys/class/net/$bridge/brif"; - if (!$config->{$zoneid}) { - #zone vlan bridge - my @iface_config = (); + my @iface_config = (); + my $vnet_bridge_ports = ""; + + if($is_ovs) { + + #ovs--->ovsintport(dot1q-tunnel tag)------->vlanawarebrige-----(tag)--->vnet + + $vlanprotocol = "802.1q" if !$vlanprotocol; + my $svlan_iface = "sv_".$zoneid; + my $zone = "z_$zoneid"; + + #ovs dot1q-tunnel port + @iface_config = (); + push @iface_config, "ovs_type OVSIntPort"; + push @iface_config, "ovs_bridge $bridge"; + push @iface_config, "ovs_options vlan_mode=dot1q-tunnel tag=$stag other_config:qinq-ethtype=$vlanprotocol"; + push(@{$config->{$svlan_iface}}, @iface_config) if !$config->{$svlan_iface}; + + + #zone vlan aware bridge + @iface_config = (); push @iface_config, "mtu $mtu" if $mtu; push @iface_config, "bridge-stp off"; + push @iface_config, "bridge-ports $svlan_iface"; push @iface_config, "bridge-fd 0"; push @iface_config, "bridge-vlan-aware yes"; push @iface_config, "bridge-vids 2-4094"; - push(@{$config->{$zoneid}}, @iface_config); + push(@{$config->{$zone}}, @iface_config) if !$config->{$zone}; + + $vnet_bridge_ports = "$zone.$ctag"; + + } elsif ($vlan_aware) { + + #vlanawarebrige-(tag)----->vlanwarebridge-(tag)----->vnet - #main bridge. ifupdown2 will merge it + my $zone = "z_$zoneid"; + + if($vlanprotocol) { + @iface_config = (); + push @iface_config, "bridge-vlan-protocol $vlanprotocol"; + push(@{$config->{$bridge}}, @iface_config) if !$config->{$bridge}; + } + + #zone vlan bridge @iface_config = (); - push @iface_config, "bridge-ports $zoneid.$tag"; - push(@{$config->{$bridge}}, @iface_config); - return $config; - } + push @iface_config, "mtu $mtu" if $mtu; + push @iface_config, "bridge-stp off"; + push @iface_config, "bridge-ports $bridge.$stag"; + push @iface_config, "bridge-fd 0"; + push @iface_config, "bridge-vlan-aware yes"; + push @iface_config, "bridge-vids 2-4094"; + push(@{$config->{$zone}}, @iface_config) if !$config->{$zone}; + + $vnet_bridge_ports = "$zone.$ctag"; + + } else { + + #eth--->eth.x(svlan)--->eth.x.y(cvlan)---->vnet + + my @bridge_ifaces = (); + my $dir = "/sys/class/net/$bridge/brif"; + PVE::Tools::dir_glob_foreach($dir, '(((eth|bond)\d+|en[^.]+)(\.\d+)?)', sub { + push @bridge_ifaces, $_[0]; + }); + + foreach my $bridge_iface (@bridge_ifaces) { + + # use named vlan interface to avoid too long names + my $svlan_iface = "sv_$vnetid"; + my $cvlan_iface = "cv_$vnetid"; + + #svlan + @iface_config = (); + push @iface_config, "vlan-raw-device $bridge_iface"; + push @iface_config, "vlan-id $stag"; + push @iface_config, "vlan-protocol $vlanprotocol" if $vlanprotocol; + push(@{$config->{$svlan_iface}}, @iface_config) if !$config->{$svlan_iface}; + + #cvlan + @iface_config = (); + push @iface_config, "vlan-raw-device $svlan_iface"; + push @iface_config, "vlan-id $ctag"; + push(@{$config->{$cvlan_iface}}, @iface_config) if !$config->{$cvlan_iface}; + + $vnet_bridge_ports .= " $cvlan_iface"; + } + } + + #vnet bridge + @iface_config = (); + push @iface_config, "bridge_ports $vnet_bridge_ports"; + 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(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; + } sub status { @@ -82,21 +174,6 @@ sub status { } } -sub get_bridge_vlan { - my ($class, $plugin_config, $vnetid, $tag) = @_; - - my $bridge = $plugin_config->{bridge}; - die "bridge $bridge is missing" if !-d "/sys/class/net/$bridge/"; - - my $vlan_aware = PVE::Tools::file_read_firstline("/sys/class/net/$bridge/bridge/vlan_filtering"); - my $is_ovs = 1 if !-d "/sys/class/net/$bridge/brif"; - - die "ovs $bridge is not supported by qinq" if $is_ovs; - die "bridge $bridge is not vlan aware" if !$vlan_aware; - - return ($bridge, $tag); -} - 1; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel