+lnet_swap_pinginfo(lnet_ping_info_t *info)
+{
+ int i;
+ lnet_ni_status_t *stat;
+
+ __swab32s(&info->pi_version);
+ __swab32s(&info->pi_pid);
+ __swab32s(&info->pi_nnis);
+ for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) {
+ stat = &info->pi_ni[i];
+ __swab64s(&stat->ns_nid);
+ __swab32s(&stat->ns_status);
+ }
+ return;
+}
+
+/* Returns # of down NIs, or negative error codes; ignore downed NIs
+ * if a NI in 'net' is up */
+int
+lnet_router_down_ni(lnet_peer_t *rtr, __u32 net)
+{
+ int i;
+ int down = 0;
+ int ptl_up = 0;
+ int ptl_down = 0;
+ lnet_ping_info_t *info;
+
+ if (!avoid_asym_router_failure)
+ return -ENOENT;
+
+ if (rtr->lp_rcd == NULL)
+ return -EINVAL;
+
+ if (!rtr->lp_alive)
+ return -EINVAL; /* stale lp_rcd */
+
+ info = rtr->lp_rcd->rcd_pinginfo;
+ LASSERT (info != NULL);
+
+ /* NB always racing with network! */
+ if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) {
+ lnet_swap_pinginfo(info);
+ } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) {
+ CDEBUG(D_NETERROR, "%s: Unexpected magic %08x\n",
+ libcfs_nid2str(rtr->lp_nid), info->pi_magic);
+ return -EPROTO;
+ }
+
+ if (info->pi_version == LNET_PROTO_PING_VERSION1)
+ return -ENOENT; /* v1 doesn't carry NI status info */
+
+ if (info->pi_version != LNET_PROTO_PING_VERSION) {
+ CDEBUG(D_NETERROR, "%s: Unexpected version 0x%x\n",
+ libcfs_nid2str(rtr->lp_nid), info->pi_version);
+ return -EPROTO;
+ }
+
+ for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) {
+ lnet_ni_status_t *stat = &info->pi_ni[i];
+ lnet_nid_t nid = stat->ns_nid;
+
+ if (nid == LNET_NID_ANY) {
+ CDEBUG(D_NETERROR, "%s: unexpected LNET_NID_ANY\n",
+ libcfs_nid2str(rtr->lp_nid));
+ return -EPROTO;
+ }
+
+ if (LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
+ continue;
+
+ if (stat->ns_status == LNET_NI_STATUS_DOWN) {
+ if (LNET_NETTYP(LNET_NIDNET(nid)) == PTLLND)
+ ptl_down = 1;
+ else
+ down++;
+ continue;
+ }
+
+ if (stat->ns_status != LNET_NI_STATUS_UP) {
+ CDEBUG(D_NETERROR, "%s: Unexpected status 0x%x\n",
+ libcfs_nid2str(rtr->lp_nid), stat->ns_status);
+ return -EPROTO;
+ }
+
+ /* ignore downed NIs if there's a NI up for dest network */
+ if (LNET_NIDNET(nid) == net)
+ return 0;
+
+ if (LNET_NETTYP(LNET_NIDNET(nid)) == PTLLND)
+ ptl_up = 1;
+ }
+
+ /* ptl NIs are considered down only when they're all down */
+ return down + (ptl_up ? 0 : ptl_down);
+}
+
+void