From caa4e838eb2926e7dcdc96b9733d4bc0a9f84b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:35:24 -0300 Subject: [PATCH] fix(dhcp): boot unknown xNBA clients with Kea --- perl-xCAT/xCAT/DHCP/Backend/Kea.pm | 3 ++- perl-xCAT/xCAT/DHCP/BootPolicy.pm | 37 ++++++++++++++++++++++++++++ xCAT-server/lib/xcat/plugins/dhcp.pm | 25 ++++++++++++++----- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/perl-xCAT/xCAT/DHCP/Backend/Kea.pm b/perl-xCAT/xCAT/DHCP/Backend/Kea.pm index 2525ae7d3..8eb5b47df 100644 --- a/perl-xCAT/xCAT/DHCP/Backend/Kea.pm +++ b/perl-xCAT/xCAT/DHCP/Backend/Kea.pm @@ -813,7 +813,8 @@ sub _render_client_class { delete @rendered{qw/additional_only only_in_additional_list only_if_required/}; delete $rendered{'only-in-additional-list'}; delete $rendered{'only-if-required'}; - $rendered{ $self->_additional_class_flag_field() } = $additional_only if defined $additional_only; + $rendered{ $self->_additional_class_flag_field() } = _json_bool($additional_only) + if defined $additional_only; return \%rendered; } diff --git a/perl-xCAT/xCAT/DHCP/BootPolicy.pm b/perl-xCAT/xCAT/DHCP/BootPolicy.pm index 4da2c7bf9..c24992d8c 100644 --- a/perl-xCAT/xCAT/DHCP/BootPolicy.pm +++ b/perl-xCAT/xCAT/DHCP/BootPolicy.pm @@ -87,6 +87,43 @@ sub kea_xnba_node_classes { return \@classes; } +sub kea_xnba_network_classes { + my ( $class, %opts ) = @_; + + return [] unless $opts{net} && defined $opts{prefix} && $opts{next_server}; + + my $xnba_user_class = xnba_user_class_test(); + my $uefi_x64_arch_match = uefi_x64_client_architecture_match_expr(); + my $httpport = $opts{httpport} || '80'; + my $portsuffix = ( $httpport eq '80' ) ? '' : ":$httpport"; + my $network_id = $opts{net} . '_' . $opts{prefix}; + my $safe_network = $network_id; + $safe_network =~ s/[^A-Za-z0-9_.-]/_/g; + my $base_url = 'http://' . $opts{next_server} . $portsuffix + . '/tftpboot/xcat/xnba/nets/' . $network_id; + my @classes; + + if ( $opts{xnba_kpxe} ) { + push @classes, { + name => "xcat-xnba-net-$safe_network-bios", + test => "$xnba_user_class and option[93].hex == 0x0000", + 'boot-file-name' => $base_url, + additional_only => 1, + }; + } + + if ( $opts{xnba_efi} ) { + push @classes, { + name => "xcat-xnba-net-$safe_network-uefi", + test => "$xnba_user_class and ($uefi_x64_arch_match)", + 'boot-file-name' => "$base_url.uefi", + additional_only => 1, + }; + } + + return \@classes; +} + sub xnba_user_class_test { return "(option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA'))"; } diff --git a/xCAT-server/lib/xcat/plugins/dhcp.pm b/xCAT-server/lib/xcat/plugins/dhcp.pm index a360c8be1..00f854e57 100644 --- a/xCAT-server/lib/xcat/plugins/dhcp.pm +++ b/xCAT-server/lib/xcat/plugins/dhcp.pm @@ -2580,7 +2580,7 @@ sub kea_build_dhcp4_intent } my @subnets; - my @opal_classes; + my @subnet_classes; my $id = 1; foreach my $route (@routes) { my ( $net, $netif, $mask, $flags ) = @$route; @@ -2599,7 +2599,7 @@ sub kea_build_dhcp4_intent my $subnet = kea_subnet4_intent($nettab, $net, $mask, $interface, $remote, $id, $httpport); return $subnet if $subnet->{error}; - push @opal_classes, @{ delete $subnet->{client_classes} || [] }; + push @subnet_classes, @{ delete $subnet->{client_classes} || [] }; push @subnets, $subnet; $id++; } @@ -2610,7 +2610,7 @@ sub kea_build_dhcp4_intent valid_lifetime => kea_dhcp_lease_time(), 'option-def' => kea_option_defs(), 'option-data' => kea_global_option_data(), - 'client-classes' => [ @{ kea_boot_client_classes() }, @opal_classes ], + 'client-classes' => [ @{ kea_boot_client_classes() }, @subnet_classes ], subnets => \@subnets, }; @@ -2999,6 +2999,17 @@ sub kea_subnet4_intent } my $opal_class = kea_opal_client_class($net, $prefix, $tftp, $httpport); + my $xnba_classes = []; + if ($dynamicrange) { + $xnba_classes = xCAT::DHCP::BootPolicy->kea_xnba_network_classes( + net => $net, + prefix => $prefix, + next_server => $tftp, + httpport => $httpport, + xnba_kpxe => -f "$tftpdir/xcat/xnba.kpxe" ? 1 : 0, + xnba_efi => -f "$tftpdir/xcat/xnba.efi" ? 1 : 0, + ); + } my %subnet = ( id => $id, subnet => "$net/$prefix", @@ -3007,9 +3018,11 @@ sub kea_subnet4_intent next_server => $tftp, ); $subnet{interface} = $interface unless $remote; - if ($opal_class) { - $subnet{additional_client_classes} = [ $opal_class->{name} ]; - $subnet{client_classes} = [$opal_class]; + my @client_classes = @$xnba_classes; + push @client_classes, $opal_class if $opal_class; + if (@client_classes) { + $subnet{additional_client_classes} = [ map { $_->{name} } @client_classes ]; + $subnet{client_classes} = \@client_classes; } return \%subnet;