use strict;
use warnings;
-use PVE::Tools;
+use PVE::Tools qw(run_command);
use PVE::JSONSchema;
use PVE::Cluster;
+use PVE::Network;
use Data::Dumper;
use PVE::JSONSchema qw(get_standard_option);
return (scalar(@elements) > 1);
}
+sub status {
+ my ($class, $plugin_config, $zone, $id, $vnet, $err_config, $status, $vnet_status, $zone_status) = @_;
+
+ $vnet_status->{$id}->{zone} = $zone;
+ $zone_status->{$zone}->{status} = 'available' if !defined($zone_status->{$zone}->{status});
+
+ if($err_config) {
+ $vnet_status->{$id}->{status} = 'pending';
+ $vnet_status->{$id}->{statusmsg} = $err_config;
+ $zone_status->{$zone}->{status} = 'pending';
+ } elsif ($status->{$id}->{status} && $status->{$id}->{status} eq 'pass') {
+ $vnet_status->{$id}->{status} = 'available';
+ my $bridgeport = $status->{$id}->{config}->{'bridge-ports'};
+
+ if ($bridgeport && $status->{$bridgeport}->{status} && $status->{$bridgeport}->{status} ne 'pass') {
+ $vnet_status->{$id}->{status} = 'error';
+ $vnet_status->{$id}->{statusmsg} = 'configuration not fully applied';
+ $zone_status->{$zone}->{status} = 'error';
+ }
+
+ } else {
+ $vnet_status->{$id}->{status} = 'error';
+ $vnet_status->{$id}->{statusmsg} = 'missing';
+ $zone_status->{$zone}->{status} = 'error';
+ }
+}
+
+
+sub get_bridge_vlan {
+ my ($class, $plugin_config, $vnetid, $tag) = @_;
+
+ my $bridge = $vnetid;
+ $tag = undef;
+
+ die "bridge $bridge is missing" if !-d "/sys/class/net/$bridge/";
+
+ return ($bridge, $tag);
+}
+
+sub tap_create {
+ my ($class, $plugin_config, $vnet, $iface, $vnetid) = @_;
+
+ my ($bridge, undef) = $class->get_bridge_vlan($plugin_config, $vnetid);
+ die "unable to get bridge setting\n" if !$bridge;
+
+ PVE::Network::tap_create($iface, $bridge);
+}
+
+sub veth_create {
+ my ($class, $plugin_config, $vnet, $veth, $vethpeer, $vnetid, $hwaddr) = @_;
+
+ my ($bridge, undef) = $class->get_bridge_vlan($plugin_config, $vnetid);
+ die "unable to get bridge setting\n" if !$bridge;
+
+ PVE::Network::veth_create($veth, $vethpeer, $bridge, $hwaddr);
+}
+
+sub tap_plug {
+ my ($class, $plugin_config, $vnet, $iface, $vnetid, $firewall, $rate) = @_;
+
+ my $tag = $vnet->{tag};
+
+ ($vnetid, $tag) = $class->get_bridge_vlan($plugin_config, $vnetid, $tag);
+ my $trunks = undef;
+
+ PVE::Network::tap_plug($iface, $vnetid, $tag, $firewall, $trunks, $rate);
+}
+
+#helper
+
+sub get_uplink_iface {
+ my ($interfaces_config, $uplink) = @_;
+
+ my $iface = undef;
+ foreach my $id (keys %{$interfaces_config->{ifaces}}) {
+ my $interface = $interfaces_config->{ifaces}->{$id};
+ if (my $iface_uplink = $interface->{'uplink-id'}) {
+ next if $iface_uplink ne $uplink;
+ if($interface->{type} ne 'eth' && $interface->{type} ne 'bond') {
+ warn "uplink $uplink is not a physical or bond interface";
+ next;
+ }
+ $iface = $id;
+ }
+ }
+
+ #create a dummy uplink interface if no uplink found
+ if(!$iface) {
+ warn "can't find uplink $uplink in physical interface";
+ $iface = "uplink${uplink}";
+ }
+
+ return $iface;
+}
+
+sub get_local_route_ip {
+ my ($targetip) = @_;
+
+ my $ip = undef;
+ my $interface = undef;
+
+ run_command(['/sbin/ip', 'route', 'get', $targetip], outfunc => sub {
+ if ($_[0] =~ m/src ($PVE::Tools::IPRE)/) {
+ $ip = $1;
+ }
+ if ($_[0] =~ m/dev (\S+)/) {
+ $interface = $1;
+ }
+
+ });
+ return ($ip, $interface);
+}
+
+
+sub find_local_ip_interface_peers {
+ my ($peers) = @_;
+
+ my $network_config = PVE::INotify::read_file('interfaces');
+ my $ifaces = $network_config->{ifaces};
+ #is a local ip member of peers list ?
+ foreach my $address (@{$peers}) {
+ while (my $interface = each %$ifaces) {
+ my $ip = $ifaces->{$interface}->{address};
+ if ($ip && $ip eq $address) {
+ return ($ip, $interface);
+ }
+ }
+ }
+
+ #if peer is remote, find source with ip route
+ foreach my $address (@{$peers}) {
+ my ($ip, $interface) = get_local_route_ip($address);
+ return ($ip, $interface);
+ }
+}
+
1;