Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Kernel Selection Algorithm Modifications

Code Block
static inline int
lnet_get_peer_net_health(struct lnet_peer_net *lpn)
{
	/*
	 * The peer net is highest health value of all lpnis in the peer
	 * This is a value which will be maintained when the lpni health
	 * value is updated.
	 */
	return lpn->lpn_health;
}


/*
 *  /*
 * select an NI from the Nets with highest priority
 */
struct lnet_ni *
lnet_find_best_ni_on_local_net(struct lnet_peer *peer, int md_cpt)
{
...
	/*
	 * All criteria are defaulted at the beginning/* ofgo thethrough loop such that
	 * the firstall the peer_net is selectednets and thenfind overwrittenthe if there is a 
	 * better peer_net found
	 */
	best_ni */
        list_for_each_entry(peer_netlpn, &peer->lp_peer_nets, lpn_peer_nets) {
	...
		struct lnet_net *net;


		best_peer_net = peer_net;

		/* get the the health of a peer net */
		peer_net_health = lnet_                /* select the preferred peer and local nets */
                lpn_healthv = lnet_get_peer_net_healthv_healthlocked(peer_netlpn);
		if (peer_net_health < best_peer_net_health)
			continue;
		else if (peer_net_health > best_peer_net_health)
			best_peer_net_health = peer_net_health;
			
		/* consider only highest priority peer_net */
		else if (peerbest_netlpn_priohealthv > best_peer_net_prio)
			continue;
		else if (peer_net_prio < best_peer_net_prio)
			peer_net_prio = best_peer_net_prio;
		net = lnet_get_net_locked(peer_net->lpn_net_id);
		if (!best_net)
			continue

		net_prio = net->net_priority;
		/*
		 * look only at the Nets with the highest priority and disregard
		 * nets which have lower priority. Nets with equal priority are
		 * examined and the best_ni is selected from amongst them.
		 */
		net_health = lnet_get_local_net_health(net)
		if (net_health < best_net_health)
			continue;
		else if (net_health > best_net_health)
			best_net_health = net_health;
		else if (net_prio > best_net_prio)
			continue;
		else if (net_prio < best_net_prio)
			best_net_prio = net_prio;


		best_net = net
	...
	}
	if (!best_net || !best_peer_net)
		goto fail;


	best_ni = lnet_find_best_ni_on_spec_net(NULL, peer,
										    best_peer_net, md_cpt, false);

...lpn_healthv)
                        continue;

                lpn_sel_prio = lpn->lpn_sel_priority;
                if (best_lpn_sel_prio > lpn_sel_prio)
                        continue;

                /*
                 * The peer's list of nets can contain non-local nets. We
                 * want to only examine the local ones.
                 */
                net = lnet_get_net_locked(lpn->lpn_net_id);
                if (!net)
                        continue;

                net_healthv = lnet_get_net_healthv_locked(net);
                if (best_net_healthv > net_healthv)
                        continue;

                net_sel_prio = net->net_sel_priority;
                if (best_net_sel_prio > net_sel_prio)
                        continue;

                best_net_heatlhv = net_healthv;
                best_net_sel_prio = net_sel_prio;
                best_lpn_healthv = lpn_healthv;
                best_lpn_sel_prio = lpn_sel_prio;
                best_lpn = lpn; 
        }

        if (best_lpn) {
                /*
                 * Now that we have the healthiest and highest priority lpn
                 * It can also be reached by the healthiest and highest priority
                 * local NI, now we select the best_ni
                 */
                best_ni = lnet_find_best_ni_on_spec_net(NULL, peer,
                                                        best_lpn, md_cpt, false);

                if (best_ni)
                        /* increment sequence number so we can round robin */
                        best_ni->ni_seq++;
        }

        return best_ni;
}

/*
 * select the NI with the highest priority 
 */
static struct lnet_ni *
lnet_get_best_ni(struct lnet_net *local_net, struct lnet_ni *best_ni,
				 struct lnet_peer *peer, struct lnet_peer_net *peer_net,
				 int md_cpt)
{
...
	ni_prio = ni->ni_priority;

	if (ni_fatal) {
		continue;
	} else if (ni_healthv < best_healthv) {
		continue;
	} else if (ni_healthv > best_healthv) {
		best_healthv = ni_healthv;
		if (distance < shortest_distance)
			shortest_distance = distance;
	/*
	 * if this NI is lower in priority than the one already set then discard it
 	 * otherwise use it and set the best priority so far to this NI's.
	 * keep track of the shortest distance because it is tested later
	 */
	} else if ni_prio > best_ni_prio) {
		continue;
	} else if (ni_prio < best_ni_prio)
		best_ni_prio = ni_prio;
		if (distance < shortest_distance)
			shortest_distance = distance;
	}

...
}

/*
 * When a UDSP rule associates local NIs with remote NIs, the list of local NIs NIDs
 * is flattened to a list in the associated peer_NI. When selecting a peer NI, the
 * peer NI with the corresponding preferred local NI is selected.
 */
bool
lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid)
{
...
}

/*
 * select the peer NI with the highest priority first and then check
 * if it's preferred.
 */ 
static struct lnet_peer_ni *
lnet_select_peer_ni(struct lnet_send_data *sd, struct lnet_peer *peer,
					struct lnet_peer_net *peer_net)
{
...
	/*
	 * For Non-MR peers we always want to use the preferred NID because
	 * if we don't the non-MR peer will have problems when it receives
	 * messages from a different NI other than the one it's expecting.
	 * However, for MR cases we need to adhere to the rule that health
	 * always trumps all other criteria. In the preferred NIDs case, if
	 * we have a healthier peer-NI which doesn't have the local_ni on its
	 * preferred list, then we should choose it.
	 *
	 * This scenario is handled here: lnet_handle_send_case_locked()
	 */
	ni_is_pref = lnet_peer_is_pref_nid_locked(lpni, best_ni->ni_nid);

	lpni_prio = lpni->lpni_priority;

	if (lpni_healthv < best_lpni_healthv)
		continue;
	/*
	 * select the NI with the highest priority.
	 */
	else if lpni_prio > best_lpni_prio)
		continue;
	else if (lpni_prio < best_lpni_prio)
		best_lpni_prio = lpni_prio;
	/*
	 * select the NI which has the best_ni's NID in its preferred list
	 */
	else if (!preferred && ni_is_pref)
		preferred = true;
...
} 


static int
lnet_handle_find_routed_path(struct lnet_send_data *sd,
							 lnet_nid_t dst_nid,
							 struct lnet_peer_ni **gw_lpni,
							 struct lnet_peer **gw_peer)
{
...
	lpni = lnet_find_peer_ni_locked(dst_nid);
	peer = lpni->lpni_net->lpn_peer;
	list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) {
		peer_net_priority = peer_net->lpn_priority;
		if (peer_net_priority > peer_net_best_priority)
			continue;
		else if (peer_net_priority < peer_net_best_priority)
			peer_net_best_priority = peer_net_priority;
		lpni = NULL;
		while ((lpni = lnet_get_next_peer_ni_locked(peer, peer_net, lpni)) {
			/* find best gw for this lpni */
			lpni_prio = lpni->lpni_priority;
			if (lpni_prio > lpni_best_prio)
				continue;
			else if (lpni_prio < lpni_best_prio)
				lpni_best_prio = lpni_prio;


			best_lpni = lpni;
			...
		}
	}
...
	/*
	 * lnet_find_route_locked will be changed to consider the list of
	 * gw NIDs on the lpni
	 */
	gw = lnet_find_route_locked(NULL, best_lpni, sd->sd_rtr_nid);
	...
	/*
	 * if gw is MR then select best_NI. Increment the sequence number of
	 * the gw NI for Round Robin selection.
	 */
}

...

  1. When examining the peer_net, we need to examin its health. The health of a peer_net can be derived from the health of the NIs in that peer_net. We can have a health value in the peer_net, which is set to the best health value of all the peer_NIs in that peer_Net. When we are selecting the peer_net in lnet_find_best_ni_on_local_net(), then we test that health value. This logic can be implemented for local networks as well. The loop will then select the best pair of peer and local Nets, then the best_ni is selected from the best network outside the loop.

    1. There are two ways to maintain the peer_net and local net health values. On the fly, whenever we change one of the constituents' health value. Or we can simply derive it by iterating through all the net constituents and find the best health value. The latter approach is easier to implement and performance wise is about the same. With the former approach, we will need to re-derive the net health every time the constituents' health value changes. It is better to just pull that information on demand.
  2. For Non-MR peers we always want to use the preferred NID because if we don't the non-MR peer will have problems when it receives messages from a different NI other than the one it's expecting. However, for MR cases we need to adhere to the rule that health always trumps all other criteria. In the preferred NIDs case, if we have a healthier peer-NI which doesn't have the local_ni on its preferred list, then we should choose i

  3. We need to select the best peer_net (highest priority). Then from that peer_net we select the peer_ni with the highest priority, and then if that peer_ni has a list of preferred routers, then we select the route to use from this list. For remote peer-nis we never ding the health value because we never send messages directly to it. So if there is a failure to send, we ding the router's NI. The only break to this rule, is for REPLY/ACK case. If we dont' receive the REPLY/ACK, whos's fault is it? the remote peer? or the router? To make things simple, we always blame the route.

  4. distance criteria in the selection of the best local_ni, should be ranked below the priority assigned by the admin.

...