ab0e4d
From f9883b51b1fafd30a91e9efda3260067a8f87ea5 Mon Sep 17 00:00:00 2001
ab0e4d
From: Enzo Matsumiya <ematsumiya@suse.de>
ab0e4d
Date: Mon, 3 Aug 2020 11:21:36 -0300
ab0e4d
Subject: [PATCH] 95nvmf: add NVMe over TCP support
ab0e4d
ab0e4d
Add support to boot from an NVMe over TCP device.
ab0e4d
ab0e4d
Example of supported command line formats:
ab0e4d
ab0e4d
nvme.discover=tcp:192.168.1.3::4420
ab0e4d
nvme.discover=tcp:192.168.1.3 # will use 4420 as default svcid
ab0e4d
ab0e4d
- Create is_nvmf() function to handle all fabrics types
ab0e4d
- Fix parse_nvmf_discover() to correctly use the default values
ab0e4d
- Auxiliary function to validate an IP connection
ab0e4d
- Fix inverted result for getargbool when reading "rd.nonvmf" command line parameter
ab0e4d
ab0e4d
Requires rd.neednet=1
ab0e4d
Requires adding/replacing STARTMODE in /etc/sysconfig/network/ifcfg-ethX to "nfsroot"
ab0e4d
to avoid shutdown hanging in initiator
ab0e4d
ab0e4d
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
ab0e4d
(cherry picked from commit 019610af266bcaef711715266bc0ca4be1044150)
ab0e4d
ab0e4d
Resolves: #1885417
ab0e4d
---
ab0e4d
 modules.d/95nvmf/module-setup.sh                | 25 ++++---
ab0e4d
 modules.d/95nvmf/parse-nvmf-boot-connections.sh | 97 ++++++++++++++++++-------
ab0e4d
 2 files changed, 84 insertions(+), 38 deletions(-)
ab0e4d
ab0e4d
diff --git a/modules.d/95nvmf/module-setup.sh b/modules.d/95nvmf/module-setup.sh
ab0e4d
index db43ec01..418b5e0c 100755
ab0e4d
--- a/modules.d/95nvmf/module-setup.sh
ab0e4d
+++ b/modules.d/95nvmf/module-setup.sh
ab0e4d
@@ -6,9 +6,9 @@ check() {
ab0e4d
     [ -f /etc/nvme/hostnqn ] || return 255
ab0e4d
     [ -f /etc/nvme/hostid ] || return 255
ab0e4d
 
ab0e4d
-    is_nvme_fc() {
ab0e4d
+    is_nvmf() {
ab0e4d
         local _dev=$1
ab0e4d
-        local traddr
ab0e4d
+        local trtype
ab0e4d
 
ab0e4d
         [[ -L "/sys/dev/block/$_dev" ]] || return 0
ab0e4d
         cd -P "/sys/dev/block/$_dev" || return 0
ab0e4d
@@ -18,19 +18,19 @@ check() {
ab0e4d
         for d in device/nvme* ; do
ab0e4d
             [ -L "$d" ] || continue
ab0e4d
             if readlink "$d" | grep -q nvme-fabrics ; then
ab0e4d
-                traddr=$(cat "$d"/address)
ab0e4d
-		break
ab0e4d
-	    fi
ab0e4d
-	done
ab0e4d
-        [[ "${traddr#traddr=nn-}" != "$traddr" ]]
ab0e4d
+                trtype=$(cat "$d"/transport)
ab0e4d
+                break
ab0e4d
+            fi
ab0e4d
+        done
ab0e4d
+        [[ "$trtype" == "fc" ]] || [[ "$trtype" == "tcp" ]] || [[ "$trtype" == "rdma" ]]
ab0e4d
     }
ab0e4d
 
ab0e4d
     [[ $hostonly ]] || [[ $mount_needs ]] && {
ab0e4d
         pushd . >/dev/null
ab0e4d
-        for_each_host_dev_and_slaves is_nvme_fc
ab0e4d
-        local _is_nvme_fc=$?
ab0e4d
+        for_each_host_dev_and_slaves is_nvmf
ab0e4d
+        local _is_nvmf=$?
ab0e4d
         popd >/dev/null
ab0e4d
-        [[ $_is_nvme_fc == 0 ]] || return 255
ab0e4d
+        [[ $_is_nvmf == 0 ]] || return 255
ab0e4d
         if [ ! -f /sys/class/fc/fc_udev_device/nvme_discovery ] ; then
ab0e4d
             if [ ! -f /etc/nvme/discovery.conf ] ; then
ab0e4d
                 echo "No discovery arguments present"
ab0e4d
@@ -43,13 +43,14 @@ check() {
ab0e4d
 
ab0e4d
 # called by dracut
ab0e4d
 depends() {
ab0e4d
-    echo bash rootfs-block
ab0e4d
+    echo bash rootfs-block network
ab0e4d
     return 0
ab0e4d
 }
ab0e4d
 
ab0e4d
 # called by dracut
ab0e4d
 installkernel() {
ab0e4d
     instmods nvme_fc lpfc qla2xxx
ab0e4d
+    hostonly="" instmods nvme_tcp nvme_fabrics
ab0e4d
 }
ab0e4d
 
ab0e4d
 # called by dracut
ab0e4d
@@ -76,6 +77,8 @@ install() {
ab0e4d
     inst_simple "/etc/nvme/hostnqn"
ab0e4d
     inst_simple "/etc/nvme/hostid"
ab0e4d
 
ab0e4d
+    inst_multiple ip sed
ab0e4d
+
ab0e4d
     inst_multiple nvme
ab0e4d
     inst_multiple -o \
ab0e4d
         "$systemdsystemunitdir/nvm*-connect@.service" \
ab0e4d
diff --git a/modules.d/95nvmf/parse-nvmf-boot-connections.sh b/modules.d/95nvmf/parse-nvmf-boot-connections.sh
ab0e4d
index 0d16b871..61c6dec1 100755
ab0e4d
--- a/modules.d/95nvmf/parse-nvmf-boot-connections.sh
ab0e4d
+++ b/modules.d/95nvmf/parse-nvmf-boot-connections.sh
ab0e4d
@@ -8,69 +8,102 @@
ab0e4d
 # Examples:
ab0e4d
 # nvmf.hostnqn=nqn.2014-08.org.nvmexpress:uuid:37303738-3034-584d-5137-333230423843
ab0e4d
 # nvmf.discover=rdma:192.168.1.3::4420
ab0e4d
+# nvme.discover=tcp:192.168.1.3::4420
ab0e4d
+# nvme.discover=tcp:192.168.1.3
ab0e4d
 # nvmf.discover=fc:auto
ab0e4d
 #
ab0e4d
 # Note: FC does autodiscovery, so typically there is no need to
ab0e4d
 # specify any discover parameters for FC.
ab0e4d
 #
ab0e4d
 
ab0e4d
+type is_ip >/dev/null 2>&1 || . /lib/net-lib.sh
ab0e4d
+
ab0e4d
+if getargbool 0 rd.nonvmf ; then
ab0e4d
+    warn "rd.nonvmf=0: skipping nvmf"
ab0e4d
+    return 0
ab0e4d
+fi
ab0e4d
+
ab0e4d
+initqueue --onetime modprobe --all -b -q nvme nvme_tcp nvme_core nvme_fabrics
ab0e4d
+
ab0e4d
+traddr="none"
ab0e4d
+trtype="none"
ab0e4d
+hosttraddr="none"
ab0e4d
+trsvcid=4420
ab0e4d
+
ab0e4d
+validate_ip_conn() {
ab0e4d
+    if ! getargbool 0 rd.neednet ; then
ab0e4d
+        warn "$trtype transport requires rd.neednet=1"
ab0e4d
+        return 1
ab0e4d
+    fi
ab0e4d
+
ab0e4d
+    local_address=$(ip -o route get to $traddr | sed -n 's/.*src \([0-9a-f.:]*\).*/\1/p')
ab0e4d
+
ab0e4d
+    # confirm we got a local IP address
ab0e4d
+    if ! is_ip "$local_address" ; then
ab0e4d
+        warn "$traddr is an invalid address";
ab0e4d
+        return 1
ab0e4d
+    fi
ab0e4d
+
ab0e4d
+    ifname=$(ip -o route get to $local_address | sed -n 's/.*dev \([^ ]*\).*/\1/p')
ab0e4d
+
ab0e4d
+    if ip l show "$ifname" >/dev/null 2>&1 ; then
ab0e4d
+       warn "invalid network interface $ifname"
ab0e4d
+       return 1
ab0e4d
+    fi
ab0e4d
+
ab0e4d
+    # confirm there's a route to destination
ab0e4d
+    if ip route get "$traddr" >/dev/null 2>&1 ; then
ab0e4d
+        warn "no route to $traddr"
ab0e4d
+        return 1
ab0e4d
+    fi
ab0e4d
+}
ab0e4d
+
ab0e4d
 parse_nvmf_discover() {
ab0e4d
     OLDIFS="$IFS"
ab0e4d
     IFS=:
ab0e4d
-    trtype="none"
ab0e4d
-    traddr="none"
ab0e4d
-    hosttraddr="none"
ab0e4d
-    trsvcid=4420
ab0e4d
-
ab0e4d
     set $1
ab0e4d
     IFS="$OLDIFS"
ab0e4d
 
ab0e4d
     case $# in
ab0e4d
         2)
ab0e4d
-            trtype=$1
ab0e4d
-            traddr=$2
ab0e4d
+            [ -n "$1" ] && trtype=$1
ab0e4d
+            [ -n "$2" ] && traddr=$2
ab0e4d
             ;;
ab0e4d
         3)
ab0e4d
-            trtype=$1
ab0e4d
-            traddr=$2
ab0e4d
-            hosttraddr=$3
ab0e4d
+            [ -n "$1" ] && trtype=$1
ab0e4d
+            [ -n "$2" ] && traddr=$2
ab0e4d
+            [ -n "$3" ] && hosttraddr=$3
ab0e4d
             ;;
ab0e4d
         4)
ab0e4d
-            trtype=$1
ab0e4d
-            traddr=$2
ab0e4d
-            hosttraddr=$3
ab0e4d
-            trsvcid=$4
ab0e4d
+            [ -n "$1" ] && trtype=$1
ab0e4d
+            [ -n "$2" ] && traddr=$2
ab0e4d
+            [ -n "$3" ] && hosttraddr=$3
ab0e4d
+            [ -n "$4" ] && trsvcid=$4
ab0e4d
             ;;
ab0e4d
         *)
ab0e4d
             warn "Invalid arguments for nvmf.discover=$1"
ab0e4d
             return 1
ab0e4d
             ;;
ab0e4d
     esac
ab0e4d
-    if [ -z "$traddr" ] ; then
ab0e4d
+    if [ "$traddr" = "none" ] ; then
ab0e4d
         warn "traddr is mandatory for $trtype"
ab0e4d
         return 1;
ab0e4d
     fi
ab0e4d
-    [ -z "$hosttraddr" ] && hosttraddr="none"
ab0e4d
-    [ -z "$trsvcid" ] && trsvcid="none"
ab0e4d
     if [ "$trtype" = "fc" ] ; then
ab0e4d
-        if [ -z "$hosttraddr" ] ; then
ab0e4d
+        if [ "$hosttraddr" = "none" ] ; then
ab0e4d
             warn "host traddr is mandatory for fc"
ab0e4d
             return 1
ab0e4d
         fi
ab0e4d
     elif [ "$trtype" != "rdma" ] && [ "$trtype" != "tcp" ] ; then
ab0e4d
         warn "unsupported transport $trtype"
ab0e4d
         return 1
ab0e4d
-    elif [ -z "$trsvcid" ] ; then
ab0e4d
-        trsvcid=4420
ab0e4d
+    fi
ab0e4d
+    if [ "$trtype" = "tcp" ]; then
ab0e4d
+        validate_ip_conn
ab0e4d
     fi
ab0e4d
     echo "--transport=$trtype --traddr=$traddr --host-traddr=$hosttraddr --trsvcid=$trsvcid" >> /etc/nvme/discovery.conf
ab0e4d
 }
ab0e4d
 
ab0e4d
-if ! getargbool 0 rd.nonvmf ; then
ab0e4d
-	info "rd.nonvmf=0: skipping nvmf"
ab0e4d
-	return 0
ab0e4d
-fi
ab0e4d
-
ab0e4d
 nvmf_hostnqn=$(getarg nvmf.hostnqn=)
ab0e4d
 if [ -n "$nvmf_hostnqn" ] ; then
ab0e4d
     echo "$nvmf_hostnqn" > /etc/nvme/hostnqn
ab0e4d
@@ -89,7 +122,17 @@ done
ab0e4d
 [ -f "/etc/nvme/hostid" ] || exit 0
ab0e4d
 
ab0e4d
 if [ -f "/etc/nvme/discovery.conf" ] ; then
ab0e4d
-    /sbin/initqueue --onetime --unique --name nvme-discover /usr/sbin/nvme connect-all
ab0e4d
+    if [ "$trtype" = "tcp" ] ; then
ab0e4d
+        /sbin/initqueue --settled --onetime --unique --name nvme-discover /usr/sbin/nvme connect-all
ab0e4d
+        > /tmp/net.$ifname.did-setup
ab0e4d
+    else
ab0e4d
+        /sbin/initqueue --onetime --unique --name nvme-discover /usr/sbin/nvme connect-all
ab0e4d
+    fi
ab0e4d
 else
ab0e4d
-    /sbin/initqueue --finished --unique --name nvme-fc-autoconnect echo 1 > /sys/class/fc/fc_udev_device/nvme_discovery
ab0e4d
+    if [ "$trtype" = "tcp" ] ; then
ab0e4d
+        /sbin/initqueue --settled --onetime --unique /usr/sbin/nvme connect-all -t tcp -a $traddr -s $trsvcid
ab0e4d
+        > /tmp/net.$ifname.did-setup
ab0e4d
+    else
ab0e4d
+        /sbin/initqueue --finished --unique --name nvme-fc-autoconnect echo 1 > /sys/class/fc/fc_udev_device/nvme_discovery
ab0e4d
+    fi
ab0e4d
 fi
ab0e4d