[pve-devel] [PATCH pve-common 2/3] Inotify : add vxlan interface support

Wolfgang Bumiller w.bumiller at proxmox.com
Mon Jun 25 11:25:26 CEST 2018


Comments inline.  Also, I would like a test case for this btw. (Which
reminds me, I should probably explain the functions used for t.*.pl
files a bit better in the comments...
Short summary: The t.create_network.pl should be a good place to copy
from, r() and w() call read/write_etc_network_interfaces() from/to
strings. load() accesses the other files in the test dir and for
convenience save() can be used to replace them temporarily.
$config globally accesses the last r()'d config in order to test
modifying the hash directly.
And finally `expect($string)` compares $string to the output of w() and
fails if they differ.

On Mon, Jun 25, 2018 at 05:41:34AM +0200, Alexandre Derumier wrote:
> ---
>  src/PVE/INotify.pm | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 53 insertions(+), 1 deletion(-)
> 
> diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm
> index 25ab868..2c1af3c 100644
> --- a/src/PVE/INotify.pm
> +++ b/src/PVE/INotify.pm
> @@ -916,6 +916,11 @@ sub __read_etc_network_interfaces {
>  			    }
>  			}
>  			$d->{$id} = $value;
> +		    } elsif ($id eq 'vxlan-id' || $id eq 'vxlan-svcnodeip' || 
> +			     $id eq 'vxlan-physdev' || $id eq 'vxlan-local-tunnelip') {
> +			$d->{$id} = $value;
> +		    } elsif ($id eq 'vxlan-remoteip') {
> +			push @{$d->{$id}}, $value;
>  		    } else {
>  			push @{$f->{options}}, $option;
>  		    }
> @@ -1012,7 +1017,9 @@ sub __read_etc_network_interfaces {
>  	} elsif ($iface =~ m/^lo$/) {
>  	    $d->{type} = 'loopback';
>  	} else {
> -	    if (!$d->{ovs_type}) {
> +	    if ($d->{'vxlan-id'}) {
> +		$d->{type} = 'vxlan';
> +	    } elsif (!$d->{ovs_type}) {
>  		$d->{type} = 'unknown';
>  	    } elsif ($d->{ovs_type} eq 'OVSIntPort') {
>  		$d->{type} = $d->{ovs_type};
> @@ -1121,6 +1128,28 @@ sub __interface_to_string {
>  	    $raw .= "\tbond-xmit-hash-policy $d->{'bond_xmit_hash_policy'}\n";
>  	}
>  	$done->{'bond_xmit_hash_policy'} = 1;
> +    } elsif ($d->{type} eq 'vxlan') {
> +
> +	$raw .= "\tvxlan-id $d->{'vxlan-id'}\n" if $d->{'vxlan-id'};
> +	$done->{'vxlan-id'} = 1;
> +	if ($d->{'vxlan-svcnodeip'}) {

I think this should use defined(), even though they're equivalent given
the contents...
And with svcnodeip, physdev and tunnelip being written out without any
processing the if() { $raw..., $done... } pattern could probably be
written out once with a loop over the 3 keys. With all the inline text
this is starting to look like quite a cryptic block. (not that the rest
of the code isn't the same already anyway ;-) )

> +	    $raw .= "\tvxlan-svcnodeip $d->{'vxlan-svcnodeip'}\n";
> +	    $done->{'vxlan-svcnodeip'} = 1;
> +	}
> +	if ($d->{'vxlan-physdev'}) {
> +	    $raw .= "\tvxlan-physdev $d->{'vxlan-physdev'}\n";
> +	    $done->{'vxlan-physdev'} = 1;
> +	}
> +	if ($d->{'vxlan-local-tunnelip'}) {
> +	    $raw .= "\tvxlan-local-tunnelip $d->{'vxlan-local-tunnelip'}\n";
> +	    $done->{'vxlan-local-tunnelip'} = 1;
> +	}
> +	if ($d->{'vxlan-remoteip'}) {
> +	    foreach my $remoteip (@{$d->{'vxlan-remoteip'}}) {
> +		$raw .= "\tvxlan-remoteip $remoteip\n";
> +	    }
> +	    $done->{'vxlan-remoteip'} = 1;
> +	}
>  
>      } elsif ($d->{type} eq 'OVSBridge') {
>  
> @@ -1293,6 +1322,28 @@ sub __write_etc_network_interfaces {
>  	}
>      }
>  
> +    # check vxlan
> +    my $vxlans = {};
> +    foreach my $iface (keys %$ifaces) {
> +	my $d = $ifaces->{$iface};
> +
> +	if ($d->{type} eq 'vxlan' && $d->{'vxlan-id'}) {
> +	    my $vxlanid = $d->{'vxlan-id'};
> +	    die "iface $iface  : duplicate vxlan-id $vxlanid already used in $vxlans->{$vxlanid}" if $vxlans->{$vxlanid};
> +	    $vxlans->{$vxlanid} = $iface;
> +	}
> +
> +	if (($d->{'vxlan-svcnodeip'} && $d->{'vxlan-remoteip'}) ||
> +	    ($d->{'vxlan-svcnodeip'} && $d->{'vxlan-local-tunnelip'}) ||
> +	    ($d->{'vxlan-local-tunnelip'} && $d->{'vxlan-remoteip'})) {
> +	    die "iface $iface : you can't use vxlan-svcnodeip / vxlan-remoteip / vxlan-local-tunnelip at the same time";

Took me a minute to read the above condition as "they're mutually
exclusive". I think the code would be clearer if we counted them:
    my $ips = 0;
    ++$ips if defined $d->{'vxlan-svcnodeip'};
    ++$ips if defined $d->{'vxlan-remoteip'};
    ++$ips if defined $d->{'vxlan-local-tunnelip'};
    if ($ips > 1) {
    	die "ifac $iface : vxlan-svcnodeip, vxlan-remoteip and vxlan-localtunnelip aremutually exclusive\n";
    }

Also note the added \n to the error.

> +	}
> +
> +	if (($d->{'vxlan-svcnodeip'} && !$d->{'vxlan-physdev'}) || (!$d->{'vxlan-svcnodeip'} && $d->{'vxlan-physdev'})) {
> +	    die "iface $iface : vxlan-svcnodeip && vxlan-physdev must be define together"; 

If the defined-ness of two values must be the same you can just do:
    if (defined($d->{'vxlan-svcnodeip'}) != defined($d->{'vxlan-physdev'})) {
        die "iface $iface : vxlan-svcnodeip and vxlan-physdev must be define together\n"; 

(Note that similarly if it's not about defined()-ness, you can compare
their negations: if (!$a != !$b))

Alternatively we could have more specific error messages
    if (defined($d->{'vxlan-svcnodeip'}) && !defined($d->{'vxlan-physdev'})) {
        die "iface $iface : vxlan-svcnodeip requires vxlan-physdev\n"; 
    }
    if (!defined($d->{'vxlan-svcnodeip'}) && defined($d->{'vxlan-physdev'})) {
        die "iface $iface : vxlan-physdev requires vxlan-svcnodeip\n"; 
    }

Either way, the error should have a newline at the end ;-)


> +	}
> +    }
> +
>      my $raw = <<'NETWORKDOC';
>  # network interface settings; autogenerated
>  # Please do NOT modify this file directly, unless you know what
> @@ -1314,6 +1365,7 @@ NETWORKDOC
>  	eth => 200000,
>  	bond => 300000,
>  	bridge => 400000,
> +	vxlan => 500000,
>     };
>  
>      my $lookup_type_prio = sub {
> -- 
> 2.11.0



More information about the pve-devel mailing list