diff options
Diffstat (limited to 'test/TEST-30-ISCSI')
-rw-r--r-- | test/TEST-30-ISCSI/Makefile | 7 | ||||
-rwxr-xr-x | test/TEST-30-ISCSI/client-init.sh | 24 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/client.link | 6 | ||||
-rwxr-xr-x | test/TEST-30-ISCSI/create-client-root.sh | 33 | ||||
-rwxr-xr-x | test/TEST-30-ISCSI/create-server-root.sh | 20 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/dhcpd.conf | 48 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/hosts | 8 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/ibft.pl | 458 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/ibft.table | bin | 0 -> 381 bytes | |||
-rwxr-xr-x | test/TEST-30-ISCSI/server-init.sh | 88 | ||||
-rw-r--r-- | test/TEST-30-ISCSI/server.link | 6 | ||||
-rwxr-xr-x | test/TEST-30-ISCSI/test.sh | 240 | ||||
-rwxr-xr-x | test/TEST-30-ISCSI/wait-if-server.sh | 4 |
13 files changed, 942 insertions, 0 deletions
diff --git a/test/TEST-30-ISCSI/Makefile b/test/TEST-30-ISCSI/Makefile new file mode 100644 index 0000000..88db701 --- /dev/null +++ b/test/TEST-30-ISCSI/Makefile @@ -0,0 +1,7 @@ +-include ../Makefile.testdir + +ibft.table: Makefile ibft.pl + perl ibft.pl \ + --initiator iqn=iqn.1994-05.com.redhat:633114aacf2 \ + --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,mac=52:54:00:12:34:00,pci=00:03.0 \ + --target nic=0,ip=192.168.50.1,port=3260,lun=1,name=iqn.2009-06.dracut:target0 >$@ diff --git a/test/TEST-30-ISCSI/client-init.sh b/test/TEST-30-ISCSI/client-init.sh new file mode 100755 index 0000000..46a5e3f --- /dev/null +++ b/test/TEST-30-ISCSI/client-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." +while read -r dev _ fstype opts rest || [ -n "$dev" ]; do + [ "$fstype" != "ext4" ] && continue + echo "iscsi-OK $dev $fstype $opts" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + break +done < /proc/mounts + +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi + +sync +poweroff -f diff --git a/test/TEST-30-ISCSI/client.link b/test/TEST-30-ISCSI/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-30-ISCSI/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-30-ISCSI/create-client-root.sh b/test/TEST-30-ISCSI/create-client-root.sh new file mode 100755 index 0000000..267c93a --- /dev/null +++ b/test/TEST-30-ISCSI/create-client-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -j -L singleroot -F /dev/disk/by-id/ata-disk_singleroot +mkdir -p /sysroot +mount -t ext4 /dev/disk/by-id/ata-disk_singleroot /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +mdadm --create /dev/md0 --run --auto=yes --level=stripe --raid-devices=2 /dev/disk/by-id/ata-disk_raid0-1 /dev/disk/by-id/ata-disk_raid0-2 +mdadm -W /dev/md0 || : +lvm pvcreate -ff -y /dev/md0 +lvm vgcreate dracut /dev/md0 +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -j -L sysroot /dev/dracut/root +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-30-ISCSI/create-server-root.sh b/test/TEST-30-ISCSI/create-server-root.sh new file mode 100755 index 0000000..2dbc2da --- /dev/null +++ b/test/TEST-30-ISCSI/create-server-root.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-30-ISCSI/dhcpd.conf b/test/TEST-30-ISCSI/dhcpd.conf new file mode 100644 index 0000000..fd306ea --- /dev/null +++ b/test/TEST-30-ISCSI/dhcpd.conf @@ -0,0 +1,48 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + option root-path "iscsi:192.168.50.1:::1:iqn.2009-06.dracut:target0"; + + host iscsi-1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.101; + } + } +} + +subnet 192.168.51.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.51.1; + next-server 192.168.51.1; + server-identifier 192.168.51.1; + option domain-name-servers 192.168.51.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + #option root-path "iscsi:192.168.51.1:::1:iqn.2009-06.dracut:target1"; + + host iscsi-2 { + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.51.101; + } + + } +} diff --git a/test/TEST-30-ISCSI/hosts b/test/TEST-30-ISCSI/hosts new file mode 100644 index 0000000..f8c18b6 --- /dev/null +++ b/test/TEST-30-ISCSI/hosts @@ -0,0 +1,8 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.2 server-ip +192.168.50.3 server-proto-ip +192.168.50.100 workstation1 +192.168.50.101 workstation2 +192.168.50.102 workstation3 +192.168.50.103 workstation4 diff --git a/test/TEST-30-ISCSI/ibft.pl b/test/TEST-30-ISCSI/ibft.pl new file mode 100644 index 0000000..c612951 --- /dev/null +++ b/test/TEST-30-ISCSI/ibft.pl @@ -0,0 +1,458 @@ +#!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0+ +# +# iBFT ACPI table generator +# $ perldoc ibft.pl if you'd like to read the manual, poor you: + +=head1 NAME + +ibft.pl - Generate iBFT ACPI table + +=head1 SYNOPSIS + +ibft.pl +[--oemid <oemid>] +[--tableid <tableid> +[--initiator isns=<ip>,slp=<ip>,radius1=<ip>,radius2=<ip>,iqn=<iqn>] +[--nic ip=<ip>[,prefix=<prefix>][,gw=<ip>][,dns1=<ip>][,dns2=<ip>][,dhcp=<ip>][,vlan=<id>][,mac=<mac>][,pci=<pci>][,hostname=<hostname>] ...] +[--target ip=<ip>[,port=<port>][,lun=<lun>][,name=<iqn> ...] + +=head1 DESCRIPTION + +B<ibft.pl> creates an image of iBFT ACPI table similar to what a real network +boot firmware would do. This is mainly useful for testing. + +=head1 OPTIONS + +=over 4 + +=item B<< --oemid <oemid> >> + +Create a table with a particular OEM ID, limited to 6 characters. +It generally doesn't matter. + +Defaults to I<DRACUT>. + +=item B<< --tableid <tableid> >> + +Create a table with a particular OEM Table ID. + +Defaults to I<TEST>, but any four-letter word would do. Any. + +=item B<< --initiator >> + +Configure the Initiator Structure. +Following parameters are supported: + +=over 4 + +=item B<< isns=<ip> >> + +iSNS server address. + +=item B<< slp=<ip> >> + +SLP server address. + +=item B<< radius1=<ip> >>, B<< radius2=<ip> >> + +Primary and secondary Radius server addresses. + +=item B<< iqn=<iqn> >> + +Override the IQN, which defaults to I<iqn.2009-06.dracut:initiator0>. + +=back + +=item B<< --nic >> + +Configure a NIC Structure. This option can be used up multiple times. + +Following parameters are supported: + +=over 4 + +=item B<< ip=<ip> >> + +Set the IP address. Both I<AF_INET> and I<AF_INET6> families are supported. +This parameter is mandatory. + +=item B<< prefix=<prefix> >> + +Set the IP address prefix. You generally also want to set this in order to +get a sensible iBFT. + +=item B<< gw=<ip> >> + +Set the gateway IP address. + +=item B<< dns1=<ip> >>, B<< dns2=<ip> >> + +Set the domain service server addresses. + +=item B<< dhcp=<ip> >> + +Specify the address of the DHCP server in case dynamic configuration is used. + +=item B<< vlan=<id> >> + +The VLAN Id. Duh. + +=item B<< mac=<mac> >> + +Specify the ethernet hardware address, in form of six colon-delimited +hexadecimal octets. + +=item B<< pci=<pci> >> + +Specify the ethernet hardware's PCI bus location, in form of +B<< <bus> >>:B<< <device> >>.B<< <function> >> where the numbers are in +hexadecimal. + +=item B<< hostname=<hostname> >> + +The host name. Defaults to B<client>. + +=back + +=item B<< --target >> + +Configure a Target Structure. This option can be used multiple times. + +Following parameters are supported: + +=over 4 + +=item B<< ip=<ip> >> + +The iSCSI target IP address. + +=item B<< port=<port> >> + +The iSCSI TCP port, in case the default of I<3260> is not good enough for +you. + +=item B<< lun=<1> >> + +The LUN number. Defaults to I<1> no less. + +=item B<< name=<iqn> >> + +The iSCSI volume name. Defaults to I<iqn.2009-06.dracut:target0> for the first +target, I<iqn.2009-06.dracut:target1> for the second one. + +=back + +=back + +=cut + +use strict; +use warnings; + +sub ip4 { + shift =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + or die 'not an INET address'; + return (map { 0x00 } 0..9), 0xff, 0xff, $1, $2, $3, $4; +} + +sub ip6 +{ + my ($beg, $end) = map { [ map { /^([0-9a-fA-F]{0,2}?)([0-9a-fA-F]{1,2})$/ + ? (hex $1, hex $2) + : die "'$_' not valid in a INET6 address" + } split /:/ ] } split /::/, shift; + + $beg ||= []; + $end ||= []; + + my $fill = 16 - scalar @$beg + scalar@$end; + die 'INET6 address too long' if $fill < 0; + + @$beg, (map { 0 } 1..$fill), @$end; +} + +sub ip +{ + my @val; + @val = eval { @val = ip6 ($_[0]) }; + @val = eval { @val = ip4 ($_[0]) } unless @val; + die "Saatana: $_[0] is not an INET or INET6 address" unless @val; + + return pack 'C16', @val; +} + +sub mac +{ + return pack 'C8', map { hex $_ } split /:/, shift; +} + +sub pci +{ + shift =~ /^([0-9a-fA-F]{1,2}?):([0-9a-fA-F]{1,2})\.([0-9a-fA-F]+)$/ + or die 'Not a PCI address'; + return (hex $1) << 8 | (hex $2) << 3 | (hex $3); +} + +sub lun +{ + return pack 'C8', 0, shift, 0, 0, 0, 0, 0, 0; +} + +# signature, length, revision, checksum, oem_id, oem_table_id, reserved +sub pack_table_hdr { pack 'a4 V C C a6 a8 a24 x![C8]', @_ } + +# id, version, length, index, flags +# extensions, initiator_off, nic0_off, tgt0_off, nic1_off, tgt1_off, ext* +sub pack_control { pack 'C C S C C S S S S S S S* x![C8]', @_ } + +# id, version, length, index, flags +# isns_adr, slp_adr, radius1_adr, radius2_adr, iqn_len, iqn_off +sub pack_initiator { pack 'C C S C C a16 a16 a16 a16 SS x![C8]', @_ } + +# id, version, length, index, flags +# adr, prefix, origin, gw, dns1, dns2, dhcp, vlan_id, mac, pci_bdf, hostname_len, hostname_off +sub pack_nic { $_[5] ? pack 'C C S C C a16 C C a16 a16 a16 a16 S a6 S SS x![C8]', @_ : '' } + +# id, version, length, index, flags +# tgt_adr, tgt_port, tgt_lun, chap_type, nic_id, tgt_len, tgt_off, +# chap_name_len, chap_name_off, chap_secret_len, chap_secret_off +# rchap_name_len, rchap_name_off, rchap_secret_len, rchap_secret_off +sub pack_tgt { $_[5] ? pack 'C C S C C a16 S a8 C C SS SS SS SS SS x![C8]', @_ : '' }; + +# str +sub pack_str { pack 'Z*', @_ } + +# Initialize some defaults +my @table_hdr = ('iBFT', 0000, 1, 0000, 'DRACUT', 'TEST', ''); +my @control = (1, 1, 18, 0, 0, 0000, 0000, 0000, 0000, 0000, 0000); +my @initiator = (2, 1, 74, 0, 0x03, '', '', '', '', (0000, 0000)); +my @nics; +my @tgts; +my $iqn = 'iqn.2009-06.dracut:initiator0'; +my @hostnames; +my @tgt_names; + +while (@ARGV) { + my $arg = shift @ARGV; + die "Saatana: $arg is missing an argument" unless @ARGV; + + if ($arg eq '--oemid') { + $table_hdr[4] = shift @ARGV; + } elsif ($arg eq '--tableid') { + $table_hdr[5] = shift @ARGV; + } elsif ($arg eq '--initiator') { + my %val = split /[,=]/, shift @ARGV; + $initiator[5] = ip (delete $val{isns}) if exists $val{isns}; + $initiator[6] = ip (delete $val{slp}) if exists $val{slp}; + $initiator[7] = ip (delete $val{radius1}) if exists $val{radius1}; + $initiator[8] = ip (delete $val{radius2}) if exists $val{radius2}; + $iqn = delete $val{iqn} if exists $val{iqn}; + die "Saatana: Extra arguments to --initiator: ".join (', ', %val) if %val; + } elsif ($arg eq '--nic') { + my @nic = (3, 1, 102, 0, 0x03, + undef, 0, 0x01, '', '', '', '', 0, '', 0, (0000, 0000)); + push @nics, \@nic; + + my %val = split /[,=]/, shift @ARGV; + die 'Saatana: --nic needs an ip' unless exists $val{ip}; + $nic[3] = $#nics; + $nic[5] = ip (delete $val{ip}); + $nic[6] = delete $val{prefix} if exists $val{prefix}; + $nic[7] = 0x03 if exists $val{dhcp}; + $nic[8] = ip (delete $val{gw}) if exists $val{gw}; + $nic[9] = ip (delete $val{dns1}) if exists $val{dns1}; + $nic[10] = ip (delete $val{dns2}) if exists $val{dns2}; + $nic[11] = ip (delete $val{dhcp}) if exists $val{dhcp}; + $nic[12] = delete $val{vlan} if exists $val{vlan}; + $nic[13] = mac (delete $val{mac}) if exists $val{mac}; + $nic[14] = pci (delete $val{pci}) if exists $val{pci}; + $hostnames[$#nics] = exists $val{hostname} ? delete $val{hostname} : 'client'; + $hostnames[$#nics] = pack_str $hostnames[$#nics]; + die "Saatana: Extra arguments to --nic: ".join (', ', %val) if %val; + + # Allocate an control expansion entry + if ($#nics > 1) { + $control[2] += 2; + push @control, (0x4444); + } + } elsif ($arg eq '--target') { + my @tgt = (4, 1, 54, 0, 0x03, + undef, 3260, lun (1), 0, 0, + (0000, 0000), + (0000, 0000), + (0000, 0000), + (0000, 0000), + (0000, 0000)); + push @tgts, \@tgt; + + my %val = split /[,=]/, shift @ARGV; + die 'Saatana: --target needs an ip' unless exists $val{ip}; + $tgt[3] = $#tgts; + $tgt[5] = ip (delete $val{ip}) if exists $val{ip}; + $tgt[6] = delete $val{port} if exists $val{port}; + $tgt[7] = lun (delete $val{lun}) if exists $val{lun}; + $tgt[9] = delete $val{nic} if exists $val{nic}; + $tgt_names[$#tgts] = exists $val{name} ? delete $val{name} + : 'iqn.2009-06.dracut:target'.$#tgts; + $tgt_names[$#tgts] = pack_str $tgt_names[$#tgts]; + die "Saatana: Extra arguments to --target: ".join (', ', %val) if %val; + + # Allocate an control expansion entry if necessary + if ($#tgts > 1) { + $control[2] += 2; + push @control, (0x1111); + } + } else { + die "Saatana: Unknown argument: $arg"; + } +} + +# Pass 1 +my $table_hdr = pack_table_hdr @table_hdr; +my $control = pack_control @control; +my $initiator = pack_initiator @initiator; +my @packed_nics = map { pack_nic @$_ } @nics; +my @packed_tgts = map { pack_tgt @$_ } @tgts; +$iqn = pack_str $iqn; + + +# Resolve the offsets +my $len = 0; +$len += length $table_hdr; +$len += length $control; +$control[6] = $len; +$len += length $initiator; + +for my $i (0..$#packed_nics) { + if ($i == 0) { + # NIC 0 + $control[7] = $len; + } elsif ($i == 1) { + # NIC 1 + $control[9] = $len; + } else { + # Expansion + $control[11 + $i - 2] = $len; + } + $len += length $packed_nics[$i]; +} + +for my $i (0..$#packed_tgts) { + if ($i == 0) { + # Target 0 + $control[8] = $len; + } elsif ($i == 1) { + # Target 1 + $control[10] = $len; + } else { + # Expansion + $control[11 + scalar @packed_nics - 2 + $i - 2] = $len; + } + $len += length $packed_tgts[$i]; +} + +$initiator[9] = -1 + length $iqn; +$initiator[10] = $len; +$len += length $iqn; + +for my $i (0..$#hostnames) { + $nics[$i]->[15] = -1 + length $hostnames[$i]; + $nics[$i]->[16] = $len; + $len += length $hostnames[$i]; +} + +for my $i (0..$#tgt_names) { + $tgts[$i]->[10] = -1 + length $tgt_names[$i]; + $tgts[$i]->[11] = $len; + $len += length $tgt_names[$i]; +} + +@table_hdr[1] = $len; + +# Pass 2, with the offsets resolved +$table_hdr = pack_table_hdr @table_hdr; +$control = pack_control @control; +$initiator = pack_initiator @initiator; +@packed_nics = map { pack_nic @$_ } @nics; +@packed_tgts = map { pack_tgt @$_ } @tgts; + +# Pass 3, calculate checksum +my $cksum = 0xff; +$cksum += ord $_ foreach split //, join '', $table_hdr, $control, $initiator, + @packed_nics, @packed_tgts, $iqn, @hostnames, @tgt_names; +$cksum = ~$cksum & 0xff; +$table_hdr[3] = $cksum; +$table_hdr = pack_table_hdr @table_hdr; + +# Puke stuff out +print $table_hdr; +print $control; +print $initiator; +print @packed_nics; +print @packed_tgts; +print $iqn; +print @hostnames; +print @tgt_names; + +=head1 EXAMPLES + +=over + +=item B<< perl ibft.pl --oemid FENSYS --tableid iPXE --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,vlan=0,mac=52:54:00:12:34:00,pci=00:02.0,hostname=iscsi-1 --target ip=192.168.50.1 >ibft.img >> + +Generate an iBFT image with a single NIC while pretending we're iPXE for +no good reason. + +=item B<<perl ibft.pl --initiator iqn=iqn.1994-05.com.redhat:633114aacf2 --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,mac=52:54:00:12:34:00,pci=00:03.0 --nic ip=192.168.51.101,prefix=24,gw=192.168.51.1,dns1=192.168.51.1,dhcp=192.168.51.1,mac=52:54:00:12:34:01,pci=00:04.0 --target ip=192.168.50.1,port=3260,lun=1,name=iqn.2009-06.dracut:target0 --target ip=192.168.51.1,port=3260,lun=2,name=iqn.2009-06.dracut:target1 >ibft.img >> + +Generate an iBFT image for two NICs while being slightly more expressive +than necessary. + +=item B<qemy-system-x86_64 -acpitable file=ibft.img> + +Use the image with QEMU. + +=back + +=head1 BUGS + +No support for CHAP secrets. + +=head1 SEE ALSO + +=over 4 + +=item L<qemu(1)>, + +=item L<iSCSI Boot Firmware Table (iBFT)|ftp://ftp.software.ibm.com/systems/support/bladecenter/iscsi_boot_firmware_table_v1.03.pdf>, + +=item L<NL_PREFIX_ORIGIN Enumeration|https://docs.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_prefix_origin> + +=back + +=head1 COPYRIGHT + +Copyright (C) 2019 Lubomir Rintel + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +=head1 AUTHOR + +Lubomir Rintel C<lkundrak@v3.sk> + +=cut + +# Forgive me. +# This would have been much easier with FORTH. diff --git a/test/TEST-30-ISCSI/ibft.table b/test/TEST-30-ISCSI/ibft.table Binary files differnew file mode 100644 index 0000000..0837940 --- /dev/null +++ b/test/TEST-30-ISCSI/ibft.table diff --git a/test/TEST-30-ISCSI/server-init.sh b/test/TEST-30-ISCSI/server-init.sh new file mode 100755 index 0000000..a1c3b7e --- /dev/null +++ b/test/TEST-30-ISCSI/server-init.sh @@ -0,0 +1,88 @@ +#!/bin/sh +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='server:\w\$ ' +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up + +ip addr add 192.168.50.1/24 dev enx525400123456 +linkup enx525400123456 + +ip addr add 192.168.51.1/24 dev enx525400123457 +linkup enx525400123457 + +modprobe af_packet + +: > /var/lib/dhcpd/dhcpd.leases +chmod 777 /var/lib/dhcpd/dhcpd.leases +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & + +tgtd +tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2009-06.dracut:target0 +tgtadm --lld iscsi --mode target --op new --tid 2 --targetname iqn.2009-06.dracut:target1 +tgtadm --lld iscsi --mode target --op new --tid 3 --targetname iqn.2009-06.dracut:target2 +tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 -b /dev/disk/by-id/ata-disk_singleroot +tgtadm --lld iscsi --mode logicalunit --op new --tid 2 --lun 2 -b /dev/disk/by-id/ata-disk_raid0-1 +tgtadm --lld iscsi --mode logicalunit --op new --tid 3 --lun 3 -b /dev/disk/by-id/ata-disk_raid0-2 +tgtadm --lld iscsi --mode target --op bind --tid 1 -I 192.168.50.101 +tgtadm --lld iscsi --mode target --op bind --tid 2 -I 192.168.51.101 +tgtadm --lld iscsi --mode target --op bind --tid 3 -I 192.168.50.101 + +# Wait forever for the VM to die +echo "Serving iSCSI" +while pidof tgtd > /dev/null; do + : > /dev/watchdog + dmesg -c + sleep 1 +done +dmesg -c +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-30-ISCSI/server.link b/test/TEST-30-ISCSI/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-30-ISCSI/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-30-ISCSI/test.sh b/test/TEST-30-ISCSI/test.sh new file mode 100755 index 0000000..ac9f096 --- /dev/null +++ b/test/TEST-30-ISCSI/test.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem over iSCSI with $USE_NETWORK" + +#DEBUGFAIL="rd.shell rd.break rd.debug loglevel=7 " +#SERVER_DEBUG="rd.debug loglevel=7" +#SERIAL="tcp:127.0.0.1:9999" + +run_server() { + # Start server first + echo "iSCSI TEST SETUP: Starting DHCP/iSCSI server" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img serverroot 0 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -net nic,macaddr=52:54:00:12:34:56,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:57,model=e1000 \ + -net socket,listen=127.0.0.1:12330 \ + -append "panic=1 oops=panic softlockup_panic=1 quiet root=/dev/disk/by-id/ata-disk_serverroot rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 $SERVER_DEBUG" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + while :; do + grep Serving "$TESTDIR"/server.log && break + echo "Waiting for the server to startup" + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi + +} + +run_client() { + local test_name=$1 + shift + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net nic,macaddr=52:54:00:12:34:00,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:01,model=e1000 \ + -net socket,connect=127.0.0.1:12330 \ + -acpitable file=ibft.table \ + -append "$*" \ + -initrd "$TESTDIR"/initramfs.testing + + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]] || ! test_marker_check iscsi-OK; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +do_test_run() { + initiator=$(iscsi-iname) + + run_client "root=dhcp" \ + "root=/dev/root netroot=dhcp ip=enp0s1:dhcp" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "netroot=iscsi target0" \ + "root=LABEL=singleroot netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target0" \ + "ip=192.168.50.101::192.168.50.1:255.255.255.0:iscsi-1:enp0s1:off" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "netroot=iscsi target1 target2" \ + "root=LABEL=sysroot" \ + "ip=dhcp" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "root=ibft" \ + "root=LABEL=singleroot" \ + "rd.iscsi.ibft=1" \ + "rd.iscsi.firmware=1" \ + || return 1 + + echo "All tests passed [OK]" + return 0 +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + do_test_run + ret=$? + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + return $ret +} + +test_check() { + if ! command -v tgtd &> /dev/null || ! command -v tgtadm &> /dev/null; then + echo "Need tgtd and tgtadm from scsi-target-utils" + return 1 + fi +} + +test_setup() { + # Create what will eventually be the client root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./client-init.sh /sbin/init \ + -I "ip ping grep setsid" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + mkdir -p -- "$TESTDIR"/overlay/source/var/lib/nfs/rpc_pipefs + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot crypt lvm mdraid" \ + -I "mkfs.ext4 setsid blockdev" \ + -i ./create-client-root.sh /lib/dracut/hooks/initqueue/01-create-client-root.sh \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot 200 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 100 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 100 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # Create what will eventually be the server root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root network network-legacy" \ + -d "iscsi_tcp crc32c ipv6" \ + -i ./server-init.sh /sbin/init \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + -I "modprobe chmod ip ping tcpdump setsid pidof tgtd tgtadm /etc/passwd" \ + --install-optional "/etc/netconfig dhcpd /etc/group /etc/nsswitch.conf /etc/rpc /etc/protocols /etc/services /usr/etc/nsswitch.conf /usr/etc/rpc /usr/etc/protocols /usr/etc/services" \ + -i "./hosts" "/etc/hosts" \ + -i "./dhcpd.conf" "/etc/dhcpd.conf" \ + --no-hostonly --no-hostonly-cmdline --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + mkdir -p "$TESTDIR"/overlay/source/var/lib/dhcpd + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot" \ + -I "mkfs.ext4" \ + -i ./create-server-root.sh /lib/dracut/hooks/initqueue/01-create-server-root.sh \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 240 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # Make server's dracut image + "$DRACUT" -l \ + -a "dash rootfs-block test kernel-modules network network-legacy" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod e1000 drbg" \ + -i "./server.link" "/etc/systemd/network/01-server.link" \ + -i ./wait-if-server.sh /lib/dracut/hooks/pre-mount/99-wait-if-server.sh \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + + # Make client's dracut image + test_dracut \ + --add "$USE_NETWORK" \ + --include "./client.link" "/etc/systemd/network/01-client.link" \ + --kernel-cmdline "rw rd.auto rd.retry=50" \ + "$TESTDIR"/initramfs.testing +} + +test_cleanup() { + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-30-ISCSI/wait-if-server.sh b/test/TEST-30-ISCSI/wait-if-server.sh new file mode 100755 index 0000000..b53e41f --- /dev/null +++ b/test/TEST-30-ISCSI/wait-if-server.sh @@ -0,0 +1,4 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 |