"htb rate ${rate}bps burst ${burst}b");
run_command("/sbin/tc qdisc add dev $iface handle ffff: ingress");
- run_command("/sbin/tc filter add dev $iface parent ffff: " .
- "prio 50 basic " .
- "police rate ${rate}bps burst ${burst}b mtu 64kb " .
- "drop");
+ run_command(
+ "/sbin/tc filter add dev $iface parent ffff: prio 50 basic police rate ${rate}bps burst ${burst}b mtu 64kb drop");
+
+ return;
}
sub tap_rate_limit {
my $burst = 1024*1024;
setup_tc_rate_limit($iface, $rate, $burst);
+
+ return;
}
sub read_bridge_mtu {
my $mtu = PVE::Tools::file_read_firstline("/sys/class/net/$bridge/mtu");
die "bridge '$bridge' does not exist\n" if !$mtu;
- # avoid insecure dependency;
- die "unable to parse mtu value" if $mtu !~ /^(\d+)$/;
- $mtu = int($1);
+
+ if ($mtu =~ /^(\d+)$/) { # avoid insecure dependency (untaint)
+ $mtu = int($1);
+ } else {
+ die "unexpeted error: unable to parse mtu value '$mtu' as integer\n";
+ }
return $mtu;
-};
+}
my $parse_tap_device_name = sub {
my ($iface, $noerr) = @_;
$vmid = $1;
$devid = $2;
} else {
- return undef if $noerr;
+ return if $noerr;
die "can't create firewall bridge for random interface name '$iface'\n";
}
return ($fwbr, $vethfw, $vethfwpeer, $ovsintport);
};
-sub iface_delete($) {
+sub iface_delete :prototype($) {
my ($iface) = @_;
run_command(['/sbin/ip', 'link', 'delete', 'dev', $iface], noerr => 1)
== 0 or die "failed to delete interface '$iface'\n";
+ return;
}
-sub iface_create($$@) {
+sub iface_create :prototype($$@) {
my ($iface, $type, @args) = @_;
run_command(['/sbin/ip', 'link', 'add', $iface, 'type', $type, @args], noerr => 1)
== 0 or die "failed to create interface '$iface'\n";
+ return;
}
-sub iface_set($@) {
+sub iface_set :prototype($@) {
my ($iface, @opts) = @_;
run_command(['/sbin/ip', 'link', 'set', $iface, @opts], noerr => 1)
== 0 or die "failed to set interface options for '$iface' (".join(' ', @opts).")\n";
+ return;
}
# helper for nicer error messages:
-sub iface_set_master($$) {
+sub iface_set_master :prototype($$) {
my ($iface, $master) = @_;
if (defined($master)) {
eval { iface_set($iface, 'master', $master) };
eval { iface_set($iface, 'nomaster') };
die "can't unenslave '$iface'\n" if $@;
}
+ return;
}
my $cond_create_bridge = sub {
open(my $fh, '>', $file) or die "failed to open $file for writing: $!\n";
print {$fh} "1\n" or die "failed to disable link-local ipv6 for $iface\n";
close($fh);
+ return;
}
my $bridge_disable_interface_learning = sub {
my $bridge_add_interface = sub {
my ($bridge, $iface, $tag, $trunks) = @_;
+ my $bridgemtu = read_bridge_mtu($bridge);
+ eval { run_command(['/sbin/ip', 'link', 'set', $iface, 'mtu', $bridgemtu]) };
+
# drop link local address (it can't be used when on a bridge anyway)
disable_ipv6($iface);
iface_set_master($iface, $bridge);
push @$cmd, "trunks=". join(',', $trunks) if $trunks;
push @$cmd, "vlan_mode=native-untagged" if $tag && $trunks;
+ my $bridgemtu = read_bridge_mtu($bridge);
+ push @$cmd, '--', 'set', 'Interface', $iface, "mtu_request=$bridgemtu";
+
if ($internal) {
# second command
push @$cmd, '--', 'set', 'Interface', $iface, 'type=internal';
};
my $activate_interface = sub {
- my ($iface) = @_;
+ my ($iface, $mtu) = @_;
+
+ my $cmd = ['/sbin/ip', 'link', 'set', $iface, 'up'];
+ push @$cmd, ('mtu', $mtu) if $mtu;
- eval { run_command(['/sbin/ip', 'link', 'set', $iface, 'up']) };
+ eval { run_command($cmd) };
die "can't activate interface '$iface' - $@\n" if $@;
};
my ($vmid, $devid) = &$parse_tap_device_name($iface, 1);
return if !defined($vmid);
- PVE::Tools::run_command(['/sbin/bridge', 'fdb', 'append', $mac, 'dev', $iface, 'master', 'static']);
+ run_command(['/sbin/bridge', 'fdb', 'append', $mac, 'dev', $iface, 'master', 'static']);
my ($fwbr, $vethfw, $vethfwpeer, $ovsintport) = &$compute_fwbr_names($vmid, $devid);
if (-d "/sys/class/net/$vethfwpeer") {
- PVE::Tools::run_command(['/sbin/bridge', 'fdb', 'append', $mac, 'dev', $vethfwpeer, 'master', 'static']);
+ run_command(['/sbin/bridge', 'fdb', 'append', $mac, 'dev', $vethfwpeer, 'master', 'static']);
}
+ return;
}
sub del_bridge_fdb {
my ($vmid, $devid) = &$parse_tap_device_name($iface, 1);
return if !defined($vmid);
- PVE::Tools::run_command(['/sbin/bridge', 'fdb', 'del', $mac, 'dev', $iface, 'master', 'static']);
+ run_command(['/sbin/bridge', 'fdb', 'del', $mac, 'dev', $iface, 'master', 'static']);
my ($fwbr, $vethfw, $vethfwpeer, $ovsintport) = &$compute_fwbr_names($vmid, $devid);
if (-d "/sys/class/net/$vethfwpeer") {
- PVE::Tools::run_command(['/sbin/bridge', 'fdb', 'del', $mac, 'dev', $vethfwpeer, 'master', 'static']);
+ run_command(['/sbin/bridge', 'fdb', 'del', $mac, 'dev', $vethfwpeer, 'master', 'static']);
}
+
+ return;
}
sub tap_create {
eval {
disable_ipv6($iface);
- PVE::Tools::run_command(['/sbin/ip', 'link', 'set', $iface, 'up', 'promisc', 'on', 'mtu', $bridgemtu]);
+ run_command(['/sbin/ip', 'link', 'set', $iface, 'up', 'promisc', 'on', 'mtu', $bridgemtu]);
};
die "interface activation failed\n" if $@;
+ return;
}
sub veth_create {
# up vethpair
disable_ipv6($veth);
disable_ipv6($vethpeer);
- &$activate_interface($veth);
- &$activate_interface($vethpeer);
+ &$activate_interface($veth, $bridgemtu);
+ &$activate_interface($vethpeer, $bridgemtu);
+
+ return;
}
sub veth_delete {
iface_delete($veth);
}
eval { tap_unplug($veth) };
+ return;
}
my $create_firewall_bridge_linux = sub {
my ($vmid, $devid) = &$parse_tap_device_name($iface);
my ($fwbr, $vethfw, $vethfwpeer) = &$compute_fwbr_names($vmid, $devid);
+ my $bridgemtu = read_bridge_mtu($bridge);
+
&$cond_create_bridge($fwbr);
- &$activate_interface($fwbr);
+ &$activate_interface($fwbr, $bridgemtu);
copy_bridge_config($bridge, $fwbr);
veth_create($vethfw, $vethfwpeer, $bridge);
my $bridgemtu = read_bridge_mtu($bridge);
&$cond_create_bridge($fwbr);
- &$activate_interface($fwbr);
+ &$activate_interface($fwbr, $bridgemtu);
&$bridge_add_interface($fwbr, $iface);
&$ovs_bridge_add_port($bridge, $ovsintport, $tag, 1, $trunks);
- &$activate_interface($ovsintport);
-
- # set the same mtu for ovs int port
- PVE::Tools::run_command(['/sbin/ip', 'link', 'set', $ovsintport, 'mtu', $bridgemtu]);
+ &$activate_interface($ovsintport, $bridgemtu);
&$bridge_add_interface($fwbr, $ovsintport);
&$bridge_disable_interface_learning($ovsintport) if $no_learning;
$opts = {} if !defined($opts);
- my $no_learning = !$opts->{learning};
+ my $no_learning = defined($opts->{learning}) && !$opts->{learning}; # default to learning on
# cleanup old port config from any openvswitch bridge
eval {
}
tap_rate_limit($iface, $rate);
+
+ return;
}
sub tap_unplug {
&$cleanup_firewall_bridge($iface);
#cleanup old port config from any openvswitch bridge
- eval {run_command("/usr/bin/ovs-vsctl del-port $iface", outfunc => sub {}, errfunc => sub {}) };
+ eval { run_command("/usr/bin/ovs-vsctl del-port $iface", outfunc => sub {}, errfunc => sub {}) };
+
+ return;
}
sub copy_bridge_config {
return if $br0 eq $br1;
- my $br_configs = [ 'ageing_time', 'stp_state', 'priority', 'forward_delay',
- 'hello_time', 'max_age', 'multicast_snooping', 'multicast_querier'];
+ my $br_configs = [
+ 'ageing_time', 'stp_state', 'priority', 'forward_delay',
+ 'hello_time', 'max_age', 'multicast_snooping', 'multicast_querier',
+ ];
foreach my $sysname (@$br_configs) {
eval {
};
warn $@ if $@;
}
+ return;
}
sub activate_bridge_vlan_slave {
# add $ifacevlan to the bridge
&$bridge_add_interface($bridgevlan, $ifacevlan);
+ return;
}
sub activate_bridge_vlan {
sub IP_from_cidr {
my ($cidr, $version) = @_;
- return if $cidr !~ m!^(\S+?)/(\S+)$!;
- my ($ip, $prefix) = ($1, $2);
+ my ($ip, $prefix) = $cidr =~ m!^(\S+?)/(\S+)$! or return;
my $ipobj = Net::IP->new($ip, $version);
return if !$ipobj;
my ($ip, $cidr, $version) = @_;
my $cidr_obj = IP_from_cidr($cidr, $version);
- return undef if !$cidr_obj;
+ return if !$cidr_obj;
my $ip_obj = Net::IP->new($ip, $version);
- return undef if !$ip_obj;
+ return if !$ip_obj;
my $overlap = $cidr_obj->overlaps($ip_obj);
-
return if !defined($overlap);
return $overlap == $Net::IP::IP_B_IN_A_OVERLAP || $overlap == $Net::IP::IP_IDENTICAL;
}
}
- return undef if !$param{all}; # getting here means no early return above triggered -> no IPs
+ return if !$param{all}; # getting here means no early return above triggered -> no IPs
my $res = []; # order gai.conf controlled first, then group v4 and v6, simply lexically sorted
if ($resolved_host) {
my @res = eval { PVE::Tools::getaddrinfo_all($hostname) };
if ($@) {
die "hostname lookup '$hostname' failed - $@" if !$noerr;
- return undef;
+ return;
}
for my $ai (@res) {
}
# NOTE: we only get here if no WAN/LAN IP was found, so this is now the error path!
die "address lookup for '$hostname' did not find any IP address\n" if !$noerr;
- return undef;
+ return;
}
sub lock_network {