Whamcloud - gitweb
LU-6142 lnet: use list_first_entry() in lnet/lnet subdirectory.
[fs/lustre-release.git] / lnet / lnet / api-ni.c
index 8528b83..d8922cc 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  */
 
 #define DEBUG_SUBSYSTEM S_LNET
@@ -40,7 +39,6 @@
 #ifdef HAVE_SCHED_HEADERS
 #include <linux/sched/signal.h>
 #endif
-
 #include <lnet/udsp.h>
 #include <lnet/lib-lnet.h>
 
@@ -72,10 +70,10 @@ static int rnet_htable_size = LNET_REMOTE_NETS_HASH_DEFAULT;
 module_param(rnet_htable_size, int, 0444);
 MODULE_PARM_DESC(rnet_htable_size, "size of remote network hash table");
 
-static int use_tcp_bonding = false;
+static int use_tcp_bonding;
 module_param(use_tcp_bonding, int, 0444);
 MODULE_PARM_DESC(use_tcp_bonding,
-                "use_tcp_bonding parameter has been deprecated");
+                "use_tcp_bonding parameter has been removed");
 
 unsigned int lnet_numa_range = 0;
 module_param(lnet_numa_range, uint, 0444);
@@ -123,13 +121,34 @@ module_param_call(lnet_recovery_interval, recovery_interval_set, param_get_int,
                  &lnet_recovery_interval, S_IRUGO|S_IWUSR);
 #endif
 MODULE_PARM_DESC(lnet_recovery_interval,
-               "Interval to recover unhealthy interfaces in seconds");
+               "DEPRECATED - Interval to recover unhealthy interfaces in seconds");
 
 unsigned int lnet_recovery_limit;
 module_param(lnet_recovery_limit, uint, 0644);
 MODULE_PARM_DESC(lnet_recovery_limit,
                 "How long to attempt recovery of unhealthy peer interfaces in seconds. Set to 0 to allow indefinite recovery");
 
+unsigned int lnet_max_recovery_ping_interval = 900;
+unsigned int lnet_max_recovery_ping_count = 9;
+static int max_recovery_ping_interval_set(const char *val,
+                                         cfs_kernel_param_arg_t *kp);
+
+#define param_check_max_recovery_ping_interval(name, p) \
+               __param_check(name, p, int)
+
+#ifdef HAVE_KERNEL_PARAM_OPS
+static struct kernel_param_ops param_ops_max_recovery_ping_interval = {
+       .set = max_recovery_ping_interval_set,
+       .get = param_get_int,
+};
+module_param(lnet_max_recovery_ping_interval, max_recovery_ping_interval, 0644);
+#else
+module_param_call(lnet_max_recovery_ping_interval, max_recovery_ping_interval,
+                 param_get_int, &lnet_max_recovery_ping_interval, 0644);
+#endif
+MODULE_PARM_DESC(lnet_max_recovery_ping_interval,
+                "The max interval between LNet recovery pings, in seconds");
+
 static int lnet_interfaces_max = LNET_INTERFACES_MAX_DEFAULT;
 static int intf_max_set(const char *val, cfs_kernel_param_arg_t *kp);
 
@@ -254,8 +273,6 @@ static void lnet_set_lnd_timeout(void)
                           (lnet_retry_count + 1);
 }
 
-unsigned int lnet_current_net_count;
-
 /*
  * This sequence number keeps track of how many times DLC was used to
  * update the local NIs. It is incremented when a NI is added or
@@ -265,8 +282,9 @@ unsigned int lnet_current_net_count;
  */
 static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0);
 
-static int lnet_ping(struct lnet_process_id id, signed long timeout,
-                    struct lnet_process_id __user *ids, int n_ids);
+static int lnet_ping(struct lnet_process_id id4, struct lnet_nid *src_nid,
+                    signed long timeout, struct lnet_process_id __user *ids,
+                    int n_ids);
 
 static int lnet_discover(struct lnet_process_id id, __u32 force,
                         struct lnet_process_id __user *ids, int n_ids);
@@ -312,29 +330,39 @@ sensitivity_set(const char *val, cfs_kernel_param_arg_t *kp)
 static int
 recovery_interval_set(const char *val, cfs_kernel_param_arg_t *kp)
 {
+       CWARN("'lnet_recovery_interval' has been deprecated\n");
+
+       return 0;
+}
+
+static int
+max_recovery_ping_interval_set(const char *val, cfs_kernel_param_arg_t *kp)
+{
        int rc;
-       unsigned *interval = (unsigned *)kp->arg;
        unsigned long value;
 
        rc = kstrtoul(val, 0, &value);
        if (rc) {
-               CERROR("Invalid module parameter value for 'lnet_recovery_interval'\n");
+               CERROR("Invalid module parameter value for 'lnet_max_recovery_ping_interval'\n");
                return rc;
        }
 
-       if (value < 1) {
-               CERROR("lnet_recovery_interval must be at least 1 second\n");
+       if (!value) {
+               CERROR("Invalid max ping timeout. Must be strictly positive\n");
                return -EINVAL;
        }
 
-       /*
-        * The purpose of locking the api_mutex here is to ensure that
+       /* The purpose of locking the api_mutex here is to ensure that
         * the correct value ends up stored properly.
         */
        mutex_lock(&the_lnet.ln_api_mutex);
-
-       *interval = value;
-
+       lnet_max_recovery_ping_interval = value;
+       lnet_max_recovery_ping_count = 0;
+       value >>= 1;
+       while (value) {
+               lnet_max_recovery_ping_count++;
+               value >>= 1;
+       }
        mutex_unlock(&the_lnet.ln_api_mutex);
 
        return 0;
@@ -749,7 +777,8 @@ static void lnet_assert_wire_constants(void)
        /* Wire protocol assertions generated by 'wirecheck'
         * running on Linux robert.bartonsoftware.com 2.6.8-1.521
         * #1 Mon Aug 16 09:01:18 EDT 2004 i686 athlon i386 GNU/Linux
-        * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7) */
+        * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7)
+        */
 
        /* Constants... */
        BUILD_BUG_ON(LNET_PROTO_TCP_MAGIC != 0xeebc0ded);
@@ -761,6 +790,27 @@ static void lnet_assert_wire_constants(void)
        BUILD_BUG_ON(LNET_MSG_REPLY != 3);
        BUILD_BUG_ON(LNET_MSG_HELLO != 4);
 
+       BUILD_BUG_ON((int)sizeof(lnet_nid_t) != 8);
+       BUILD_BUG_ON((int)sizeof(lnet_pid_t) != 4);
+
+       /* Checks for struct lnet_nid */
+       BUILD_BUG_ON((int)sizeof(struct lnet_nid) != 20);
+       BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_size) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_size) != 1);
+       BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_type) != 1);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_type) != 1);
+       BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_num) != 2);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_num) != 2);
+       BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_addr) != 4);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_addr) != 16);
+
+       /* Checks for struct lnet_process_id_packed */
+       BUILD_BUG_ON((int)sizeof(struct lnet_process_id_packed) != 12);
+       BUILD_BUG_ON((int)offsetof(struct lnet_process_id_packed, nid) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_process_id_packed *)0)->nid) != 8);
+       BUILD_BUG_ON((int)offsetof(struct lnet_process_id_packed, pid) != 8);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_process_id_packed *)0)->pid) != 4);
+
        /* Checks for struct lnet_handle_wire */
        BUILD_BUG_ON((int)sizeof(struct lnet_handle_wire) != 16);
        BUILD_BUG_ON((int)offsetof(struct lnet_handle_wire,
@@ -780,64 +830,64 @@ static void lnet_assert_wire_constants(void)
                                   version_minor) != 6);
        BUILD_BUG_ON((int)sizeof(((struct lnet_magicversion *)0)->version_minor) != 2);
 
-       /* Checks for struct struct lnet_hdr */
-       BUILD_BUG_ON((int)sizeof(struct lnet_hdr) != 72);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_nid) != 0);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_nid) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_nid) != 8);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_nid) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_pid) != 16);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_pid) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_pid) != 20);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_pid) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, type) != 24);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->type) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, payload_length) != 28);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->payload_length) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg) != 40);
+       /* Checks for struct _lnet_hdr_nid4 */
+       BUILD_BUG_ON((int)sizeof(struct _lnet_hdr_nid4) != 72);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, dest_nid) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->dest_nid) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, src_nid) != 8);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->src_nid) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, dest_pid) != 16);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->dest_pid) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, src_pid) != 20);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->src_pid) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, type) != 24);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->type) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, payload_length) != 28);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->payload_length) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg) != 40);
 
        /* Ack */
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.dst_wmd) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.dst_wmd) != 16);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.match_bits) != 48);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.match_bits) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.mlength) != 56);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.mlength) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.dst_wmd) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.dst_wmd) != 16);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.match_bits) != 48);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.match_bits) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.mlength) != 56);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.mlength) != 4);
 
        /* Put */
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ack_wmd) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ack_wmd) != 16);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.match_bits) != 48);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.match_bits) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.hdr_data) != 56);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.hdr_data) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ptl_index) != 64);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ptl_index) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.offset) != 68);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.offset) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.ack_wmd) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.ack_wmd) != 16);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.match_bits) != 48);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.match_bits) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.hdr_data) != 56);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.hdr_data) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.ptl_index) != 64);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.ptl_index) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.offset) != 68);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.offset) != 4);
 
        /* Get */
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.return_wmd) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.return_wmd) != 16);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.match_bits) != 48);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.match_bits) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.ptl_index) != 56);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.ptl_index) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.src_offset) != 60);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.src_offset) != 4);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.sink_length) != 64);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.sink_length) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.return_wmd) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.return_wmd) != 16);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.match_bits) != 48);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.match_bits) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.ptl_index) != 56);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.ptl_index) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.src_offset) != 60);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.src_offset) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.sink_length) != 64);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.sink_length) != 4);
 
        /* Reply */
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.reply.dst_wmd) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.reply.dst_wmd) != 16);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.reply.dst_wmd) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.reply.dst_wmd) != 16);
 
        /* Hello */
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.incarnation) != 32);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.incarnation) != 8);
-       BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.type) != 40);
-       BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.type) != 4);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.hello.incarnation) != 32);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.hello.incarnation) != 8);
+       BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.hello.type) != 40);
+       BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.hello.type) != 4);
 
        /* Checks for struct lnet_ni_status and related constants */
        BUILD_BUG_ON(LNET_NI_STATUS_INVALID != 0x00000000);
@@ -875,6 +925,52 @@ static void lnet_assert_wire_constants(void)
        BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_nnis) != 4);
        BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_ni) != 16);
        BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_ni) != 0);
+
+       /* Acceptor connection request */
+       BUILD_BUG_ON(LNET_PROTO_ACCEPTOR_VERSION != 1);
+
+       /* Checks for struct lnet_acceptor_connreq */
+       BUILD_BUG_ON((int)sizeof(struct lnet_acceptor_connreq) != 16);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_magic) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_magic) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_version) != 4);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_version) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_nid) != 8);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_nid) != 8);
+
+       /* Checks for struct lnet_acceptor_connreq_v2 */
+       BUILD_BUG_ON((int)sizeof(struct lnet_acceptor_connreq_v2) != 28);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_magic) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_magic) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_version) != 4);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_version) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_nid) != 8);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_nid) != 20);
+
+       /* Checks for struct lnet_counters_common */
+       BUILD_BUG_ON((int)sizeof(struct lnet_counters_common) != 60);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_msgs_alloc) != 0);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_msgs_alloc) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_msgs_max) != 4);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_msgs_max) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_errors) != 8);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_errors) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_send_count) != 12);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_send_count) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_recv_count) != 16);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_recv_count) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_route_count) != 20);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_route_count) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_drop_count) != 24);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_drop_count) != 4);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_send_length) != 28);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_send_length) != 8);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_recv_length) != 36);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_recv_length) != 8);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_route_length) != 44);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_route_length) != 8);
+       BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_drop_length) != 52);
+       BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_drop_length) != 8);
 }
 
 static const struct lnet_lnd *lnet_find_lnd_by_type(__u32 type)
@@ -1308,7 +1404,7 @@ lnet_prepare(lnet_pid_t requested_pid)
 }
 
 static int
-lnet_unprepare (void)
+lnet_unprepare(void)
 {
        /* NB no LNET_LOCK since this is the last reference.  All LND instances
         * have shut down already, so it is safe to unlink and free all
@@ -1363,8 +1459,8 @@ lnet_net2ni_locked(__u32 net_id, int cpt)
 
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                if (net->net_id == net_id) {
-                       ni = list_entry(net->net_ni_list.next, struct lnet_ni,
-                                       ni_netlist);
+                       ni = list_first_entry(&net->net_ni_list, struct lnet_ni,
+                                             ni_netlist);
                        return ni;
                }
        }
@@ -1421,7 +1517,7 @@ lnet_net_clr_pref_rtrs(struct lnet_net *net)
 
 int
 lnet_net_add_pref_rtr(struct lnet_net *net,
-                     lnet_nid_t gw_nid)
+                     struct lnet_nid *gw_nid)
 __must_hold(&the_lnet.ln_api_mutex)
 {
        struct lnet_nid_list *ne;
@@ -1432,7 +1528,7 @@ __must_hold(&the_lnet.ln_api_mutex)
         * lock.
         */
        list_for_each_entry(ne, &net->net_rtr_pref_nids, nl_list) {
-               if (ne->nl_nid == gw_nid)
+               if (nid_same(&ne->nl_nid, gw_nid))
                        return -EEXIST;
        }
 
@@ -1440,7 +1536,7 @@ __must_hold(&the_lnet.ln_api_mutex)
        if (!ne)
                return -ENOMEM;
 
-       ne->nl_nid = gw_nid;
+       ne->nl_nid = *gw_nid;
 
        /* Lock the cpt to protect against addition and checks in the
         * selection algorithm
@@ -1453,11 +1549,11 @@ __must_hold(&the_lnet.ln_api_mutex)
 }
 
 bool
-lnet_net_is_pref_rtr_locked(struct lnet_net *net, lnet_nid_t rtr_nid)
+lnet_net_is_pref_rtr_locked(struct lnet_net *net, struct lnet_nid *rtr_nid)
 {
        struct lnet_nid_list *ne;
 
-       CDEBUG(D_NET, "%s: rtr pref emtpy: %d\n",
+       CDEBUG(D_NET, "%s: rtr pref empty: %d\n",
               libcfs_net2str(net->net_id),
               list_empty(&net->net_rtr_pref_nids));
 
@@ -1466,36 +1562,60 @@ lnet_net_is_pref_rtr_locked(struct lnet_net *net, lnet_nid_t rtr_nid)
 
        list_for_each_entry(ne, &net->net_rtr_pref_nids, nl_list) {
                CDEBUG(D_NET, "Comparing pref %s with gw %s\n",
-                      libcfs_nid2str(ne->nl_nid),
-                      libcfs_nid2str(rtr_nid));
-               if (rtr_nid == ne->nl_nid)
+                      libcfs_nidstr(&ne->nl_nid),
+                      libcfs_nidstr(rtr_nid));
+               if (nid_same(rtr_nid, &ne->nl_nid))
                        return true;
        }
 
        return false;
 }
 
+static unsigned int
+lnet_nid4_cpt_hash(lnet_nid_t nid, unsigned int number)
+{
+       __u64 key = nid;
+       __u64 pair_bits = 0x0001000100010001LLU;
+       __u64 mask = pair_bits * 0xFF;
+       __u64 pair_sum;
+
+       /* Use (sum-by-multiplication of nid bytes) mod (number of CPTs)
+        * to match nid to a CPT.
+        */
+       pair_sum = (key & mask) + ((key >> 8) & mask);
+       pair_sum = (pair_sum * pair_bits) >> 48;
+
+       CDEBUG(D_NET, "Match nid %s to cpt %u\n",
+              libcfs_nid2str(nid), (unsigned int)(pair_sum) % number);
+
+       return (unsigned int)(pair_sum) % number;
+}
+
 unsigned int
-lnet_nid_cpt_hash(lnet_nid_t nid, unsigned int number)
+lnet_nid_cpt_hash(struct lnet_nid *nid, unsigned int number)
 {
-       __u64           key = nid;
-       unsigned int    val;
+       unsigned int val;
+       u32 h = 0;
+       int i;
 
        LASSERT(number >= 1 && number <= LNET_CPT_NUMBER);
 
        if (number == 1)
                return 0;
 
-       val = hash_long(key, LNET_CPT_BITS);
-       /* NB: LNET_CP_NUMBER doesn't have to be PO2 */
+       if (nid_is_nid4(nid))
+               return lnet_nid4_cpt_hash(lnet_nid_to_nid4(nid), number);
+
+       for (i = 0; i < 4; i++)
+               h = hash_32(nid->nid_addr[i]^h, 32);
+       val = hash_32(LNET_NID_NET(nid) ^ h, LNET_CPT_BITS);
        if (val < number)
                return val;
-
-       return (unsigned int)(key + val + (val >> 1)) % number;
+       return (unsigned int)(h + val + (val >> 1)) % number;
 }
 
 int
-lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni)
+lnet_cpt_of_nid_locked(struct lnet_nid *nid, struct lnet_ni *ni)
 {
        struct lnet_net *net;
 
@@ -1519,7 +1639,7 @@ lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni)
        }
 
        /* no NI provided so look at the net */
-       net = lnet_get_net_locked(LNET_NIDNET(nid));
+       net = lnet_get_net_locked(LNET_NID_NET(nid));
 
        if (net != NULL && net->net_cpts != NULL) {
                return net->net_cpts[lnet_nid_cpt_hash(nid, net->net_ncpts)];
@@ -1529,7 +1649,7 @@ lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni)
 }
 
 int
-lnet_cpt_of_nid(lnet_nid_t nid, struct lnet_ni *ni)
+lnet_nid2cpt(struct lnet_nid *nid, struct lnet_ni *ni)
 {
        int     cpt;
        int     cpt2;
@@ -1545,6 +1665,19 @@ lnet_cpt_of_nid(lnet_nid_t nid, struct lnet_ni *ni)
 
        return cpt2;
 }
+EXPORT_SYMBOL(lnet_nid2cpt);
+
+int
+lnet_cpt_of_nid(lnet_nid_t nid4, struct lnet_ni *ni)
+{
+       struct lnet_nid nid;
+
+       if (LNET_CPT_NUMBER == 1)
+               return 0; /* the only one */
+
+       lnet_nid4_to_nid(nid4, &nid);
+       return lnet_nid2cpt(&nid, ni);
+}
 EXPORT_SYMBOL(lnet_cpt_of_nid);
 
 int
@@ -1576,16 +1709,16 @@ lnet_islocalnet(__u32 net_id)
 }
 
 struct lnet_ni  *
-lnet_nid2ni_locked(lnet_nid_t nid, int cpt)
+lnet_nid_to_ni_locked(struct lnet_nid *nid, int cpt)
 {
        struct lnet_net  *net;
-       struct lnet_ni   *ni;
+       struct lnet_ni *ni;
 
        LASSERT(cpt != LNET_LOCK_EX);
 
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
-                       if (ni->ni_nid == nid)
+                       if (nid_same(&ni->ni_nid, nid))
                                return ni;
                }
        }
@@ -1593,13 +1726,25 @@ lnet_nid2ni_locked(lnet_nid_t nid, int cpt)
        return NULL;
 }
 
+struct lnet_ni  *
+lnet_nid2ni_locked(lnet_nid_t nid4, int cpt)
+{
+       struct lnet_nid nid;
+
+       lnet_nid4_to_nid(nid4, &nid);
+       return lnet_nid_to_ni_locked(&nid, cpt);
+}
+
 struct lnet_ni *
-lnet_nid2ni_addref(lnet_nid_t nid)
+lnet_nid2ni_addref(lnet_nid_t nid4)
 {
        struct lnet_ni *ni;
+       struct lnet_nid nid;
+
+       lnet_nid4_to_nid(nid4, &nid);
 
        lnet_net_lock(0);
-       ni = lnet_nid2ni_locked(nid, 0);
+       ni = lnet_nid_to_ni_locked(&nid, 0);
        if (ni)
                lnet_ni_addref_locked(ni, 0);
        lnet_net_unlock(0);
@@ -1608,14 +1753,29 @@ lnet_nid2ni_addref(lnet_nid_t nid)
 }
 EXPORT_SYMBOL(lnet_nid2ni_addref);
 
+struct lnet_ni *
+lnet_nid_to_ni_addref(struct lnet_nid *nid)
+{
+       struct lnet_ni *ni;
+
+       lnet_net_lock(0);
+       ni = lnet_nid_to_ni_locked(nid, 0);
+       if (ni)
+               lnet_ni_addref_locked(ni, 0);
+       lnet_net_unlock(0);
+
+       return ni;
+}
+EXPORT_SYMBOL(lnet_nid_to_ni_addref);
+
 int
-lnet_islocalnid(lnet_nid_t nid)
+lnet_islocalnid(struct lnet_nid *nid)
 {
        struct lnet_ni  *ni;
        int             cpt;
 
        cpt = lnet_net_lock_current();
-       ni = lnet_nid2ni_locked(nid, cpt);
+       ni = lnet_nid_to_ni_locked(nid, cpt);
        lnet_net_unlock(cpt);
 
        return ni != NULL;
@@ -1727,23 +1887,6 @@ lnet_get_ni_count(void)
        return count;
 }
 
-int
-lnet_get_net_count(void)
-{
-       struct lnet_net *net;
-       int count = 0;
-
-       lnet_net_lock(0);
-
-       list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
-               count++;
-       }
-
-       lnet_net_unlock(0);
-
-       return count;
-}
-
 void
 lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf)
 {
@@ -1818,8 +1961,8 @@ lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf,
                       struct lnet_handle_md *ping_mdh,
                       int ni_count, bool set_eq)
 {
-       struct lnet_process_id id = {
-               .nid = LNET_NID_ANY,
+       struct lnet_processid id = {
+               .nid = LNET_ANY_NID,
                .pid = LNET_PID_ANY
        };
        struct lnet_me *me;
@@ -1837,7 +1980,7 @@ lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf,
        }
 
        /* Ping target ME/MD */
-       me = LNetMEAttach(LNET_RESERVED_PORTAL, id,
+       me = LNetMEAttach(LNET_RESERVED_PORTAL, &id,
                          LNET_PROTO_PING_MATCHBITS, 0,
                          LNET_UNLINK, LNET_INS_AFTER);
        if (IS_ERR(me)) {
@@ -1902,12 +2045,12 @@ lnet_ping_target_install_locked(struct lnet_ping_buffer *pbuf)
 
                        ns = &pbuf->pb_info.pi_ni[i];
 
-                       ns->ns_nid = ni->ni_nid;
+                       if (!nid_is_nid4(&ni->ni_nid))
+                               continue;
+                       ns->ns_nid = lnet_nid_to_nid4(&ni->ni_nid);
 
                        lnet_ni_lock(ni);
-                       ns->ns_status = (ni->ni_status != NULL) ?
-                                        ni->ni_status->ns_status :
-                                               LNET_NI_STATUS_UP;
+                       ns->ns_status = lnet_ni_get_status_locked(ni);
                        ni->ni_status = ns;
                        lnet_ni_unlock(ni);
 
@@ -2035,12 +2178,12 @@ again:
 int lnet_push_target_post(struct lnet_ping_buffer *pbuf,
                          struct lnet_handle_md *mdhp)
 {
-       struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY };
+       struct lnet_processid id = { LNET_ANY_NID, LNET_PID_ANY };
        struct lnet_md md = { NULL };
        struct lnet_me *me;
        int rc;
 
-       me = LNetMEAttach(LNET_RESERVED_PORTAL, id,
+       me = LNetMEAttach(LNET_RESERVED_PORTAL, &id,
                          LNET_PROTO_PING_MATCHBITS, 0,
                          LNET_UNLINK, LNET_INS_AFTER);
        if (IS_ERR(me)) {
@@ -2189,12 +2332,12 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net)
         * list and shut them down in guaranteed thread context
         */
        i = 2;
-       while (!list_empty(zombie_list)) {
-               int     *ref;
-               int     j;
+       while ((ni = list_first_entry_or_null(zombie_list,
+                                             struct lnet_ni,
+                                             ni_netlist)) != NULL) {
+               int *ref;
+               int j;
 
-               ni = list_entry(zombie_list->next,
-                               struct lnet_ni, ni_netlist);
                list_del_init(&ni->ni_netlist);
                /* the ni should be in deleting state. If it's not it's
                 * a bug */
@@ -2219,7 +2362,7 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net)
                        if ((i & (-i)) == i) {
                                CDEBUG(D_WARNING,
                                       "Waiting for zombie LNI %s\n",
-                                      libcfs_nid2str(ni->ni_nid));
+                                      libcfs_nidstr(&ni->ni_nid));
                        }
                        schedule_timeout_uninterruptible(cfs_time_seconds(1));
 
@@ -2233,18 +2376,20 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net)
                islo = ni->ni_net->net_lnd->lnd_type == LOLND;
 
                LASSERT(!in_interrupt());
-               /* Holding the mutex makes it safe for lnd_shutdown
+               /* Holding the LND mutex makes it safe for lnd_shutdown
                 * to call module_put(). Module unload cannot finish
                 * until lnet_unregister_lnd() completes, and that
-                * requires the mutex.
+                * requires the LND mutex.
                 */
+               mutex_unlock(&the_lnet.ln_api_mutex);
                mutex_lock(&the_lnet.ln_lnd_mutex);
                (net->net_lnd->lnd_shutdown)(ni);
                mutex_unlock(&the_lnet.ln_lnd_mutex);
+               mutex_lock(&the_lnet.ln_api_mutex);
 
                if (!islo)
                        CDEBUG(D_LNI, "Removed LNI %s\n",
-                             libcfs_nid2str(ni->ni_nid));
+                             libcfs_nidstr(&ni->ni_nid));
 
                lnet_ni_free(ni);
                i = 2;
@@ -2285,9 +2430,9 @@ lnet_shutdown_lndnet(struct lnet_net *net)
 
        list_del_init(&net->net_list);
 
-       while (!list_empty(&net->net_ni_list)) {
-               ni = list_entry(net->net_ni_list.next,
-                               struct lnet_ni, ni_netlist);
+       while ((ni = list_first_entry_or_null(&net->net_ni_list,
+                                             struct lnet_ni,
+                                             ni_netlist)) != NULL) {
                lnet_net_unlock(LNET_LOCK_EX);
                lnet_shutdown_lndni(ni);
                lnet_net_lock(LNET_LOCK_EX);
@@ -2311,7 +2456,8 @@ lnet_shutdown_lndnets(void)
        /* NB called holding the global mutex */
 
        /* All quiet on the API front */
-       LASSERT(the_lnet.ln_state == LNET_STATE_RUNNING);
+       LASSERT(the_lnet.ln_state == LNET_STATE_RUNNING ||
+               the_lnet.ln_state == LNET_STATE_STOPPING);
        LASSERT(the_lnet.ln_refcount == 0);
 
        lnet_net_lock(LNET_LOCK_EX);
@@ -2332,11 +2478,10 @@ lnet_shutdown_lndnets(void)
        lnet_net_unlock(LNET_LOCK_EX);
 
        /* iterate through the net zombie list and delete each net */
-       while (!list_empty(&the_lnet.ln_net_zombie)) {
-               net = list_entry(the_lnet.ln_net_zombie.next,
-                                struct lnet_net, net_list);
+       while ((net = list_first_entry_or_null(&the_lnet.ln_net_zombie,
+                                              struct lnet_net,
+                                              net_list)) != NULL)
                lnet_shutdown_lndnet(net);
-       }
 
        spin_lock(&the_lnet.ln_msg_resend_lock);
        list_splice(&the_lnet.ln_msg_resend, &resend);
@@ -2417,8 +2562,13 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_lnd_tunables *tun)
                   lnet_ni_tq_credits(ni) * ni->ni_ncpts);
        atomic_set(&ni->ni_healthv, LNET_MAX_HEALTH_VALUE);
 
+       /* Nodes with small feet have little entropy. The NID for this
+        * node gives the most entropy in the low bits.
+        */
+       add_device_randomness(&ni->ni_nid, sizeof(ni->ni_nid));
+
        CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n",
-               libcfs_nid2str(ni->ni_nid),
+               libcfs_nidstr(&ni->ni_nid),
                ni->ni_net->net_tunables.lct_peer_tx_credits,
                lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER,
                ni->ni_net->net_tunables.lct_peer_rtr_credits,
@@ -2509,28 +2659,15 @@ lnet_startup_lndnet(struct lnet_net *net, struct lnet_lnd_tunables *tun)
         * After than we want to delete the network being added,
         * to avoid a memory leak.
         */
-
-       /*
-        * When a network uses TCP bonding then all its interfaces
-        * must be specified when the network is first defined: the
-        * TCP bonding code doesn't allow for interfaces to be added
-        * or removed.
-        */
-       if (net_l != net && net_l != NULL && use_tcp_bonding &&
-           LNET_NETTYP(net_l->net_id) == SOCKLND) {
-               rc = -EINVAL;
-               goto failed0;
-       }
-
-       while (!list_empty(&net->net_ni_added)) {
-               ni = list_entry(net->net_ni_added.next, struct lnet_ni,
-                               ni_netlist);
+       while ((ni = list_first_entry_or_null(&net->net_ni_added,
+                                             struct lnet_ni,
+                                             ni_netlist)) != NULL) {
                list_del_init(&ni->ni_netlist);
 
                /* make sure that the the NI we're about to start
                 * up is actually unique. if it's not fail. */
                if (!lnet_ni_unique_net(&net_l->net_ni_list,
-                                       ni->ni_interfaces[0])) {
+                                       ni->ni_interface)) {
                        rc = -EEXIST;
                        goto failed1;
                }
@@ -2581,9 +2718,6 @@ lnet_startup_lndnet(struct lnet_net *net, struct lnet_lnd_tunables *tun)
                lnet_net_unlock(LNET_LOCK_EX);
        }
 
-       /* update net count */
-       lnet_current_net_count = lnet_get_net_count();
-
        return ni_count;
 
 failed1:
@@ -2591,12 +2725,10 @@ failed1:
         * shutdown the new NIs that are being started up
         * free the NET being started
         */
-       while (!list_empty(&local_ni_list)) {
-               ni = list_entry(local_ni_list.next, struct lnet_ni,
-                               ni_netlist);
-
+       while ((ni = list_first_entry_or_null(&local_ni_list,
+                                             struct lnet_ni,
+                                             ni_netlist)) != NULL)
                lnet_shutdown_lndni(ni);
-       }
 
 failed0:
        lnet_net_free(net);
@@ -2620,8 +2752,9 @@ lnet_startup_lndnets(struct list_head *netlist)
        the_lnet.ln_state = LNET_STATE_RUNNING;
        lnet_net_unlock(LNET_LOCK_EX);
 
-       while (!list_empty(netlist)) {
-               net = list_entry(netlist->next, struct lnet_net, net_list);
+       while ((net = list_first_entry_or_null(netlist,
+                                              struct lnet_net,
+                                              net_list)) != NULL) {
                list_del_init(&net->net_list);
 
                rc = lnet_startup_lndnet(net, NULL);
@@ -2639,6 +2772,86 @@ failed:
        return rc;
 }
 
+static int lnet_genl_parse_list(struct sk_buff *msg,
+                               const struct ln_key_list *data[], u16 idx)
+{
+       const struct ln_key_list *list = data[idx];
+       const struct ln_key_props *props;
+       struct nlattr *node;
+       u16 count;
+
+       if (!list)
+               return 0;
+
+       if (!list->lkl_maxattr)
+               return -ERANGE;
+
+       props = list->lkl_list;
+       if (!props)
+               return -EINVAL;
+
+       node = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
+       if (!node)
+               return -ENOBUFS;
+
+       for (count = 1; count <= list->lkl_maxattr; count++) {
+               struct nlattr *key = nla_nest_start(msg, count);
+
+               if (count == 1)
+                       nla_put_u16(msg, LN_SCALAR_ATTR_LIST_SIZE,
+                                   list->lkl_maxattr);
+
+               nla_put_u16(msg, LN_SCALAR_ATTR_INDEX, count);
+               if (props[count].lkp_value)
+                       nla_put_string(msg, LN_SCALAR_ATTR_VALUE,
+                                      props[count].lkp_value);
+               if (props[count].lkp_key_format)
+                       nla_put_u16(msg, LN_SCALAR_ATTR_KEY_FORMAT,
+                                   props[count].lkp_key_format);
+               nla_put_u16(msg, LN_SCALAR_ATTR_NLA_TYPE,
+                           props[count].lkp_data_type);
+               if (props[count].lkp_data_type == NLA_NESTED) {
+                       int rc;
+
+                       rc = lnet_genl_parse_list(msg, data, ++idx);
+                       if (rc < 0)
+                               return rc;
+                       idx = rc;
+               }
+
+               nla_nest_end(msg, key);
+       }
+
+       nla_nest_end(msg, node);
+       return idx;
+}
+
+int lnet_genl_send_scalar_list(struct sk_buff *msg, u32 portid, u32 seq,
+                              const struct genl_family *family, int flags,
+                              u8 cmd, const struct ln_key_list *data[])
+{
+       int rc = 0;
+       void *hdr;
+
+       if (!data[0])
+               return -EINVAL;
+
+       hdr = genlmsg_put(msg, portid, seq, family, flags, cmd);
+       if (!hdr)
+               GOTO(canceled, rc = -EMSGSIZE);
+
+       rc = lnet_genl_parse_list(msg, data, 0);
+       if (rc < 0)
+               GOTO(canceled, rc);
+
+       genlmsg_end(msg, hdr);
+canceled:
+       if (rc < 0)
+               genlmsg_cancel(msg, hdr);
+       return rc > 0 ? 0 : rc;
+}
+EXPORT_SYMBOL(lnet_genl_send_scalar_list);
+
 /**
  * Initialize LNet library.
  *
@@ -2748,6 +2961,11 @@ LNetNIInit(lnet_pid_t requested_pid)
 
        CDEBUG(D_OTHER, "refs %d\n", the_lnet.ln_refcount);
 
+       if (the_lnet.ln_state == LNET_STATE_STOPPING) {
+               mutex_unlock(&the_lnet.ln_api_mutex);
+               return -ESHUTDOWN;
+       }
+
        if (the_lnet.ln_refcount > 0) {
                rc = the_lnet.ln_refcount++;
                mutex_unlock(&the_lnet.ln_api_mutex);
@@ -2774,7 +2992,7 @@ LNetNIInit(lnet_pid_t requested_pid)
        }
 
        if (use_tcp_bonding)
-               CWARN("'use_tcp_bonding' option has been deprecated. See LU-13641\n");
+               CWARN("use_tcp_bonding has been removed. Use Multi-Rail and Dynamic Discovery instead, see LU-13641\n");
 
        /* If LNet is being initialized via DLC it is possible
         * that the user requests not to load module parameters (ones which
@@ -2783,8 +3001,7 @@ LNetNIInit(lnet_pid_t requested_pid)
         * in this case.  On cleanup in case of failure only clean up
         * routes if it has been loaded */
        if (!the_lnet.ln_nis_from_mod_params) {
-               rc = lnet_parse_networks(&net_head, lnet_get_networks(),
-                                        use_tcp_bonding);
+               rc = lnet_parse_networks(&net_head, lnet_get_networks());
                if (rc < 0)
                        goto err_empty_list;
        }
@@ -2862,10 +3079,9 @@ err_empty_list:
        lnet_unprepare();
        LASSERT(rc < 0);
        mutex_unlock(&the_lnet.ln_api_mutex);
-       while (!list_empty(&net_head)) {
-               struct lnet_net *net;
-
-               net = list_entry(net_head.next, struct lnet_net, net_list);
+       while ((net = list_first_entry_or_null(&net_head,
+                                              struct lnet_net,
+                                              net_list)) != NULL) {
                list_del_init(&net->net_list);
                lnet_net_free(net);
        }
@@ -2894,6 +3110,10 @@ LNetNIFini(void)
        } else {
                LASSERT(!the_lnet.ln_niinit_self);
 
+               lnet_net_lock(LNET_LOCK_EX);
+               the_lnet.ln_state = LNET_STATE_STOPPING;
+               lnet_net_unlock(LNET_LOCK_EX);
+
                lnet_fault_fini();
 
                lnet_router_debugfs_fini();
@@ -2933,25 +3153,17 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni,
        size_t min_size = 0;
        int i;
 
-       if (!ni || !cfg_ni || !tun)
+       if (!ni || !cfg_ni || !tun || !nid_is_nid4(&ni->ni_nid))
                return;
 
-       if (ni->ni_interfaces[0] != NULL) {
-               for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) {
-                       if (ni->ni_interfaces[i] != NULL) {
-                               strncpy(cfg_ni->lic_ni_intf[i],
-                                       ni->ni_interfaces[i],
-                                       sizeof(cfg_ni->lic_ni_intf[i]));
-                       }
-               }
+       if (ni->ni_interface != NULL) {
+               strncpy(cfg_ni->lic_ni_intf,
+                       ni->ni_interface,
+                       sizeof(cfg_ni->lic_ni_intf));
        }
 
-       cfg_ni->lic_nid = ni->ni_nid;
-       if (ni->ni_nid == LNET_NID_LO_0)
-               cfg_ni->lic_status = LNET_NI_STATUS_UP;
-       else
-               cfg_ni->lic_status = ni->ni_status->ns_status;
-       cfg_ni->lic_tcp_bonding = use_tcp_bonding;
+       cfg_ni->lic_nid = lnet_nid_to_nid4(&ni->ni_nid);
+       cfg_ni->lic_status = lnet_ni_get_status_locked(ni);
        cfg_ni->lic_dev_cpt = ni->ni_dev_cpt;
 
        memcpy(&tun->lt_cmn, &ni->ni_net->net_tunables, sizeof(tun->lt_cmn));
@@ -3010,26 +3222,21 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni,
        size_t min_size, tunable_size = 0;
        int i;
 
-       if (!ni || !config)
+       if (!ni || !config || !nid_is_nid4(&ni->ni_nid))
                return;
 
        net_config = (struct lnet_ioctl_net_config *) config->cfg_bulk;
        if (!net_config)
                return;
 
-       BUILD_BUG_ON(ARRAY_SIZE(ni->ni_interfaces) !=
-                    ARRAY_SIZE(net_config->ni_interfaces));
-
-       for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) {
-               if (!ni->ni_interfaces[i])
-                       break;
+       if (!ni->ni_interface)
+               return;
 
-               strncpy(net_config->ni_interfaces[i],
-                       ni->ni_interfaces[i],
-                       sizeof(net_config->ni_interfaces[i]));
-       }
+       strncpy(net_config->ni_interface,
+               ni->ni_interface,
+               sizeof(net_config->ni_interface));
 
-       config->cfg_nid = ni->ni_nid;
+       config->cfg_nid = lnet_nid_to_nid4(&ni->ni_nid);
        config->cfg_config_u.cfg_net.net_peer_timeout =
                ni->ni_net->net_tunables.lct_peer_timeout;
        config->cfg_config_u.cfg_net.net_max_tx_credits =
@@ -3039,10 +3246,7 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni,
        config->cfg_config_u.cfg_net.net_peer_rtr_credits =
                ni->ni_net->net_tunables.lct_peer_rtr_credits;
 
-       if (ni->ni_nid == LNET_NID_LO_0)
-               net_config->ni_status = LNET_NI_STATUS_UP;
-       else
-               net_config->ni_status = ni->ni_status->ns_status;
+       net_config->ni_status = lnet_ni_get_status_locked(ni);
 
        if (ni->ni_cpts) {
                int num_cpts = min(ni->ni_ncpts, LNET_MAX_SHOW_NUM_CPT);
@@ -3098,11 +3302,12 @@ int lnet_get_net_healthv_locked(struct lnet_net *net)
 {
        struct lnet_ni *ni;
        int best_healthv = 0;
-       int healthv;
+       int healthv, ni_fatal;
 
        list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
                healthv = atomic_read(&ni->ni_healthv);
-               if (healthv > best_healthv)
+               ni_fatal = atomic_read(&ni->ni_fatal_error_on);
+               if (!ni_fatal && healthv > best_healthv)
                        best_healthv = healthv;
        }
 
@@ -3120,14 +3325,15 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev)
         * a message being sent. This function accessed the net without
         * checking if the list is empty
         */
-       if (prev == NULL) {
-               if (net == NULL)
-                       net = list_entry(the_lnet.ln_nets.next, struct lnet_net,
-                                       net_list);
+       if (!prev) {
+               if (!net)
+                       net = list_first_entry(&the_lnet.ln_nets,
+                                              struct lnet_net,
+                                              net_list);
                if (list_empty(&net->net_ni_list))
                        return NULL;
-               ni = list_entry(net->net_ni_list.next, struct lnet_ni,
-                               ni_netlist);
+               ni = list_first_entry(&net->net_ni_list, struct lnet_ni,
+                                     ni_netlist);
 
                return ni;
        }
@@ -3145,13 +3351,13 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev)
                        return NULL;
 
                /* get the next net */
-               net = list_entry(prev->ni_net->net_list.next, struct lnet_net,
-                                net_list);
+               net = list_first_entry(&prev->ni_net->net_list, struct lnet_net,
+                                      net_list);
                if (list_empty(&net->net_ni_list))
                        return NULL;
                /* get the ni on it */
-               ni = list_entry(net->net_ni_list.next, struct lnet_ni,
-                               ni_netlist);
+               ni = list_first_entry(&net->net_ni_list, struct lnet_ni,
+                                     ni_netlist);
 
                return ni;
        }
@@ -3160,7 +3366,7 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev)
                return NULL;
 
        /* there are more nis left */
-       ni = list_entry(prev->ni_netlist.next, struct lnet_ni, ni_netlist);
+       ni = list_first_entry(&prev->ni_netlist, struct lnet_ni, ni_netlist);
 
        return ni;
 }
@@ -3313,7 +3519,7 @@ static int lnet_add_net_common(struct lnet_net *net,
                rc = lnet_udsp_apply_policies_on_ni(ni);
                if (rc)
                        CERROR("Failed to apply UDSPs on ni %s\n",
-                              libcfs_nid2str(ni->ni_nid));
+                              libcfs_nidstr(&ni->ni_nid));
        }
        lnet_net_unlock(LNET_LOCK_EX);
 
@@ -3370,15 +3576,21 @@ static int lnet_handle_legacy_ip2nets(char *ip2nets,
        if (rc < 0)
                return rc;
 
-       rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
+       rc = lnet_parse_networks(&net_head, nets);
        if (rc < 0)
                return rc;
 
        lnet_set_tune_defaults(tun);
 
        mutex_lock(&the_lnet.ln_api_mutex);
-       while (!list_empty(&net_head)) {
-               net = list_entry(net_head.next, struct lnet_net, net_list);
+       if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+               rc = -ESHUTDOWN;
+               goto out;
+       }
+
+       while ((net = list_first_entry_or_null(&net_head,
+                                              struct lnet_net,
+                                              net_list)) != NULL) {
                list_del_init(&net->net_list);
                rc = lnet_add_net_common(net, tun);
                if (rc < 0)
@@ -3388,8 +3600,9 @@ static int lnet_handle_legacy_ip2nets(char *ip2nets,
 out:
        mutex_unlock(&the_lnet.ln_api_mutex);
 
-       while (!list_empty(&net_head)) {
-               net = list_entry(net_head.next, struct lnet_net, net_list);
+       while ((net = list_first_entry_or_null(&net_head,
+                                              struct lnet_net,
+                                              net_list)) != NULL) {
                list_del_init(&net->net_list);
                lnet_net_free(net);
        }
@@ -3433,15 +3646,17 @@ int lnet_dyn_add_ni(struct lnet_ioctl_config_ni *conf)
        }
 
        ni = lnet_ni_alloc_w_cpt_array(net, conf->lic_cpts, conf->lic_ncpts,
-                                      conf->lic_ni_intf[0]);
+                                      conf->lic_ni_intf);
        if (!ni)
                return -ENOMEM;
 
        lnet_set_tune_defaults(tun);
 
        mutex_lock(&the_lnet.ln_api_mutex);
-
-       rc = lnet_add_net_common(net, tun);
+       if (the_lnet.ln_state != LNET_STATE_RUNNING)
+               rc = -ESHUTDOWN;
+       else
+               rc = lnet_add_net_common(net, tun);
 
        mutex_unlock(&the_lnet.ln_api_mutex);
 
@@ -3464,6 +3679,10 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf)
                return -EINVAL;
 
        mutex_lock(&the_lnet.ln_api_mutex);
+       if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+               rc = -ESHUTDOWN;
+               goto unlock_api_mutex;
+       }
 
        lnet_net_lock(0);
 
@@ -3552,18 +3771,22 @@ lnet_dyn_add_net(struct lnet_ioctl_config_data *conf)
        const char *nets = conf->cfg_config_u.cfg_net.net_intf;
 
        /* Create a net/ni structures for the network string */
-       rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
+       rc = lnet_parse_networks(&net_head, nets);
        if (rc <= 0)
                return rc == 0 ? -EINVAL : rc;
 
        mutex_lock(&the_lnet.ln_api_mutex);
+       if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+               rc = -ESHUTDOWN;
+               goto out_unlock_clean;
+       }
 
        if (rc > 1) {
                rc = -EINVAL; /* only add one network per call */
                goto out_unlock_clean;
        }
 
-       net = list_entry(net_head.next, struct lnet_net, net_list);
+       net = list_first_entry(&net_head, struct lnet_net, net_list);
        list_del_init(&net->net_list);
 
        LASSERT(lnet_net_unique(net->net_id, &the_lnet.ln_nets, NULL));
@@ -3586,9 +3809,10 @@ lnet_dyn_add_net(struct lnet_ioctl_config_data *conf)
 
 out_unlock_clean:
        mutex_unlock(&the_lnet.ln_api_mutex);
-       while (!list_empty(&net_head)) {
-               /* net_head list is empty in success case */
-               net = list_entry(net_head.next, struct lnet_net, net_list);
+       /* net_head list is empty in success case */
+       while ((net = list_first_entry_or_null(&net_head,
+                                              struct lnet_net,
+                                              net_list)) != NULL) {
                list_del_init(&net->net_list);
                lnet_net_free(net);
        }
@@ -3609,6 +3833,10 @@ lnet_dyn_del_net(__u32 net_id)
                return -EINVAL;
 
        mutex_lock(&the_lnet.ln_api_mutex);
+       if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+               rc = -ESHUTDOWN;
+               goto out;
+       }
 
        lnet_net_lock(0);
 
@@ -3660,12 +3888,13 @@ lnet_ni_set_healthv(lnet_nid_t nid, int value, bool all)
        lnet_net_lock(LNET_LOCK_EX);
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
-                       if (ni->ni_nid == nid || all) {
+                       if (all || (nid_is_nid4(&ni->ni_nid) &&
+                                   lnet_nid_to_nid4(&ni->ni_nid) == nid)) {
                                atomic_set(&ni->ni_healthv, value);
                                if (list_empty(&ni->ni_recovery) &&
                                    value < LNET_MAX_HEALTH_VALUE) {
                                        CERROR("manually adding local NI %s to recovery\n",
-                                              libcfs_nid2str(ni->ni_nid));
+                                              libcfs_nidstr(&ni->ni_nid));
                                        list_add_tail(&ni->ni_recovery,
                                                      &the_lnet.ln_mt_localNIRecovq);
                                        lnet_ni_addref_locked(ni, 0);
@@ -3680,6 +3909,30 @@ lnet_ni_set_healthv(lnet_nid_t nid, int value, bool all)
        lnet_net_unlock(LNET_LOCK_EX);
 }
 
+static void
+lnet_ni_set_conns_per_peer(lnet_nid_t nid, int value, bool all)
+{
+       struct lnet_net *net;
+       struct lnet_ni *ni;
+
+       lnet_net_lock(LNET_LOCK_EX);
+       list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
+               list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
+                       if (lnet_nid_to_nid4(&ni->ni_nid) != nid && !all)
+                               continue;
+                       if (LNET_NETTYP(net->net_id) == SOCKLND)
+                               ni->ni_lnd_tunables.lnd_tun_u.lnd_sock.lnd_conns_per_peer = value;
+                       else if (LNET_NETTYP(net->net_id) == O2IBLND)
+                               ni->ni_lnd_tunables.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = value;
+                       if (!all) {
+                               lnet_net_unlock(LNET_LOCK_EX);
+                               return;
+                       }
+               }
+       }
+       lnet_net_unlock(LNET_LOCK_EX);
+}
+
 static int
 lnet_get_local_ni_hstats(struct lnet_ioctl_local_ni_hstats *stats)
 {
@@ -3701,7 +3954,10 @@ lnet_get_local_ni_hstats(struct lnet_ioctl_local_ni_hstats *stats)
        stats->hlni_local_no_route = atomic_read(&ni->ni_hstats.hlt_local_no_route);
        stats->hlni_local_timeout = atomic_read(&ni->ni_hstats.hlt_local_timeout);
        stats->hlni_local_error = atomic_read(&ni->ni_hstats.hlt_local_error);
+       stats->hlni_fatal_error = atomic_read(&ni->ni_fatal_error_on);
        stats->hlni_health_value = atomic_read(&ni->ni_healthv);
+       stats->hlni_ping_count = ni->ni_ping_count;
+       stats->hlni_next_ping = ni->ni_next_ping;
 
 unlock:
        lnet_net_unlock(cpt);
@@ -3717,7 +3973,9 @@ lnet_get_local_ni_recovery_list(struct lnet_ioctl_recovery_list *list)
 
        lnet_net_lock(LNET_LOCK_EX);
        list_for_each_entry(ni, &the_lnet.ln_mt_localNIRecovq, ni_recovery) {
-               list->rlst_nid_array[i] = ni->ni_nid;
+               if (!nid_is_nid4(&ni->ni_nid))
+                       continue;
+               list->rlst_nid_array[i] = lnet_nid_to_nid4(&ni->ni_nid);
                i++;
                if (i >= LNET_MAX_SHOW_NUM_NID)
                        break;
@@ -3736,7 +3994,7 @@ lnet_get_peer_ni_recovery_list(struct lnet_ioctl_recovery_list *list)
 
        lnet_net_lock(LNET_LOCK_EX);
        list_for_each_entry(lpni, &the_lnet.ln_mt_peerNIRecovq, lpni_recovery) {
-               list->rlst_nid_array[i] = lpni->lpni_nid;
+               list->rlst_nid_array[i] = lnet_nid_to_nid4(&lpni->lpni_nid);
                i++;
                if (i >= LNET_MAX_SHOW_NUM_NID)
                        break;
@@ -3756,8 +4014,10 @@ LNetCtl(unsigned int cmd, void *arg)
 {
        struct libcfs_ioctl_data *data = arg;
        struct lnet_ioctl_config_data *config;
-       struct lnet_process_id    id = {0};
+       struct lnet_process_id    id4 = {};
+       struct lnet_processid     id = {};
        struct lnet_ni           *ni;
+       struct lnet_nid           nid;
        int                       rc;
 
        BUILD_BUG_ON(sizeof(struct lnet_ioctl_net_config) +
@@ -3766,7 +4026,7 @@ LNetCtl(unsigned int cmd, void *arg)
        switch (cmd) {
        case IOC_LIBCFS_GET_NI:
                rc = LNetGetId(data->ioc_count, &id);
-               data->ioc_nid = id.nid;
+               data->ioc_nid = lnet_nid_to_nid4(&id.nid);
                return rc;
 
        case IOC_LIBCFS_FAIL_NID:
@@ -3785,10 +4045,11 @@ LNetCtl(unsigned int cmd, void *arg)
                          config->cfg_config_u.cfg_route.rtr_sensitivity;
                }
 
+               lnet_nid4_to_nid(config->cfg_nid, &nid);
                mutex_lock(&the_lnet.ln_api_mutex);
                rc = lnet_add_route(config->cfg_net,
                                    config->cfg_config_u.cfg_route.rtr_hop,
-                                   config->cfg_nid,
+                                   &nid,
                                    config->cfg_config_u.cfg_route.
                                        rtr_priority, sensitivity);
                mutex_unlock(&the_lnet.ln_api_mutex);
@@ -3801,8 +4062,9 @@ LNetCtl(unsigned int cmd, void *arg)
                if (config->cfg_hdr.ioc_len < sizeof(*config))
                        return -EINVAL;
 
+               lnet_nid4_to_nid(config->cfg_nid, &nid);
                mutex_lock(&the_lnet.ln_api_mutex);
-               rc = lnet_del_route(config->cfg_net, config->cfg_nid);
+               rc = lnet_del_route(config->cfg_net, &nid);
                mutex_unlock(&the_lnet.ln_api_mutex);
                return rc;
 
@@ -3892,6 +4154,14 @@ LNetCtl(unsigned int cmd, void *arg)
                return rc;
        }
 
+       case IOC_LIBCFS_RESET_LNET_STATS:
+       {
+               mutex_lock(&the_lnet.ln_api_mutex);
+               lnet_counters_reset();
+               mutex_unlock(&the_lnet.ln_api_mutex);
+               return 0;
+       }
+
        case IOC_LIBCFS_CONFIG_RTR:
                config = arg;
 
@@ -3990,27 +4260,31 @@ LNetCtl(unsigned int cmd, void *arg)
 
        case IOC_LIBCFS_ADD_PEER_NI: {
                struct lnet_ioctl_peer_cfg *cfg = arg;
+               struct lnet_nid prim_nid;
 
                if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg))
                        return -EINVAL;
 
                mutex_lock(&the_lnet.ln_api_mutex);
-               rc = lnet_add_peer_ni(cfg->prcfg_prim_nid,
-                                     cfg->prcfg_cfg_nid,
-                                     cfg->prcfg_mr);
+               lnet_nid4_to_nid(cfg->prcfg_prim_nid, &prim_nid);
+               lnet_nid4_to_nid(cfg->prcfg_cfg_nid, &nid);
+               rc = lnet_add_peer_ni(&prim_nid, &nid, cfg->prcfg_mr, false);
                mutex_unlock(&the_lnet.ln_api_mutex);
                return rc;
        }
 
        case IOC_LIBCFS_DEL_PEER_NI: {
                struct lnet_ioctl_peer_cfg *cfg = arg;
+               struct lnet_nid prim_nid;
 
                if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg))
                        return -EINVAL;
 
                mutex_lock(&the_lnet.ln_api_mutex);
-               rc = lnet_del_peer_ni(cfg->prcfg_prim_nid,
-                                     cfg->prcfg_cfg_nid);
+               lnet_nid4_to_nid(cfg->prcfg_prim_nid, &prim_nid);
+               lnet_nid4_to_nid(cfg->prcfg_cfg_nid, &nid);
+               rc = lnet_del_peer_ni(&prim_nid,
+                                     &nid);
                mutex_unlock(&the_lnet.ln_api_mutex);
                return rc;
        }
@@ -4087,6 +4361,25 @@ LNetCtl(unsigned int cmd, void *arg)
                return 0;
        }
 
+       case IOC_LIBCFS_SET_CONNS_PER_PEER: {
+               struct lnet_ioctl_reset_conns_per_peer_cfg *cfg = arg;
+               int value;
+
+               if (cfg->rcpp_hdr.ioc_len < sizeof(*cfg))
+                       return -EINVAL;
+               if (cfg->rcpp_value < 0)
+                       value = 1;
+               else
+                       value = cfg->rcpp_value;
+               CDEBUG(D_NET,
+                      "Setting conns_per_peer to %d for %s. all = %d\n",
+                      value, libcfs_nid2str(cfg->rcpp_nid), cfg->rcpp_all);
+               mutex_lock(&the_lnet.ln_api_mutex);
+               lnet_ni_set_conns_per_peer(cfg->rcpp_nid, value, cfg->rcpp_all);
+               mutex_unlock(&the_lnet.ln_api_mutex);
+               return 0;
+       }
+
        case IOC_LIBCFS_NOTIFY_ROUTER: {
                time64_t deadline = ktime_get_real_seconds() - data->ioc_u64[0];
 
@@ -4100,10 +4393,12 @@ LNetCtl(unsigned int cmd, void *arg)
        }
 
        case IOC_LIBCFS_LNET_DIST:
-               rc = LNetDist(data->ioc_nid, &data->ioc_nid, &data->ioc_u32[1]);
+               lnet_nid4_to_nid(data->ioc_nid, &nid);
+               rc = LNetDist(&nid, &nid, &data->ioc_u32[1]);
                if (rc < 0 && rc != -EHOSTUNREACH)
                        return rc;
 
+               data->ioc_nid = lnet_nid_to_nid4(&nid);
                data->ioc_u32[0] = rc;
                return 0;
 
@@ -4117,8 +4412,8 @@ LNetCtl(unsigned int cmd, void *arg)
        case IOC_LIBCFS_PING: {
                signed long timeout;
 
-               id.nid = data->ioc_nid;
-               id.pid = data->ioc_u32[0];
+               id4.nid = data->ioc_nid;
+               id4.pid = data->ioc_u32[0];
 
                /* If timeout is negative then set default of 3 minutes */
                if (((s32)data->ioc_u32[1] <= 0) ||
@@ -4127,7 +4422,7 @@ LNetCtl(unsigned int cmd, void *arg)
                else
                        timeout = nsecs_to_jiffies(data->ioc_u32[1] * NSEC_PER_MSEC);
 
-               rc = lnet_ping(id, timeout, data->ioc_pbuf1,
+               rc = lnet_ping(id4, &LNET_ANY_NID, timeout, data->ioc_pbuf1,
                               data->ioc_plen1 / sizeof(struct lnet_process_id));
 
                if (rc < 0)
@@ -4139,9 +4434,21 @@ LNetCtl(unsigned int cmd, void *arg)
 
        case IOC_LIBCFS_PING_PEER: {
                struct lnet_ioctl_ping_data *ping = arg;
+               struct lnet_nid src_nid = LNET_ANY_NID;
                struct lnet_peer *lp;
                signed long timeout;
 
+               /* Check if the supplied ping data supports source nid
+                * NB: This check is sufficient if lnet_ioctl_ping_data has
+                * additional fields added, but if they are re-ordered or
+                * fields removed then this will break. It is expected that
+                * these ioctls will be replaced with netlink implementation, so
+                * it is probably not worth coming up with a more robust version
+                * compatibility scheme.
+                */
+               if (ping->ping_hdr.ioc_len >= sizeof(struct lnet_ioctl_ping_data))
+                       lnet_nid4_to_nid(ping->ping_src, &src_nid);
+
                /* If timeout is negative then set default of 3 minutes */
                if (((s32)ping->op_param) <= 0 ||
                    ping->op_param > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC))
@@ -4149,16 +4456,18 @@ LNetCtl(unsigned int cmd, void *arg)
                else
                        timeout = nsecs_to_jiffies(ping->op_param * NSEC_PER_MSEC);
 
-               rc = lnet_ping(ping->ping_id, timeout,
+               rc = lnet_ping(ping->ping_id, &src_nid, timeout,
                               ping->ping_buf,
                               ping->ping_count);
                if (rc < 0)
                        return rc;
 
                mutex_lock(&the_lnet.ln_api_mutex);
-               lp = lnet_find_peer(ping->ping_id.nid);
+               lnet_nid4_to_nid(ping->ping_id.nid, &nid);
+               lp = lnet_find_peer(&nid);
                if (lp) {
-                       ping->ping_id.nid = lp->lp_primary_nid;
+                       ping->ping_id.nid =
+                               lnet_nid_to_nid4(&lp->lp_primary_nid);
                        ping->mr_info = lnet_peer_is_multi_rail(lp);
                        lnet_peer_decref_locked(lp);
                }
@@ -4179,9 +4488,11 @@ LNetCtl(unsigned int cmd, void *arg)
                        return rc;
 
                mutex_lock(&the_lnet.ln_api_mutex);
-               lp = lnet_find_peer(discover->ping_id.nid);
+               lnet_nid4_to_nid(discover->ping_id.nid, &nid);
+               lp = lnet_find_peer(&nid);
                if (lp) {
-                       discover->ping_id.nid = lp->lp_primary_nid;
+                       discover->ping_id.nid =
+                               lnet_nid_to_nid4(&lp->lp_primary_nid);
                        discover->mr_info = lnet_peer_is_multi_rail(lp);
                        lnet_peer_decref_locked(lp);
                }
@@ -4191,6 +4502,106 @@ LNetCtl(unsigned int cmd, void *arg)
                return 0;
        }
 
+       case IOC_LIBCFS_ADD_UDSP: {
+               struct lnet_ioctl_udsp *ioc_udsp = arg;
+               __u32 bulk_size = ioc_udsp->iou_hdr.ioc_len;
+
+               mutex_lock(&the_lnet.ln_api_mutex);
+               rc = lnet_udsp_demarshal_add(arg, bulk_size);
+               if (!rc) {
+                       rc = lnet_udsp_apply_policies(NULL, false);
+                       CDEBUG(D_NET, "policy application returned %d\n", rc);
+                       rc = 0;
+               }
+               mutex_unlock(&the_lnet.ln_api_mutex);
+
+               return rc;
+       }
+
+       case IOC_LIBCFS_DEL_UDSP: {
+               struct lnet_ioctl_udsp *ioc_udsp = arg;
+               int idx = ioc_udsp->iou_idx;
+
+               if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp))
+                       return -EINVAL;
+
+               mutex_lock(&the_lnet.ln_api_mutex);
+               rc = lnet_udsp_del_policy(idx);
+               if (!rc) {
+                       rc = lnet_udsp_apply_policies(NULL, false);
+                       CDEBUG(D_NET, "policy re-application returned %d\n",
+                              rc);
+                       rc = 0;
+               }
+               mutex_unlock(&the_lnet.ln_api_mutex);
+
+               return rc;
+       }
+
+       case IOC_LIBCFS_GET_UDSP_SIZE: {
+               struct lnet_ioctl_udsp *ioc_udsp = arg;
+               struct lnet_udsp *udsp;
+
+               if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp))
+                       return -EINVAL;
+
+               rc = 0;
+
+               mutex_lock(&the_lnet.ln_api_mutex);
+               udsp = lnet_udsp_get_policy(ioc_udsp->iou_idx);
+               if (!udsp) {
+                       rc = -ENOENT;
+               } else {
+                       /* coming in iou_idx will hold the idx of the udsp
+                        * to get the size of. going out the iou_idx will
+                        * hold the size of the UDSP found at the passed
+                        * in index.
+                        */
+                       ioc_udsp->iou_idx = lnet_get_udsp_size(udsp);
+                       if (ioc_udsp->iou_idx < 0)
+                               rc = -EINVAL;
+               }
+               mutex_unlock(&the_lnet.ln_api_mutex);
+
+               return rc;
+       }
+
+       case IOC_LIBCFS_GET_UDSP: {
+               struct lnet_ioctl_udsp *ioc_udsp = arg;
+               struct lnet_udsp *udsp;
+
+               if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp))
+                       return -EINVAL;
+
+               rc = 0;
+
+               mutex_lock(&the_lnet.ln_api_mutex);
+               udsp = lnet_udsp_get_policy(ioc_udsp->iou_idx);
+               if (!udsp)
+                       rc = -ENOENT;
+               else
+                       rc = lnet_udsp_marshal(udsp, ioc_udsp);
+               mutex_unlock(&the_lnet.ln_api_mutex);
+
+               return rc;
+       }
+
+       case IOC_LIBCFS_GET_CONST_UDSP_INFO: {
+               struct lnet_ioctl_construct_udsp_info *info = arg;
+
+               if (info->cud_hdr.ioc_len < sizeof(*info))
+                       return -EINVAL;
+
+               CDEBUG(D_NET, "GET_UDSP_INFO for %s\n",
+                      libcfs_nid2str(info->cud_nid));
+
+               mutex_lock(&the_lnet.ln_api_mutex);
+               lnet_udsp_get_construct_info(info);
+               mutex_unlock(&the_lnet.ln_api_mutex);
+
+               return 0;
+       }
+
        default:
                ni = lnet_net2ni_addref(data->ioc_net);
                if (ni == NULL)
@@ -4208,9 +4619,9 @@ LNetCtl(unsigned int cmd, void *arg)
 }
 EXPORT_SYMBOL(LNetCtl);
 
-void LNetDebugPeer(struct lnet_process_id id)
+void LNetDebugPeer(struct lnet_processid *id)
 {
-       lnet_debug_peer(id.nid);
+       lnet_debug_peer(lnet_nid_to_nid4(&id->nid));
 }
 EXPORT_SYMBOL(LNetDebugPeer);
 
@@ -4222,7 +4633,7 @@ EXPORT_SYMBOL(LNetDebugPeer);
  * \retval true                If peer NID is on the local node.
  * \retval false       If peer NID is not on the local node.
  */
-bool LNetIsPeerLocal(lnet_nid_t nid)
+bool LNetIsPeerLocal(struct lnet_nid *nid)
 {
        struct lnet_net *net;
        struct lnet_ni *ni;
@@ -4231,7 +4642,7 @@ bool LNetIsPeerLocal(lnet_nid_t nid)
        cpt = lnet_net_lock_current();
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
-                       if (ni->ni_nid == nid) {
+                       if (nid_same(&ni->ni_nid, nid)) {
                                lnet_net_unlock(cpt);
                                return true;
                        }
@@ -4255,7 +4666,7 @@ EXPORT_SYMBOL(LNetIsPeerLocal);
  * \retval -ENOENT If no interface has been found.
  */
 int
-LNetGetId(unsigned int index, struct lnet_process_id *id)
+LNetGetId(unsigned int index, struct lnet_processid *id)
 {
        struct lnet_ni   *ni;
        struct lnet_net  *net;
@@ -4268,6 +4679,9 @@ LNetGetId(unsigned int index, struct lnet_process_id *id)
 
        list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
                list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
+                       if (!nid_is_nid4(&ni->ni_nid))
+                               /* FIXME this needs to be handled */
+                               continue;
                        if (index-- != 0)
                                continue;
 
@@ -4310,20 +4724,22 @@ lnet_ping_event_handler(struct lnet_event *event)
                complete(&pd->completion);
 }
 
-static int lnet_ping(struct lnet_process_id id, signed long timeout,
-                    struct lnet_process_id __user *ids, int n_ids)
+static int lnet_ping(struct lnet_process_id id4, struct lnet_nid *src_nid,
+                    signed long timeout, struct lnet_process_id __user *ids,
+                    int n_ids)
 {
        struct lnet_md md = { NULL };
        struct ping_data pd = { 0 };
        struct lnet_ping_buffer *pbuf;
        struct lnet_process_id tmpid;
+       struct lnet_processid id;
        int i;
        int nob;
        int rc;
        int rc2;
 
        /* n_ids limit is arbitrary */
-       if (n_ids <= 0 || id.nid == LNET_NID_ANY)
+       if (n_ids <= 0 || id4.nid == LNET_NID_ANY)
                return -EINVAL;
 
        /*
@@ -4333,8 +4749,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
        if (n_ids > lnet_interfaces_max)
                n_ids = lnet_interfaces_max;
 
-       if (id.pid == LNET_PID_ANY)
-               id.pid = LNET_PID_LUSTRE;
+       if (id4.pid == LNET_PID_ANY)
+               id4.pid = LNET_PID_LUSTRE;
 
        pbuf = lnet_ping_buffer_alloc(n_ids, GFP_NOFS);
        if (!pbuf)
@@ -4357,8 +4773,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
                goto fail_ping_buffer_decref;
        }
 
-       rc = LNetGet(LNET_NID_ANY, pd.mdh, id,
-                    LNET_RESERVED_PORTAL,
+       lnet_pid4_to_pid(id4, &id);
+       rc = LNetGet(src_nid, pd.mdh, &id, LNET_RESERVED_PORTAL,
                     LNET_PROTO_PING_MATCHBITS, 0, false);
 
        if (rc != 0) {
@@ -4386,7 +4802,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
 
        if (nob < 8) {
                CERROR("%s: ping info too short %d\n",
-                      libcfs_id2str(id), nob);
+                      libcfs_idstr(&id), nob);
                goto fail_ping_buffer_decref;
        }
 
@@ -4394,19 +4810,19 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
                lnet_swap_pinginfo(pbuf);
        } else if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) {
                CERROR("%s: Unexpected magic %08x\n",
-                      libcfs_id2str(id), pbuf->pb_info.pi_magic);
+                      libcfs_idstr(&id), pbuf->pb_info.pi_magic);
                goto fail_ping_buffer_decref;
        }
 
        if ((pbuf->pb_info.pi_features & LNET_PING_FEAT_NI_STATUS) == 0) {
                CERROR("%s: ping w/o NI status: 0x%x\n",
-                      libcfs_id2str(id), pbuf->pb_info.pi_features);
+                      libcfs_idstr(&id), pbuf->pb_info.pi_features);
                goto fail_ping_buffer_decref;
        }
 
        if (nob < LNET_PING_INFO_SIZE(0)) {
                CERROR("%s: Short reply %d(%d min)\n",
-                      libcfs_id2str(id),
+                      libcfs_idstr(&id),
                       nob, (int)LNET_PING_INFO_SIZE(0));
                goto fail_ping_buffer_decref;
        }
@@ -4416,7 +4832,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
 
        if (nob < LNET_PING_INFO_SIZE(n_ids)) {
                CERROR("%s: Short reply %d(%d expected)\n",
-                      libcfs_id2str(id),
+                      libcfs_idstr(&id),
                       nob, (int)LNET_PING_INFO_SIZE(n_ids));
                goto fail_ping_buffer_decref;
        }
@@ -4438,21 +4854,23 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout,
 }
 
 static int
-lnet_discover(struct lnet_process_id id, __u32 force,
+lnet_discover(struct lnet_process_id id4, __u32 force,
              struct lnet_process_id __user *ids, int n_ids)
 {
        struct lnet_peer_ni *lpni;
        struct lnet_peer_ni *p;
        struct lnet_peer *lp;
        struct lnet_process_id *buf;
+       struct lnet_processid id;
        int cpt;
        int i;
        int rc;
 
        if (n_ids <= 0 ||
-           id.nid == LNET_NID_ANY)
+           id4.nid == LNET_NID_ANY)
                return -EINVAL;
 
+       lnet_pid4_to_pid(id4, &id);
        if (id.pid == LNET_PID_ANY)
                id.pid = LNET_PID_LUSTRE;
 
@@ -4468,7 +4886,7 @@ lnet_discover(struct lnet_process_id id, __u32 force,
                return -ENOMEM;
 
        cpt = lnet_net_lock_current();
-       lpni = lnet_nid2peerni_locked(id.nid, LNET_NID_ANY, cpt);
+       lpni = lnet_peerni_by_nid_locked(&id.nid, NULL, cpt);
        if (IS_ERR(lpni)) {
                rc = PTR_ERR(lpni);
                goto out;
@@ -4489,11 +4907,23 @@ lnet_discover(struct lnet_process_id id, __u32 force,
        if (rc)
                goto out_decref;
 
+       /* The lpni (or lp) for this NID may have changed and our ref is
+        * the only thing keeping the old one around. Release the ref
+        * and lookup the lpni again
+        */
+       lnet_peer_ni_decref_locked(lpni);
+       lpni = lnet_peer_ni_find_locked(&id.nid);
+       if (!lpni) {
+               rc = -ENOENT;
+               goto out;
+       }
+       lp = lpni->lpni_peer_net->lpn_peer;
+
        i = 0;
        p = NULL;
        while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) {
                buf[i].pid = id.pid;
-               buf[i].nid = p->lpni_nid;
+               buf[i].nid = lnet_nid_to_nid4(&p->lpni_nid);
                if (++i >= n_ids)
                        break;
        }