-void
-lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf)
-{
- struct lnet_ni_status *stat;
- int nnis;
- int i;
-
- __swab32s(&pbuf->pb_info.pi_magic);
- __swab32s(&pbuf->pb_info.pi_features);
- __swab32s(&pbuf->pb_info.pi_pid);
- __swab32s(&pbuf->pb_info.pi_nnis);
- nnis = pbuf->pb_info.pi_nnis;
- if (nnis > pbuf->pb_nnis)
- nnis = pbuf->pb_nnis;
- for (i = 0; i < nnis; i++) {
- stat = &pbuf->pb_info.pi_ni[i];
- __swab64s(&stat->ns_nid);
- __swab32s(&stat->ns_status);
- }
- return;
-}
-
-/**
- * parse router-checker pinginfo, record number of down NIs for remote
- * networks on that router.
- */
-static void
-lnet_parse_rc_info(struct lnet_rc_data *rcd)
-{
- struct lnet_ping_buffer *pbuf = rcd->rcd_pingbuffer;
- struct lnet_peer_ni *gw = rcd->rcd_gateway;
- struct lnet_route *rte;
- int nnis;
-
- if (!gw->lpni_alive || !pbuf)
- return;
-
- /*
- * Protect gw->lpni_ping_feats. This can be set from
- * lnet_notify_locked with different locks being held
- */
- spin_lock(&gw->lpni_lock);
-
- if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC))
- lnet_swap_pinginfo(pbuf);
-
- /* NB always racing with network! */
- if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) {
- CDEBUG(D_NET, "%s: Unexpected magic %08x\n",
- libcfs_nid2str(gw->lpni_nid), pbuf->pb_info.pi_magic);
- gw->lpni_ping_feats = LNET_PING_FEAT_INVAL;
- goto out;
- }
-
- gw->lpni_ping_feats = pbuf->pb_info.pi_features;
-
- /* Without NI status info there's nothing more to do. */
- if ((gw->lpni_ping_feats & LNET_PING_FEAT_NI_STATUS) == 0)
- goto out;
-
- /* Determine the number of NIs for which there is data. */
- nnis = pbuf->pb_info.pi_nnis;
- if (pbuf->pb_nnis < nnis) {
- if (rcd->rcd_nnis < nnis)
- rcd->rcd_nnis = nnis;
- nnis = pbuf->pb_nnis;
- }
-
- list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) {
- int down = 0;
- int up = 0;
- int i;
-
- /* If routing disabled then the route is down. */
- if ((gw->lpni_ping_feats & LNET_PING_FEAT_RTE_DISABLED) != 0) {
- rte->lr_downis = 1;
- continue;
- }
-
- for (i = 0; i < nnis; i++) {
- struct lnet_ni_status *stat = &pbuf->pb_info.pi_ni[i];
- lnet_nid_t nid = stat->ns_nid;
-
- if (nid == LNET_NID_ANY) {
- CDEBUG(D_NET, "%s: unexpected LNET_NID_ANY\n",
- libcfs_nid2str(gw->lpni_nid));
- gw->lpni_ping_feats = LNET_PING_FEAT_INVAL;
- goto out;
- }
-
- if (LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
- continue;
-
- if (stat->ns_status == LNET_NI_STATUS_DOWN) {
- down++;
- continue;
- }
-
- if (stat->ns_status == LNET_NI_STATUS_UP) {
- if (LNET_NIDNET(nid) == rte->lr_net) {
- up = 1;
- break;
- }
- continue;
- }
-
- CDEBUG(D_NET, "%s: Unexpected status 0x%x\n",
- libcfs_nid2str(gw->lpni_nid), stat->ns_status);
- gw->lpni_ping_feats = LNET_PING_FEAT_INVAL;
- goto out;
- }
-
- if (up) { /* ignore downed NIs if NI for dest network is up */
- rte->lr_downis = 0;
- continue;
- }
- /* if @down is zero and this route is single-hop, it means
- * we can't find NI for target network */
- if (down == 0 && rte->lr_hops == 1)
- down = 1;
-
- rte->lr_downis = down;
- }
-out:
- spin_unlock(&gw->lpni_lock);
-}
-
-static void
-lnet_router_checker_event(struct lnet_event *event)
-{
- struct lnet_rc_data *rcd = event->md.user_ptr;
- struct lnet_peer_ni *lp;
-
- LASSERT(rcd != NULL);
-
- if (event->unlinked) {
- LNetInvalidateMDHandle(&rcd->rcd_mdh);
- return;
- }
-
- LASSERT(event->type == LNET_EVENT_SEND ||
- event->type == LNET_EVENT_REPLY);
-
- lp = rcd->rcd_gateway;
- LASSERT(lp != NULL);
-
- /* NB: it's called with holding lnet_res_lock, we have a few
- * places need to hold both locks at the same time, please take
- * care of lock ordering */
- lnet_net_lock(lp->lpni_cpt);
- if (!lnet_isrouter(lp) || lp->lpni_rcd != rcd) {
- /* ignore if no longer a router or rcd is replaced */
- goto out;
- }
-
- if (event->type == LNET_EVENT_SEND) {
- lp->lpni_ping_notsent = 0;
- if (event->status == 0)
- goto out;
- }
-
- /* LNET_EVENT_REPLY */
- /* A successful REPLY means the router is up. If _any_ comms
- * to the router fail I assume it's down (this will happen if
- * we ping alive routers to try to detect router death before
- * apps get burned). */
-
- lnet_notify_locked(lp, 1, !event->status, ktime_get_seconds());
- /* The router checker will wake up very shortly and do the
- * actual notification.
- * XXX If 'lp' stops being a router before then, it will still
- * have the notification pending!!! */
-
- if (avoid_asym_router_failure && event->status == 0)
- lnet_parse_rc_info(rcd);
-
- out:
- lnet_net_unlock(lp->lpni_cpt);
-}
-