use PVE::INotify;
use File::Basename;
use IO::Socket::IP;
+use Socket qw(NI_NUMERICHOST NI_NUMERICSERV);
use POSIX qw(ECONNREFUSED);
use Net::IP;
# host network related utility functions
+our $PHYSICAL_NIC_RE = qr/(?:eth\d+|en[^:.]+|ib\d+)/;
+
our $ipv4_reverse_mask = [
'0.0.0.0',
'128.0.0.0',
run_command("/sbin/tc filter add dev $iface parent ffff: " .
"prio 50 basic " .
"police rate ${rate}bps burst ${burst}b mtu 64kb " .
- "drop flowid :1");
+ "drop");
if ($debug) {
print "DEBUG tc settings\n";
return ($fwbr, $vethfw, $vethfwpeer, $ovsintport);
};
+sub iface_delete($) {
+ my ($iface) = @_;
+ run_command(['/sbin/ip', 'link', 'delete', 'dev', $iface], noerr => 1)
+ == 0 or die "failed to delete interface '$iface'\n";
+}
+
+sub iface_create($$@) {
+ 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";
+}
+
+sub iface_set($@) {
+ 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";
+}
+
+# helper for nicer error messages:
+sub iface_set_master($$) {
+ my ($iface, $master) = @_;
+ if (defined($master)) {
+ eval { iface_set($iface, 'master', $master) };
+ die "can't enslave '$iface' to '$master'\n" if $@;
+ } else {
+ eval { iface_set($iface, 'nomaster') };
+ die "can't unenslave '$iface'\n" if $@;
+ }
+}
+
my $cond_create_bridge = sub {
my ($bridge) = @_;
if (! -d "/sys/class/net/$bridge") {
- system("/sbin/brctl addbr $bridge") == 0 ||
- die "can't add bridge '$bridge'\n";
+ iface_create($bridge, 'bridge');
disable_ipv6($bridge);
}
};
# drop link local address (it can't be used when on a bridge anyway)
disable_ipv6($iface);
- system("/sbin/brctl addif $bridge $iface") == 0 ||
- die "can't add interface 'iface' to bridge '$bridge'\n";
+ iface_set_master($iface, $bridge);
my $vlan_aware = PVE::Tools::file_read_firstline("/sys/class/net/$bridge/bridge/vlan_filtering");
my ($veth) = @_;
if (-d "/sys/class/net/$veth") {
- run_command("/sbin/ip link delete dev $veth", outfunc => sub {}, errfunc => sub {});
+ iface_delete($veth);
}
eval { tap_unplug($veth) };
}
# cleanup fwbr bridge
if (-d "/sys/class/net/$fwbr") {
- run_command("/sbin/ip link set dev $fwbr down", outfunc => sub {}, errfunc => sub {});
- run_command("/sbin/brctl delbr $fwbr", outfunc => sub {}, errfunc => sub {});
+ iface_delete($fwbr);
}
};
#avoid insecure dependency;
($bridge) = $bridge =~ /(\S+)/;
- system("/sbin/brctl delif $bridge $iface") == 0 ||
- die "can't del interface '$iface' from bridge '$bridge'\n";
-
+ iface_set_master($iface, undef);
}
&$cleanup_firewall_bridge($iface);
lock_network(sub {
# add bridgevlan if it doesn't already exist
if (! -d "/sys/class/net/$bridgevlan") {
- system("/sbin/brctl addbr $bridgevlan") == 0 ||
- die "can't add bridge $bridgevlan\n";
+ iface_create($bridgevlan, 'bridge');
}
# for each physical interface (eth or bridge) bind them to bridge vlan
return $IPs;
}
+sub addr_to_ip {
+ my ($addr) = @_;
+ my ($err, $host, $port) = Socket::getnameinfo($addr, NI_NUMERICHOST | NI_NUMERICSERV);
+ die "failed to get numerical host address: $err\n" if $err;
+ return ($host, $port) if wantarray;
+ return $host;
+}
+
+sub get_ip_from_hostname {
+ my ($hostname, $noerr) = @_;
+
+ my ($family, $ip);
+
+ eval {
+ my @res = PVE::Tools::getaddrinfo_all($hostname);
+ $family = $res[0]->{family};
+ $ip = addr_to_ip($res[0]->{addr})
+ };
+ if ($@) {
+ die "hostname lookup '$hostname' failed - $@" if !$noerr;
+ return undef;
+ }
+
+ if ($ip =~ m/^127\.|^::1$/) {
+ die "hostname lookup '$hostname' failed - got local IP address '$ip'\n" if !$noerr;
+ return undef;
+ }
+
+ return wantarray ? ($ip, $family) : $ip;
+}
+
sub lock_network {
my ($code, @param) = @_;
my $res = lock_file('/var/lock/pve-network.lck', 10, $code, @param);