Whamcloud - gitweb
LU-15983 lnet: Define KFILND network type
[fs/lustre-release.git] / lustre / tests / sanity-lnet.sh
index 784ad85..bc67e12 100755 (executable)
@@ -12,12 +12,6 @@ ONLY=${ONLY:-"$*"}
 ALWAYS_EXCEPT="$SANITY_LNET_EXCEPT "
 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
 
-# skip the grant tests for ARM until they are fixed
-if [[ $(uname -m) = aarch64 ]]; then
-       # bug number:    LU-14067
-       ALWAYS_EXCEPT+=" 300"
-fi
-
 [ "$SLOW" = "no" ] && EXCEPT_SLOW=""
 
 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
@@ -25,7 +19,7 @@ LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
 . $LUSTRE/tests/test-framework.sh
 CLEANUP=${CLEANUP:-:}
 SETUP=${SETUP:-:}
-init_test_env $@
+init_test_env "$@"
 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
 init_logging
 
@@ -56,7 +50,7 @@ fi
 cleanup_testsuite() {
        trap "" EXIT
        # Cleanup any tmp files created by the sub tests
-       rm -f $TMP/sanity-lnet*
+       rm -f $TMP/sanity-lnet-*.yaml $LNET_PARAMS_FILE
        cleanup_netns
        cleanup_lnet
        if $restore_mounts; then
@@ -68,39 +62,11 @@ cleanup_testsuite() {
        return 0
 }
 
-load_lnet() {
-       load_module ../libcfs/libcfs/libcfs
-       # Prevent local MODOPTS_LIBCFS being passed as part of environment
-       # variable to remote nodes
-       unset MODOPTS_LIBCFS
-
-       set_default_debug "neterror net nettrace malloc"
-       load_module ../lnet/lnet/lnet "$@"
-
-       LNDPATH=${LNDPATH:-"../lnet/klnds"}
-       if [ -z "$LNETLND" ]; then
-               case $NETTYPE in
-               o2ib*)  LNETLND="o2iblnd/ko2iblnd" ;;
-               tcp*)   LNETLND="socklnd/ksocklnd" ;;
-               *)      local lnd="${NETTYPE%%[0-9]}lnd"
-                       [ -f "$LNDPATH/$lnd/k$lnd.ko" ] &&
-                               LNETLND="$lnd/k$lnd" ||
-                               LNETLND="socklnd/ksocklnd"
-               esac
-       fi
-       load_module ../lnet/klnds/$LNETLND
-}
-
-do_lnetctl() {
-       echo "$LNETCTL $@"
-       $LNETCTL "$@"
-}
-
 TESTNS='test_ns'
 FAKE_IF="test1pg"
 FAKE_IP="10.1.2.3"
 do_ns() {
-       echo "ip netns exec $TESTNS $@"
+       echo "ip netns exec $TESTNS $*"
        ip netns exec $TESTNS "$@"
 }
 
@@ -195,7 +161,7 @@ validate_nid() {
        local num_re='[0-9]\+'
        local ip_re="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
 
-       if [[ $net =~ gni[0-9]* ]]; then
+       if [[ $net =~ gni[0-9]* ]] || [[ $net =~ kfi[0-9]* ]]; then
                [[ $addr =~ ${num_re} ]] && return 0
        else
                [[ $addr =~ ${ip_re} ]] && return 0
@@ -249,23 +215,12 @@ cleanupall -f
 setup_netns || error "setup_netns failed with $?"
 
 # Determine the local interface(s) used for LNet
-load_modules || error "Failed to load modules"
-NIDS=( $($LCTL list_nids | xargs echo) )
-if [[ -z ${NIDS[@]} ]]; then
-       error "No NID configured after module load"
-fi
+load_lnet "config_on_load=1" || error "Failed to load modules"
 
-declare -a INTERFACES
-for ((i = 0; i < ${#NIDS[@]}; i++)); do
-       ip=$(sed 's/^\(.*\)@.*$/\1/'<<<${NIDS[i]})
-       INTERFACES[i]=$(ip -o a s |
-                       awk '$4 ~ /^'$ip'\//{print $2}')
-       if [[ -z ${INTERFACES[i]} ]]; then
-               error "Can't determine interface name for NID ${NIDS[i]}"
-       elif [[ 1 -ne $(wc -w <<<${INTERFACES[i]}) ]]; then
-               error "Found $(wc -w <<<${INTERFACES[i]}) interfaces for NID ${NIDS[i]}. Expect 1"
-       fi
-done
+do_lnetctl net show
+ip a
+
+INTERFACES=( $(lnet_if_list) )
 
 cleanup_lnet || error "Failed to cleanup LNet"
 
@@ -403,10 +358,17 @@ peer:
         - nid: 6.6.3.6@o2ib
         - nid: 6@gni
         - nid: 10@gni
+        - nid: 6@kfi
+        - nid: 10@kfi
 EOF
        append_global_yaml
-       compare_peer_add "6.6.6.6@tcp" \
-               "6.6.[6-7].[0-4/2]@tcp,6.6.[1-4/2].[0-6/3]@o2ib,[6-12/4]@gni"
+
+       local nid_expr="6.6.[6-7].[0-4/2]@tcp"
+       nid_expr+=",6.6.[1-4/2].[0-6/3]@o2ib"
+       nid_expr+=",[6-12/4]@gni"
+       nid_expr+=",[6-12/4]@kfi"
+
+       compare_peer_add "6.6.6.6@tcp" "${nid_expr}"
 }
 run_test 6 "Add peer with multiple nidranges"
 
@@ -459,9 +421,18 @@ test_7() {
                error "Peer add failed $?"
        compare_peer_del "7@gni"
 
-       echo "Delete peer that has tcp, o2ib and gni nids"
+       echo "Delete peer with single nid (kfi)"
+       do_lnetctl peer add --prim_nid 7@kfi || error "Peer add failed $?"
+       compare_peer_del "7@kfi"
+
+       echo "Delete peer that has multiple nids (kfi)"
+       do_lnetctl peer add --prim_nid 7@kfi --nid [8-12]@kfi ||
+               error "Peer add failed $?"
+       compare_peer_del "7@kfi"
+
+       echo "Delete peer that has tcp, o2ib, gni and kfi nids"
        do_lnetctl peer add --prim_nid 7@gni \
-               --nid [8-12]@gni,7.7.7.[9-12]@tcp,7.7.7.[13-15]@o2ib ||
+               --nid [8-12]@gni,7.7.7.[1-4]@tcp,7.7.7.[5-9]@o2ib,[1-5]@kfi ||
                error "Peer add failed $?"
        compare_peer_del "7@gni"
 }
@@ -593,7 +564,7 @@ create_nid() {
        local num="$1"
        local net="$2"
 
-       if [[ $net =~ gni* ]]; then
+       if [[ $net =~ gni* ]] || [[ $net =~ kfi* ]]; then
                echo "${num}@${net}"
        else
                echo "${num}.${num}.${num}.${num}@${net}"
@@ -1254,7 +1225,29 @@ EOF
 }
 run_test 104 "Set/check response_tracking param"
 
-### load lnet in default namespace, configure in target namespace
+test_105() {
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}"
+       do_lnetctl route add --net tcp105 --gateway 105.105.105.105@tcp ||
+               error "route add failed $?"
+       do_lnetctl peer add --prim 105.105.105.105@tcp &&
+               error "peer add should fail"
+
+       return 0
+}
+run_test 105 "Adding duplicate GW peer should fail"
+
+test_106() {
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}"
+       do_lnetctl route add --net tcp106 --gateway 106.106.106.106@tcp ||
+               error "route add failed $?"
+       do_lnetctl peer del --prim 106.106.106.106@tcp &&
+               error "peer del should fail"
+
+       return 0
+}
+run_test 106 "Deleting GW peer should fail"
 
 test_200() {
        cleanup_lnet || exit 1
@@ -1314,18 +1307,12 @@ function lnet_health_pre() {
        $LNETCTL set transaction_timeout 10 ||
                error "Failed to set transaction_timeout $?"
 
-       # Increase recovery interval so we have time to capture health values
-       $LNETCTL set recovery_interval 20 ||
-               error "Failed to set recovery_interval $?"
-
        RETRY_PARAM=$($LNETCTL global show | awk '/retry_count/{print $NF}')
        RSND_PRE=$($LNETCTL stats show | awk '/resend_count/{print $NF}')
        LO_HVAL_PRE=$($LNETCTL net show -v 2 | awk '/health value/{print $NF}' |
                      xargs echo | sed 's/ /+/g' | bc -l)
 
-       local my_nid=$($LCTL list_nids | head -n 1)
-
-       RMT_HVAL_PRE=$($LNETCTL peer show --nid $my_nid -v 2 2>/dev/null |
+       RMT_HVAL_PRE=$($LNETCTL peer show --nid ${RNIDS[0]} -v 2 2>/dev/null |
                       awk '/health value/{print $NF}' | xargs echo |
                       sed 's/ /+/g' | bc -l)
 
@@ -1341,9 +1328,7 @@ function lnet_health_post() {
                       awk '/health value/{print $NF}' |
                       xargs echo | sed 's/ /+/g' | bc -l)
 
-       local my_nid=$($LCTL list_nids | head -n 1)
-
-       RMT_HVAL_POST=$($LNETCTL peer show --nid $my_nid -v 2 2>/dev/null |
+       RMT_HVAL_POST=$($LNETCTL peer show --nid ${RNIDS[0]} -v 2 2>/dev/null |
                        awk '/health value/{print $NF}' | xargs echo |
                        sed 's/ /+/g' | bc -l)
 
@@ -1361,6 +1346,9 @@ function lnet_health_post() {
 
        restore_lnet_params
 
+       do_lnetctl peer set --health 1000 --all
+       do_lnetctl net set --health 1000 --all
+
        return 0
 }
 
@@ -1414,48 +1402,177 @@ function check_remote_health() {
        return 0
 }
 
+RNODE=""
+RLOADED=false
+NET_DEL_ARGS=""
+RNIDS=( )
+LNIDS=( )
+setup_health_test() {
+       local need_mr=$1
+       local rc=0
+
+       local rnodes=$(remote_nodes_list)
+       [[ -z $rnodes ]] && skip "Need at least 1 remote node"
+
+       cleanup_lnet || error "Failed to cleanup before test execution"
+
+       # Loading modules should configure LNet with the appropriate
+       # test-framework configuration
+       load_lnet "config_on_load=1" || error "Failed to load modules"
+
+       LNIDS=( $($LCTL list_nids | xargs echo) )
+
+       RNODE=$(awk '{print $1}' <<<$rnodes)
+       RNIDS=( $(do_node $RNODE $LCTL list_nids | xargs echo) )
+
+       if [[ -z ${RNIDS[@]} ]]; then
+               do_rpc_nodes $RNODE load_lnet "config_on_load=1"
+               RLOADED=true
+               RNIDS=( $(do_node $RNODE $LCTL list_nids | xargs echo) )
+       fi
+
+       [[ ${#LNIDS[@]} -lt 1 ]] &&
+               error "No NIDs configured for local host $HOSTNAME"
+       [[ ${#RNIDS[@]} -lt 1 ]] &&
+               error "No NIDs configured for remote host $RNODE"
+
+       do_lnetctl discover ${RNIDS[0]} ||
+               error "Unable to discover ${RNIDS[0]}"
+
+       local mr=$($LNETCTL peer show --nid ${RNIDS[0]} |
+                  awk '/Multi-Rail/{print $NF}')
+
+       if ${need_mr} && [[ $mr == False ]]; then
+               cleanup_health_test || return $?
+               skip "Need MR peer"
+       fi
+
+       if ( ! ${need_mr} && [[ ${#RNIDS[@]} -gt 1 ]] ) ||
+          ( ! ${need_mr} && [[ ${#LNIDS[@]} -gt 1 ]] ); then
+               cleanup_health_test || return $?
+               skip "Need SR peer"
+       fi
+
+       if ${need_mr} && [[ ${#RNIDS[@]} -lt 2 ]]; then
+               # Add a second, reachable NID to rnode.
+               local net=${RNIDS[0]}
+
+               net="${net//*@/}1"
+
+               local if=$(do_rpc_nodes --quiet $RNODE lnet_if_list)
+               [[ -z $if ]] &&
+                       error "Failed to determine interface for $RNODE"
+
+               do_rpc_nodes $RNODE "$LNETCTL lnet configure"
+               do_rpc_nodes $RNODE "$LNETCTL net add --net $net --if $if" ||
+                       rc=$?
+               if [[ $rc -ne 0 ]]; then
+                       error "Failed to add interface to $RNODE rc=$?"
+               else
+                       RNIDS[1]="${RNIDS[0]}1"
+                       NET_DEL_ARGS="--net $net --if $if"
+               fi
+       fi
+
+       if ${need_mr} && [[ ${#LNIDS[@]} -lt 2 ]]; then
+               local net=${LNIDS[0]}
+               net="${net//*@/}1"
+
+               do_lnetctl lnet configure &&
+                       do_lnetctl net add --net $net --if ${INTERFACES[0]} ||
+                       rc=$?
+               if [[ $rc -ne 0 ]]; then
+                       error "Failed to add interface rc=$?"
+               else
+                       LNIDS[1]="${LNIDS[0]}1"
+               fi
+       fi
+
+       $LNETCTL net show
+
+       $LNETCTL peer show -v 2 | egrep -e nid -e health
+
+       $LCTL set_param debug=+net
+
+       return 0
+
+}
+
+cleanup_health_test() {
+       local rc=0
+
+       if [[ -n $NET_DEL_ARGS ]]; then
+               do_rpc_nodes $RNODE \
+                       "$LNETCTL net del $NET_DEL_ARGS" ||
+                       rc=$((rc + $?))
+               NET_DEL_ARGS=""
+       fi
+
+       unload_modules || rc=$?
+
+       if $RLOADED; then
+               do_rpc_nodes $RNODE unload_modules_local ||
+                       rc=$((rc + $?))
+               RLOADED=false
+       fi
+
+       [[ $rc -ne 0 ]] &&
+               error "Failed cleanup"
+
+       return $rc
+}
+
+add_health_test_drop_rules() {
+       local hstatus=$1
+       local lnid rnid
+
+       for lnid in "${LNIDS[@]}"; do
+               for rnid in "${RNIDS[@]}"; do
+                       $LCTL net_drop_add -s $lnid -d $rnid -m GET -r 1 -e ${hstatus}
+               done
+       done
+}
+
 # See lnet/lnet/lib-msg.c:lnet_health_check()
 LNET_LOCAL_RESEND_STATUSES="local_interrupt local_dropped local_aborted"
 LNET_LOCAL_RESEND_STATUSES+=" local_no_route local_timeout"
 LNET_LOCAL_NO_RESEND_STATUSES="local_error"
 test_204() {
-       reinit_dlc || return $?
-       add_net "tcp" "${INTERFACES[0]}" || return $?
-
-       lnet_health_pre || return $?
+       setup_health_test false || return $?
 
        local hstatus
        for hstatus in ${LNET_LOCAL_RESEND_STATUSES} \
                       ${LNET_LOCAL_NO_RESEND_STATUSES}; do
                echo "Simulate $hstatus"
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+               lnet_health_pre || return $?
+
+               add_health_test_drop_rules ${hstatus}
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
                $LCTL net_drop_del -a
-       done
 
-       lnet_health_post
+               lnet_health_post
 
-       check_no_resends || return $?
-       check_no_local_health || return $?
+               check_no_resends || return $?
+               check_no_local_health || return $?
+       done
+
+       cleanup_health_test || return $?
 
        return 0
 }
 run_test 204 "Check no health or resends for single-rail local failures"
 
 test_205() {
+       setup_health_test true || return $?
+
        local hstatus
        for hstatus in ${LNET_LOCAL_RESEND_STATUSES}; do
-               reinit_dlc || return $?
-               add_net "tcp" "${INTERFACES[0]}" || return $?
-               add_net "tcp1" "${INTERFACES[0]}" || return $?
-
                echo "Simulate $hstatus"
-               lnet_health_pre
+               lnet_health_pre || return $?
 
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+               add_health_test_drop_rules ${hstatus}
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
                $LCTL net_drop_del -a
 
@@ -1466,16 +1583,11 @@ test_205() {
        done
 
        for hstatus in ${LNET_LOCAL_NO_RESEND_STATUSES}; do
-               reinit_dlc || return $?
-               add_net "tcp" "${INTERFACES[0]}" || return $?
-               add_net "tcp1" "${INTERFACES[0]}" || return $?
-
                echo "Simulate $hstatus"
                lnet_health_pre || return $?
 
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+               add_health_test_drop_rules ${hstatus}
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
                $LCTL net_drop_del -a
 
@@ -1485,6 +1597,8 @@ test_205() {
                check_local_health || return $?
        done
 
+       cleanup_health_test || return $?
+
        return 0
 }
 run_test 205 "Check health and resends for multi-rail local failures"
@@ -1493,81 +1607,77 @@ run_test 205 "Check health and resends for multi-rail local failures"
 LNET_REMOTE_RESEND_STATUSES="remote_dropped"
 LNET_REMOTE_NO_RESEND_STATUSES="remote_error remote_timeout"
 test_206() {
-       reinit_dlc || return $?
-       add_net "tcp" "${INTERFACES[0]}" || return $?
-
-       do_lnetctl discover $($LCTL list_nids | head -n 1) ||
-               error "failed to discover myself"
-
-       lnet_health_pre || return $?
+       setup_health_test false || return $?
 
        local hstatus
        for hstatus in ${LNET_REMOTE_RESEND_STATUSES} \
                       ${LNET_REMOTE_NO_RESEND_STATUSES}; do
                echo "Simulate $hstatus"
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+               lnet_health_pre || return $?
+
+               add_health_test_drop_rules ${hstatus}
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
                $LCTL net_drop_del -a
-       done
 
-       lnet_health_post
+               lnet_health_post
 
-       check_no_resends || return $?
-       check_no_local_health || return $?
-       check_no_remote_health || return $?
+               check_no_resends || return $?
+               check_no_local_health || return $?
+               check_no_remote_health || return $?
+       done
+
+       cleanup_health_test || return $?
 
        return 0
 }
 run_test 206 "Check no health or resends for single-rail remote failures"
 
 test_207() {
+       setup_health_test true || return $?
+
        local hstatus
        for hstatus in ${LNET_REMOTE_RESEND_STATUSES}; do
-               reinit_dlc || return $?
-               add_net "tcp" "${INTERFACES[0]}" || return $?
-               add_net "tcp1" "${INTERFACES[0]}" || return $?
-
-               do_lnetctl discover $($LCTL list_nids | head -n 1) ||
-                       error "failed to discover myself"
-
                echo "Simulate $hstatus"
                lnet_health_pre || return $?
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+
+               add_health_test_drop_rules ${hstatus}
+
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
-               $LCTL net_drop_del -a
 
                lnet_health_post
 
+               $LCTL net_drop_del -a
+
                check_resends || return $?
                check_no_local_health || return $?
                check_remote_health || return $?
+               do_lnetctl peer set --health 1000 --all ||
+                       error "Unable to reset health rc=$?"
        done
        for hstatus in ${LNET_REMOTE_NO_RESEND_STATUSES}; do
-               reinit_dlc || return $?
-               add_net "tcp" "${INTERFACES[0]}" || return $?
-               add_net "tcp1" "${INTERFACES[0]}" || return $?
-
-               do_lnetctl discover $($LCTL list_nids | head -n 1) ||
-                       error "failed to discover myself"
-
                echo "Simulate $hstatus"
                lnet_health_pre || return $?
-               $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e ${hstatus}
-               $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e ${hstatus}
-               do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+
+               add_health_test_drop_rules ${hstatus}
+
+               do_lnetctl discover ${RNIDS[0]} &&
                        error "Should have failed"
-               $LCTL net_drop_del -a
 
                lnet_health_post
 
+               $LCTL net_drop_del -a
+
                check_no_resends || return $?
                check_no_local_health || return $?
                check_remote_health || return $?
+               do_lnetctl peer set --health 1000 --all ||
+                       error "Unable to reset health rc=$?"
        done
 
+       cleanup_health_test || return $?
+
        return 0
 }
 run_test 207 "Check health and resends for multi-rail remote errors"
@@ -1613,6 +1723,7 @@ test_208() {
        local if0_ip=$(ip --oneline addr show dev ${INTERFACES[0]} |
                       awk '/inet /{print $4}' |
                       sed 's:/.*::')
+       if0_ip=($(echo "${if0_ip[@]}" | tr ' ' '\n' | uniq | tr '\n' ' '))
        local ip2nets_str="tcp(${INTERFACES[0]}) $if0_ip"
 
        echo "Configure single NID \"$ip2nets_str\""
@@ -1655,17 +1766,14 @@ test_208() {
 run_test 208 "Test various kernel ip2nets configurations"
 
 test_209() {
-       reinit_dlc || return $?
-       add_net "tcp" "${INTERFACES[0]}" || return $?
-
-       do_lnetctl discover $($LCTL list_nids | head -n 1) ||
-               error "failed to discover myself"
+       setup_health_test false || return $?
 
        echo "Simulate network_timeout w/SR config"
        lnet_health_pre
 
-       $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e network_timeout
-       do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+       add_health_test_drop_rules network_timeout
+
+       do_lnetctl discover ${RNIDS[0]} &&
                error "Should have failed"
        $LCTL net_drop_del -a
 
@@ -1675,19 +1783,17 @@ test_209() {
        check_no_local_health || return $?
        check_no_remote_health || return $?
 
-       reinit_dlc || return $?
-       add_net "tcp" "${INTERFACES[0]}" || return $?
-       add_net "tcp1" "${INTERFACES[0]}" || return $?
+       cleanup_health_test || return $?
 
-       do_lnetctl discover $($LCTL list_nids | head -n 1) ||
-               error "failed to discover myself"
+       setup_health_test true || return $?
 
        echo "Simulate network_timeout w/MR config"
+
        lnet_health_pre
 
-       $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e network_timeout
-       $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e network_timeout
-       do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+       add_health_test_drop_rules network_timeout
+
+       do_lnetctl discover ${RNIDS[0]} &&
                error "Should have failed"
        $LCTL net_drop_del -a
 
@@ -1697,6 +1803,8 @@ test_209() {
        check_local_health || return $?
        check_remote_health || return $?
 
+       cleanup_health_test || return $?
+
        return 0
 }
 run_test 209 "Check health, but not resends, for network timeout"
@@ -1708,7 +1816,7 @@ check_nid_in_recovq() {
        local found=false
        local nid=""
 
-       echo "Check recovery queue"
+       echo "Check \"$1\" recovery queue"
        echo "$recovq"
        if [[ $(grep -c 'nid-'<<<$recovq) -ne $expect ]]; then
                error "Expect $expect NIDs found: \"$recovq\""
@@ -1739,6 +1847,18 @@ check_nid_in_recovq() {
 # If the recovery limit is 10 seconds, then when the 5th enqueue happens
 # we expect the peer NI to have aged out, so it will not actually be
 # queued.
+# If max_recovery_ping_interval is set to 2 then:
+#  First enqueue happens at time 0.
+#  2nd at 0 + 2^0 = 1
+#  3rd at 1 + 2^1 = 3
+#  4th at 3 + 2^1 = 5
+#  5th at 5 + 2^1 = 7
+#  6th at 7 + 2^1 = 9
+#  7th at 9 + 2^1 = 11
+# e.g. after 4 seconds we would expect to have seen the 3th enqueue,
+# (2 pings sent, 3rd about to happen), and the 4th enqueue is yet to happen
+# e.g. after 10 seconds we would expect to have seen the 6th enqueue,
+# (5 pings sent, 6th about to happen), and the 8th enqueue is yet to happen
 check_ping_count() {
        local queue="$1"
        local expect="$2"
@@ -1760,7 +1880,7 @@ check_ping_count() {
 
        local count
        local found=false
-       for count in ${ping_count[@]}; do
+       for count in "${ping_count[@]}"; do
                if [[ $count -eq $expect ]]; then
                        if [[ $expect -ne 0 ]] && $found ; then
                                error "Found more than one interface matching \"$expect\" ping count"
@@ -1788,6 +1908,8 @@ test_210() {
        do_lnetctl discover $prim_nid ||
                error "failed to discover myself"
 
+       local default=$($LNETCTL global show |
+                       awk '/recovery_limit/{print $NF}')
        # Set recovery limit to 10 seconds.
        do_lnetctl set recovery_limit 10 ||
                error "failed to set recovery_limit"
@@ -1796,20 +1918,59 @@ test_210() {
        # Use local_error so LNet doesn't attempt to resend the discovery ping
        $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e local_error
        $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e local_error
-       do_lnetctl discover $($LCTL list_nids | head -n 1) &&
+       do_lnetctl discover $prim_nid &&
                error "Expected discovery to fail"
 
+       # See comment for check_ping_count()
        sleep 5
-       check_nid_in_recovq "-l" 1
+       check_nid_in_recovq "-l" "1"
        check_ping_count "ni" "2"
 
        sleep 5
 
-       check_nid_in_recovq "-l" 1
+       check_nid_in_recovq "-l" "1"
        check_ping_count "ni" "3"
 
        $LCTL net_drop_del -a
 
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       add_net "tcp1" "${INTERFACES[0]}" || return $?
+
+       local prim_nid=$($LCTL list_nids | head -n 1)
+
+       do_lnetctl discover $prim_nid ||
+               error "failed to discover myself"
+
+       do_lnetctl set recovery_limit $default ||
+               error "failed to set recovery_limit"
+
+       default=$($LNETCTL global show |
+                 awk '/max_recovery_ping_interval/{print $NF}')
+       do_lnetctl set max_recovery_ping_interval 2 ||
+               error "failed to set max_recovery_ping_interval"
+
+       $LCTL set_param debug=+net
+       # Use local_error so LNet doesn't attempt to resend the discovery ping
+       $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e local_error
+       $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e local_error
+       do_lnetctl discover $prim_nid &&
+               error "Expected discovery to fail"
+
+       # See comment for check_ping_count()
+       sleep 4
+       check_nid_in_recovq "-l" "1"
+       check_ping_count "ni" "2"
+
+       sleep 6
+       check_nid_in_recovq "-l" "1"
+       check_ping_count "ni" "5"
+
+       $LCTL net_drop_del -a
+
+       do_lnetctl set max_recovery_ping_interval $default ||
+               error "failed to set max_recovery_ping_interval"
+
        return 0
 }
 run_test 210 "Local NI recovery checks"
@@ -1824,6 +1985,8 @@ test_211() {
        do_lnetctl discover $prim_nid ||
                error "failed to discover myself"
 
+       local default=$($LNETCTL global show |
+                       awk '/recovery_limit/{print $NF}')
        # Set recovery limit to 10 seconds.
        do_lnetctl set recovery_limit 10 ||
                error "failed to set recovery_limit"
@@ -1868,6 +2031,44 @@ test_211() {
        check_nid_in_recovq "-p" 0
        check_ping_count "peer_ni" "0"
 
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       add_net "tcp1" "${INTERFACES[0]}" || return $?
+
+       local prim_nid=$($LCTL list_nids | head -n 1)
+
+       do_lnetctl discover $prim_nid ||
+               error "failed to discover myself"
+
+       do_lnetctl set recovery_limit $default ||
+               error "failed to set recovery_limit"
+
+       default=$($LNETCTL global show |
+                 awk '/max_recovery_ping_interval/{print $NF}')
+       do_lnetctl set max_recovery_ping_interval 2 ||
+               error "failed to set max_recovery_ping_interval"
+
+       $LCTL net_drop_add -s *@tcp -d *@tcp -m GET -r 1 -e remote_error
+       $LCTL net_drop_add -s *@tcp1 -d *@tcp1 -m GET -r 1 -e remote_error
+
+       # Set health to 0 on one interface. This forces it onto the recovery
+       # queue.
+       $LNETCTL peer set --nid $prim_nid --health 0
+
+       # See comment for check_ping_count()
+       sleep 4
+       check_nid_in_recovq "-p" "1"
+       check_ping_count "peer_ni" "2"
+
+       sleep 6
+       check_nid_in_recovq "-p" "1"
+       check_ping_count "peer_ni" "5"
+
+       $LCTL net_drop_del -a
+
+       do_lnetctl set max_recovery_ping_interval $default ||
+               error "failed to set max_recovery_ping_interval"
+
        return 0
 }
 run_test 211 "Remote NI recovery checks"
@@ -1880,7 +2081,7 @@ test_212() {
 
        # Loading modules should configure LNet with the appropriate
        # test-framework configuration
-       load_modules || error "Failed to load modules"
+       load_lnet "config_on_load=1" || error "Failed to load modules"
 
        local my_nid=$($LCTL list_nids | head -n 1)
        [[ -z $my_nid ]] &&
@@ -1891,7 +2092,7 @@ test_212() {
        local rloaded=false
 
        if [[ -z $rnodenids ]]; then
-               do_rpc_nodes $rnode load_modules_local
+               do_rpc_nodes $rnode load_lnet "config_on_load=1"
                rloaded=true
                rnodenids=$(do_node $rnode $LCTL list_nids | xargs echo)
        fi
@@ -1998,12 +2199,311 @@ test_213() {
 }
 run_test 213 "Check LNetDist calculation for multiple local NIDs"
 
+function check_ni_status() {
+       local nid="$1"
+       local expect="$2"
+
+       local status=$($LNETCTL net show |
+                      grep -A 1 ${nid} |
+                      awk '/status/{print $NF}')
+
+       echo "NI ${nid} expect status \"${expect}\" found \"${status}\""
+       if [[ $status != $expect ]]; then
+               error "Error: Expect NI status \"$expect\" for NID \"$nid\" but found \"$status\""
+       fi
+
+       return 0
+}
+
+test_214() {
+       cleanup_netns || error "Failed to cleanup netns before test execution"
+       cleanup_lnet || error "Failed to unload modules before test execution"
+
+       setup_fakeif || error "Failed to add fake IF"
+       have_interface "$FAKE_IF" ||
+               error "Expect $FAKE_IF configured but not found"
+
+       reinit_dlc || return $?
+
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       add_net "tcp" "$FAKE_IF" || return $?
+
+       local nid1=$(lctl list_nids | head -n 1)
+       local nid2=$(lctl list_nids | tail --lines 1)
+
+       check_ni_status "0@lo" up
+       check_ni_status "$nid1" up
+       check_ni_status "$nid2" up
+
+       echo "Set $FAKE_IF down"
+       echo "ip link set dev $FAKE_IF down"
+       ip link set dev $FAKE_IF down
+       check_ni_status "0@lo" up
+       check_ni_status "$nid1" up
+       check_ni_status "$nid2" down
+}
+run_test 214 "Check local NI status when link is downed"
+
+get_ni_stat() {
+       local nid=$1
+       local stat=$2
+
+       $LNETCTL net show -v 2 |
+               egrep -e nid -e $stat |
+               grep -wA 1 $nid |
+               awk '/'$stat':/{print $NF}'
+}
+
+ni_stats_pre() {
+       local nidvar s
+       for nidvar in nid1 nid2; do
+               for stat in send_count recv_count; do
+                       s=$(get_ni_stat ${!nidvar} $stat)
+                       eval ${nidvar}_pre_${stat}=$s
+               done
+       done
+}
+
+ni_stats_post() {
+       local nidvar s
+       for nidvar in nid1 nid2; do
+               for stat in send_count recv_count; do
+                       s=$(get_ni_stat ${!nidvar} $stat)
+                       eval ${nidvar}_post_${stat}=$s
+               done
+       done
+}
+
+ni_stat_changed() {
+       local nidvar=$1
+       local stat=$2
+
+       local pre post
+       eval pre=\${${nidvar}_pre_${stat}}
+       eval post=\${${nidvar}_post_${stat}}
+
+       echo "${!nidvar} pre ${stat} $pre post ${stat} $post"
+
+       [[ $pre -ne $post ]]
+}
+
+test_215() {
+       cleanup_netns || error "Failed to cleanup netns before test execution"
+       cleanup_lnet || error "Failed to unload modules before test execution"
+
+       reinit_dlc || return $?
+
+       add_net "tcp1" "${INTERFACES[0]}" || return $?
+       add_net "tcp2" "${INTERFACES[0]}" || return $?
+
+       local nid1=$($LCTL list_nids | head -n 1)
+       local nid2=$($LCTL list_nids | tail --lines 1)
+
+       do_lnetctl peer add --prim $nid1 --nid $nid2 ||
+               error "Failed to add peer"
+
+       local npings=25
+
+       for nidvarA in nid1 nid2; do
+               src=${!nidvarA}
+               dst=${!nidvarA}
+               for nidvarB in nid1 nid2; do
+                       [[ $nidvarA == $nidvarB ]] && continue
+
+                       ni_stats_pre
+
+                       echo "$LNETCTL ping $dst x $npings"
+                       for i in $(seq 1 $npings); do
+                               $LNETCTL ping $dst &>/dev/null ||
+                                       error "$LNETCTL ping $dst failed"
+                       done
+
+                       ni_stats_post
+
+                       # No source specified, sends to either NID should cause
+                       # counts to increase across both NIs
+                       for nidvar in nid1 nid2; do
+                               for stat in send_count recv_count; do
+                                       ni_stat_changed $nidvar $stat ||
+                                               error "$stat unchanged for ${!nidvar}"
+                               done
+                       done
+
+                       ni_stats_pre
+
+                       echo "$LNETCTL ping --source $src $dst x $npings"
+                       for i in $(seq 1 $npings); do
+                               $LNETCTL ping --source $src $dst &>/dev/null ||
+                                       error "$LNETCTL ping --source $src $dst failed"
+                       done
+
+                       ni_stats_post
+
+                       # src nid == dest nid means stats for the _other_ NI
+                       # should be unchanged
+                       for nidvar in nid1 nid2; do
+                               for stat in send_count recv_count; do
+                                       if [[ ${!nidvar} == $src ]]; then
+                                               ni_stat_changed $nidvar $stat ||
+                                                       error "$stat unchanged for ${!nidvar}"
+                                       else
+                                               ni_stat_changed $nidvar $stat &&
+                                                       error "$stat changed for ${!nidvar}"
+                                       fi
+                               done
+                       done
+               done
+               # Double number of pings for next iteration because the net
+               # sequence numbers will have diverged
+               npings=$(($npings * 2))
+       done
+
+       # Ping from nid1 to nid2 should fail
+       do_lnetctl ping --source $nid1 $nid2 &&
+               error "ping from $nid1 to $nid2 should fail"
+
+       # Ping from nid2 to nid1 should fail
+       do_lnetctl ping --source $nid2 $nid1 &&
+               error "ping from $nid2 to $nid1 should fail"
+
+       return 0
+}
+run_test 215 "Test lnetctl ping --source option"
+
+test_216() {
+       local rc=0
+
+       reinit_dlc || return $?
+
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       add_net "tcp1" "${INTERFACES[0]}" || return $?
+
+       local nids=( $($LCTL list_nids | xargs echo) )
+
+       do_lnetctl discover ${nids[0]} ||
+               error "Initial discovery failed"
+
+       do_lnetctl ping --source ${nids[0]} ${nids[0]} ||
+               error "Initial ping failed $?"
+
+       do_lnetctl ping --source ${nids[1]} ${nids[1]} ||
+               error "Initial ping failed $?"
+
+       local src dst
+       for src in "${nids[@]}"; do
+               for dst in "${nids[@]}"; do
+                       $LCTL net_drop_add -r 1 -s $src -d $dst -e network_timeout
+               done
+       done
+
+       do_lnetctl ping ${nids[0]} || rc=$?
+
+       $LCTL net_drop_del -a
+
+       [[ $rc -eq 0 ]] &&
+               error "expected ping to fail"
+
+       check_nid_in_recovq "-p" 0
+       check_nid_in_recovq "-l" 1
+
+       return 0
+}
+run_test 216 "Failed send to peer NI owned by local host should not trigger peer NI recovery"
+
+test_217() {
+       reinit_dlc || return $?
+
+       [[ $($LNETCTL net show | grep -c nid) -ne 1 ]] &&
+               error "Unexpected number of NIs after initalizing DLC"
+
+       do_lnetctl discover 0@lo ||
+               error "Failed to discover 0@lo"
+
+       unload_modules
+}
+run_test 217 "Don't leak memory when discovering peer with nnis <= 1"
+
+test_218() {
+       reinit_dlc || return $?
+
+       [[ ${#INTERFACES[@]} -lt 2 ]] &&
+               skip "Need two LNet interfaces"
+
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+
+       local nid1=$($LCTL list_nids | head -n 1)
+
+       do_lnetctl ping $nid1 ||
+               error "ping failed"
+
+       add_net "tcp" "${INTERFACES[1]}" || return $?
+
+       local nid2=$($LCTL list_nids | tail --lines 1)
+
+       do_lnetctl ping $nid2 ||
+               error "ping failed"
+
+       $LCTL net_drop_add -s $nid1 -d $nid1 -e local_error -r 1
+
+       do_lnetctl ping $nid1 &&
+               error "ping should have failed"
+
+       local health_recovered
+       local i
+
+       for i in $(seq 1 5); do
+               health_recovered=$($LNETCTL net show -v 2 |
+                                  grep -c 'health value: 1000')
+
+               if [[ $health_recovered -ne 2 ]]; then
+                       echo "Wait 1 second for health to recover"
+                       sleep 1
+               else
+                       break
+               fi
+       done
+
+       health_recovered=$($LNETCTL net show -v 2 |
+                          grep -c 'health value: 1000')
+
+       $LCTL net_drop_del -a
+
+       [[ $health_recovered -ne 2 ]] &&
+               do_lnetctl net show -v 2 | egrep -e nid -e health &&
+               error "Health hasn't recovered"
+
+       return 0
+}
+run_test 218 "Local recovery pings should exercise all available paths"
+
+test_219() {
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       add_net "tcp1" "${INTERFACES[0]}" || return $?
+
+       local nid1=$(lctl list_nids | head -n 1)
+       local nid2=$(lctl list_nids | tail --lines 1)
+
+       do_lnetctl ping $nid1 ||
+               error "Ping failed $?"
+       do_lnetctl ping $nid2 ||
+               error "Ping failed $?"
+
+       do_lnetctl discover $nid2 ||
+               error "Discovery failed"
+
+       $LNETCTL peer show --nid $nid1 | grep -q $nid2 ||
+               error "$nid2 is not listed under $nid1"
+}
+run_test 219 "Consolidate peer entries"
+
 test_230() {
        # LU-12815
        echo "Check valid values; Should succeed"
        local i
        local lnid
-       for ((i = 4; i < 16; i+=4)); do
+       local cmd
+       for ((i = 4; i < 16; i+=1)); do
                reinit_dlc || return $?
                add_net "tcp" "${INTERFACES[0]}" || return $?
                do_lnetctl net set --all --conns-per-peer $i ||
@@ -2013,7 +2513,21 @@ test_230() {
                lnid="$(lctl list_nids | head -n 1)"
                do_lnetctl ping "$lnid" ||
                        error "failed to ping myself"
-               printf 'network tcp\nconn_list\n' | lctl | grep -c "$lnid" | grep -q $((2+i*2)) ||
+
+               # "lctl --net tcp conn_list" prints the list of active
+               # connections. Since we're pinging ourselves, there should be
+               # 2 Control connections plus 2*conns_per_peer connections
+               # created (one Bulk Input, one Bulk Output in each pair).
+               # Here's the sample output for conns_per_peer set to 1:
+               # 12345-1.1.1.1@tcp I[0]host01->host01:988 2626560/1061296 nonagle
+               # 12345-1.1.1.1@tcp O[0]host01->host01:1022 2626560/1061488 nonagle
+               # 12345-1.1.1.1@tcp C[0]host01->host01:988 2626560/1061296 nonagle
+               # 12345-1.1.1.1@tcp C[0]host01->host01:1023 2626560/1061488 nonagle
+               cmd="printf 'network tcp\nconn_list\n' | lctl | grep -c '$lnid'"
+
+               # Expect 2+conns_per_peer*2 connections. Wait no longer
+               # than 2 seconds.
+               wait_update $HOSTNAME "$cmd" "$((2+i*2))" 2 ||
                        error "expected number of tcp connections $((2+i*2))"
        done
 
@@ -2033,6 +2547,14 @@ test_230() {
 }
 run_test 230 "Test setting conns-per-peer"
 
+### Test that linux route is added for each ni
+test_250() {
+       reinit_dlc || return $?
+       add_net "tcp" "${INTERFACES[0]}" || return $?
+       ip route show table ${INTERFACES[0]} | grep -q "${INTERFACES[0]}"
+}
+run_test 250 "test that linux routes are added"
+
 test_300() {
        # LU-13274
        local header