* parsing ipv6 blocks * parsing extra lines like source/source-directory/...
The returned config hash is not just the interface hash anymore. Interfaces are now in its 'ifaces' member hash. All unknown options (including mappings) end up in its 'options' hash. Added a comment describing the config hash's layout in detail. An interface can now have an ipv4 and an ipv6 entry, they will be returned as a single interface with address/netmask/gateway and address6/netmask6/gateway6 elements. Additionally a 'families' array is available listing which families are available. Ideally we'll at some point allow unhandled families to be kept too, however, now that extra lines like 'source' and 'source-directory' are preserved, it is recommended to move all custom configuration into separate files to not interfere with our interface parsing. --- src/PVE/INotify.pm | 112 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 26 deletions(-) diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index 077975b..5bae210 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -745,10 +745,49 @@ my $extract_ovs_option = sub { return $v; }; +# config => { +# ifaces => { +# $ifname => { +# <optional> exists => BOOL, +# <optional> active => BOOL, +# <optional> autostart => BOOL, +# <auto> priority => INT, +# +# type => "eth" | "bridge" | "bond" | "loopback" | "OVS*" | ... , +# +# families => ["inet", "inet6", ...], +# +# method => "manual" | "static" | "dhcp" | ... , +# address => IP, +# netmask => SUBNET, +# broadcast => IP, +# gateway => IP, +# comments => [ "..." ], +# +# method6 => "manual" | "static" | "dhcp" | ... , +# address6 => IP, +# netmask6 => SUBNET, +# gateway6 => IP, +# comments6 => [ "..." ], +# +# <known options>, # like bridge_ports, ovs_* +# +# # extra/unknown options stored by-family: +# options4 => { <inet options>... } +# options6 => { <inet6 options>... } +# } +# }, +# options => [ +# # mappings end up here as well, as we don't need to understand them +# [priority,line] +# ] +# } sub read_etc_network_interfaces { my ($filename, $fh) = @_; - my $ifaces = {}; + my $config = {}; + my $ifaces = $config->{ifaces} = {}; + my $options = $config->{options} = []; my $line; @@ -775,19 +814,23 @@ sub read_etc_network_interfaces { $ifaces->{$a}->{autostart} = 1; } - } elsif ($line =~ m/^\s*iface\s+(\S+)\s+inet\s+(\S+)\s*$/) { + } elsif ($line =~ m/^\s*iface\s+(\S+)\s+(inet6?)\s+(\S+)\s*$/) { my $i = $1; - $ifaces->{$i}->{method} = $2; - $ifaces->{$i}->{priority} = $priority++; + my $family = $2; + my $f = { method => $3 }; # by family, merged to $d with a $suffix + (my $suffix = $family) =~ s/^inet//; my $d = $ifaces->{$i}; + $d->{priority} = $priority++ if !$d->{priority}; + push @{$d->{families}}, $family; + while (defined ($line = <$fh>)) { chomp $line; if ($line =~ m/^\s*#(.*)$/) { # NOTE: we use 'comments' instead of 'comment' to # avoid automatic utf8 conversion - $d->{comments} = '' if !$d->{comments}; - $d->{comments} .= "$1\n"; + $f->{comments} = '' if !$f->{comments}; + $f->{comments} .= "$1\n"; } elsif ($line =~ m/^\s*(?:iface\s |mapping\s |auto\s @@ -800,7 +843,7 @@ sub read_etc_network_interfaces { my $option = $1; my ($id, $value) = ($2, $3); if (($id eq 'address') || ($id eq 'netmask') || ($id eq 'broadcast') || ($id eq 'gateway')) { - $d->{$id} = $value; + $f->{$id} = $value; } elsif ($id eq 'ovs_type' || $id eq 'ovs_options'|| $id eq 'ovs_bridge' || $id eq 'ovs_bonds' || $id eq 'ovs_ports') { $d->{$id} = $value; @@ -835,14 +878,17 @@ sub read_etc_network_interfaces { } $d->{$id} = $value; } else { - push @{$d->{options}}, $option; + push @{$f->{options}}, $option; } } else { last; } } + $d->{"$_$suffix"} = $f->{$_} foreach (keys %$f); last SECTION if !defined($line); redo SECTION; + } elsif ($line =~ /\w/) { + push @$options, [$priority++, $line]; } } @@ -925,6 +971,7 @@ sub read_etc_network_interfaces { } $d->{method} = 'manual' if !$d->{method}; + $d->{method6} = 'manual' if !$d->{method6}; } if (my $fd2 = IO::File->new("/proc/net/if_inet6", "r")) { @@ -936,25 +983,29 @@ sub read_etc_network_interfaces { close ($fd2); } - return $ifaces; + return $config; } sub __interface_to_string { - my ($iface, $d) = @_; + my ($iface, $d, $family) = @_; + + (my $suffix = $family) =~ s/^inet//; - return '' if !($d && $d->{method}); + return '' if !($d && $d->{"method$suffix"}); my $raw = ''; - $raw .= "iface $iface inet $d->{method}\n"; - $raw .= "\taddress $d->{address}\n" if $d->{address}; - $raw .= "\tnetmask $d->{netmask}\n" if $d->{netmask}; - $raw .= "\tgateway $d->{gateway}\n" if $d->{gateway}; - $raw .= "\tbroadcast $d->{broadcast}\n" if $d->{broadcast}; + $raw .= "iface $iface $family " . $d->{"method$suffix"} . "\n"; + $raw .= "\taddress " . $d->{"address$suffix"} . "\n" if $d->{"address$suffix"}; + $raw .= "\tnetmask " . $d->{"netmask$suffix"} . "\n" if $d->{"netmask$suffix"}; + $raw .= "\tgateway " . $d->{"gateway$suffix"} . "\n" if $d->{"gateway$suffix"}; + $raw .= "\tbroadcast " . $d->{"broadcast$suffix"} . "\n" if $d->{"broadcast$suffix"}; my $done = { type => 1, priority => 1, method => 1, active => 1, exists => 1, comments => 1, autostart => 1, options => 1, - address => 1, netmask => 1, gateway => 1, broadcast => 1 }; + address => 1, netmask => 1, gateway => 1, broadcast => 1, + method6=> 1, families => 1, + address6 => 1, netmask6 => 1, gateway6 => 1, broadcast6 => 1 }; if ($d->{type} eq 'bridge') { @@ -1052,27 +1103,26 @@ sub __interface_to_string { $raw .= "\t$k $d->{$k}\n"; } - foreach my $option (@{$d->{options}}) { + foreach my $option (@{$d->{"options$suffix"}}) { $raw .= "\t$option\n"; } # add comments - my $comments = $d->{comments} || ''; + my $comments = $d->{"comments$suffix"} || ''; foreach my $cl (split(/\n/, $comments)) { $raw .= "#$cl\n"; } - if ($d->{autostart}) { - $raw = "auto $iface\n$raw"; - } - $raw .= "\n"; return $raw; } sub write_etc_network_interfaces { - my ($filename, $fh, $ifaces) = @_; + my ($filename, $fh, $config) = @_; + + my $ifaces = $config->{ifaces}; + my @options = @{$config->{options}}; my $used_ports = {}; @@ -1199,10 +1249,20 @@ sub write_etc_network_interfaces { next if $printed->{$iface}; + if (@options) { + while (@options && $options[0]->[0] < $d->{priority}) { + $raw .= (shift @options)->[1] . "\n" + } + $raw .= "\n"; + } + $printed->{$iface} = 1; - $raw .= __interface_to_string($iface, $d); + $raw .= "auto $iface\n" if $d->{autostart}; + $raw .= __interface_to_string($iface, $d, $_) foreach @{$d->{families}}; } - + + $raw .= $_->[1] . "\n" foreach @options; + PVE::Tools::safe_print($filename, $fh, $raw); } -- 2.1.4 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel