From a4109f6865bc2ac845d206d1951ec3932fed51b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:54:08 -0300 Subject: [PATCH] feat(genesis): add s390x network boot --- perl-xCAT/xCAT/DHCP/BootPolicy.pm | 43 ++++++++++++++ xCAT-server/lib/xcat/plugins/dhcp.pm | 12 ++++ xCAT-server/lib/xcat/plugins/mknb.pm | 85 ++++++++++++++++++++++++++-- xCAT-server/sbin/xcatconfig | 2 +- xCAT-server/share/xcat/tools/go-xcat | 4 +- xCAT/debian/control | 2 +- xCAT/xCAT.spec | 1 + xCATsn/debian/control | 2 +- xCATsn/xCATsn.spec | 1 + 9 files changed, 143 insertions(+), 9 deletions(-) diff --git a/perl-xCAT/xCAT/DHCP/BootPolicy.pm b/perl-xCAT/xCAT/DHCP/BootPolicy.pm index 3c6c976ef..8b11fd815 100644 --- a/perl-xCAT/xCAT/DHCP/BootPolicy.pm +++ b/perl-xCAT/xCAT/DHCP/BootPolicy.pm @@ -103,6 +103,46 @@ sub kea_httpboot_network_classes { return \@classes; } +sub kea_s390x_network_classes { + my ( $class, %opts ) = @_; + + return [] unless $opts{net} && defined( $opts{prefix} ); + + my $network_id = "$opts{net}_$opts{prefix}"; + my $safe_network = $network_id; + $safe_network =~ s/[^A-Za-z0-9_.-]/_/g; + + return [ + { + name => "xcat-s390x-qemu-$safe_network", + test => 'option[93].hex == 0x001f', + additional_only => 1, + 'option-data' => [ + { + name => 'conf-file', + data => $network_id, + 'always-send' => 1, + }, + { + name => 'path-prefix', + data => 'pxelinux.cfg/s390x/', + 'always-send' => 1, + }, + ], + }, + ]; +} + +sub ensure_isc_path_prefix_definition { + my ($class, $config) = @_; + + return 0 if grep { /^\s*option\s+path-prefix\s+code\s+210\b/ } @{$config}; + + my $index = @{$config} && $config->[0] =~ /^#xCAT/ ? 1 : 0; + splice @{$config}, $index, 0, "option path-prefix code 210 = text;\n"; + return 1; +} + sub isc_client_architecture_lines { my ( $class, %opts ) = @_; @@ -136,6 +176,9 @@ sub isc_client_architecture_lines { " } else if option client-architecture = 00:1c { #riscv64 uefi http boot\n ", " option vendor-class-identifier \"HTTPClient\";\n", " filename \"http://$tftp$portsuffix/tftpboot/boot/grub2/grub2.riscv64\";\n", + " } else if option client-architecture = 00:1f { #QEMU s390x\n ", + " option path-prefix = \"pxelinux.cfg/s390x/\";\n", + " option conf-file = \"${net}_${maskbits}\";\n", " } else if option client-architecture = 00:0e { #OPAL-v3\n ", " option conf-file = \"http://$tftp$portsuffix/tftpboot/pxelinux.cfg/p/${net}_${maskbits}\";\n", " } else if substring (option vendor-class-identifier,0,11) = \"onie_vendor\" { #for onie on cumulus switch\n", diff --git a/xCAT-server/lib/xcat/plugins/dhcp.pm b/xCAT-server/lib/xcat/plugins/dhcp.pm index 3b3807ffd..d7e6d67c7 100644 --- a/xCAT-server/lib/xcat/plugins/dhcp.pm +++ b/xCAT-server/lib/xcat/plugins/dhcp.pm @@ -2354,6 +2354,10 @@ sub process_request $restartdhcp = 1; newconfig(); } + if ($^O ne 'aix' && + xCAT::DHCP::BootPolicy->ensure_isc_path_prefix_definition(\@dhcpconf)) { + $restartdhcp = 1; + } if ($usingipv6 and not $dhcp6conf[0]) { $restartdhcp6 = 1; newconfig6(); @@ -3362,6 +3366,12 @@ sub kea_subnet4_intent loader_present => sub { -e $_[0] }, ) }; + push @client_classes, @{ + xCAT::DHCP::BootPolicy->kea_s390x_network_classes( + net => $net, + prefix => $prefix, + ) + }; if (@client_classes) { $subnet{additional_client_classes} = [ map { $_->{name} } @client_classes ]; $subnet{client_classes} = \@client_classes; @@ -3885,6 +3895,7 @@ sub kea_option_defs { return [ { name => 'conf-file', code => 209, type => 'string', space => 'dhcp4' }, + { name => 'path-prefix', code => 210, type => 'string', space => 'dhcp4' }, { name => 'iscsi-initiator-iqn', code => 203, type => 'string', space => 'dhcp4' }, { name => 'cumulus-provision-url', code => 239, type => 'string', space => 'dhcp4' }, ]; @@ -4792,6 +4803,7 @@ sub newconfig push @dhcpconf, "#xCAT generated dhcp configuration\n"; push @dhcpconf, "\n"; push @dhcpconf, "option conf-file code 209 = text;\n"; + push @dhcpconf, "option path-prefix code 210 = text;\n"; push @dhcpconf, "option space isan;\n"; push @dhcpconf, "option isan-encap-opts code 43 = encapsulate isan;\n"; push @dhcpconf, "option isan.iqn code 203 = string;\n"; diff --git a/xCAT-server/lib/xcat/plugins/mknb.pm b/xCAT-server/lib/xcat/plugins/mknb.pm index 891310e2d..f08f8b7e5 100644 --- a/xCAT-server/lib/xcat/plugins/mknb.pm +++ b/xCAT-server/lib/xcat/plugins/mknb.pm @@ -10,7 +10,7 @@ use File::Copy; my $GENESIS_EXPORT_MANIFEST = 'xcat-genesis.manifest'; my %GENESIS_ARCHITECTURES = map { $_ => 1 } - qw(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64); + qw(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64 s390x); sub _canonical_genesis_arch { my ($arch) = @_; @@ -300,6 +300,11 @@ sub _remove_openembedded_genesis { "$directory/genesis.fs.$arch.lzma", "$directory/genesis.exact-arch.$arch", ); + if ($arch eq 's390x') { + foreach my $path (glob("$tftpdir/pxelinux.cfg/s390x/*")) { + push(@artifacts, $path) if _is_generated_s390x_config($path); + } + } my $removed = 0; my @failed; foreach my $artifact (@artifacts) { @@ -320,6 +325,15 @@ sub _remove_openembedded_genesis { return ($removed, undef); } +sub _is_generated_s390x_config { + my ($path) = @_; + return 0 if -l $path || !-f $path; + open(my $config, '<', $path) or return 0; + my $header = <$config>; + close($config); + return defined($header) && $header eq "# pxelinux.cfg xCAT Genesis s390x\n"; +} + sub genesis_lzma_command { my ($have_lzma, $have_xz) = @_; return 'lzma -C crc32 -9' if $have_lzma; @@ -417,7 +431,7 @@ sub process_request { my $tftpdir = xCAT::TableUtils->getTftpDir(); my $requested_arch = $request->{arg}->[0]; if (!$requested_arch) { - $callback->({ error => "Need to specify architecture (x86, x86_64, ppc64, ppc64le, armv7hf, aarch64 or riscv64)" }, { errorcode => [1] }); + $callback->({ error => "Need to specify architecture (x86, x86_64, ppc64, ppc64le, armv7hf, aarch64, riscv64 or s390x)" }, { errorcode => [1] }); return; } @@ -680,7 +694,9 @@ sub process_request { $normnet_addresses, \@master_addresses ); my $consolecmdline; - if (defined($serialport) and $serialspeed) { + if ($arch eq 's390x') { + $consolecmdline = 'console=ttysclp0'; + } elsif (defined($serialport) and $serialspeed) { if ($arch =~ /ppc/) { $consolecmdline = "console=tty0 console=hvc$serialport,$serialspeed"; } else { @@ -714,6 +730,9 @@ sub process_request { } elsif (exists $GRUB2_DISCOVERY_ARCHES{$arch}) { mkpath("$tftpdir/boot/grub2"); chmod(0755, "$tftpdir/boot/grub2"); + } elsif ($arch eq 's390x') { + mkpath("$tftpdir/pxelinux.cfg/s390x"); + chmod(0755, "$tftpdir/pxelinux.cfg/s390x"); } my $dopxe = 0; foreach (keys %{$normnets}) { @@ -721,9 +740,13 @@ sub process_request { my $nicip = $normnets->{$net}; my $xcatd_address = defined($xcatdnormnets->{$net}) ? $xcatdnormnets->{$net} : $nicip; $net =~ s/\//_/; - if (defined($nobootnicips{$nicip})) { + if (defined($nobootnicips{$nicip}) + || ($arch eq 's390x' && defined($nobootnicips{$xcatd_address}))) { if ($arch =~ /ppc/ and -r "$tftpdir/pxelinux.cfg/p/$net") { unlink("$tftpdir/pxelinux.cfg/p/$net"); + } elsif ($arch eq 's390x') { + my $path = "$tftpdir/pxelinux.cfg/s390x/$net"; + unlink($path) if _is_generated_s390x_config($path); } next; } @@ -785,6 +808,19 @@ sub process_request { print $cfgfile " initrd http://" . $xcatd_address . "$portsuffix/$initrd_file\n"; print $cfgfile ' append "xcatd=' . $xcatd_address . ":$xcatdport $consolecmdline\"\n"; close($cfgfile); + } elsif ($arch eq 's390x') { + my (undef, $config_error) = _write_s390x_discovery_config( + tftpdir => $tftpdir, + network => $net, + xcatd_address => $xcatd_address, + xcatdport => $xcatdport, + consolecmdline => $consolecmdline, + initrd => $initrd_file, + ); + if ($config_error) { + $callback->({ error => [$config_error], errorcode => [1] }); + return; + } } } $dopxe = 0; @@ -854,6 +890,47 @@ sub process_request { } } +sub _write_s390x_discovery_config { + my (%args) = @_; + my $tftpdir = $args{tftpdir}; + my $initrd = $args{initrd}; + $initrd =~ s{^\Q$tftpdir\E/?}{}; + my $cmdline = "xcatd=$args{xcatd_address}:$args{xcatdport} xcat.bootloader=s390-ccw"; + if (defined($args{consolecmdline}) and $args{consolecmdline} ne '') { + $cmdline .= " $args{consolecmdline}"; + } + + my $qemu_path = "$tftpdir/pxelinux.cfg/s390x/$args{network}"; + my $qemu_config = "# pxelinux.cfg xCAT Genesis s390x\n" + . "DEFAULT xCAT\n" + . "LABEL xCAT\n" + . " KERNEL xcat/genesis.kernel.s390x\n" + . " INITRD $initrd\n" + . " APPEND $cmdline\n"; + my $error = _write_s390x_config($qemu_path, $qemu_config); + return (undef, $error) if $error; + + return ($qemu_path, undef); +} + +sub _write_s390x_config { + my ($path, $contents) = @_; + open(my $config, '>', $path) + or return "Unable to write s390x Genesis configuration: $path: $!"; + unless (print {$config} $contents) { + my $error = $!; + close($config); + unlink($path); + return "Unable to write s390x Genesis configuration: $path: $error"; + } + unless (close($config)) { + my $error = $!; + unlink($path); + return "Unable to write s390x Genesis configuration: $path: $error"; + } + return; +} + # Return the grub2-class architectures whose Genesis kernel and initrd are # published under $tftpdir/xcat, as [arch, grub_cpu, kernel, initrd] with the # file names relative to the TFTP root. diff --git a/xCAT-server/sbin/xcatconfig b/xCAT-server/sbin/xcatconfig index f4c1394ab..612f4d20b 100755 --- a/xCAT-server/sbin/xcatconfig +++ b/xCAT-server/sbin/xcatconfig @@ -1998,7 +1998,7 @@ sub setupLinuxexports sub _installed_genesis_architectures { my ($xcatroot) = @_; - my @supported = qw(aarch64 armv7hf ppc64 ppc64le riscv64 x86 x86_64); + my @supported = qw(aarch64 armv7hf ppc64 ppc64le riscv64 s390x x86 x86_64); my %supported = map { $_ => 1 } @supported; my %installed; diff --git a/xCAT-server/share/xcat/tools/go-xcat b/xCAT-server/share/xcat/tools/go-xcat index 09aee446d..bf3a0f267 100755 --- a/xCAT-server/share/xcat/tools/go-xcat +++ b/xCAT-server/share/xcat/tools/go-xcat @@ -208,7 +208,7 @@ GO_XCAT_UNINSTALL_LIST=("${GO_XCAT_INSTALL_LIST[@]}" xCAT-genesis-openembedded-x86 xCAT-genesis-openembedded-x86_64 xCAT-genesis-openembedded-ppc64 xCAT-genesis-openembedded-ppc64le xCAT-genesis-openembedded-armv7hf xCAT-genesis-openembedded-aarch64 - xCAT-genesis-openembedded-riscv64 + xCAT-genesis-openembedded-riscv64 xCAT-genesis-openembedded-s390x xCAT-openbmc-py xCAT-probe xCAT-test xCAT-vlan xCATsn xCAT-UI-deps xCAT-buildkit conserver-xcat yaboot-xcat) # For Debian/Ubuntu, it will need a slightly different package list @@ -218,7 +218,7 @@ GO_XCAT_UNINSTALL_LIST=("${GO_XCAT_INSTALL_LIST[@]}" xcat-genesis-openembedded-x86 xcat-genesis-openembedded-x86-64 xcat-genesis-openembedded-ppc64 xcat-genesis-openembedded-ppc64le xcat-genesis-openembedded-armv7hf xcat-genesis-openembedded-aarch64 - xcat-genesis-openembedded-riscv64 + xcat-genesis-openembedded-riscv64 xcat-genesis-openembedded-s390x xcat-buildkit conserver-xcat) PATH="/usr/sbin:/usr/bin:/sbin:/bin" diff --git a/xCAT/debian/control b/xCAT/debian/control index 74ff70c64..57a82ffdf 100644 --- a/xCAT/debian/control +++ b/xCAT/debian/control @@ -10,7 +10,7 @@ Homepage: https://xcat.org/ Package: xcat Architecture: amd64 ppc64el Depends: ${perl:Depends}, goconserver(>= 0.3.3-snap000000000000), xcat-server (>= 2.13-snap000000000000), xcat-client (>= 2.13-snap000000000000), libdbd-sqlite3-perl, isc-dhcp-server | kea, bind9, apache2, nfs-kernel-server, libxml-parser-perl, rsync, tftpd-hpa, libnet-telnet-perl, chrony | ntp, xcat-genesis-scripts-amd64 (>= 2.13-snap000000000000) -Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, util-linux-extra, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64 +Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, util-linux-extra, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64, xcat-genesis-openembedded-s390x Suggests: yaboot-xcat Description: Metapackage for a common, default xCAT setup xCAT is Extreme Cluster/Cloud Administration Toolkit. xCAT offers complete diff --git a/xCAT/xCAT.spec b/xCAT/xCAT.spec index 8772828b9..d48accaac 100644 --- a/xCAT/xCAT.spec +++ b/xCAT/xCAT.spec @@ -63,6 +63,7 @@ Requires: xCAT-probe = 4:%{version}-%{release} Recommends: xCAT-genesis-openembedded-x86_64 Recommends: xCAT-genesis-openembedded-ppc64le Recommends: xCAT-genesis-openembedded-riscv64 +Recommends: xCAT-genesis-openembedded-s390x %endif %endif diff --git a/xCATsn/debian/control b/xCATsn/debian/control index 281c92066..063bf4716 100644 --- a/xCATsn/debian/control +++ b/xCATsn/debian/control @@ -9,7 +9,7 @@ Homepage: https://xcat.org/ Package: xcatsn Architecture: amd64 ppc64el Depends: ${perl:Depends}, goconserver (>=0.3.3-snap000000000000), xcat-server (>= 2.13-snap000000000000), xcat-client (>= 2.13-snap000000000000), libdbd-sqlite3-perl, libxml-parser-perl, tftpd-hpa, libnet-telnet-perl, isc-dhcp-server | kea, bind9, apache2, nfs-kernel-server, xcat-genesis-scripts-amd64 (>= 2.13-snap000000000000) -Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64 +Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64, xcat-genesis-openembedded-s390x Suggests: yaboot-xcat Description: Metapackage for a common, default xCAT service node setup xCATsn is a service node management package intended for at-scale diff --git a/xCATsn/xCATsn.spec b/xCATsn/xCATsn.spec index 1f8d9f47d..718c3ecb3 100644 --- a/xCATsn/xCATsn.spec +++ b/xCATsn/xCATsn.spec @@ -26,6 +26,7 @@ Requires: xCAT-probe = 4:%{version}-%{release} Recommends: xCAT-genesis-openembedded-x86_64 Recommends: xCAT-genesis-openembedded-ppc64le Recommends: xCAT-genesis-openembedded-riscv64 +Recommends: xCAT-genesis-openembedded-s390x %endif # Match xCAT-genesis-scripts package naming by build architecture.