Whamcloud - gitweb
LU-12200 lnet: check peer timeout on a router
[fs/lustre-release.git] / lnet / lnet / lib-move.c
index c6265af..d3cf14b 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 
+extern unsigned int lnet_current_net_count;
+
 static int local_nid_dist_zero = 1;
 module_param(local_nid_dist_zero, int, 0444);
 MODULE_PARM_DESC(local_nid_dist_zero, "Reserved");
@@ -794,12 +796,32 @@ lnet_ni_eager_recv(struct lnet_ni *ni, struct lnet_msg *msg)
        return rc;
 }
 
+static bool
+lnet_is_peer_deadline_passed(struct lnet_peer_ni *lpni, time64_t now)
+{
+       time64_t deadline;
+
+       deadline = lpni->lpni_last_alive +
+                  lpni->lpni_net->net_tunables.lct_peer_timeout;
+
+       /*
+        * assume peer_ni is alive as long as we're within the configured
+        * peer timeout
+        */
+       if (deadline > now)
+               return false;
+
+       return true;
+}
+
 /* NB: returns 1 when alive, 0 when dead, negative when error;
  *     may drop the lnet_net_lock */
 static int
 lnet_peer_alive_locked(struct lnet_ni *ni, struct lnet_peer_ni *lpni,
                       struct lnet_msg *msg)
 {
+       time64_t now = ktime_get_seconds();
+
        if (!lnet_peer_aliveness_enabled(lpni))
                return -ENODEV;
 
@@ -819,6 +841,9 @@ lnet_peer_alive_locked(struct lnet_ni *ni, struct lnet_peer_ni *lpni,
            msg->msg_type == LNET_MSG_REPLY)
                return 1;
 
+       if (!lnet_is_peer_deadline_passed(lpni, now))
+               return true;
+
        return lnet_is_peer_ni_alive(lpni);
 }
 
@@ -1972,6 +1997,11 @@ lnet_initiate_peer_discovery(struct lnet_peer_ni *lpni,
                return 0;
        }
 
+       if (!lnet_msg_discovery(msg) || lnet_peer_is_uptodate(peer)) {
+               lnet_peer_ni_decref_locked(lpni);
+               return 0;
+       }
+
        rc = lnet_discover_peer_locked(lpni, cpt, false);
        if (rc) {
                lnet_peer_ni_decref_locked(lpni);
@@ -2001,22 +2031,61 @@ lnet_handle_find_routed_path(struct lnet_send_data *sd,
                             struct lnet_peer_ni **gw_lpni,
                             struct lnet_peer **gw_peer)
 {
+       int rc;
        struct lnet_peer *gw;
+       struct lnet_peer *lp;
+       struct lnet_peer_net *lpn;
+       struct lnet_peer_net *best_lpn = NULL;
+       struct lnet_remotenet *rnet;
        struct lnet_route *best_route;
        struct lnet_route *last_route;
        struct lnet_peer_ni *lpni = NULL;
+       struct lnet_peer_ni *gwni = NULL;
        lnet_nid_t src_nid = sd->sd_src_nid;
 
-       best_route = lnet_find_route_locked(NULL, LNET_NIDNET(dst_nid),
+       /* we've already looked up the initial lpni using dst_nid */
+       lpni = sd->sd_best_lpni;
+       /* the peer tree must be in existence */
+       LASSERT(lpni && lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer);
+       lp = lpni->lpni_peer_net->lpn_peer;
+
+       list_for_each_entry(lpn, &lp->lp_peer_nets, lpn_peer_nets) {
+               /* is this remote network reachable?  */
+               rnet = lnet_find_rnet_locked(lpn->lpn_net_id);
+               if (!rnet)
+                       continue;
+
+               if (!best_lpn)
+                       best_lpn = lpn;
+
+               if (best_lpn->lpn_seq <= lpn->lpn_seq)
+                       continue;
+
+               best_lpn = lpn;
+       }
+
+       if (!best_lpn) {
+               CERROR("peer %s has no available nets \n",
+                      libcfs_nid2str(sd->sd_dst_nid));
+               return -EHOSTUNREACH;
+       }
+
+       sd->sd_best_lpni = lnet_find_best_lpni_on_net(sd, lp, best_lpn->lpn_net_id);
+       if (!sd->sd_best_lpni) {
+               CERROR("peer %s down\n", libcfs_nid2str(sd->sd_dst_nid));
+               return -EHOSTUNREACH;
+       }
+
+       best_route = lnet_find_route_locked(NULL, best_lpn->lpn_net_id,
                                            sd->sd_rtr_nid, &last_route,
-                                           &lpni);
+                                           &gwni);
        if (!best_route) {
                CERROR("no route to %s from %s\n",
                       libcfs_nid2str(dst_nid), libcfs_nid2str(src_nid));
                return -EHOSTUNREACH;
        }
 
-       if (!lpni) {
+       if (!gwni) {
                CERROR("Internal Error. Route expected to %s from %s\n",
                        libcfs_nid2str(dst_nid),
                        libcfs_nid2str(src_nid));
@@ -2024,19 +2093,18 @@ lnet_handle_find_routed_path(struct lnet_send_data *sd,
        }
 
        gw = best_route->lr_gateway;
-       LASSERT(gw == lpni->lpni_peer_net->lpn_peer);
+       LASSERT(gw == gwni->lpni_peer_net->lpn_peer);
 
        /*
         * Discover this gateway if it hasn't already been discovered.
         * This means we might delay the message until discovery has
         * completed
         */
-       if (lnet_msg_discovery(sd->sd_msg) &&
-           !lnet_peer_is_uptodate(gw)) {
-               sd->sd_msg->msg_src_nid_param = sd->sd_src_nid;
-               return lnet_initiate_peer_discovery(lpni, sd->sd_msg,
-                                                   sd->sd_rtr_nid, sd->sd_cpt);
-       }
+       sd->sd_msg->msg_src_nid_param = sd->sd_src_nid;
+       rc = lnet_initiate_peer_discovery(gwni, sd->sd_msg, sd->sd_rtr_nid,
+                                         sd->sd_cpt);
+       if (rc)
+               return rc;
 
        if (!sd->sd_best_ni)
                sd->sd_best_ni = lnet_find_best_ni_on_spec_net(NULL, gw,
@@ -2053,15 +2121,16 @@ lnet_handle_find_routed_path(struct lnet_send_data *sd,
                return -EFAULT;
        }
 
-       *gw_lpni = lpni;
+       *gw_lpni = gwni;
        *gw_peer = gw;
 
        /*
-        * increment the route sequence number since now we're sure we're
-        * going to use it
+        * increment the sequence numbers since now we're sure we're
+        * going to use this path
         */
        LASSERT(best_route && last_route);
        best_route->lr_seq = last_route->lr_seq + 1;
+       best_lpn->lpn_seq++;
 
        return 0;
 }
@@ -2121,7 +2190,8 @@ lnet_handle_spec_router_dst(struct lnet_send_data *sd)
 }
 
 struct lnet_ni *
-lnet_find_best_ni_on_local_net(struct lnet_peer *peer, int md_cpt)
+lnet_find_best_ni_on_local_net(struct lnet_peer *peer, int md_cpt,
+                              bool discovery)
 {
        struct lnet_peer_net *peer_net = NULL;
        struct lnet_ni *best_ni = NULL;
@@ -2143,6 +2213,14 @@ lnet_find_best_ni_on_local_net(struct lnet_peer *peer, int md_cpt)
                        continue;
                best_ni = lnet_find_best_ni_on_spec_net(best_ni, peer,
                                                   peer_net, md_cpt, false);
+
+               /*
+                * if this is a discovery message and lp_disc_net_id is
+                * specified then use that net to send the discovery on.
+                */
+               if (peer->lp_disc_net_id == peer_net->lpn_net_id &&
+                   discovery)
+                       break;
        }
 
        if (best_ni)
@@ -2312,7 +2390,8 @@ lnet_handle_any_mr_dsta(struct lnet_send_data *sd)
         * networks.
         */
        sd->sd_best_ni = lnet_find_best_ni_on_local_net(sd->sd_peer,
-                                                       sd->sd_md_cpt);
+                                       sd->sd_md_cpt,
+                                       lnet_msg_discovery(sd->sd_msg));
        if (sd->sd_best_ni) {
                sd->sd_best_lpni =
                  lnet_find_best_lpni_on_net(sd, sd->sd_peer,
@@ -2422,11 +2501,11 @@ lnet_handle_any_mr_dst(struct lnet_send_data *sd)
                return rc;
 
        /*
-        * TODO; One possible enhancement is to run the selection
-        * algorithm on the peer. However for remote peers the credits are
-        * not decremented, so we'll be basically going over the peer NIs
-        * in round robin. An MR router will run the selection algorithm
-        * on the next-hop interfaces.
+        * Now that we must route to the destination, we must consider the
+        * MR case, where the destination has multiple interfaces, some of
+        * which we can route to and others we do not. For this reason we
+        * need to select the destination which we can route to and if
+        * there are multiple, we need to round robin.
         */
        rc = lnet_handle_find_routed_path(sd, sd->sd_dst_nid, &gw_lpni,
                                          &gw_peer);
@@ -2597,8 +2676,8 @@ again:
         * trigger discovery.
         */
        peer = lpni->lpni_peer_net->lpn_peer;
-       if (lnet_msg_discovery(msg) && !lnet_peer_is_uptodate(peer)) {
-               rc = lnet_initiate_peer_discovery(lpni, msg, rtr_nid, cpt);
+       rc = lnet_initiate_peer_discovery(lpni, msg, rtr_nid, cpt);
+       if (rc) {
                lnet_peer_ni_decref_locked(lpni);
                lnet_net_unlock(cpt);
                return rc;
@@ -2685,8 +2764,13 @@ lnet_send(lnet_nid_t src_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid)
        LASSERT(!msg->msg_tx_committed);
 
        rc = lnet_select_pathway(src_nid, dst_nid, msg, rtr_nid);
-       if (rc < 0)
+       if (rc < 0) {
+               if (rc == -EHOSTUNREACH)
+                       msg->msg_health_status = LNET_MSG_STATUS_REMOTE_ERROR;
+               else
+                       msg->msg_health_status = LNET_MSG_STATUS_LOCAL_ERROR;
                return rc;
+       }
 
        if (rc == LNET_CREDIT_OK)
                lnet_ni_send(msg->msg_txni, msg);
@@ -3400,9 +3484,15 @@ lnet_monitor_thread(void *arg)
                 * if we wake up every 1 second? Although, we've seen
                 * cases where we get a complaint that an idle thread
                 * is waking up unnecessarily.
+                *
+                * Take into account the current net_count when you wake
+                * up for alive router checking, since we need to check
+                * possibly as many networks as we have configured.
                 */
                interval = min(lnet_recovery_interval,
-                              lnet_transaction_timeout / 2);
+                              min((unsigned int) alive_router_check_interval /
+                                       lnet_current_net_count,
+                                  lnet_transaction_timeout / 2));
                wait_event_interruptible_timeout(the_lnet.ln_mt_waitq,
                                                false,
                                                cfs_time_seconds(interval));
@@ -4103,16 +4193,17 @@ int
 lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid,
           void *private, int rdma_req)
 {
-       int             rc = 0;
-       int             cpt;
-       int             for_me;
-       struct lnet_msg *msg;
-       lnet_pid_t     dest_pid;
-       lnet_nid_t     dest_nid;
-       lnet_nid_t     src_nid;
        struct lnet_peer_ni *lpni;
-       __u32          payload_length;
-       __u32          type;
+       struct lnet_msg *msg;
+       __u32 payload_length;
+       lnet_pid_t dest_pid;
+       lnet_nid_t dest_nid;
+       lnet_nid_t src_nid;
+       bool push = false;
+       int for_me;
+       __u32 type;
+       int rc = 0;
+       int cpt;
 
        LASSERT (!in_interrupt ());
 
@@ -4167,16 +4258,22 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid,
        }
 
        if (the_lnet.ln_routing &&
-           ni->ni_last_alive != ktime_get_real_seconds()) {
-               /* NB: so far here is the only place to set NI status to "up */
+           ni->ni_net->net_last_alive != ktime_get_real_seconds()) {
                lnet_ni_lock(ni);
-               ni->ni_last_alive = ktime_get_real_seconds();
+               spin_lock(&ni->ni_net->net_lock);
+               ni->ni_net->net_last_alive = ktime_get_real_seconds();
+               spin_unlock(&ni->ni_net->net_lock);
                if (ni->ni_status != NULL &&
-                   ni->ni_status->ns_status == LNET_NI_STATUS_DOWN)
+                   ni->ni_status->ns_status == LNET_NI_STATUS_DOWN) {
                        ni->ni_status->ns_status = LNET_NI_STATUS_UP;
+                       push = true;
+               }
                lnet_ni_unlock(ni);
        }
 
+       if (push)
+               lnet_push_update_to_peers(1);
+
        /* Regard a bad destination NID as a protocol error.  Senders should
         * know what they're doing; if they don't they're misconfigured, buggy
         * or malicious so we chop them off at the knees :) */
@@ -4234,7 +4331,7 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid,
        }
 
        if (!list_empty(&the_lnet.ln_drop_rules) &&
-           lnet_drop_rule_match(hdr, NULL)) {
+           lnet_drop_rule_match(hdr, ni->ni_nid, NULL)) {
                CDEBUG(D_NET, "%s, src %s, dst %s: Dropping %s to simulate"
                              "silent message loss\n",
                       libcfs_nid2str(from_nid), libcfs_nid2str(src_nid),
@@ -4346,6 +4443,10 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid,
                        return 0;
                goto drop;
        }
+
+       if (the_lnet.ln_routing)
+               lpni->lpni_last_alive = ktime_get_seconds();
+
        msg->msg_rxpeer = lpni;
        msg->msg_rxni = ni;
        lnet_ni_addref_locked(ni, cpt);