mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-08-25 08:06:42 +00:00
Merge pull request #7752 from VersatusHPC/refactor/networkutils-netmask-helpers
refactor(network): reuse shared netmask helpers
This commit is contained in:
@@ -866,7 +866,7 @@ sub dhcp_dynamic_range_check {
|
||||
}
|
||||
foreach my $subnet4 (@{ $config_json->{Dhcp4}{subnet4} || [] }) {
|
||||
next unless $subnet4->{subnet} && $subnet4->{subnet} =~ m{^([^/]+)/(\d+)$};
|
||||
my $mask = prefix_to_netmask($2);
|
||||
my $mask = xCAT::NetworkUtils::formatNetmask($2, 1, 0);
|
||||
my @ranges;
|
||||
foreach my $pool (@{ $subnet4->{pools} || [] }) {
|
||||
next unless $pool->{pool};
|
||||
@@ -1036,17 +1036,6 @@ sub compare_ip_value {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub prefix_to_netmask {
|
||||
my $prefix = shift;
|
||||
|
||||
my $mask_num = 0;
|
||||
for my $idx (0 .. $prefix - 1) {
|
||||
$mask_num |= (1 << (31 - $idx));
|
||||
}
|
||||
|
||||
return join('.', map { ($mask_num >> (8 * (3 - $_))) & 0xff } 0 .. 3);
|
||||
}
|
||||
|
||||
#------------------------------------------
|
||||
|
||||
=head3
|
||||
|
||||
@@ -2902,7 +2902,7 @@ sub local_ipv4_routes
|
||||
next;
|
||||
}
|
||||
next unless $line =~ /^(\d+(?:\.\d+){3})\/(\d+)\b.*\bdev\s+(\S+)/;
|
||||
push @routes, [ $1, $3, kea_prefix_to_mask($2), '' ];
|
||||
push @routes, [ $1, $3, xCAT::NetworkUtils::formatNetmask( $2, 1, 0 ), '' ];
|
||||
}
|
||||
} else {
|
||||
my $netstat = kea_command_path('netstat');
|
||||
@@ -2981,13 +2981,8 @@ sub kea_subnet4_intent
|
||||
if ($gateway && $gateway eq '<xcatmaster>') {
|
||||
$gateway = xCAT::NetworkUtils->ip_forwarding_enabled() ? $myip : '';
|
||||
}
|
||||
if ($gateway) {
|
||||
my $maskn = unpack("N", inet_aton($mask));
|
||||
my $netn = unpack("N", inet_aton($net));
|
||||
my $gaten = unpack("N", inet_aton($gateway));
|
||||
if (($gaten & $maskn) != ($maskn & $netn)) {
|
||||
return { error => "Specified gateway $gateway is not valid for $net/$mask, must be on same network" };
|
||||
}
|
||||
if ( $gateway && !xCAT::NetworkUtils::isInSameSubnet( $gateway, $net, $mask, 0 ) ) {
|
||||
return { error => "Specified gateway $gateway is not valid for $net/$mask, must be on same network" };
|
||||
}
|
||||
|
||||
my @option_data;
|
||||
@@ -3004,7 +2999,7 @@ sub kea_subnet4_intent
|
||||
my $domainstring = join(', ', map { $_ eq $domain ? $_ : $_ } grep { $_ } @alldomains);
|
||||
push @option_data, { name => 'domain-search', data => $domainstring } if $domainstring;
|
||||
|
||||
my $prefix = kea_mask_to_prefix($mask);
|
||||
my $prefix = xCAT::NetworkUtils::formatNetmask( $mask, 0, 1 );
|
||||
my $dynamicrange = $ent ? $ent->{dynamicrange} : undef;
|
||||
if ( $dynamicrange && $ent->{dhcpserver} && xCAT::NetworkUtils->thishostisnot( $ent->{dhcpserver} ) ) {
|
||||
$dynamicrange = undef;
|
||||
@@ -3588,28 +3583,6 @@ sub kea_control_agent_live_enabled
|
||||
return $backend->host_cmds_hook_path() ? 1 : 0;
|
||||
}
|
||||
|
||||
sub kea_mask_to_prefix
|
||||
{
|
||||
my ($mask) = @_;
|
||||
|
||||
my $maskn = unpack("N", inet_aton($mask));
|
||||
my $bits = 0;
|
||||
for my $idx (0 .. 31) {
|
||||
$bits++ if $maskn & (1 << (31 - $idx));
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
sub kea_prefix_to_mask
|
||||
{
|
||||
my ($prefix) = @_;
|
||||
|
||||
return '0.0.0.0' unless defined($prefix) && $prefix =~ /^\d+$/ && $prefix > 0 && $prefix <= 32;
|
||||
my $maskn = (0xffffffff << (32 - $prefix)) & 0xffffffff;
|
||||
return inet_ntoa(pack("N", $maskn));
|
||||
}
|
||||
|
||||
sub kea_skip_ipv4_network
|
||||
{
|
||||
my ($net) = @_;
|
||||
|
||||
@@ -7,6 +7,7 @@ use FindBin;
|
||||
use lib "$FindBin::Bin/../../perl-xCAT";
|
||||
|
||||
use File::Temp qw(tempdir);
|
||||
use Socket ();
|
||||
use Test::More;
|
||||
|
||||
BEGIN {
|
||||
@@ -39,6 +40,34 @@ BEGIN {
|
||||
sub thishostisnot { return 0; }
|
||||
sub ip_forwarding_enabled { return 0; }
|
||||
sub nodeonmynet { return 1; }
|
||||
sub formatNetmask {
|
||||
my ( $mask, $orig_type, $new_type ) = @_;
|
||||
my $mask_number;
|
||||
|
||||
if ( $orig_type == 0 ) {
|
||||
$mask_number = unpack( 'N', Socket::inet_aton($mask) );
|
||||
} elsif ( $orig_type == 1 ) {
|
||||
$mask_number = ( 2**$mask - 1 ) << ( 32 - $mask );
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
return Socket::inet_ntoa( pack( 'N', $mask_number ) ) if $new_type == 0;
|
||||
if ( $new_type == 1 ) {
|
||||
my $binary_mask = unpack( 'B32', pack( 'N', $mask_number ) );
|
||||
return $binary_mask =~ tr/1/1/;
|
||||
}
|
||||
return;
|
||||
}
|
||||
sub isInSameSubnet {
|
||||
my ( $ip1, $ip2, $mask, $mask_type ) = @_;
|
||||
return unless $mask_type == 0;
|
||||
|
||||
my $mask_number = unpack( 'N', Socket::inet_aton($mask) );
|
||||
my $ip1_number = unpack( 'N', Socket::inet_aton($ip1) );
|
||||
my $ip2_number = unpack( 'N', Socket::inet_aton($ip2) );
|
||||
return ( $ip1_number & $mask_number ) == ( $ip2_number & $mask_number );
|
||||
}
|
||||
$INC{'xCAT/NetworkUtils.pm'} = __FILE__;
|
||||
|
||||
package xCAT::ServiceNodeUtils;
|
||||
@@ -156,6 +185,40 @@ ok(!xCAT_plugin::dhcp::dhcpd_sysconfig_uses_interface_key('opensuse-tumbleweed')
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
my $tmpdir = tempdir(CLEANUP => 1);
|
||||
my $fake_ip = "$tmpdir/ip";
|
||||
open(my $ip_fh, '>', $fake_ip) or die "Cannot write fake ip command: $!";
|
||||
print {$ip_fh} "#!/bin/sh\n";
|
||||
print {$ip_fh} "cat <<'EOF'\n";
|
||||
print {$ip_fh} "0.0.0.0/0 dev eth0 proto kernel scope link\n";
|
||||
print {$ip_fh} "128.0.0.0/1 dev eth1 proto kernel scope link\n";
|
||||
print {$ip_fh} "192.0.2.0/24 dev eth24 proto kernel scope link\n";
|
||||
print {$ip_fh} "198.51.100.7/32 dev eth32 proto kernel scope link\n";
|
||||
print {$ip_fh} "203.0.113.0/not-a-prefix dev invalid proto kernel scope link\n";
|
||||
print {$ip_fh} "EOF\n";
|
||||
close($ip_fh);
|
||||
chmod 0755, $fake_ip;
|
||||
|
||||
no warnings 'redefine';
|
||||
local *xCAT_plugin::dhcp::kea_command_path = sub {
|
||||
my ($command) = @_;
|
||||
return $fake_ip if $command eq 'ip';
|
||||
return;
|
||||
};
|
||||
|
||||
is_deeply(
|
||||
[ xCAT_plugin::dhcp::local_ipv4_routes() ],
|
||||
[
|
||||
[ '0.0.0.0', 'eth0', '0.0.0.0', '' ],
|
||||
[ '128.0.0.0', 'eth1', '128.0.0.0', '' ],
|
||||
[ '192.0.2.0', 'eth24', '255.255.255.0', '' ],
|
||||
[ '198.51.100.7', 'eth32', '255.255.255.255', '' ],
|
||||
],
|
||||
'local IPv4 route detection converts boundary prefixes and ignores malformed prefixes'
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT_plugin::dhcp::kea_ipv4_routes = sub {
|
||||
@@ -179,6 +242,64 @@ ok(!xCAT_plugin::dhcp::dhcpd_sysconfig_uses_interface_key('opensuse-tumbleweed')
|
||||
is( $intent->{subnets}[0]{subnet}, '10.0.0.0/24', 'rendered subnet comes from local route' );
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT::NetworkUtils::thishostisnot = sub { return 0; };
|
||||
|
||||
my @prefix_cases = (
|
||||
[ '0.0.0.0', '0.0.0.0', 0 ],
|
||||
[ '128.0.0.0', '128.0.0.0', 1 ],
|
||||
[ '192.0.2.0', '255.255.255.0', 24 ],
|
||||
[ '198.51.100.7', '255.255.255.255', 32 ],
|
||||
);
|
||||
|
||||
foreach my $case (@prefix_cases) {
|
||||
my ( $net, $mask, $prefix ) = @$case;
|
||||
my $nettab = DHCPKeaIntentNetTable->new(
|
||||
{
|
||||
%network_entry,
|
||||
net => $net,
|
||||
mask => $mask,
|
||||
dynamicrange => undef,
|
||||
gateway => undef,
|
||||
}
|
||||
);
|
||||
my $subnet = xCAT_plugin::dhcp::kea_subnet4_intent( $nettab, $net, $mask, 'eth0', 0, 1, 80 );
|
||||
is( $subnet->{subnet}, "$net/$prefix", "$mask renders as prefix $prefix" );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT::NetworkUtils::thishostisnot = sub { return 0; };
|
||||
|
||||
my $same_subnet_table = DHCPKeaIntentNetTable->new(
|
||||
{
|
||||
%network_entry,
|
||||
gateway => '10.0.0.254',
|
||||
}
|
||||
);
|
||||
my $same_subnet = xCAT_plugin::dhcp::kea_subnet4_intent(
|
||||
$same_subnet_table, '10.0.0.0', '255.255.255.0', 'eth0', 0, 1, 80
|
||||
);
|
||||
ok( !$same_subnet->{error}, 'gateway in the subnet remains valid' );
|
||||
|
||||
my $different_subnet_table = DHCPKeaIntentNetTable->new(
|
||||
{
|
||||
%network_entry,
|
||||
gateway => '192.0.2.1',
|
||||
}
|
||||
);
|
||||
my $different_subnet = xCAT_plugin::dhcp::kea_subnet4_intent(
|
||||
$different_subnet_table, '10.0.0.0', '255.255.255.0', 'eth0', 0, 1, 80
|
||||
);
|
||||
is(
|
||||
$different_subnet->{error},
|
||||
'Specified gateway 192.0.2.1 is not valid for 10.0.0.0/255.255.255.0, must be on same network',
|
||||
'gateway outside the subnet keeps the existing error'
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT_plugin::dhcp::kea_ipv4_routes = sub {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../../perl-xCAT";
|
||||
use Test::More;
|
||||
|
||||
require xCAT::NetworkUtils;
|
||||
|
||||
my @prefix_cases = (
|
||||
[ 0, '0.0.0.0' ],
|
||||
[ 1, '128.0.0.0' ],
|
||||
[ 24, '255.255.255.0' ],
|
||||
[ 32, '255.255.255.255' ],
|
||||
);
|
||||
|
||||
foreach my $case (@prefix_cases) {
|
||||
my ( $prefix, $mask ) = @$case;
|
||||
is(
|
||||
xCAT::NetworkUtils::formatNetmask( $prefix, 1, 0 ),
|
||||
$mask,
|
||||
"prefix $prefix converts to $mask"
|
||||
);
|
||||
is(
|
||||
xCAT::NetworkUtils::formatNetmask( $mask, 0, 1 ),
|
||||
$prefix,
|
||||
"$mask converts to prefix $prefix"
|
||||
);
|
||||
}
|
||||
|
||||
is(
|
||||
xCAT::NetworkUtils::formatNetmask( undef, 1, 0 ),
|
||||
undef,
|
||||
'undefined netmask input fails cleanly'
|
||||
);
|
||||
is(
|
||||
xCAT::NetworkUtils::formatNetmask( 24, 3, 0 ),
|
||||
undef,
|
||||
'unsupported input format fails cleanly'
|
||||
);
|
||||
is(
|
||||
xCAT::NetworkUtils::formatNetmask( 24, 1, 3 ),
|
||||
undef,
|
||||
'unsupported output format fails cleanly'
|
||||
);
|
||||
|
||||
ok(
|
||||
xCAT::NetworkUtils::isInSameSubnet( '10.0.0.254', '10.0.0.0', '255.255.255.0', 0 ),
|
||||
'gateway inside an IPv4 subnet matches'
|
||||
);
|
||||
ok(
|
||||
!xCAT::NetworkUtils::isInSameSubnet( '192.0.2.1', '10.0.0.0', '255.255.255.0', 0 ),
|
||||
'gateway outside an IPv4 subnet does not match'
|
||||
);
|
||||
|
||||
done_testing();
|
||||
Reference in New Issue
Block a user