linux bridge
-------------

eth0------->vmbr0
eth0.94---->vmbr0v94<-----tapXiY (non firewalled tap)
                    <--linkXiY----->linkXiYp--->fwbrXiY---->tapXiY (firewalled 
tap)

openvswitch
---------------
eth0-->vmbr0--vlan--ovsintXiY-->fwbr---->tapXiY (firewalled tap)

            --vlan---->tapXiY (non firewall tap)

Signed-off-by: Alexandre Derumier <[email protected]>
---
 data/PVE/Network.pm |  242 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 223 insertions(+), 19 deletions(-)

diff --git a/data/PVE/Network.pm b/data/PVE/Network.pm
index 4677bf9..fb89cbf 100644
--- a/data/PVE/Network.pm
+++ b/data/PVE/Network.pm
@@ -2,10 +2,12 @@ package PVE::Network;
 
 use strict;
 use warnings;
-use PVE::Tools qw(run_command);
+use PVE::Tools qw(run_command file_get_contents);
 use PVE::ProcFSTools;
 use PVE::INotify;
+use PVE::Firewall;
 use File::Basename;
+use JSON;
 
 # host network related utility functions
 
@@ -68,37 +70,74 @@ sub tap_create {
 }
 
 sub tap_plug {
-    my ($iface, $bridge, $tag) = @_;
+    my ($iface, $bridge, $tag, $tapfirewall) = @_;
+
+    my $iface_suffix = undef;
+    my $vmid = undef;
+
+    if ($iface =~ m/^tap((\d+)i(\d+))$/){
+       $iface_suffix = $1;
+       $vmid = $2;
+    }elsif ($iface =~ m/^veth((\d+)\.(\d+))$/){
+       $iface_suffix = $1;
+       $vmid = $2;
+    }else{
+       die "wrong interface name $iface";
+    }
 
-    #cleanup old port config from any openvswitch bridge
-    eval {run_command("/usr/bin/ovs-vsctl del-port $iface", outfunc => sub {}, 
errfunc => sub {}) };
+    my $vmfw_conf = PVE::Firewall::load_vmfw_conf($vmid);
+    my $fwenable = $vmfw_conf->{options}->{enable};
+
+    $fwenable = $tapfirewall if $fwenable;
+
+    my $ovsintport = "ovsint$iface_suffix";
+
+    bridge_cleanup($iface);
 
     if (-d "/sys/class/net/$bridge/bridge") {
-       my $newbridge = activate_bridge_vlan($bridge, $tag);
+
+       my $newbridge = undef;
+       #create bridge vlan
+       $newbridge = activate_bridge_vlan($bridge, $tag);
        copy_bridge_config($bridge, $newbridge) if $bridge ne $newbridge;
+       $newbridge = fwbridge_create($iface, $newbridge) if $fwenable;
+
+        system("/sbin/brctl addif $newbridge $iface") == 0 ||
+            die "can't add interface $iface to bridge $newbridge\n";
 
-       system("/sbin/brctl addif $newbridge $iface") == 0 ||
-           die "can't add interface to bridge\n";
     } else {
-       my $cmd = "/usr/bin/ovs-vsctl add-port $bridge $iface";
-       $cmd .= " tag=$tag" if $tag;
-       system($cmd) == 0 ||
-           die "can't add interface to bridge\n";
+
+       my $bridge_hash = {};
+
+       eval { $bridge_hash = read_openvswitch_config() };
+
+       die "$bridge is not an linux bridge or openvswitch switch" if 
!$bridge_hash->{$bridge};
+       if(!$fwenable){ 
+           my $cmd = "/usr/bin/ovs-vsctl add-port $bridge $iface";
+           $cmd .= " tag=$tag" if $tag;
+           system($cmd) == 0 ||
+               die "can't add interface $iface to bridge $bridge\n";
+       }else{
+           ovs_firewall_tap_plug($iface, $bridge, $tag);               
+        }
+
     }
 }
 
 sub tap_unplug {
-    my ($iface, $bridge, $tag) = @_;
-
-    if (-d "/sys/class/net/$bridge/bridge") {
-       $bridge .= "v$tag" if $tag;
+    my ($iface, $bridge, $tag, $tapfirewall) = @_;
 
+    my $path= "/sys/class/net/$iface/brport/bridge";
+    if (-l $path) {
+       $bridge = basename(readlink($path));
+       #avoid insecure dependency;
+       ($bridge) = $bridge =~ /(\S+)/;
        system("/sbin/brctl delif $bridge $iface") == 0 ||
-           die "can't del interface from bridge\n";
-    } else {
-       system ("/usr/bin/ovs-vsctl del-port $iface") == 0 ||
-           die "can't del interface from bridge\n";
+           die "can't del interface $iface from bridge $bridge\n";
     }
+
+    bridge_cleanup($iface);
+
 }
 
 sub copy_bridge_config {
@@ -193,4 +232,169 @@ sub activate_bridge_vlan {
     return $bridgevlan;
 }
 
+sub read_openvswitch_config {
+
+    my $filename = '/etc/openvswitch/conf.db';
+    my $config = file_get_contents($filename, 5*1024*1024);
+    my @lines = split('\n', $config);
+    my $bridge_hash = {};
+    foreach my $line (@lines) {
+       my $json = {};
+       eval { $json = decode_json($line)};
+       foreach my $bridgekey (keys %{$json->{Bridge}}) {
+           my $bridgename = $json->{Bridge}->{$bridgekey}->{name};
+           $bridge_hash->{$bridgename} = 1 if $bridgename;
+        }
+    }
+
+    return $bridge_hash;
+
+}
+
+sub ovs_firewall_tap_plug {
+    my ($iface, $bridge, $tag) = @_;
+
+    my $iface_suffix = $1 if $iface =~ m/^tap((\d+)i(\d+))$/;
+    die "wrong interface name $iface" if !$iface_suffix;
+
+    my $ovsintport = "ovsint$iface_suffix";
+    my $bridgetap = "fwbr$iface_suffix";
+
+    my $cmd = "/usr/bin/ovs-vsctl add-port $bridge $ovsintport";
+    $cmd .= " tag=$tag" if $tag;
+    $cmd .= " -- set Interface $ovsintport type=internal";
+    system($cmd) == 0 ||
+       die "$cmd : can't create ovs intport $ovsintport\n";
+
+    # set the same mtu for ovs int port
+    my $bridgemtu = 
PVE::Tools::file_read_firstline("/sys/class/net/$bridge/mtu");
+       die "bridge '$bridge' does not exist\n" if !$bridgemtu;
+
+    eval { 
+       PVE::Tools::run_command("/sbin/ifconfig $ovsintport mtu $bridgemtu");
+    };
+
+    # add bridgetap if it doesn't already exist
+    if (! -d "/sys/class/net/$bridgetap") {
+       system("/sbin/brctl addbr $bridgetap") == 0 ||
+           die "can't add bridge $bridgetap\n";
+    }
+
+    # be sure to have the bridgetap up
+    system("/sbin/ip link set $bridgetap up") == 0 ||
+       die "can't up bridge $bridgetap\n";
+
+    # add ovsintport to bridgetap
+    system("/sbin/brctl addif $bridgetap $ovsintport") == 0 ||
+       die "can't add interface $ovsintport to bridge $bridgetap\n";
+
+    # add vm tap interface to bridgetap
+    system("/sbin/brctl addif $bridgetap $iface") == 0 ||
+       die "can't add interface $iface to bridge $bridgetap\n";
+
+}
+
+sub fwbridge_create {
+    my ($iface, $bridge) = @_;
+
+       my $iface_suffix = undef;
+       my $vmid = undef;
+
+       if ($iface =~ m/^tap((\d+)i(\d+))$/){
+           $iface_suffix = $1;
+           $vmid = $2;
+       }elsif ($iface =~ m/^veth((\d+)\.(\d+))$/){
+           $iface_suffix = $1;
+           $vmid = $2;
+       }else{
+           die "wrong interface name $iface";
+       }
+
+       my $bridgetap = "fwbr$iface_suffix";
+
+       my $vethfw = "link$iface_suffix";
+       my $vethfwpeer = $vethfw."p";
+
+
+       my $bridgemtu = 
PVE::Tools::file_read_firstline("/sys/class/net/$bridge/mtu");
+       die "bridge '$bridge' does not exist\n" if !$bridgemtu;
+#        #avoid insecure dependency;
+       ($bridgemtu) = $bridgemtu =~ /(\d+)/;
+
+        # add bridgetap if it doesn't already exist
+        if (! -d "/sys/class/net/$bridgetap") {
+        system("/sbin/brctl addbr $bridgetap") == 0 ||
+            die "can't add bridge $bridgetap\n";
+        }
+
+        # be sure to have the bridgetap up
+        system("/sbin/ip link set $bridgetap up") == 0 ||
+            die "can't up bridge $bridgetap\n";
+
+       copy_bridge_config($bridge, $bridgetap);
+       # create veth pair
+        if (! -d "/sys/class/net/$vethfw") {
+           system("/sbin/ip link add name $vethfw type veth peer name 
$vethfwpeer mtu $bridgemtu") == 0 ||
+               die "can't create interface $vethfw\n";
+       }
+
+       #up vethpair
+        system("/sbin/ip link set up dev $vethfw") == 0 ||
+            die "can't up veth $vethfw\n";
+
+        system("/sbin/ip link set up dev $vethfwpeer") == 0 ||
+            die "can't up veth $vethfw\n";
+
+
+        # add veth to main bridge
+        system("/sbin/brctl addif $bridge $vethfw") == 0 ||
+            die "can't add interface $vethfw to bridge $bridge\n";
+
+        # add vethpeer to bridgetap
+        system("/sbin/brctl addif $bridgetap $vethfwpeer") == 0 ||
+            die "can't add interface $vethfwpeer to bridge $bridgetap\n";
+
+       return $bridgetap;
+
+}
+
+sub bridge_cleanup {
+    my ($iface) = @_;
+
+    my $iface_suffix = undef;
+    my $vmid = undef;
+
+    if ($iface =~ m/^tap((\d+)i(\d+))$/){
+       $iface_suffix = $1;
+       $vmid = $2;
+    }elsif ($iface =~ m/^veth((\d+)\.(\d+))$/){
+       $iface_suffix = $1;
+       $vmid = $2;
+    }else{
+       die "wrong interface name $iface";
+    }
+
+    my $ovsintport = "ovsint$iface_suffix";
+    my $vethfw = "link$iface_suffix";
+
+    eval {run_command("/usr/bin/ovs-vsctl del-port $iface", outfunc => sub {}, 
errfunc => sub {}) };
+
+    #cleanup old port config from any openvswitch bridge
+    if (-d "/sys/class/net/$ovsintport") {
+       eval {run_command("/usr/bin/ovs-vsctl del-port $ovsintport", outfunc => 
sub {}, errfunc => sub {}) };
+    }
+
+    #cleanup old vethfw interface
+    if (-d "/sys/class/net/$vethfw") {
+       run_command("/sbin/ip link delete dev $vethfw", outfunc => sub {}, 
errfunc => sub {});
+    }
+
+    my $bridgetap = "fwbr$iface_suffix";
+
+    # cleanup fwbrtap bridge
+    if (-d "/sys/class/net/$bridgetap") {
+       run_command("/sbin/ip link set dev $bridgetap down", outfunc => sub {}, 
errfunc => sub {});
+       run_command("/sbin/brctl delbr $bridgetap", outfunc => sub {}, errfunc 
=> sub {});
+    }
+}
 1;
-- 
1.7.10.4

_______________________________________________
pve-devel mailing list
[email protected]
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to