[pve-devel] [PATCH] linux bridge and ovs new model implementation v3
Alexandre Derumier
aderumier at odiso.com
Tue Apr 29 17:23:06 CEST 2014
bridge kernel 2.6.32
---------------------
eth0.94---->vmbr0v94<-----tapXiY (non firewalled tap)
<--vethXiY----->vethXiYp--->fwbrXiY---->tapXiY (firewalled tap)
bridge kernel 3.10
------------------
vlans are managed at veth level
non firewalled and firewalled taps have a bridge
eth0-->vmbr0<--veth----->vethXiYp-->vethpvlan--->fwbrtapXiY---->tapXiY (firewalled tap)
<--vethXiY----->vethXiYp---vethvlan--->brtapXiY---->tapXiY (non firewalled tap)
openvswitch
---------------
eth0-->vmbr0--vlan--ovsintXiY-->fwbr---->tapXiY (firewalled tap)
--vlan---->tapXiY (non firewall tap)
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
data/PVE/Network.pm | 258 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 238 insertions(+), 20 deletions(-)
diff --git a/data/PVE/Network.pm b/data/PVE/Network.pm
index 4677bf9..f257c60 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,77 @@ sub tap_create {
}
sub tap_plug {
- my ($iface, $bridge, $tag) = @_;
+ my ($iface, $bridge, $tag, $tapfirewall) = @_;
- #cleanup old port config from any openvswitch bridge
- eval {run_command("/usr/bin/ovs-vsctl del-port $iface", outfunc => sub {}, errfunc => sub {}) };
+ my $iface_suffix = undef;
+ my $vmid = undef;
+
+ if ($iface =~ m/^tap((\d+)i(\d+))$/){
+ $iface_suffix = $1;
+ $vmid = $2;
+ }else{
+ die "wrong interface name $iface";
+ }
+
+ my $vmfw_conf = PVE::Firewall::load_vmfw_conf($vmid);
+ my $fwenable = $vmfw_conf->{options}->{enable};
+
+ $fwenable = $tapfirewall if $fwenable;
+
+ my $ovsintport = "ovsint$iface_suffix";
+ my $bridgetap = "fwbr$iface_suffix";
+
+ bridge_cleanup($iface);
if (-d "/sys/class/net/$bridge/bridge") {
- my $newbridge = activate_bridge_vlan($bridge, $tag);
- copy_bridge_config($bridge, $newbridge) if $bridge ne $newbridge;
- system("/sbin/brctl addif $newbridge $iface") == 0 ||
- die "can't add interface to bridge\n";
+ my $newbridge = undef;
+ #vlan management
+ if(!kernel_310()){
+ #create bridge vlan
+ $newbridge = activate_bridge_vlan($bridge, $tag);
+ copy_bridge_config($bridge, $newbridge) if $bridge ne $newbridge;
+ $newbridge = bridgetap_create($iface, $newbridge, undef, $fwenable) if $fwenable;
+ }else{
+ $newbridge = bridgetap_create($iface, $bridge, $tag, $fwenable);
+ }
+
+ system("/sbin/brctl addif $newbridge $iface") == 0 ||
+ die "can't add interface $iface to bridge $newbridge\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 +235,180 @@ 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 bridgetap_create {
+ my ($iface, $bridge, $tag, $fwenable) = @_;
+
+ my $iface_suffix = $1 if $iface =~ m/^tap((\d+)i(\d+))$/;
+ die "wrong interface name $iface" if !$iface_suffix;
+
+ my $bridgetap = "br$iface_suffix";
+ $bridgetap = "fw$bridgetap" if $fwenable;
+
+ my $vethfw = "veth$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";
+
+
+ if($tag){
+
+ if (! -d "/sys/class/net/$vethfwpeer.$tag") {
+ system("/sbin/ip link add link $vethfwpeer name $vethfwpeer.$tag type vlan id $tag") == 0 ||
+ die "can't create interface vlan $vethfwpeer.$tag\n";
+ }
+
+ $vethfwpeer .= ".$tag";
+
+ system("/sbin/ip link set up dev $vethfwpeer") == 0 ||
+ die "can't up veth $vethfwpeer\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 kernel_310 {
+ my (undef, undef, $release) = POSIX::uname();
+ if ($release =~ m/^(\d+)\.(\d+)\.\d+-/) {
+ my ($major, $minor) = ($1, $2);
+ return 1 if ($major == 3 && $minor >= 10);
+ }
+
+}
+
+sub bridge_cleanup {
+ my ($iface) = @_;
+
+ 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 $vethfw = "veth$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 {});
+ }
+ $bridgetap = "br$iface_suffix";
+
+ # cleanup brtap 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
More information about the pve-devel
mailing list