X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=src%2FPVE%2FNetwork.pm;h=342153233bd580442f1a2a695e4b6f21a7a56ab7;hp=69051b9de048e5a6023902b9898af9cd5ab655b5;hb=505786f6a4430ceea3aa5d29504274f1bb95ec4f;hpb=86330049bed1391232ae584f7301f4c368b75375 diff --git a/src/PVE/Network.pm b/src/PVE/Network.pm index 69051b9..3421532 100644 --- a/src/PVE/Network.pm +++ b/src/PVE/Network.pm @@ -7,12 +7,15 @@ use PVE::ProcFSTools; 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', @@ -99,7 +102,7 @@ sub setup_tc_rate_limit { 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"; @@ -162,12 +165,42 @@ my $compute_fwbr_names = sub { 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); } }; @@ -185,8 +218,7 @@ my $bridge_add_interface = sub { # 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"); @@ -275,7 +307,7 @@ sub veth_delete { 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) }; } @@ -287,7 +319,6 @@ my $create_firewall_bridge_linux = sub { my ($fwbr, $vethfw, $vethfwpeer) = &$compute_fwbr_names($vmid, $devid); &$cond_create_bridge($fwbr); - disable_ipv6($fwbr); &$activate_interface($fwbr); copy_bridge_config($bridge, $fwbr); @@ -308,7 +339,6 @@ my $create_firewall_bridge_ovs = sub { my $bridgemtu = &$read_bridge_mtu($bridge); &$cond_create_bridge($fwbr); - disable_ipv6($fwbr); &$activate_interface($fwbr); &$bridge_add_interface($fwbr, $iface); @@ -339,8 +369,7 @@ my $cleanup_firewall_bridge = sub { # 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); } }; @@ -391,9 +420,7 @@ sub tap_unplug { #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); @@ -429,10 +456,10 @@ sub activate_bridge_vlan_slave { if (! -d "/sys/class/net/$ifacevlan") { system("/sbin/ip link add link $iface name $ifacevlan type vlan id $tag") == 0 || die "can't add vlan tag $tag to interface $iface\n"; - } - # remove ipv6 link-local address before activation - disable_ipv6($ifacevlan); + # remove ipv6 link-local address before activation + disable_ipv6($ifacevlan); + } # be sure to have the $ifacevlan up &$activate_interface($ifacevlan); @@ -477,8 +504,7 @@ sub activate_bridge_vlan { 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 @@ -576,6 +602,37 @@ sub get_local_ip_from_cidr { 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);