mirror of
https://git.proxmox.com/git/pve-common
synced 2025-08-08 11:29:42 +00:00
Fix #882: active state of interfaces depends on ipv6
read_etc_network_interfaces used the content of /proc/net/if_inet6 to decide whether an interface's state is "active", which means an interface is only active when it has an ipv6 address, thus using net.ipv6.conf.*.disable_ipv6 on an interface will cause it to show as inactive in the web interface. We now filter the interfaces found in /proc/dev/net by their IFF_UP flag read via an SIOCGIFFLAGS ioctl().
This commit is contained in:
parent
2701dc7479
commit
12a235d624
@ -785,12 +785,12 @@ my $extract_ovs_option = sub {
|
|||||||
sub read_etc_network_interfaces {
|
sub read_etc_network_interfaces {
|
||||||
my ($filename, $fh) = @_;
|
my ($filename, $fh) = @_;
|
||||||
my $proc_net_dev = IO::File->new('/proc/net/dev', 'r');
|
my $proc_net_dev = IO::File->new('/proc/net/dev', 'r');
|
||||||
my $proc_net_if_inet6 = IO::File->new('/proc/net/if_inet6', 'r');
|
my $active = PVE::Network::get_active_interfaces();
|
||||||
return __read_etc_network_interfaces($fh, $proc_net_dev, $proc_net_if_inet6);
|
return __read_etc_network_interfaces($fh, $proc_net_dev, $active);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub __read_etc_network_interfaces {
|
sub __read_etc_network_interfaces {
|
||||||
my ($fh, $proc_net_dev, $proc_net_if_inet6) = @_;
|
my ($fh, $proc_net_dev, $active_ifaces) = @_;
|
||||||
|
|
||||||
my $config = {};
|
my $config = {};
|
||||||
my $ifaces = $config->{ifaces} = {};
|
my $ifaces = $config->{ifaces} = {};
|
||||||
@ -905,7 +905,11 @@ sub __read_etc_network_interfaces {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach my $ifname (@$active_ifaces) {
|
||||||
|
if (my $iface = $ifaces->{$ifname}) {
|
||||||
|
$iface->{active} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$ifaces->{lo}) {
|
if (!$ifaces->{lo}) {
|
||||||
$ifaces->{lo}->{priority} = 1;
|
$ifaces->{lo}->{priority} = 1;
|
||||||
@ -997,15 +1001,6 @@ sub __read_etc_network_interfaces {
|
|||||||
$d->{families} ||= ['inet'];
|
$d->{families} ||= ['inet'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($proc_net_if_inet6) {
|
|
||||||
while (defined ($line = <$proc_net_if_inet6>)) {
|
|
||||||
if ($line =~ m/^[a-f0-9]{32}\s+[a-f0-9]{2}\s+[a-f0-9]{2}\s+[a-f0-9]{2}\s+[a-f0-9]{2}\s+(\S+)$/) {
|
|
||||||
$ifaces->{$1}->{active} = 1 if defined($ifaces->{$1});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close ($proc_net_if_inet6);
|
|
||||||
}
|
|
||||||
|
|
||||||
# OVS bridges create "allow-$BRIDGE $IFACE" lines which we need to remove
|
# OVS bridges create "allow-$BRIDGE $IFACE" lines which we need to remove
|
||||||
# from the {options} hash for them to be removed correctly.
|
# from the {options} hash for them to be removed correctly.
|
||||||
@$options = grep {defined($_)} map {
|
@$options = grep {defined($_)} map {
|
||||||
|
@ -11,6 +11,12 @@ use POSIX qw(ECONNREFUSED);
|
|||||||
|
|
||||||
use Net::IP;
|
use Net::IP;
|
||||||
|
|
||||||
|
require "sys/ioctl.ph";
|
||||||
|
use Socket qw(IPPROTO_IP);
|
||||||
|
|
||||||
|
use constant IFF_UP => 1;
|
||||||
|
use constant IFNAMSIZ => 16;
|
||||||
|
|
||||||
# host network related utility functions
|
# host network related utility functions
|
||||||
|
|
||||||
our $ipv4_reverse_mask = [
|
our $ipv4_reverse_mask = [
|
||||||
@ -514,4 +520,34 @@ sub is_ip_in_cidr {
|
|||||||
return $cidr_obj->overlaps($ip_obj) == $Net::IP::IP_B_IN_A_OVERLAP;
|
return $cidr_obj->overlaps($ip_obj) == $Net::IP::IP_B_IN_A_OVERLAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# struct ifreq { // FOR SIOCGIFFLAGS:
|
||||||
|
# char ifrn_name[IFNAMSIZ]
|
||||||
|
# short ifru_flags
|
||||||
|
# };
|
||||||
|
my $STRUCT_IFREQ_SIOCGIFFLAGS = 'Z' . IFNAMSIZ . 's1';
|
||||||
|
sub get_active_interfaces {
|
||||||
|
# Use the interface name list from /proc/net/dev
|
||||||
|
open my $fh, '<', '/proc/net/dev'
|
||||||
|
or die "failed to open /proc/net/dev: $!\n";
|
||||||
|
# And filter by IFF_UP flag fetched via a PF_INET6 socket ioctl:
|
||||||
|
socket my $sock, PF_INET6, SOCK_DGRAM, &IPPROTO_IP
|
||||||
|
or die "failed to open socket\n";
|
||||||
|
|
||||||
|
my $ifaces = [];
|
||||||
|
while(defined(my $line = <$fh>)) {
|
||||||
|
next if $line !~ /^\s*([^:\s]+):/;
|
||||||
|
my $ifname = $1;
|
||||||
|
my $ifreq = pack($STRUCT_IFREQ_SIOCGIFFLAGS, $1, 0);
|
||||||
|
if (!defined(ioctl($sock, &SIOCGIFFLAGS, $ifreq))) {
|
||||||
|
warn "failed to get interface flags for: $ifname\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my ($name, $flags) = unpack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifreq);
|
||||||
|
push @$ifaces, $1 if ($flags & IFF_UP);
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
close $sock;
|
||||||
|
return $ifaces;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
3
test/etc_network_interfaces/active_interfaces
Normal file
3
test/etc_network_interfaces/active_interfaces
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
lo
|
||||||
|
eth0
|
||||||
|
vmbr0
|
@ -1,3 +0,0 @@
|
|||||||
00000000000000000000000000000001 01 80 10 80 lo
|
|
||||||
fe80000000000000ae9e17fffe846a7a 03 40 20 80 vmbr0
|
|
||||||
fc050000000000000000000010000001 03 70 00 80 vmbr0
|
|
@ -59,16 +59,15 @@ sub flush_files() {
|
|||||||
## Interface parsing:
|
## Interface parsing:
|
||||||
##
|
##
|
||||||
|
|
||||||
# Read an interfaces file with optional /proc/net/dev and /proc/net/if_inet6
|
# Read an interfaces file with optional /proc/net/dev file content string and
|
||||||
# file content strings, which default to the provided ones.
|
# the list of active interfaces, which otherwise default
|
||||||
sub r($;$$) {
|
sub r($;$$) {
|
||||||
my ($ifaces, $proc_net_dev, $proc_net_if_inet6) = @_;
|
my ($ifaces, $proc_net_dev, $active) = @_;
|
||||||
$proc_net_dev //= load('proc_net_dev');
|
$proc_net_dev //= load('proc_net_dev');
|
||||||
$proc_net_if_inet6 //= load('proc_net_if_inet6');
|
$active //= [split(/\s+/, load('active_interfaces'))];
|
||||||
open my $fh1, '<', \$ifaces;
|
open my $fh1, '<', \$ifaces;
|
||||||
open my $fh2, '<', \$proc_net_dev;
|
open my $fh2, '<', \$proc_net_dev;
|
||||||
open my $fh3, '<', \$proc_net_if_inet6;
|
$config = PVE::INotify::__read_etc_network_interfaces($fh1, $fh2, $active);
|
||||||
$config = PVE::INotify::__read_etc_network_interfaces($fh1, $fh2, $fh3);
|
|
||||||
close $fh1;
|
close $fh1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user