6aee12
From 43e9997521d6c10ec8dae340dc117dd6cbd73a2a Mon Sep 17 00:00:00 2001
6aee12
From: Martin Wilck <mwilck@suse.com>
6aee12
Date: Fri, 16 Sep 2022 21:36:52 +0200
6aee12
Subject: [PATCH] (Cherry-picked commits:
6aee12
 9664e98b5db603567d42d4d0c6e6ea1bd3d5bf24
6aee12
 b3ff3f3fbce6878a754332cd4a05374e5e1156c8
6aee12
 a3cf4ec92202df43adf368c7fdd12e35d304a0e4
6aee12
 03921ec09e95ea49f89ae307dcca4e2e3d1bc6d6
6aee12
 e93e46520dd89a7357a15441ab6b141ff9ff9aeb
6aee12
 556ef46aa96650d72b2fd850a09fa04dff64bbb8
6aee12
 a93968b07567a654d18b8ef2144337d803186eca
6aee12
 a65fab69662d3adf52eb968411f59ebc5a173f7c
6aee12
 cf8986af7d9a3ce73f330de23d5312f924acea34
6aee12
 7c28e1148c086d8504caab6e70a1bcfda1bbf0b9
6aee12
 b03dc850e4630c3b727f71b853a1be588507a59e
6aee12
 0a4d7f9aece172f0f9a9286c94308b7e1ef8d500)
6aee12
6aee12
fix(nvmf): nvme list-subsys prints the address using commas as separator
6aee12
6aee12
nvme-cli 1.x printed the address using spaces as separator, but nvme-cli 2.x
6aee12
prints the address using commas as separator (exact output from sysfs). E.g.,
6aee12
output from `cat /sys/class/nvme/nvme0/address`:
6aee12
6aee12
traddr=nn-0x201700a09890f5bf:pn-0x201900a09890f5bf,host_traddr=nn-0x200000109b579ef5:pn-0x100000109b579ef5
6aee12
6aee12
Also, I suppress rd.nvmf.discover= cmdline option if all fields are empty.
6aee12
6aee12
fix(nvmf): don't try to validate network connections in cmdline hook
6aee12
6aee12
The cmdline hook runs before any network interfaces have been brought
6aee12
up. There's no point in trying to validate the connections at this
6aee12
stage.
6aee12
6aee12
fix(nvmf): no need to load the nvme module
6aee12
6aee12
The module "nvme" is not required for NVMeoF.
6aee12
6aee12
fix(nvmf): don't create did-setup file
6aee12
6aee12
did-setup files are meant to indicate that an interface setup
6aee12
was successful. Don't do it here.
6aee12
6aee12
fix(nvmf): don't use "finished" queue for autoconnect
6aee12
6aee12
The "finished" initqueue is for testing if everything is alright,
6aee12
not for triggering any actions.
6aee12
6aee12
fix(nvmf): make sure "rd.nvmf.discover=fc,auto" takes precedence
6aee12
6aee12
The command line may contain several rd.nvmf.discover options.
6aee12
The "fc,auto" option should take precedence.
6aee12
6aee12
fix(nvmf): avoid calling "exit" in a cmdline hook
6aee12
6aee12
"exit" should never be executed in dracut hooks, because the
6aee12
hooks are sourced by the main script.
6aee12
6aee12
fix(nvmf): run cmdline hook before parse-ip-opts.sh
6aee12
6aee12
This way we can set "rd.neednet" and have it seen by parse-ip-options.sh
6aee12
6aee12
feat(nvmf): set rd.neednet=1 if tcp records encountered
6aee12
6aee12
This is currently always the case for NBFT records.
6aee12
We can do this now, as we run before parse-ip-options.sh
6aee12
6aee12
fix(nvmf): install 8021q module unconditionally
6aee12
6aee12
In NBFT setups, VLAN can be configured in the firmware.
6aee12
Add the 8021q module in hostonly mode even if VLAN is currently
6aee12
not used to be prepared for such configuration change.
6aee12
6aee12
fix(nvmf): support /etc/nvme/config.json
6aee12
6aee12
Since nvme-cli 2.0, configuration of subsystems to connect to is
6aee12
stored under `/etc/nvme` in either `discovery.conf` or `config.json`.
6aee12
Attempt discovery also if the latter exists, but not the former.
6aee12
Also, install "config.json" if it's present on the root FS.
6aee12
6aee12
As before, "rd.nvmf.discover=fc,auto" will force either file to be ignored,
6aee12
and NBFT-defined targets take precedence if found.
6aee12
6aee12
feat(nvmf): add code for parsing the NBFT
6aee12
6aee12
Add code to parse the Nvme-oF Boot Firmware Table (NBFT) according
6aee12
to the NVM Express Boot Specification 1.0 [1]. The implementation in
6aee12
dracut follows a similar general approach as iBFT support in the
6aee12
iscsi module.
6aee12
6aee12
NBFT support requires two steps:
6aee12
6aee12
(1) Setting up the network and routing according to the
6aee12
    HFI ("Host Fabric Interface") records in the NBFT,
6aee12
(2) Establishing the actual NVMe-oF connection.
6aee12
6aee12
(1) is accomplished by reading the NBFT using JSON output from
6aee12
the "nvme nbft show" command, and transforming it into command
6aee12
line options ("ip=", "rd.neednet", etc.) understood by dracut's
6aee12
network module and its backends. The resulting network setup code
6aee12
is backend-agnostic. It has been tested with the "network-legacy"
6aee12
and "network-manager" network backend modules. The network setup
6aee12
code supports IPv4 and IPv6 with static, RA, or DHCP configurations,
6aee12
802.1q VLANs, and simple routing / gateway setup.
6aee12
6aee12
(2) is done using the "nvme connect-all" command [2] in the netroot handler,
6aee12
which is invoked by networking backends when an interface gets fully
6aee12
configured. This patch adds support for "netboot=nbft". The "nbftroot"
6aee12
handler calls nvmf-autoconnect.sh, which contains the actual connect
6aee12
logic. nvmf-autoconnect.sh itself is preserved, because there are
6aee12
other NVMe-oF setups like NVMe over FC which don't depend on the
6aee12
network.
6aee12
6aee12
The various ways to configure NVMe-oF are prioritized like this:
6aee12
6aee12
 1 FC autoconnect from kernel commandline (rd.nvmf.discover=fc,auto)
6aee12
 2 NBFT, if present
6aee12
 3 discovery.conf or config.json, if present, and cmdline.d parameters,
6aee12
   if present (rd.nvmf.discovery=...)
6aee12
 4 FC autoconnect (without kernel command line)
6aee12
6aee12
The reason for this priorization is that in the initial RAM fs, we try
6aee12
to activate only those connections that are necessary to mount the root
6aee12
file system. This avoids confusion, possible contradicting or ambiguous
6aee12
configuration, and timeouts from unavailable targets.
6aee12
6aee12
A retry logic is implemented for enabling the NVMe-oF connections,
6aee12
using the "settled" initqueue, the netroot handler, and eventually, the
6aee12
"timeout" initqueue. This is similar to the retry logic of the iscsi module.
6aee12
In the "timeout" case, connection to all possible NVMe-oF subsystems
6aee12
is attempted.
6aee12
6aee12
Two new command line parameters are introduced to make it possible to
6aee12
change the priorities above:
6aee12
6aee12
 - "rd.nvmf.nonbft" causes the NBFT to be ignored,
6aee12
 - "rd.nvmf.nostatic" causes any statically configured NVMe-oF targets
6aee12
   (config.json, discovery.conf, and cmdline.d) to be ignored.
6aee12
6aee12
These parameters may be helpful to skip attempts to set up broken
6aee12
configurations.
6aee12
6aee12
At initramfs build time, the nvmf module is now enabled if an NBFT
6aee12
table is detected in the system.
6aee12
6aee12
[1] https://nvmexpress.org/wp-content/uploads/NVM-Express-Boot-Specification-2022.11.15-Ratified.pdf
6aee12
[2] NBFT support in nvme-cli requires the latest upstream code (> v2.4).
6aee12
6aee12
Signed-off-by: Martin Wilck <mwilck@suse.com>
6aee12
Co-authored-by: John Meneghini <jmeneghi@redhat.com>
6aee12
Co-authored-by: Charles Rose <charles.rose@dell.com>
6aee12
---
6aee12
 man/dracut.cmdline.7.asc                      |   9 +
6aee12
 modules.d/95nvmf/module-setup.sh              |  36 ++-
6aee12
 modules.d/95nvmf/nbftroot.sh                  |   5 +
6aee12
 modules.d/95nvmf/nvmf-autoconnect.sh          |  55 +++-
6aee12
 .../95nvmf/parse-nvmf-boot-connections.sh     | 237 ++++++++++++++++--
6aee12
 create mode 100755 modules.d/95nvmf/nbftroot.sh
6aee12
6aee12
diff --git a/man/dracut.cmdline.7.asc b/man/dracut.cmdline.7.asc
6aee12
index 93861c56..47a6b6c7 100644
6aee12
--- a/man/dracut.cmdline.7.asc
6aee12
+++ b/man/dracut.cmdline.7.asc
6aee12
@@ -898,6 +898,15 @@ NVMf
6aee12
 **rd.nonvmf**::
6aee12
     Disable NVMf
6aee12
 
6aee12
+**rd.nvmf.nonbft**::
6aee12
+    Disable connecting to targets from the NVMe Boot Firmware Table. Without
6aee12
+    this parameter, NBFT connections will take precedence over _rd.nvmf.discover_.
6aee12
+
6aee12
+**rd.nvmf.nostatic**::
6aee12
+    Disable connecting to targets that have been statically configured when
6aee12
+    the initramfs was built. Targets specified with rd.nvmf.discover on the
6aee12
+    kernel command line will still be tried.
6aee12
+
6aee12
 **rd.nvmf.hostnqn=**__<hostNQN>__::
6aee12
     NVMe host NQN to use
6aee12
 
6aee12
diff --git a/modules.d/95nvmf/module-setup.sh b/modules.d/95nvmf/module-setup.sh
6aee12
index 476b7f7..1dd2ca5 100755
6aee12
--- a/modules.d/95nvmf/module-setup.sh
6aee12
+++ b/modules.d/95nvmf/module-setup.sh
6aee12
@@ -2,7 +2,7 @@
6aee12
 
6aee12
 # called by dracut
6aee12
 check() {
6aee12
-    require_binaries nvme || return 1
6aee12
+    require_binaries nvme jq || return 1
6aee12
     [ -f /etc/nvme/hostnqn ] || return 255
6aee12
     [ -f /etc/nvme/hostid ] || return 255
6aee12
 
6aee12
@@ -18,24 +18,34 @@ check() {
6aee12
         for d in device/nvme*; do
6aee12
             [ -L "$d" ] || continue
6aee12
             if readlink "$d" | grep -q nvme-fabrics; then
6aee12
-                read -r trtype < "$d"/transport
6aee12
+                trtype=$(cat "$d"/transport)
6aee12
                 break
6aee12
             fi
6aee12
         done
6aee12
         [[ $trtype == "fc" ]] || [[ $trtype == "tcp" ]] || [[ $trtype == "rdma" ]]
6aee12
     }
6aee12
 
6aee12
+    has_nbft() {
6aee12
+        local f found=
6aee12
+        for f in /sys/firmware/acpi/tables/NBFT*; do
6aee12
+            [ -f "$f" ] || continue
6aee12
+            found=1
6aee12
+            break
6aee12
+        done
6aee12
+        [[ $found ]]
6aee12
+    }
6aee12
+
6aee12
     [[ $hostonly ]] || [[ $mount_needs ]] && {
6aee12
         pushd . > /dev/null
6aee12
         for_each_host_dev_and_slaves is_nvmf
6aee12
         local _is_nvmf=$?
6aee12
         popd > /dev/null || exit
6aee12
         [[ $_is_nvmf == 0 ]] || return 255
6aee12
-        if [ ! -f /sys/class/fc/fc_udev_device/nvme_discovery ]; then
6aee12
-            if [ ! -f /etc/nvme/discovery.conf ]; then
6aee12
-                echo "No discovery arguments present"
6aee12
-                return 255
6aee12
-            fi
6aee12
+        if [ ! -f /sys/class/fc/fc_udev_device/nvme_discovery ] \
6aee12
+            && [ ! -f /etc/nvme/discovery.conf ] \
6aee12
+            && [ ! -f /etc/nvme/config.json ] && ! has_nbft; then
6aee12
+            echo "No discovery arguments present"
6aee12
+            return 255
6aee12
         fi
6aee12
     }
6aee12
     return 0
6aee12
@@ -50,7 +60,7 @@ depends() {
6aee12
 # called by dracut
6aee12
 installkernel() {
6aee12
     instmods nvme_fc lpfc qla2xxx
6aee12
-    hostonly="" instmods nvme_tcp nvme_fabrics
6aee12
+    hostonly="" instmods nvme_tcp nvme_fabrics 8021q
6aee12
 }
6aee12
 
6aee12
 # called by dracut
6aee12
@@ -75,7 +85,7 @@ cmdline() {
6aee12
         for d in device/nvme*; do
6aee12
             [ -L "$d" ] || continue
6aee12
             if readlink "$d" | grep -q nvme-fabrics; then
6aee12
-                read -r trtype < "$d"/transport
6aee12
+                trtype=$(cat "$d"/transport)
6aee12
                 break
6aee12
             fi
6aee12
         done
6aee12
@@ -98,11 +108,11 @@ cmdline() {
6aee12
     }
6aee12
 
6aee12
     if [ -f /etc/nvme/hostnqn ]; then
6aee12
-        read -r _hostnqn < /etc/nvme/hostnqn
6aee12
+        _hostnqn=$(cat /etc/nvme/hostnqn)
6aee12
         echo -n " rd.nvmf.hostnqn=${_hostnqn}"
6aee12
     fi
6aee12
     if [ -f /etc/nvme/hostid ]; then
6aee12
-        read -r _hostid < /etc/nvme/hostid
6aee12
+        _hostid=$(cat /etc/nvme/hostid)
6aee12
         echo -n " rd.nvmf.hostid=${_hostid}"
6aee12
     fi
6aee12
 
6aee12
@@ -126,10 +136,12 @@ install() {
6aee12
     inst_multiple ip sed
6aee12
 
6aee12
     inst_script "${moddir}/nvmf-autoconnect.sh" /sbin/nvmf-autoconnect.sh
6aee12
+    inst_script "${moddir}/nbftroot.sh" /sbin/nbftroot
6aee12
 
6aee12
-    inst_multiple nvme
6aee12
+    inst_multiple nvme jq
6aee12
     inst_hook cmdline 92 "$moddir/parse-nvmf-boot-connections.sh"
6aee12
     inst_simple "/etc/nvme/discovery.conf"
6aee12
+    inst_simple "/etc/nvme/config.json"
6aee12
     inst_rules /usr/lib/udev/rules.d/71-nvmf-iopolicy-netapp.rules
6aee12
     inst_rules "$moddir/95-nvmf-initqueue.rules"
6aee12
     dracut_need_initqueue
6aee12
diff --git a/modules.d/95nvmf/nbftroot.sh b/modules.d/95nvmf/nbftroot.sh
6aee12
new file mode 100755
6aee12
index 0000000..0f33499
6aee12
--- /dev/null
6aee12
+++ b/modules.d/95nvmf/nbftroot.sh
6aee12
@@ -0,0 +1,5 @@
6aee12
+#! /bin/sh
6aee12
+# This script is called from /sbin/netroot
6aee12
+
6aee12
+/sbin/nvmf-autoconnect.sh online
6aee12
+exit 0
6aee12
diff --git a/modules.d/95nvmf/nvmf-autoconnect.sh b/modules.d/95nvmf/nvmf-autoconnect.sh
6aee12
index c8f676a..35ee948 100755
6aee12
--- a/modules.d/95nvmf/nvmf-autoconnect.sh
6aee12
+++ b/modules.d/95nvmf/nvmf-autoconnect.sh
6aee12
@@ -1,5 +1,54 @@
6aee12
-#!/bin/bash
6aee12
+#!/bin/sh
6aee12
+# Argument $1 is "settled", "online", or "timeout", indicating
6aee12
+# the queue from which the script is called.
6aee12
+# In the "timeout" case, try everything.
6aee12
+# Otherwise, try options according to the priorities below.
6aee12
 
6aee12
-[ -f /sys/class/fc/fc_udev_device/nvme_discovery ] || exit 1
6aee12
-echo add > /sys/class/fc/fc_udev_device/nvme_discovery
6aee12
+[ "$RD_DEBUG" != yes ] || set -x
6aee12
+
6aee12
+if [ "$1" = timeout ]; then
6aee12
+    [ ! -f /sys/class/fc/fc_udev_device/nvme_discovery ] \
6aee12
+        || echo add > /sys/class/fc/fc_udev_device/nvme_discovery
6aee12
+    /usr/sbin/nvme connect-all
6aee12
+    exit 0
6aee12
+fi
6aee12
+
6aee12
+NVMF_HOSTNQN_OK=
6aee12
+[ ! -f "/etc/nvme/hostnqn" ] || [ ! -f "/etc/nvme/hostid" ] || NVMF_HOSTNQN_OK=1
6aee12
+
6aee12
+# Only nvme-cli 2.5 or newer supports the options --nbft and --no-nbft
6aee12
+# for the connect-all command.
6aee12
+# Make sure we don't use unsupported options with earlier versions.
6aee12
+NBFT_SUPPORTED=
6aee12
+# shellcheck disable=SC2016
6aee12
+/usr/sbin/nvme connect-all --help 2>&1 | sed -n '/[[:space:]]--nbft[[:space:]]/q1;$q0' \
6aee12
+    || NBFT_SUPPORTED=1
6aee12
+
6aee12
+if [ -e /tmp/nvmf-fc-auto ] && [ "$NVMF_HOSTNQN_OK" ] \
6aee12
+    && [ -f /sys/class/fc/fc_udev_device/nvme_discovery ]; then
6aee12
+    # prio 1: cmdline override "rd.nvmf.discovery=fc,auto"
6aee12
+    echo add > /sys/class/fc/fc_udev_device/nvme_discovery
6aee12
+    exit 0
6aee12
+fi
6aee12
+if [ "$NBFT_SUPPORTED" ] && [ -e /tmp/valid_nbft_entry_found ]; then
6aee12
+    # prio 2: NBFT
6aee12
+    /usr/sbin/nvme connect-all --nbft
6aee12
+    exit 0
6aee12
+fi
6aee12
+if [ -f /etc/nvme/discovery.conf ] || [ -f /etc/nvme/config.json ] \
6aee12
+    && [ "$NVMF_HOSTNQN_OK" ]; then
6aee12
+    # prio 3: configuration from initrd and/or kernel command line
6aee12
+    # We can get here even if "rd.nvmf.nonbft" was given, thus use --no-nbft
6aee12
+    if [ "$NBFT_SUPPORTED" ]; then
6aee12
+        /usr/sbin/nvme connect-all --no-nbft
6aee12
+    else
6aee12
+        /usr/sbin/nvme connect-all
6aee12
+    fi
6aee12
+    exit 0
6aee12
+fi
6aee12
+if [ "$NVMF_HOSTNQN_OK" ] \
6aee12
+    && [ -f /sys/class/fc/fc_udev_device/nvme_discovery ]; then
6aee12
+    # prio 4: no discovery entries, try NVMeoFC autoconnect
6aee12
+    echo add > /sys/class/fc/fc_udev_device/nvme_discovery
6aee12
+fi
6aee12
 exit 0
6aee12
diff --git a/modules.d/95nvmf/parse-nvmf-boot-connections.sh b/modules.d/95nvmf/parse-nvmf-boot-connections.sh
6aee12
index 6b26f76..6601837 100755
6aee12
--- a/modules.d/95nvmf/parse-nvmf-boot-connections.sh
6aee12
+++ b/modules.d/95nvmf/parse-nvmf-boot-connections.sh
6aee12
@@ -17,13 +17,225 @@
6aee12
 # specify any discover parameters for FC.
6aee12
 #
6aee12
 
6aee12
-type is_ip > /dev/null 2>&1 || . /lib/net-lib.sh
6aee12
+command -v getarg > /dev/null || . /lib/dracut-lib.sh
6aee12
+command -v is_ip > /dev/null || . /lib/net-lib.sh
6aee12
+
6aee12
+## Sample NBFT output from nvme show-nbft -H -s -d -o json
6aee12
+# [
6aee12
+#   {
6aee12
+#     "filename":"/sys/firmware/acpi/tables/NBFT",
6aee12
+#     "host":{
6aee12
+#       "nqn":"nqn.2014-08.org.nvmexpress:uuid:d6f07002-7eb5-4841-a185-400e296afae4",
6aee12
+#       "id":"111919da-21ea-cc4e-bafe-216d8372dd31",
6aee12
+#       "host_id_configured":0,
6aee12
+#       "host_nqn_configured":0,
6aee12
+#       "primary_admin_host_flag":"not indicated"
6aee12
+#     },
6aee12
+#     "subsystem":[
6aee12
+#       {
6aee12
+#         "index":1,
6aee12
+#         "num_hfis":1,
6aee12
+#         "hfis":[
6aee12
+#           1
6aee12
+#         ],
6aee12
+#         "transport":"tcp",
6aee12
+#         "transport_address":"192.168.100.216",
6aee12
+#         "transport_svcid":"4420",
6aee12
+#         "subsys_port_id":0,
6aee12
+#         "nsid":1,
6aee12
+#         "nid_type":"uuid",
6aee12
+#         "nid":"424d1c8a-8ef9-4681-b2fc-8c343bd8fa69",
6aee12
+#         "subsys_nqn":"timberland-01",
6aee12
+#         "controller_id":0,
6aee12
+#         "asqsz":0,
6aee12
+#         "pdu_header_digest_required":0,
6aee12
+#         "data_digest_required":0
6aee12
+#       }
6aee12
+#     ],
6aee12
+#     "hfi":[
6aee12
+#       {
6aee12
+#         "index":1,
6aee12
+#         "transport":"tcp",
6aee12
+#         "pcidev":"0:0:2.0",
6aee12
+#         "mac_addr":"52:54:00:4f:97:e9",
6aee12
+#         "vlan":0,
6aee12
+#         "ip_origin":63,
6aee12
+#         "ipaddr":"192.168.100.217",
6aee12
+#         "subnet_mask_prefix":24,
6aee12
+#         "gateway_ipaddr":"0.0.0.0",
6aee12
+#         "route_metric":0,
6aee12
+#         "primary_dns_ipaddr":"0.0.0.0",
6aee12
+#         "secondary_dns_ipaddr":"0.0.0.0",
6aee12
+#         "dhcp_server_ipaddr":"",
6aee12
+#         "this_hfi_is_default_route":1
6aee12
+#       }
6aee12
+#     ],
6aee12
+#     "discovery":[
6aee12
+#     ]
6aee12
+#   }
6aee12
+# ]
6aee12
+#
6aee12
+# If the IP address is derived from DHCP, it sets the field
6aee12
+# "hfi.dhcp_server_ipaddr" to a non-emtpy value.
6aee12
+#
6aee12
+#
6aee12
+
6aee12
+nbft_run_jq() {
6aee12
+    local st
6aee12
+    local opts="-e"
6aee12
+
6aee12
+    while [ $# -gt 0 ]; do
6aee12
+        case $1 in
6aee12
+            -*)
6aee12
+                opts="$opts $1"
6aee12
+                ;;
6aee12
+            *)
6aee12
+                break
6aee12
+                ;;
6aee12
+        esac
6aee12
+        shift
6aee12
+    done
6aee12
+    # Not quoting is intentional here. We won't get glob expressions passed.
6aee12
+    # shellcheck disable=SC2086
6aee12
+    jq $opts "$1" << EOF
6aee12
+$2
6aee12
+EOF
6aee12
+    st=$?
6aee12
+    if [ $st -ne 0 ]; then
6aee12
+        warn "NBFT: jq error while processing \"$1\""
6aee12
+        return $st
6aee12
+    else
6aee12
+        return 0
6aee12
+    fi
6aee12
+}
6aee12
+
6aee12
+nbft_check_empty_address() {
6aee12
+    # suppress meaningless or empty IP addresses
6aee12
+    # "null" is returned by jq if no match found for expression
6aee12
+    case $1 in
6aee12
+        null | "::" | "0.0.0.0") ;;
6aee12
+        *)
6aee12
+            echo "$1"
6aee12
+            ;;
6aee12
+    esac
6aee12
+}
6aee12
+
6aee12
+nbft_parse_hfi() {
6aee12
+    # false positive of shellcheck - no expansion in variable assignments
6aee12
+    # shellcheck disable=2086
6aee12
+    local hfi_json=$1
6aee12
+    local mac iface ipaddr prefix vlan gateway dns1 dns2 hostname adrfam dhcp
6aee12
+
6aee12
+    mac=$(nbft_run_jq -r .mac_addr "$hfi_json") || return 1
6aee12
+    iface=$(set_ifname nbft "$mac")
6aee12
+
6aee12
+    vlan=$(nbft_run_jq .vlan "$hfi_json") || vlan=0
6aee12
+    # treat VLAN zero as "no vlan"
6aee12
+    [ "$vlan" -ne 0 ] || vlan=
6aee12
+
6aee12
+    [ ! -e /tmp/net."${iface}${vlan:+.$vlan}".has_ibft_config ] || return 0
6aee12
+
6aee12
+    dhcp=$(nbft_run_jq -r .dhcp_server_ipaddr "$hfi_json")
6aee12
+    # We need to check $? here as the above is an assignment
6aee12
+    # shellcheck disable=2181
6aee12
+    if [ $? -eq 0 ] && [ "$dhcp" ] && [ "$dhcp" != null ]; then
6aee12
+        case $dhcp in
6aee12
+            *:*)
6aee12
+                echo ip="$iface${vlan:+.$vlan}:dhcp6"
6aee12
+                ;;
6aee12
+            *.*.*.*)
6aee12
+                echo ip="$iface${vlan:+.$vlan}:dhcp"
6aee12
+                ;;
6aee12
+            *)
6aee12
+                warn "Invalid value for dhcp_server_ipaddr: $dhcp"
6aee12
+                return 1
6aee12
+                ;;
6aee12
+        esac
6aee12
+    else
6aee12
+        ipaddr=$(nbft_run_jq -r .ipaddr "$hfi_json") || return 1
6aee12
+
6aee12
+        case $ipaddr in
6aee12
+            *.*.*.*)
6aee12
+                adrfam=ipv4
6aee12
+                ;;
6aee12
+            *:*)
6aee12
+                adrfam=ipv6
6aee12
+                ;;
6aee12
+            *)
6aee12
+                warn "invalid address: $ipaddr"
6aee12
+                return 1
6aee12
+                ;;
6aee12
+        esac
6aee12
+        prefix=$(nbft_run_jq -r .subnet_mask_prefix "$hfi_json")
6aee12
+        # Need to check $? here as he above is an assignment
6aee12
+        # shellcheck disable=2181
6aee12
+        if [ $? -ne 0 ] && [ "$adrfam" = ipv6 ]; then
6aee12
+            prefix=128
6aee12
+        fi
6aee12
+        # Use brackets for IPv6
6aee12
+        if [ "$adrfam" = ipv6 ]; then
6aee12
+            ipaddr="[$ipaddr]"
6aee12
+        fi
6aee12
+
6aee12
+        gateway=$(nbft_check_empty_address \
6aee12
+            "$(nbft_run_jq -r .gateway_ipaddr "$hfi_json")")
6aee12
+        dns1=$(nbft_check_empty_address \
6aee12
+            "$(nbft_run_jq -r .primary_dns_ipaddr "$hfi_json")")
6aee12
+        dns2=$(nbft_check_empty_address \
6aee12
+            "$(nbft_run_jq -r .secondary_dns_ipaddr "$hfi_json")")
6aee12
+        hostname=$(nbft_run_jq -r .host_name "$hfi_json" 2> /dev/null) || hostname=
6aee12
+
6aee12
+        echo "ip=$ipaddr::$gateway:$prefix:$hostname:$iface${vlan:+.$vlan}:none${dns1:+:$dns1}${dns2:+:$dns2}"
6aee12
+    fi
6aee12
+
6aee12
+    if [ "$vlan" ]; then
6aee12
+        echo "vlan=$iface.$vlan:$iface"
6aee12
+        echo "$mac" > "/tmp/net.$iface.$vlan.has_ibft_config"
6aee12
+    else
6aee12
+        echo "$mac" > "/tmp/net.$iface.has_ibft_config"
6aee12
+    fi
6aee12
+    : > /tmp/valid_nbft_entry_found
6aee12
+}
6aee12
+
6aee12
+nbft_parse() {
6aee12
+    local nbft_json n_nbft all_hfi_json n_hfi
6aee12
+    local j=0 i
6aee12
+
6aee12
+    nbft_json=$(nvme nbft show -H -o json) || return 0
6aee12
+    n_nbft=$(nbft_run_jq ". | length" "$nbft_json") || return 0
6aee12
+
6aee12
+    while [ "$j" -lt "$n_nbft" ]; do
6aee12
+        all_hfi_json=$(nbft_run_jq ".[$j].hfi" "$nbft_json") || continue
6aee12
+        n_hfi=$(nbft_run_jq ". | length" "$all_hfi_json") || continue
6aee12
+        i=0
6aee12
+
6aee12
+        while [ "$i" -lt "$n_hfi" ]; do
6aee12
+            nbft_parse_hfi "$(nbft_run_jq ".[$i]" "$all_hfi_json")"
6aee12
+            i=$((i + 1))
6aee12
+        done
6aee12
+        j=$((j + 1))
6aee12
+    done >> /etc/cmdline.d/40-nbft.conf
6aee12
+}
6aee12
 
6aee12
 if getargbool 0 rd.nonvmf; then
6aee12
     warn "rd.nonvmf=0: skipping nvmf"
6aee12
     return 0
6aee12
 fi
6aee12
 
6aee12
+if getargbool 0 rd.nvmf.nostatic; then
6aee12
+    rm -f /etc/cmdline.d/95nvmf-args.conf
6aee12
+    rm -f /etc/nvme/discovery.conf /etc/nvme/config.json
6aee12
+fi
6aee12
+
6aee12
+if ! getargbool 0 rd.nvmf.nonbft; then
6aee12
+    for _x in /sys/firmware/acpi/tables/NBFT*; do
6aee12
+        if [ -f "$_x" ]; then
6aee12
+            nbft_parse
6aee12
+            break
6aee12
+        fi
6aee12
+    done
6aee12
+fi
6aee12
+
6aee12
 initqueue --onetime modprobe --all -b -q nvme_tcp nvme_core nvme_fabrics
6aee12
 
6aee12
 parse_nvmf_discover() {
6aee12
@@ -66,7 +278,7 @@ parse_nvmf_discover() {
6aee12
         : > /tmp/nvmf_needs_network
6aee12
     elif [ "$trtype" = "fc" ]; then
6aee12
         if [ "$traddr" = "auto" ]; then
6aee12
-            rm /etc/nvme/discovery.conf
6aee12
+            rm -f /etc/nvme/discovery.conf /etc/nvme/config.json
6aee12
             return 1
6aee12
         fi
6aee12
         if [ "$hosttraddr" = "none" ]; then
6aee12
@@ -94,26 +306,21 @@ if [ -n "$nvmf_hostid" ]; then
6aee12
     echo "$nvmf_hostid" > /etc/nvme/hostid
6aee12
 fi
6aee12
 
6aee12
-NVMF_FC_AUTO=
6aee12
+rm -f /tmp/nvmf-fc-auto
6aee12
 for d in $(getargs rd.nvmf.discover -d nvmf.discover=); do
6aee12
     parse_nvmf_discover "$d" || {
6aee12
-        NVMF_FC_AUTO=1
6aee12
+        : > /tmp/nvmf-fc-auto
6aee12
         break
6aee12
     }
6aee12
 done
6aee12
 
6aee12
-if [ -e /tmp/nvmf_needs_network ]; then
6aee12
+if [ -e /tmp/nvmf_needs_network ] || [ -e /tmp/valid_nbft_entry_found ]; then
6aee12
     echo "rd.neednet=1" > /etc/cmdline.d/nvmf-neednet.conf
6aee12
+    # netroot is a global variable that is present in all "sourced" scripts
6aee12
+    # shellcheck disable=SC2034
6aee12
+    netroot=nbft
6aee12
     rm -f /tmp/nvmf_needs_network
6aee12
 fi
6aee12
 
6aee12
-# Host NQN and host id are mandatory for NVMe-oF
6aee12
-if [ -f "/etc/nvme/hostnqn" ] && [ -f "/etc/nvme/hostid" ]; then
6aee12
-
6aee12
-    # If no nvme command line arguments present, try autodiscovery
6aee12
-    if [ $NVMF_FC_AUTO ] || [ ! -f "/etc/nvme/discovery.conf" ]; then
6aee12
-        /sbin/initqueue --settled --onetime --unique --name nvme-fc-autoconnect /sbin/nvmf-autoconnect.sh
6aee12
-    else
6aee12
-        /sbin/initqueue --settled --onetime --unique --name nvme-discover /usr/sbin/nvme connect-all
6aee12
-    fi
6aee12
-fi
6aee12
+/sbin/initqueue --settled --onetime --name nvmf-connect-settled /sbin/nvmf-autoconnect.sh settled
6aee12
+/sbin/initqueue --timeout --onetime --name nvmf-connect-timeout /sbin/nvmf-autoconnect.sh timeout
6aee12
-- 
6aee12
2.39.1
6aee12