mirror of
git://git.proxmox.com/git/pve-common.git
synced 2025-03-11 20:58:41 +03:00
interfaces: support stanzas without types/methods
This is allowed in ifupdown2 and previously interfaces named 'vmbr\d+' were recognized as bridges even if they used this mode. With commit e68ebda4f109 this is no longer the case. Fixes: e68ebda4f109 ("fix #545: interfaces: allow arbitrary bridge names in network config") Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
a061517cdd
commit
b518bbd5f9
@ -912,23 +912,29 @@ sub __read_etc_network_interfaces {
|
||||
# FIXME: handle those differently? auto makes it required on-boot, vs. best-effort
|
||||
$ifaces->{$_}->{autostart} = 1 for split (/\s+/, $2);
|
||||
|
||||
} elsif ($line =~ m/^\s*iface\s+(\S+)\s+(inet6?)\s+(\S+)\s*$/) {
|
||||
} elsif ($line =~ m/^\s*iface\s+(\S+)(?:\s+(inet6?)\s+(\S+))?\s*$/) {
|
||||
my $i = $1;
|
||||
my $family = $2;
|
||||
my $f = { method => $3 }; # by family, merged to $d with a $suffix
|
||||
(my $suffix = $family) =~ s/^inet//;
|
||||
my $suffix = $family;
|
||||
$suffix =~ s/^inet// if defined $suffix;
|
||||
|
||||
my $d = $ifaces->{$i} ||= {};
|
||||
$d->{priority} = $priority++ if !$d->{priority};
|
||||
|
||||
# $family may be undef, an undef family means we have a stanza
|
||||
# without an `inet` or `inet6` section
|
||||
push @{$d->{families}}, $family;
|
||||
|
||||
|
||||
while (defined ($line = <$fh>)) {
|
||||
$line =~ s/\s+$//; # drop trailing whitespaces
|
||||
|
||||
if ($line =~ m/^\s*#(.*?)\s*$/) {
|
||||
$f->{comments} = '' if !$f->{comments};
|
||||
my $pushto = defined($suffix) ? $f : $d;
|
||||
$pushto->{comments} = '' if !$pushto->{comments};
|
||||
my $comment = decode('UTF-8', $1);
|
||||
$f->{comments} .= "$comment\n";
|
||||
$pushto->{comments} .= "$comment\n";
|
||||
} elsif ($line =~ m/^\s*(?:(?:iface|mapping|auto|source|source-directory)\s|allow-)/) {
|
||||
last;
|
||||
} elsif ($line =~ m/^\s*((\S+)\s+(.+))$/) {
|
||||
@ -967,7 +973,17 @@ sub __read_etc_network_interfaces {
|
||||
};
|
||||
|
||||
if ($id eq 'address' || $id eq 'netmask' || $id eq 'broadcast' || $id eq 'gateway') {
|
||||
$f->{$id} = $value;
|
||||
if (defined($suffix)) {
|
||||
$d->{$id.$suffix} = $value;
|
||||
} elsif ($id ne 'netmask') {
|
||||
if ($value =~ /:/) {
|
||||
$d->{$id.'6'} = $value;
|
||||
} else {
|
||||
$d->{$id} = $value;
|
||||
}
|
||||
} else {
|
||||
$d->{$id} = $value;
|
||||
}
|
||||
} elsif ($simple_options->{$id}) {
|
||||
$d->{$id} = $value;
|
||||
} elsif ($id eq 'slaves' || $id eq 'bridge_ports') {
|
||||
@ -1002,13 +1018,16 @@ sub __read_etc_network_interfaces {
|
||||
} elsif ($id eq 'vxlan-remoteip') {
|
||||
push @{$d->{$id}}, $value;
|
||||
} else {
|
||||
push @{$f->{options}}, $option;
|
||||
my $pushto = defined($suffix) ? $f : $d;
|
||||
push @{$pushto->{options}}, $option;
|
||||
}
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
$d->{"$_$suffix"} = $f->{$_} for keys $f->%*;
|
||||
if (defined($suffix)) {
|
||||
$d->{"$_$suffix"} = $f->{$_} for keys $f->%*;
|
||||
}
|
||||
last SECTION if !defined($line);
|
||||
redo SECTION;
|
||||
} elsif ($line =~ /\w/) {
|
||||
@ -1227,24 +1246,37 @@ sub _get_cidr {
|
||||
sub __interface_to_string {
|
||||
my ($iface, $d, $family, $first_block, $ifupdown2) = @_;
|
||||
|
||||
(my $suffix = $family) =~ s/^inet//;
|
||||
my $suffix = $family;
|
||||
$suffix =~ s/^inet// if defined($suffix);
|
||||
|
||||
return '' if !($d && $d->{"method$suffix"});
|
||||
return '' if $family && !($d && $d->{"method$suffix"});
|
||||
|
||||
my $raw = "iface $iface $family " . $d->{"method$suffix"} . "\n";
|
||||
my $raw = "iface $iface";
|
||||
$raw .= " $family " . $d->{"method$suffix"} if defined $family;
|
||||
$raw .= "\n";
|
||||
|
||||
if (my $addr = $d->{"address$suffix"}) {
|
||||
if ($addr !~ /\/\d+$/ && $d->{"netmask$suffix"}) {
|
||||
if ($d->{"netmask$suffix"} =~ m/^\d+$/) {
|
||||
$addr .= "/" . $d->{"netmask$suffix"};
|
||||
} elsif (my $mask = PVE::JSONSchema::get_netmask_bits($d->{"netmask$suffix"})) {
|
||||
$addr .= "/" . $mask;
|
||||
my $add_addr = sub {
|
||||
my ($suffix) = @_;
|
||||
if (my $addr = $d->{"address$suffix"}) {
|
||||
if ($addr !~ /\/\d+$/ && $d->{"netmask$suffix"}) {
|
||||
if ($d->{"netmask$suffix"} =~ m/^\d+$/) {
|
||||
$addr .= "/" . $d->{"netmask$suffix"};
|
||||
} elsif (my $mask = PVE::JSONSchema::get_netmask_bits($d->{"netmask$suffix"})) {
|
||||
$addr .= "/" . $mask;
|
||||
}
|
||||
}
|
||||
$raw .= "\taddress ${addr}\n";
|
||||
}
|
||||
$raw .= "\taddress ${addr}\n";
|
||||
}
|
||||
|
||||
$raw .= "\tgateway " . $d->{"gateway$suffix"} . "\n" if $d->{"gateway$suffix"};
|
||||
$raw .= "\tgateway " . $d->{"gateway$suffix"} . "\n" if $d->{"gateway$suffix"};
|
||||
};
|
||||
|
||||
if ($family) {
|
||||
$add_addr->($suffix);
|
||||
} else {
|
||||
$add_addr->('');
|
||||
$add_addr->('6');
|
||||
}
|
||||
|
||||
my $done = {
|
||||
type => 1, priority => 1, method => 1, active => 1, exists => 1, comments => 1,
|
||||
@ -1413,14 +1445,25 @@ sub __interface_to_string {
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $option (@{$d->{"options$suffix"}}) {
|
||||
$raw .= "\t$option\n";
|
||||
}
|
||||
my $add_options_comments = sub {
|
||||
my ($suffix) = @_;
|
||||
|
||||
# add comments
|
||||
my $comments = $d->{"comments$suffix"} || '';
|
||||
foreach my $cl (split(/\n/, $comments)) {
|
||||
$raw .= "#$cl\n";
|
||||
foreach my $option (@{$d->{"options$suffix"}}) {
|
||||
$raw .= "\t$option\n";
|
||||
}
|
||||
|
||||
# add comments
|
||||
my $comments = $d->{"comments$suffix"} || '';
|
||||
foreach my $cl (split(/\n/, $comments)) {
|
||||
$raw .= "#$cl\n";
|
||||
}
|
||||
};
|
||||
|
||||
if ($family) {
|
||||
$add_options_comments->($suffix);
|
||||
} else {
|
||||
$add_options_comments->('');
|
||||
$add_options_comments->('6');
|
||||
}
|
||||
|
||||
$raw .= "\n";
|
||||
@ -1750,7 +1793,7 @@ NETWORKDOC
|
||||
}
|
||||
|
||||
# if 'inet6' is the only family
|
||||
if (scalar($d->{families}->@*) == 1 && $d->{families}[0] eq 'inet6') {
|
||||
if (scalar($d->{families}->@*) == 1 && defined($d->{families}->[0]) && $d->{families}->[0] eq 'inet6') {
|
||||
$d->{comments6} = delete $d->{comments};
|
||||
}
|
||||
|
||||
|
47
test/etc_network_interfaces/t.ifupdown2-typeless.pl
Normal file
47
test/etc_network_interfaces/t.ifupdown2-typeless.pl
Normal file
@ -0,0 +1,47 @@
|
||||
my $ip = '10.0.0.2/24';
|
||||
my $gw = '10.0.0.1';
|
||||
my $ip6 = 'fc05::1:2/112';
|
||||
my $gw6 = 'fc05::1:1';
|
||||
|
||||
r(load('base') . <<"EOF");
|
||||
auto vmbr1
|
||||
iface vmbr1
|
||||
address 1.2.3.4/24
|
||||
address fccc::a:1/64
|
||||
gateway 1.2.3.1
|
||||
gateway fccc::1
|
||||
bridge-ports eth0
|
||||
bridge-stp off
|
||||
bridge-fd 0
|
||||
# Comment
|
||||
|
||||
EOF
|
||||
|
||||
my $run = 'first';
|
||||
my $ifaces = $config->{ifaces};
|
||||
|
||||
my $ck = sub {
|
||||
my ($i, $v, $e) = @_;
|
||||
$ifaces->{$i}->{$v} eq $e
|
||||
or die "$run run: $i variable $v: got \"$ifaces->{$i}->{$v}\", expected: $e\n";
|
||||
};
|
||||
|
||||
my $check_config = sub {
|
||||
$ck->('vmbr1', type => 'bridge');
|
||||
$ck->('vmbr1', cidr => '1.2.3.4/24');
|
||||
$ck->('vmbr1', gateway => '1.2.3.1');
|
||||
$ck->('vmbr1', cidr6 => 'fccc::a:1/64');
|
||||
$ck->('vmbr1', gateway6 => 'fccc::1');
|
||||
};
|
||||
|
||||
$check_config->();
|
||||
|
||||
# idempotency
|
||||
save('idem', w());
|
||||
r(load('idem'));
|
||||
expect load('idem');
|
||||
|
||||
$run = 'second';
|
||||
$check_config->();
|
||||
|
||||
1;
|
Loading…
x
Reference in New Issue
Block a user