X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FNetwork%2FSDN%2FZones%2FVlanPlugin.pm;h=cda2a364f2a1631d9a0d2a4a0c871c4a56a3bbc0;hb=fdf22d5f6b6c1ba5e61c1222e2548f236da47a1b;hp=dd03838d0d9be8fd1d18ebe6e60c91ea3281e461;hpb=3fd3e9173ae1474dd8b73323af6560adce88ff16;p=pve-network.git diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm index dd03838..cda2a36 100644 --- a/PVE/Network/SDN/Zones/VlanPlugin.pm +++ b/PVE/Network/SDN/Zones/VlanPlugin.pm @@ -3,6 +3,7 @@ package PVE::Network::SDN::Zones::VlanPlugin; use strict; use warnings; use PVE::Network::SDN::Zones::Plugin; +use PVE::Exception qw(raise raise_param_exc); use base('PVE::Network::SDN::Zones::Plugin'); @@ -21,14 +22,8 @@ sub pve_verify_sdn_vlanrange { sub properties { return { - 'uplink-id' => { - type => 'integer', - minimum => 1, maximum => 4096, - description => 'Uplink interface', - }, - 'vlan-allowed' => { - type => 'string', format => 'pve-sdn-vlanrange', - description => "Allowed vlan range", + 'bridge' => { + type => 'string', }, }; } @@ -36,36 +31,99 @@ sub properties { sub options { return { - 'uplink-id' => { optional => 0 }, - 'vlan-allowed' => { optional => 1 }, + nodes => { optional => 1}, + 'bridge' => { optional => 0 }, + mtu => { optional => 1 }, + dns => { optional => 1 }, + reversedns => { optional => 1 }, + dnszone => { optional => 1 }, + ipam => { optional => 0 }, }; } # Plugin implementation sub generate_sdn_config { - my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_; + my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $controller_cfg, $subnet_cfg, $interfaces_config, $config) = @_; + + my $bridge = $plugin_config->{bridge}; + PVE::Network::SDN::Zones::Plugin::find_bridge($bridge); + + my $vlan_aware = PVE::Network::SDN::Zones::Plugin::is_vlanaware($bridge); + my $is_ovs = PVE::Network::SDN::Zones::Plugin::is_ovs($bridge); my $tag = $vnet->{tag}; - my $mtu = $vnet->{mtu}; my $alias = $vnet->{alias}; - my $uplink = $plugin_config->{'uplink-id'}; - - die "missing vlan tag" if !$tag; + my $mtu = $plugin_config->{mtu}; - my $iface = $uplinks->{$uplink}->{name}; - $iface = "uplink${uplink}" if !$iface; - $iface .= ".$tag"; + my $vnet_uplink = "ln_".$vnetid; + my $vnet_uplinkpeer = "pr_".$vnetid; - #tagged interface my @iface_config = (); - push @iface_config, "mtu $mtu" if $mtu; - push(@{$config->{$iface}}, @iface_config) if !$config->{$iface}; + + if($is_ovs) { + + # keep vmbrXvY for compatibility with existing network + # eth0----ovs vmbr0--(ovsintport tag)---->vnet---->vm + + @iface_config = (); + push @iface_config, "ovs_type OVSIntPort"; + push @iface_config, "ovs_bridge $bridge"; + push @iface_config, "ovs_mtu $mtu" if $mtu; + if($vnet->{vlanaware}) { + push @iface_config, "ovs_options vlan_mode=dot1q-tunnel other_config:qinq-ethtype=802.1q tag=$tag"; + } else { + push @iface_config, "ovs_options tag=$tag"; + } + push(@{$config->{$vnet_uplink}}, @iface_config) if !$config->{$vnet_uplink}; + + #redefine main ovs bridge, ifupdown2 will merge ovs_ports + @iface_config = (); + push @iface_config, "ovs_ports $vnet_uplink"; + push(@{$config->{$bridge}}, @iface_config); + + } elsif ($vlan_aware) { + # eth0----vlanaware bridge vmbr0--(vmbr0.X tag)---->vnet---->vm + $vnet_uplink = "$bridge.$tag"; + } else { + + # keep vmbrXvY for compatibility with existing network + # eth0<---->eth0.X----vmbr0v10------vnet---->vm + + my $bridgevlan = $bridge."v".$tag; + + my @bridge_ifaces = PVE::Network::SDN::Zones::Plugin::get_bridge_ifaces($bridge); + + my $bridge_ports = ""; + foreach my $bridge_iface (@bridge_ifaces) { + $bridge_ports .= " $bridge_iface.$tag"; + } + + @iface_config = (); + push @iface_config, "link-type veth"; + push @iface_config, "veth-peer-name $vnet_uplinkpeer"; + push(@{$config->{$vnet_uplink}}, @iface_config) if !$config->{$vnet_uplink}; + + @iface_config = (); + push @iface_config, "link-type veth"; + push @iface_config, "veth-peer-name $vnet_uplink"; + push(@{$config->{$vnet_uplinkpeer}}, @iface_config) if !$config->{$vnet_uplinkpeer}; + + @iface_config = (); + push @iface_config, "bridge_ports $bridge_ports $vnet_uplinkpeer"; + push @iface_config, "bridge_stp off"; + push @iface_config, "bridge_fd 0"; + push(@{$config->{$bridgevlan}}, @iface_config) if !$config->{$bridgevlan}; + } #vnet bridge @iface_config = (); - push @iface_config, "bridge_ports $iface"; + push @iface_config, "bridge_ports $vnet_uplink"; push @iface_config, "bridge_stp off"; push @iface_config, "bridge_fd 0"; + if($vnet->{vlanaware}) { + push @iface_config, "bridge-vlan-aware yes"; + push @iface_config, "bridge-vids 2-4094"; + } push @iface_config, "mtu $mtu" if $mtu; push @iface_config, "alias $alias" if $alias; push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; @@ -73,42 +131,62 @@ sub generate_sdn_config { return $config; } -sub on_delete_hook { - my ($class, $transportid, $sdn_cfg) = @_; +sub status { + my ($class, $plugin_config, $zone, $vnetid, $vnet, $status) = @_; + + my $bridge = $plugin_config->{bridge}; - # verify that no vnet are associated to this transport - foreach my $id (keys %{$sdn_cfg->{ids}}) { - my $sdn = $sdn_cfg->{ids}->{$id}; - die "transport $transportid is used by vnet $id" - if ($sdn->{type} eq 'vnet' && defined($sdn->{zone}) && $sdn->{zone} eq $transportid); + my $err_msg = []; + if (!-d "/sys/class/net/$bridge") { + push @$err_msg, "missing $bridge"; + return $err_msg; + } + + my $vlan_aware = PVE::Network::SDN::Zones::Plugin::is_vlanaware($bridge); + my $is_ovs = PVE::Network::SDN::Zones::Plugin::is_ovs($bridge); + + my $tag = $vnet->{tag}; + my $vnet_uplink = "ln_".$vnetid; + my $vnet_uplinkpeer = "pr_".$vnetid; + + # ifaces to check + my $ifaces = [ $vnetid, $bridge ]; + if($is_ovs) { + push @$ifaces, $vnet_uplink; + } elsif (!$vlan_aware) { + my $bridgevlan = $bridge."v".$tag; + push @$ifaces, $bridgevlan; + push @$ifaces, $vnet_uplink; + push @$ifaces, $vnet_uplinkpeer; } -} -sub on_update_hook { - my ($class, $transportid, $sdn_cfg) = @_; - - my $transport = $sdn_cfg->{ids}->{$transportid}; - - # verify that vlan-allowed don't conflict with another vlan-allowed transport - - # verify that vlan-allowed is matching currently vnet tag in this transport - my $vlanallowed = $transport->{'vlan-allowed'}; - if ($vlanallowed) { - foreach my $id (keys %{$sdn_cfg->{ids}}) { - my $sdn = $sdn_cfg->{ids}->{$id}; - if ($sdn->{type} eq 'vnet' && defined($sdn->{tag})) { - if(defined($sdn->{zone}) && $sdn->{zone} eq $transportid) { - my $tag = $sdn->{tag}; - eval { - PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vlanallowed, '4096', $tag); - }; - if($@) { - die "vlan $tag is not allowed in transport $transportid"; - } - } - } + foreach my $iface (@{$ifaces}) { + if (!$status->{$iface}->{status}) { + push @$err_msg, "missing $iface"; + } elsif ($status->{$iface}->{status} ne 'pass') { + push @$err_msg, "error iface $iface"; } } + return $err_msg; +} + +sub vnet_update_hook { + my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_; + + my $vnet = $vnet_cfg->{ids}->{$vnetid}; + my $tag = $vnet->{tag}; + + raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag}); + raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096; + + # verify that tag is not already defined in another vnet on same zone + foreach my $id (keys %{$vnet_cfg->{ids}}) { + next if $id eq $vnetid; + my $othervnet = $vnet_cfg->{ids}->{$id}; + my $other_tag = $othervnet->{tag}; + next if $vnet->{zone} ne $othervnet->{zone}; + raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $other_tag && $tag eq $other_tag; + } } 1;