From: Alexandre Derumier Date: Wed, 3 Apr 2019 13:36:07 +0000 (+0200) Subject: merge Transport && Vnet to PVE::Network::Network X-Git-Url: https://git.proxmox.com/?p=pve-network.git;a=commitdiff_plain;h=6bad73d02e934a0953cebec2b07615302ac8304b merge Transport && Vnet to PVE::Network::Network config is now merged in /etc/pve/networks.cfg Vnet is a Plugin --- diff --git a/PVE/API2/Makefile b/PVE/API2/Makefile index 3e0ae7e..28b2830 100644 --- a/PVE/API2/Makefile +++ b/PVE/API2/Makefile @@ -1,8 +1,4 @@ -SOURCES=NetworkConfig.pm - -PERL5DIR=${DESTDIR}/usr/share/perl5 .PHONY: install install: - for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/API2/$$i; done make -C Network install diff --git a/PVE/API2/Network/Makefile b/PVE/API2/Network/Makefile index b563481..a7f3c31 100644 --- a/PVE/API2/Network/Makefile +++ b/PVE/API2/Network/Makefile @@ -1,4 +1,4 @@ -SOURCES=Transport.pm Vnet.pm +SOURCES=Network.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/PVE/API2/Network/Transport.pm b/PVE/API2/Network/Transport.pm deleted file mode 100644 index 0e1610f..0000000 --- a/PVE/API2/Network/Transport.pm +++ /dev/null @@ -1,235 +0,0 @@ -package PVE::API2::Network::Transport; - -use strict; -use warnings; - -use PVE::SafeSyslog; -use PVE::Tools qw(extract_param); -use PVE::Cluster qw(cfs_read_file cfs_write_file); -use PVE::Network::Transport; -use PVE::Network::Transport::Plugin; -use PVE::Network::Transport::VlanPlugin; -use PVE::Network::Transport::VxlanMulticastPlugin; -use Storable qw(dclone); -use PVE::JSONSchema qw(get_standard_option); -use PVE::RPCEnvironment; - -use PVE::RESTHandler; - -use base qw(PVE::RESTHandler); - -my $transport_type_enum = PVE::Network::Transport::Plugin->lookup_types(); - -my $api_transport_config = sub { - my ($cfg, $transportid) = @_; - - my $scfg = dclone(PVE::Network::Transport::transport_config($cfg, $transportid)); - $scfg->{transport} = $transportid; - $scfg->{digest} = $cfg->{digest}; - - return $scfg; -}; - -__PACKAGE__->register_method ({ - name => 'index', - path => '', - method => 'GET', - description => "Transport index.", - permissions => { - description => "Only list entries where you have 'NetworkTransport.Audit' or 'NetworkTransport.Allocate' permissions on '/cluster/network/transport/'", - user => 'all', - }, - parameters => { - additionalProperties => 0, - properties => { - type => { - description => "Only list transport of specific type", - type => 'string', - enum => $transport_type_enum, - optional => 1, - }, - }, - }, - returns => { - type => 'array', - items => { - type => "object", - properties => { transport => { type => 'string'} }, - }, - links => [ { rel => 'child', href => "{transport}" } ], - }, - code => sub { - my ($param) = @_; - - my $rpcenv = PVE::RPCEnvironment::get(); - my $authuser = $rpcenv->get_user(); - - - my $cfg = PVE::Network::Transport::config(); - - my @sids = PVE::Network::Transport::transports_ids($cfg); - my $res = []; - foreach my $transportid (@sids) { -# my $privs = [ 'NetworkTransport.Audit', 'NetworkTransport.Allocate' ]; -# next if !$rpcenv->check_any($authuser, "/cluster/network/transport/$transportid", $privs, 1); - - my $scfg = &$api_transport_config($cfg, $transportid); - next if $param->{type} && $param->{type} ne $scfg->{type}; - push @$res, $scfg; - } - - return $res; - }}); - -__PACKAGE__->register_method ({ - name => 'read', - path => '{transport}', - method => 'GET', - description => "Read transport configuration.", -# permissions => { -# check => ['perm', '/cluster/network/transport/{transport}', ['NetworkTransport.Allocate']], -# }, - - parameters => { - additionalProperties => 0, - properties => { - transport => get_standard_option('pve-transport-id'), - }, - }, - returns => { type => 'object' }, - code => sub { - my ($param) = @_; - - my $cfg = PVE::Network::Transport::config(); - - return &$api_transport_config($cfg, $param->{transport}); - }}); - -__PACKAGE__->register_method ({ - name => 'create', - protected => 1, - path => '', - method => 'POST', - description => "Create a new network transport.", -# permissions => { -# check => ['perm', '/cluster/network/transport', ['NetworkTransport.Allocate']], -# }, - parameters => PVE::Network::Transport::Plugin->createSchema(), - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $type = extract_param($param, 'type'); - my $transportid = extract_param($param, 'transport'); - - my $plugin = PVE::Network::Transport::Plugin->lookup($type); - my $opts = $plugin->check_config($transportid, $param, 1, 1); - - PVE::Network::Transport::lock_transport_config( - sub { - - my $cfg = PVE::Network::Transport::config(); - - if (my $scfg = PVE::Network::Transport::transport_config($cfg, $transportid, 1)) { - die "network transport ID '$transportid' already defined\n"; - } - - $cfg->{ids}->{$transportid} = $opts; - - #improveme: - #check local configuration of all nodes for conflict - - PVE::Network::Transport::write_config($cfg); - - }, "create network transport failed"); - - return undef; - }}); - -__PACKAGE__->register_method ({ - name => 'update', - protected => 1, - path => '{transport}', - method => 'PUT', - description => "Update network transport configuration.", -# permissions => { -# check => ['perm', '/cluster/network/transport', ['NetworkTransport.Allocate']], -# }, - parameters => PVE::Network::Transport::Plugin->updateSchema(), - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $transportid = extract_param($param, 'transport'); - my $digest = extract_param($param, 'digest'); - - PVE::Network::Transport::lock_transport_config( - sub { - - my $cfg = PVE::Network::Transport::config(); - - PVE::SectionConfig::assert_if_modified($cfg, $digest); - - my $scfg = PVE::Network::Transport::transport_config($cfg, $transportid); - - my $plugin = PVE::Network::Transport::Plugin->lookup($scfg->{type}); - my $opts = $plugin->check_config($transportid, $param, 0, 1); - - foreach my $k (%$opts) { - $scfg->{$k} = $opts->{$k}; - } - #improveme: - #add vlan/vxlan check on existingvnets - #check local configuration of all nodes for conflict - PVE::Network::Transport::write_config($cfg); - - }, "update network transport failed"); - - return undef; - }}); - -__PACKAGE__->register_method ({ - name => 'delete', - protected => 1, - path => '{transport}', # /cluster/network/transport/{transport} - method => 'DELETE', - description => "Delete network transport configuration.", -# permissions => { -# check => ['perm', '/cluster/network/transport', ['NetworkTransport.Allocate']], -# }, - parameters => { - additionalProperties => 0, - properties => { - transport => get_standard_option('pve-transport-id', { - completion => \&PVE::Network::Transport::complete_transport, - }), - }, - }, - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $transportid = extract_param($param, 'transport'); - - PVE::Network::Transport::lock_transport_config( - sub { - - my $cfg = PVE::Network::Transport::config(); - - my $scfg = PVE::Network::Transport::transport_config($cfg, $transportid); - -# my $plugin = PVE::Network::Transport::Plugin->lookup($scfg->{type}); -# $plugin->on_delete_hook($transportid, $scfg); - - delete $cfg->{ids}->{$transportid}; - #improveme: - #check that vnet don't use this transport - PVE::Network::Transport::write_config($cfg); - - }, "delete network transport failed"); - - - return undef; - }}); - -1; diff --git a/PVE/API2/Network/Vnet.pm b/PVE/API2/Network/Vnet.pm deleted file mode 100644 index 74f59fc..0000000 --- a/PVE/API2/Network/Vnet.pm +++ /dev/null @@ -1,218 +0,0 @@ -package PVE::API2::Network::Vnet; - -use strict; -use warnings; - -use PVE::SafeSyslog; -use PVE::Tools qw(extract_param); -use PVE::Cluster qw(cfs_read_file cfs_write_file); -use PVE::Network::Vnet; -use PVE::Network::Vnet::Plugin; -use Storable qw(dclone); -use PVE::JSONSchema qw(get_standard_option); -use PVE::RPCEnvironment; - -use PVE::RESTHandler; - -use base qw(PVE::RESTHandler); - -my $api_vnet_config = sub { - my ($cfg, $vnetid) = @_; - - my $scfg = dclone(PVE::Network::Vnet::vnet_config($cfg, $vnetid)); - $scfg->{vnet} = $vnetid; - $scfg->{digest} = $cfg->{digest}; - - return $scfg; -}; - -__PACKAGE__->register_method ({ - name => 'index', - path => '', - method => 'GET', - description => "Vnet index.", - permissions => { - description => "Only list entries where you have 'NetworkVnet.Audit' or 'NetworkVnet.Allocate' permissions on '/cluster/network/vnet/'", - user => 'all', - }, - parameters => { - additionalProperties => 0, - properties => { - type => { - description => "Only list vnet of specific type", - type => 'string', - optional => 1, - }, - }, - }, - returns => { - type => 'array', - items => { - type => "object", - properties => { vnet => { type => 'string'} }, - }, - links => [ { rel => 'child', href => "{vnet}" } ], - }, - code => sub { - my ($param) = @_; - - my $rpcenv = PVE::RPCEnvironment::get(); - my $authuser = $rpcenv->get_user(); - - - my $cfg = PVE::Network::Vnet::config(); - - my @sids = PVE::Network::Vnet::vnets_ids($cfg); - my $res = []; - foreach my $vnetid (@sids) { -# my $privs = [ 'NetworkVnet.Audit', 'NetworkVnet.Allocate' ]; -# next if !$rpcenv->check_any($authuser, "/cluster/network/vnet/$vnetid", $privs, 1); - - my $scfg = &$api_vnet_config($cfg, $vnetid); - next if $param->{type} && $param->{type} ne $scfg->{type}; - push @$res, $scfg; - } - - return $res; - }}); - -__PACKAGE__->register_method ({ - name => 'read', - path => '{vnet}', - method => 'GET', - description => "Read vnet configuration.", -# permissions => { -# check => ['perm', '/cluster/network/vnet/{vnet}', ['NetworkVnet.Allocate']], -# }, - - parameters => { - additionalProperties => 0, - properties => { - vnet => get_standard_option('pve-vnet-id'), - }, - }, - returns => { type => 'object' }, - code => sub { - my ($param) = @_; - - my $cfg = PVE::Network::Vnet::config(); - - return &$api_vnet_config($cfg, $param->{vnet}); - }}); - -__PACKAGE__->register_method ({ - name => 'create', - protected => 1, - path => '', - method => 'POST', - description => "Create a new network vnet.", -# permissions => { -# check => ['perm', '/cluster/network/vnet', ['NetworkVnet.Allocate']], -# }, - parameters => PVE::Network::Vnet::Plugin->createSchema(), - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $vnetid = extract_param($param, 'vnet'); - my $type = "vnet"; - my $plugin = PVE::Network::Vnet::Plugin->lookup($type); - my $opts = $plugin->check_config($vnetid, $param, 1, 1); - - PVE::Network::Vnet::lock_vnet_config( - sub { - - my $cfg = PVE::Network::Vnet::config(); - - if (my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid, 1)) { - die "network vnet ID '$vnetid' already defined\n"; - } - - $cfg->{ids}->{$vnetid} = $opts; - - PVE::Network::Vnet::write_config($cfg); - - }, "create network vnet failed"); - - return undef; - }}); - -__PACKAGE__->register_method ({ - name => 'update', - protected => 1, - path => '{vnet}', - method => 'PUT', - description => "Update network vnet configuration.", -# permissions => { -# check => ['perm', '/cluster/network/vnet', ['NetworkVnet.Allocate']], -# }, - parameters => PVE::Network::Vnet::Plugin->updateSchema(), - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $vnetid = extract_param($param, 'vnet'); - my $digest = extract_param($param, 'digest'); - - PVE::Network::Vnet::lock_vnet_config( - sub { - - my $cfg = PVE::Network::Vnet::config(); - - PVE::SectionConfig::assert_if_modified($cfg, $digest); - - my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid); - my $plugin = PVE::Network::Vnet::Plugin->lookup($scfg->{type}); - my $opts = $plugin->check_config($vnetid, $param, 0, 1); - - foreach my $k (%$opts) { - $scfg->{$k} = $opts->{$k}; - } - PVE::Network::Vnet::write_config($cfg); - - }, "update network vnet failed"); - - return undef; - }}); - -__PACKAGE__->register_method ({ - name => 'delete', - protected => 1, - path => '{vnet}', # /networkvnets/{vnet} - method => 'DELETE', - description => "Delete network vnet configuration.", -# permissions => { -# check => ['perm', '/networkvnets', ['NetworkVnet.Allocate']], -# }, - parameters => { - additionalProperties => 0, - properties => { - vnet => get_standard_option('pve-vnet-id', { - completion => \&PVE::Network::Vnet::complete_vnet, - }), - }, - }, - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $vnetid = extract_param($param, 'vnet'); - - PVE::Network::Vnet::lock_vnet_config( - sub { - - my $cfg = PVE::Network::Vnet::config(); - - my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid); - - delete $cfg->{ids}->{$vnetid}; - - PVE::Network::Vnet::write_config($cfg); - - }, "delete network vnet failed"); - - - return undef; - }}); - -1; diff --git a/PVE/API2/NetworkConfig.pm b/PVE/API2/NetworkConfig.pm deleted file mode 100644 index 91b7699..0000000 --- a/PVE/API2/NetworkConfig.pm +++ /dev/null @@ -1,62 +0,0 @@ -package PVE::API2::NetworkConfig; - -use strict; -use warnings; - -use PVE::SafeSyslog; -use PVE::Tools; -use PVE::Cluster qw(cfs_lock_file cfs_read_file cfs_write_file); -use PVE::RESTHandler; -use PVE::RPCEnvironment; -use PVE::JSONSchema qw(get_standard_option); -use PVE::Exception qw(raise_param_exc); -use PVE::API2::Network::Transport; -use PVE::API2::Network::Vnet; - -use base qw(PVE::RESTHandler); - -__PACKAGE__->register_method ({ - subclass => "PVE::API2::Network::Transport", - path => 'transport', - }); - -__PACKAGE__->register_method ({ - subclass => "PVE::API2::Network::Vnet", - path => 'vnet', - }); - -__PACKAGE__->register_method({ - name => 'index', - path => '', - method => 'GET', - description => "Directory index.", - permissions => { - check => ['perm', '/', [ 'Sys.Audit' ]], - }, - parameters => { - additionalProperties => 0, - properties => {}, - }, - returns => { - type => 'array', - items => { - type => "object", - properties => { - id => { type => 'string' }, - }, - }, - links => [ { rel => 'child', href => "{id}" } ], - }, - code => sub { - my ($param) = @_; - - my $res = [ - { id => 'transport' }, - { id => 'vnet' }, - ]; - - return $res; - }}); - - -1; diff --git a/PVE/Network/Makefile b/PVE/Network/Makefile index 66eeec8..6f17f37 100644 --- a/PVE/Network/Makefile +++ b/PVE/Network/Makefile @@ -1,4 +1,4 @@ -SOURCES=Vnet.pm Transport.pm +SOURCES=Network.pm PERL5DIR=${DESTDIR}/usr/share/perl5 @@ -6,5 +6,4 @@ PERL5DIR=${DESTDIR}/usr/share/perl5 .PHONY: install install: for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/$$i; done - make -C Vnet install - make -C Transport install + make -C Network install diff --git a/PVE/Network/Network/Makefile b/PVE/Network/Network/Makefile new file mode 100644 index 0000000..085f93d --- /dev/null +++ b/PVE/Network/Network/Makefile @@ -0,0 +1,9 @@ +SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanMulticastPlugin.pm + + +PERL5DIR=${DESTDIR}/usr/share/perl5 + +.PHONY: install +install: + for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/Network/$$i; done + diff --git a/PVE/Network/Network/Plugin.pm b/PVE/Network/Network/Plugin.pm new file mode 100644 index 0000000..4ec6d0a --- /dev/null +++ b/PVE/Network/Network/Plugin.pm @@ -0,0 +1,93 @@ +package PVE::Network::Network::Plugin; + +use strict; +use warnings; + +use PVE::Tools; +use PVE::JSONSchema; +use PVE::Cluster; + +use Data::Dumper; +use PVE::JSONSchema qw(get_standard_option); +use base qw(PVE::SectionConfig); + +PVE::Cluster::cfs_register_file('networks.cfg', + sub { __PACKAGE__->parse_config(@_); }, + sub { __PACKAGE__->write_config(@_); }); + +my $defaultData = { + + propertyList => { + type => { + description => "Plugin type.", + type => 'string', format => 'pve-configid', + type => 'string', + }, + network => get_standard_option('pve-network-id', + { completion => \&PVE::Network::Network::complete_network }), + }, +}; + +sub private { + return $defaultData; +} + +sub parse_section_header { + my ($class, $line) = @_; + + if ($line =~ m/^(\S+):\s*(\S+)\s*$/) { + my ($type, $networkid) = (lc($1), $2); + my $errmsg = undef; # set if you want to skip whole section + eval { PVE::JSONSchema::pve_verify_configid($type); }; + $errmsg = $@ if $@; + my $config = {}; # to return additional attributes + return ($type, $networkid, $errmsg, $config); + } + return undef; +} + +sub generate_network_config { + my ($class, $plugin_config, $node, $data, $ctime) = @_; + + die "please implement inside plugin"; +} + +#helpers +sub parse_tag_number_or_range { + my ($str, $max, $tag) = @_; + + my @elements = split(/,/, $str); + my $count = 0; + my $allowed = undef; + + die "extraneous commas in list\n" if $str ne join(',', @elements); + foreach my $item (@elements) { + if ($item =~ m/^([0-9]+)-([0-9]+)$/) { + $count += 2; + my ($port1, $port2) = ($1, $2); + die "invalid port '$port1'\n" if $port1 > $max; + die "invalid port '$port2'\n" if $port2 > $max; + die "backwards range '$port1:$port2' not allowed, did you mean '$port2:$port1'?\n" if $port1 > $port2; + + if ($tag && $tag >= $port1 && $tag <= $port2){ + $allowed = 1; + last; + } + + } elsif ($item =~ m/^([0-9]+)$/) { + $count += 1; + my $port = $1; + die "invalid port '$port'\n" if $port > $max; + + if ($tag && $tag == $port){ + $allowed = 1; + last; + } + } + } + die "tag $tag is not allowed" if $tag && !$allowed; + + return (scalar(@elements) > 1); +} + +1; diff --git a/PVE/Network/Network/VlanPlugin.pm b/PVE/Network/Network/VlanPlugin.pm new file mode 100644 index 0000000..fd53617 --- /dev/null +++ b/PVE/Network/Network/VlanPlugin.pm @@ -0,0 +1,101 @@ +package PVE::Network::Network::VlanPlugin; + +use strict; +use warnings; +use PVE::Network::Network::Plugin; + +use base('PVE::Network::Network::Plugin'); + +sub type { + return 'vlan'; +} + +PVE::JSONSchema::register_format('pve-network-vlanrange', \&pve_verify_network_vlanrange); +sub pve_verify_network_vlanrange { + my ($vlanstr) = @_; + + PVE::Network::Network::Plugin::parse_tag_number_or_range($vlanstr, '4096'); + + return $vlanstr; +} + +sub properties { + return { + 'uplink-id' => { + type => 'integer', + minimum => 1, maximum => 4096, + description => 'Uplink interface', + }, + 'vlan-allowed' => { + type => 'string', format => 'pve-network-vlanrange', + description => "Allowed vlan range", + }, + 'vlan-aware' => { + type => 'boolean', + description => "enable 802.1q stacked vlan", + }, + 'vlan-protocol' => { + type => 'string', + enum => ['802.1q', '802.1ad'], + default => '802.1q', + optional => 1, + description => "vlan protocol", + } + }; +} + +sub options { + + return { + 'uplink-id' => { optional => 1 }, + 'vlan-allowed' => { optional => 1 }, + 'vlan-protocol' => { optional => 1 }, + 'vlan-aware' => { optional => 1 }, + + }; +} + +# Plugin implementation +sub generate_network_config { + my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks) = @_; + + my $tag = $vnet->{tag}; + my $mtu = $vnet->{mtu}; + my $vlanaware = $plugin_config->{'vlan-aware'}; + my $vlanprotocol = $plugin_config->{'vlan-protocol'}; + my $uplink = $plugin_config->{'uplink-id'}; + my $vlanallowed = $plugin_config->{'vlan-allowed'}; + + die "missing vlan tag" if !$tag; + die "uplink $uplink is not defined" if !$uplinks->{$uplink}; + + eval { + PVE::Network::Network::Plugin::parse_tag_number_or_range($vlanallowed, '4096', $tag) if $vlanallowed; + }; + if($@) { + die "vlan $tag is not allowed in transport $zoneid"; + } + + my $iface = $uplinks->{$uplink}; + $iface .= ".$tag"; + + my $config = "\n"; + $config .= "auto $iface\n"; + $config .= "iface $iface inet manual\n"; + $config .= " vlan-protocol $vlanprotocol\n" if $vlanprotocol; + $config .= " mtu $mtu\n" if $mtu; + $config .= "\n"; + $config .= "auto $vnetid\n"; + $config .= "iface $vnetid inet manual\n"; + $config .= " bridge_ports $iface\n"; + $config .= " bridge_stp off\n"; + $config .= " bridge_fd 0\n"; + $config .= " bridge-vlan-aware yes \n" if $vlanaware; + $config .= " mtu $mtu\n" if $mtu; + + return $config; +} + +1; + + diff --git a/PVE/Network/Network/VnetPlugin.pm b/PVE/Network/Network/VnetPlugin.pm new file mode 100644 index 0000000..c2a4020 --- /dev/null +++ b/PVE/Network/Network/VnetPlugin.pm @@ -0,0 +1,68 @@ +package PVE::Network::Network::VnetPlugin; + +use strict; +use warnings; +use PVE::Network::Network::Plugin; + +use base('PVE::Network::Network::Plugin'); + +sub type { + return 'vnet'; +} + + + +sub properties { + return { + transportzone => { + type => 'string', + description => "transportzone id", + optional => 1, + }, + tag => { + type => 'integer', + description => "vlan or vxlan id", + optional => 1, + }, + name => { + type => 'string', + description => "name of the network", + optional => 1, + }, + mtu => { + type => 'integer', + description => "mtu", + optional => 1, + }, + ipv4 => { + description => "Anycast router ipv4 address.", + type => 'string', format => 'ipv4', + optional => 1, + }, + ipv6 => { + description => "Anycast router ipv6 address.", + type => 'string', format => 'ipv6', + optional => 1, + }, + mac => { + type => 'boolean', + description => "Anycast router mac address", + optional => 1, + } + }; +} + +sub options { + return { + transportzone => { optional => 1 }, + tag => { optional => 1 }, + name => { optional => 1 }, + ipv4 => { optional => 1 }, + ipv6 => { optional => 1 }, + name => { optional => 1 }, + mtu => { optional => 1 }, + }; +} + + +1; diff --git a/PVE/Network/Network/VxlanMulticastPlugin.pm b/PVE/Network/Network/VxlanMulticastPlugin.pm new file mode 100644 index 0000000..bcdc133 --- /dev/null +++ b/PVE/Network/Network/VxlanMulticastPlugin.pm @@ -0,0 +1,85 @@ +package PVE::Network::Network::VxlanMulticastPlugin; + +use strict; +use warnings; +use PVE::Network::Network::Plugin; + +use base('PVE::Network::Network::Plugin'); + +PVE::JSONSchema::register_format('pve-network-vxlanrange', \&pve_verify_network_vxlanrange); +sub pve_verify_network_vxlanrange { + my ($vxlanstr) = @_; + + PVE::Network::Network::Plugin::parse_tag_number_or_range($vxlanstr, '16777216'); + + return $vxlanstr; +} + +sub type { + return 'vxlanmulticast'; +} + +sub properties { + return { + 'vxlan-allowed' => { + type => 'string', format => 'pve-network-vxlanrange', + description => "Allowed vlan range", + }, + 'multicast-address' => { + description => "Multicast address.", + type => 'string', #fixme: format + }, + + }; +} + +sub options { + + return { + 'uplink-id' => { optional => 1 }, + 'multicast-address' => { fixed => 1 }, + 'vxlan-allowed' => { optional => 1 }, + }; +} + +# Plugin implementation +sub generate_network_config { + my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks) = @_; + + my $tag = $vnet->{tag}; + my $mtu = $vnet->{mtu}; + my $multicastaddress = $plugin_config->{'multicast-address'}; + my $uplink = $plugin_config->{'uplink-id'}; + my $vxlanallowed = $plugin_config->{'vxlan-allowed'}; + + die "missing vxlan tag" if !$tag; + die "uplink $uplink is not defined" if !$uplinks->{$uplink}; + my $iface = $uplinks->{$uplink}; + + eval { + PVE::Network::Network::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag) if $vxlanallowed; + }; + if($@) { + die "vlan $tag is not allowed in transport $zoneid"; + } + + my $config = "\n"; + $config .= "auto vxlan$vnetid\n"; + $config .= "iface vxlan$vnetid inet manual\n"; + $config .= " vxlan-id $tag\n" if $tag; + $config .= " vxlan-svcnodeip $multicastaddress\n" if $multicastaddress; + $config .= " vxlan-physdev $iface\n" if $iface; + $config .= "\n"; + $config .= "auto $vnetid\n"; + $config .= "iface $vnetid inet manual\n"; + $config .= " bridge_ports vxlan$vnetid\n"; + $config .= " bridge_stp off\n"; + $config .= " bridge_fd 0\n"; + $config .= " mtu $mtu\n" if $mtu; + + return $config; +} + +1; + + diff --git a/PVE/Network/Transport.pm b/PVE/Network/Transport.pm deleted file mode 100644 index 72cb0b5..0000000 --- a/PVE/Network/Transport.pm +++ /dev/null @@ -1,62 +0,0 @@ -package PVE::Network::Transport; - -use strict; -use warnings; -use Data::Dumper; -use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); -use PVE::Network::Transport::Plugin; -use PVE::Network::Transport::VlanPlugin; -use PVE::Network::Transport::VxlanMulticastPlugin; - -PVE::Network::Transport::VlanPlugin->register(); -PVE::Network::Transport::VxlanMulticastPlugin->register(); -PVE::Network::Transport::Plugin->init(); - - -sub transport_config { - my ($cfg, $transportid, $noerr) = @_; - - die "no transport ID specified\n" if !$transportid; - - my $scfg = $cfg->{ids}->{$transportid}; - die "transport '$transportid' does not exists\n" if (!$noerr && !$scfg); - - return $scfg; -} - -sub config { - - return cfs_read_file("network/transports.cfg"); -} - -sub write_config { - my ($cfg) = @_; - - cfs_write_file("network/transports.cfg", $cfg); -} - -sub lock_transport_config { - my ($code, $errmsg) = @_; - - cfs_lock_file("network/transports.cfg", undef, $code); - my $err = $@; - if ($err) { - $errmsg ? die "$errmsg: $err" : die $err; - } -} - -sub transports_ids { - my ($cfg) = @_; - - return keys %{$cfg->{ids}}; -} - -sub complete_transport { - my ($cmdname, $pname, $cvalue) = @_; - - my $cfg = PVE::Network::Transport::config(); - - return $cmdname eq 'add' ? [] : [ PVE::Network::Transport::transports_ids($cfg) ]; -} - -1; diff --git a/PVE/Network/Transport/Makefile b/PVE/Network/Transport/Makefile deleted file mode 100644 index 938e87b..0000000 --- a/PVE/Network/Transport/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -SOURCES=Plugin.pm VlanPlugin.pm VxlanMulticastPlugin.pm - - -PERL5DIR=${DESTDIR}/usr/share/perl5 - -.PHONY: install -install: - for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/Transport/$$i; done - diff --git a/PVE/Network/Transport/Plugin.pm b/PVE/Network/Transport/Plugin.pm deleted file mode 100644 index dcebbcf..0000000 --- a/PVE/Network/Transport/Plugin.pm +++ /dev/null @@ -1,93 +0,0 @@ -package PVE::Network::Transport::Plugin; - -use strict; -use warnings; - -use PVE::Tools; -use PVE::JSONSchema; -use PVE::Cluster; - -use Data::Dumper; -use PVE::JSONSchema qw(get_standard_option); -use base qw(PVE::SectionConfig); - -PVE::Cluster::cfs_register_file('network/transports.cfg', - sub { __PACKAGE__->parse_config(@_); }, - sub { __PACKAGE__->write_config(@_); }); - -my $defaultData = { - - propertyList => { - type => { - description => "Plugin type.", - type => 'string', format => 'pve-configid', - type => 'string', - }, - transport => get_standard_option('pve-transport-id', - { completion => \&PVE::Network::Transport::complete_transport }), - }, -}; - -sub private { - return $defaultData; -} - -sub parse_section_header { - my ($class, $line) = @_; - - if ($line =~ m/^(\S+):\s*(\S+)\s*$/) { - my ($type, $transportid) = (lc($1), $2); - my $errmsg = undef; # set if you want to skip whole section - eval { PVE::JSONSchema::pve_verify_configid($type); }; - $errmsg = $@ if $@; - my $config = {}; # to return additional attributes - return ($type, $transportid, $errmsg, $config); - } - return undef; -} - -sub generate_network_config { - my ($class, $plugin_config, $node, $data, $ctime) = @_; - - die "please implement inside plugin"; -} - -#helpers -sub parse_tag_number_or_range { - my ($str, $max, $tag) = @_; - - my @elements = split(/,/, $str); - my $count = 0; - my $allowed = undef; - - die "extraneous commas in list\n" if $str ne join(',', @elements); - foreach my $item (@elements) { - if ($item =~ m/^([0-9]+)-([0-9]+)$/) { - $count += 2; - my ($port1, $port2) = ($1, $2); - die "invalid port '$port1'\n" if $port1 > $max; - die "invalid port '$port2'\n" if $port2 > $max; - die "backwards range '$port1:$port2' not allowed, did you mean '$port2:$port1'?\n" if $port1 > $port2; - - if ($tag && $tag >= $port1 && $tag <= $port2){ - $allowed = 1; - last; - } - - } elsif ($item =~ m/^([0-9]+)$/) { - $count += 1; - my $port = $1; - die "invalid port '$port'\n" if $port > $max; - - if ($tag && $tag == $port){ - $allowed = 1; - last; - } - } - } - die "tag $tag is not allowed" if $tag && !$allowed; - - return (scalar(@elements) > 1); -} - -1; diff --git a/PVE/Network/Transport/VlanPlugin.pm b/PVE/Network/Transport/VlanPlugin.pm deleted file mode 100644 index 8ee8bdc..0000000 --- a/PVE/Network/Transport/VlanPlugin.pm +++ /dev/null @@ -1,101 +0,0 @@ -package PVE::Network::Transport::VlanPlugin; - -use strict; -use warnings; -use PVE::Network::Transport::Plugin; - -use base('PVE::Network::Transport::Plugin'); - -sub type { - return 'vlan'; -} - -PVE::JSONSchema::register_format('pve-network-vlanrange', \&pve_verify_network_vlanrange); -sub pve_verify_network_vlanrange { - my ($vlanstr) = @_; - - PVE::Network::Transport::Plugin::parse_tag_number_or_range($vlanstr, '4096'); - - return $vlanstr; -} - -sub properties { - return { - 'uplink-id' => { - type => 'integer', - minimum => 1, maximum => 4096, - description => 'Uplink interface', - }, - 'vlan-allowed' => { - type => 'string', format => 'pve-network-vlanrange', - description => "Allowed vlan range", - }, - 'vlan-aware' => { - type => 'boolean', - description => "enable 802.1q stacked vlan", - }, - 'vlan-protocol' => { - type => 'string', - enum => ['802.1q', '802.1ad'], - default => '802.1q', - optional => 1, - description => "vlan protocol", - } - }; -} - -sub options { - - return { - 'uplink-id' => { optional => 1 }, - 'vlan-allowed' => { optional => 1 }, - 'vlan-protocol' => { optional => 1 }, - 'vlan-aware' => { optional => 1 }, - - }; -} - -# Plugin implementation -sub generate_network_config { - my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks) = @_; - - my $tag = $vnet->{tag}; - my $mtu = $vnet->{mtu}; - my $vlanaware = $plugin_config->{'vlan-aware'}; - my $vlanprotocol = $plugin_config->{'vlan-protocol'}; - my $uplink = $plugin_config->{'uplink-id'}; - my $vlanallowed = $plugin_config->{'vlan-allowed'}; - - die "missing vlan tag" if !$tag; - die "uplink $uplink is not defined" if !$uplinks->{$uplink}; - - eval { - PVE::Network::Transport::Plugin::parse_tag_number_or_range($vlanallowed, '4096', $tag) if $vlanallowed; - }; - if($@) { - die "vlan $tag is not allowed in transport $zoneid"; - } - - my $iface = $uplinks->{$uplink}; - $iface .= ".$tag"; - - my $config = "\n"; - $config .= "auto $iface\n"; - $config .= "iface $iface inet manual\n"; - $config .= " vlan-protocol $vlanprotocol\n" if $vlanprotocol; - $config .= " mtu $mtu\n" if $mtu; - $config .= "\n"; - $config .= "auto $vnetid\n"; - $config .= "iface $vnetid inet manual\n"; - $config .= " bridge_ports $iface\n"; - $config .= " bridge_stp off\n"; - $config .= " bridge_fd 0\n"; - $config .= " bridge-vlan-aware yes \n" if $vlanaware; - $config .= " mtu $mtu\n" if $mtu; - - return $config; -} - -1; - - diff --git a/PVE/Network/Transport/VxlanMulticastPlugin.pm b/PVE/Network/Transport/VxlanMulticastPlugin.pm deleted file mode 100644 index c6fa29d..0000000 --- a/PVE/Network/Transport/VxlanMulticastPlugin.pm +++ /dev/null @@ -1,85 +0,0 @@ -package PVE::Network::Transport::VxlanMulticastPlugin; - -use strict; -use warnings; -use PVE::Network::Transport::Plugin; - -use base('PVE::Network::Transport::Plugin'); - -PVE::JSONSchema::register_format('pve-network-vxlanrange', \&pve_verify_network_vxlanrange); -sub pve_verify_network_vxlanrange { - my ($vxlanstr) = @_; - - PVE::Network::Transport::Plugin::parse_tag_number_or_range($vxlanstr, '16777216'); - - return $vxlanstr; -} - -sub type { - return 'vxlanmulticast'; -} - -sub properties { - return { - 'vxlan-allowed' => { - type => 'string', format => 'pve-network-vxlanrange', - description => "Allowed vlan range", - }, - 'multicast-address' => { - description => "Multicast address.", - type => 'string', #fixme: format - }, - - }; -} - -sub options { - - return { - 'uplink-id' => { optional => 1 }, - 'multicast-address' => { fixed => 1 }, - 'vxlan-allowed' => { optional => 1 }, - }; -} - -# Plugin implementation -sub generate_network_config { - my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks) = @_; - - my $tag = $vnet->{tag}; - my $mtu = $vnet->{mtu}; - my $multicastaddress = $plugin_config->{'multicast-address'}; - my $uplink = $plugin_config->{'uplink-id'}; - my $vxlanallowed = $plugin_config->{'vxlan-allowed'}; - - die "missing vxlan tag" if !$tag; - die "uplink $uplink is not defined" if !$uplinks->{$uplink}; - my $iface = $uplinks->{$uplink}; - - eval { - PVE::Network::Transport::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag) if $vxlanallowed; - }; - if($@) { - die "vlan $tag is not allowed in transport $zoneid"; - } - - my $config = "\n"; - $config .= "auto vxlan$vnetid\n"; - $config .= "iface vxlan$vnetid inet manual\n"; - $config .= " vxlan-id $tag\n" if $tag; - $config .= " vxlan-svcnodeip $multicastaddress\n" if $multicastaddress; - $config .= " vxlan-physdev $iface\n" if $iface; - $config .= "\n"; - $config .= "auto $vnetid\n"; - $config .= "iface $vnetid inet manual\n"; - $config .= " bridge_ports vxlan$vnetid\n"; - $config .= " bridge_stp off\n"; - $config .= " bridge_fd 0\n"; - $config .= " mtu $mtu\n" if $mtu; - - return $config; -} - -1; - - diff --git a/PVE/Network/Vnet.pm b/PVE/Network/Vnet.pm deleted file mode 100644 index 947dae6..0000000 --- a/PVE/Network/Vnet.pm +++ /dev/null @@ -1,71 +0,0 @@ -package PVE::Network::Vnet; - -use strict; -use warnings; -use Data::Dumper; -use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); - - -sub vnet_config { - my ($cfg, $vnetid, $noerr) = @_; - - die "no vnet ID specified\n" if !$vnetid; - - my $scfg = $cfg->{ids}->{$vnetid}; - die "vnet '$vnetid' does not exists\n" if (!$noerr && !$scfg); - - return $scfg; -} - -sub config { - - return cfs_read_file("network/vnet.cfg"); -} - -sub write_config { - my ($cfg) = @_; - cfs_write_file("network/vnet.cfg", $cfg); -} - -sub lock_vnet_config { - my ($code, $errmsg) = @_; - - cfs_lock_file("network/vnet.cfg", undef, $code); - my $err = $@; - if ($err) { - $errmsg ? die "$errmsg: $err" : die $err; - } -} - -sub vnets_ids { - my ($cfg) = @_; - - return keys %{$cfg->{ids}}; -} - -sub complete_vnet { - my ($cmdname, $pname, $cvalue) = @_; - - my $cfg = PVE::Network::Vnet::config(); - - return $cmdname eq 'add' ? [] : [ PVE::Network::Vnet::vnets_ids($cfg) ]; -} - - -my $format_config_line = sub { - my ($schema, $key, $value) = @_; - - my $ct = $schema->{type}; - - die "property '$key' contains a line feed\n" - if ($key =~ m/[\n\r]/) || ($value =~ m/[\n\r]/); - - if ($ct eq 'boolean') { - return "\t$key " . ($value ? 1 : 0) . "\n" - if defined($value); - } else { - return "\t$key $value\n" if "$value" ne ''; - } -}; - -1; diff --git a/PVE/Network/Vnet/Makefile b/PVE/Network/Vnet/Makefile deleted file mode 100644 index 8d4a818..0000000 --- a/PVE/Network/Vnet/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -SOURCES=Plugin.pm - - -PERL5DIR=${DESTDIR}/usr/share/perl5 - -.PHONY: install -install: - for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/Vnet/$$i; done - diff --git a/PVE/Network/Vnet/Plugin.pm b/PVE/Network/Vnet/Plugin.pm deleted file mode 100644 index 0a7053c..0000000 --- a/PVE/Network/Vnet/Plugin.pm +++ /dev/null @@ -1,99 +0,0 @@ -package PVE::Network::Vnet::Plugin; - -use strict; -use warnings; - -use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); -use PVE::JSONSchema qw(get_standard_option); -use PVE::SectionConfig; - -use base qw(PVE::SectionConfig); - -PVE::Cluster::cfs_register_file('network/vnet.cfg', - sub { __PACKAGE__->parse_config(@_); }, - sub { __PACKAGE__->write_config(@_); }); - - -sub options { - return { - vnet => { optional => 1 }, - transportzone => { optional => 1 }, - tag => { optional => 1 }, - name => { optional => 1 }, - ipv4 => { optional => 1 }, - ipv6 => { optional => 1 }, - name => { optional => 1 }, - mtu => { optional => 1 }, - }; -} - -my $defaultData = { - propertyList => { - vnet => get_standard_option('pve-vnet-id', - { completion => \&PVE::Network::Vnet::complete_vnet }), - - transportzone => { - type => 'string', - description => "transportzone id", - optional => 1, - }, - tag => { - type => 'integer', - description => "vlan or vxlan id", - optional => 1, - }, - name => { - type => 'string', - description => "name of the network", - optional => 1, - }, - mtu => { - type => 'integer', - description => "mtu", - optional => 1, - }, - ipv4 => { - description => "Anycast router ipv4 address.", - type => 'string', format => 'ipv4', - optional => 1, - }, - ipv6 => { - description => "Anycast router ipv6 address.", - type => 'string', format => 'ipv6', - optional => 1, - }, - mac => { - type => 'boolean', - description => "Anycast router mac address", - optional => 1, - } - }, -}; - -sub type { - return 'vnet'; -} - -sub private { - return $defaultData; -} - - -sub parse_section_header { - my ($class, $line) = @_; - - if ($line =~ m/^(\S+):\s*(\S+)\s*$/) { - my ($type, $vnetid) = (lc($1), $2); - my $errmsg = undef; # set if you want to skip whole section - eval { PVE::JSONSchema::pve_verify_configid($type); }; - $errmsg = $@ if $@; - my $config = {}; # to return additional attributes - return ($type, $vnetid, $errmsg, $config); - } - return undef; -} - -__PACKAGE__->register(); -__PACKAGE__->init(); - -1;