Esempio n. 1
0
static struct rtentry *
rt_mpath_selectrte(struct rtentry *rte, uint32_t hash)
{
	struct radix_node *rn0, *rn;
	uint32_t total_weight;
	struct rtentry *rt;
	int64_t weight;

	/* beyond here, we use rn as the master copy */
	rn0 = rn = (struct radix_node *)rte;
	rt = rte;

	/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
	total_weight = rn_mpath_count(rn0);
	hash += hashjitter;
	hash %= total_weight;
	for (weight = abs((int32_t)hash);
	     rt != NULL && weight >= rt->rt_weight; 
	     weight -= (rt == NULL) ? 0 : rt->rt_weight) {
		
		/* stay within the multipath routes */
		if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
			break;
		rn = rn->rn_dupedkey;
		rt = (struct rtentry *)rn;
	}

	return (rt);
}
Esempio n. 2
0
void
rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
{
	struct radix_node *rn0, *rn;
	u_int32_t n;
	struct rtentry *rt;
	int64_t weight;

	/*
	 * XXX we don't attempt to lookup cached route again; what should
	 * be done for sendto(3) case?
	 */
	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)
	    && RT_LINK_IS_UP(ro->ro_rt->rt_ifp))
		return;				 
	ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, 0, fibnum);

	/* if the route does not exist or it is not multipath, don't care */
	if (ro->ro_rt == NULL)
		return;
	if (rn_mpath_next((struct radix_node *)ro->ro_rt) == NULL) {
		RT_UNLOCK(ro->ro_rt);
		return;
	}

	/* beyond here, we use rn as the master copy */
	rn0 = rn = (struct radix_node *)ro->ro_rt;
	n = rn_mpath_count(rn0);

	/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
	hash += hashjitter;
	hash %= n;
	for (weight = abs((int32_t)hash), rt = ro->ro_rt;
	     weight >= rt->rt_weight && rn; 
	     weight -= rt->rt_weight) {
		
		/* stay within the multipath routes */
		if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
			break;
		rn = rn->rn_dupedkey;
		rt = (struct rtentry *)rn;
	}
	/* XXX try filling rt_gwroute and avoid unreachable gw  */

	/* gw selection has failed - there must be only zero weight routes */
	if (!rn) {
		RT_UNLOCK(ro->ro_rt);
		ro->ro_rt = NULL;
		return;
	}
	if (ro->ro_rt != rt) {
		RTFREE_LOCKED(ro->ro_rt);
		ro->ro_rt = (struct rtentry *)rn;
		RT_LOCK(ro->ro_rt);
		RT_ADDREF(ro->ro_rt);

	} 
	RT_UNLOCK(ro->ro_rt);
}
Esempio n. 3
0
/*
 * allocate a route, potentially using multipath to select the peer.
 */
void
rtalloc_mpath(struct route *ro, u_int32_t *srcaddrp)
{
#if defined(INET) || defined(INET6)
	struct radix_node *rn;
	int hash, npaths, threshold;
#endif

	/*
	 * return a cached entry if it is still valid, otherwise we increase
	 * the risk of disrupting local flows.
	 */
	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
		return;
	ro->ro_rt = rtalloc1(&ro->ro_dst, RT_REPORT, ro->ro_tableid);

	/* if the route does not exist or it is not multipath, don't care */
	if (!ro->ro_rt || !(ro->ro_rt->rt_flags & RTF_MPATH))
		return;

	/* check if multipath routing is enabled for the specified protocol */
	if (!(0
#ifdef INET
	    || (ipmultipath && ro->ro_dst.sa_family == AF_INET)
#endif
#ifdef INET6
	    || (ip6_multipath && ro->ro_dst.sa_family == AF_INET6)
#endif
	    ))
		return;

#if defined(INET) || defined(INET6)
	/* gw selection by Hash-Threshold (RFC 2992) */
	rn = (struct radix_node *)ro->ro_rt;
	npaths = rn_mpath_count(rn);
	hash = rn_mpath_hash(ro, srcaddrp) & 0xffff;
	threshold = 1 + (0xffff / npaths);
	while (hash > threshold && rn) {
		/* stay within the multipath routes */
		if (rn_mpath_next(rn, 0) == NULL)
			break;
		rn = rn->rn_dupedkey;
		hash -= threshold;
	}

	/* XXX try filling rt_gwroute and avoid unreachable gw  */

	/* if gw selection fails, use the first match (default) */
	if (!rn)
		return;

	rtfree(ro->ro_rt);
	ro->ro_rt = (struct rtentry *)rn;
	ro->ro_rt->rt_refcnt++;
#endif
}
Esempio n. 4
0
void
rtalloc_mpath(struct route *ro, int hash)
{
	struct radix_node *rn0, *rn;
	int n;

	/*
	 * XXX we don't attempt to lookup cached route again; what should
	 * be done for sendto(3) case?
	 */
	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
		return;				 /* XXX */
#ifdef __FreeBSD__
	ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL);
#else
	ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
#endif
	/* if the route does not exist or it is not multipath, don't care */
	if (!ro->ro_rt || !rn_mpath_next((struct radix_node *)ro->ro_rt))
		return;

	/* beyond here, we use rn as the master copy */
	rn0 = rn = (struct radix_node *)ro->ro_rt;
	n = rn_mpath_count(rn0);

	/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
	hash += hashjitter;
	hash %= n;
	while (hash-- > 0 && rn) {
		/* stay within the multipath routes */
		if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
			break;
		rn = rn->rn_dupedkey;
	}

	/* XXX try filling rt_gwroute and avoid unreachable gw  */

	/* if gw selection fails, use the first match (default) */
	if (!rn)
		return;

	rtfree(ro->ro_rt);
	ro->ro_rt = (struct rtentry *)rn;
	ro->ro_rt->rt_refcnt++;
}
Esempio n. 5
0
void
rn_mpath_reprio(struct radix_node *rn, int newprio)
{
	struct radix_node	*prev = rn->rn_p;
	struct radix_node	*next = rn->rn_dupedkey;
	struct radix_node	*t, *tt, *saved_tt, *head;
	struct rtentry		*rt = (struct rtentry *)rn;
	int			 mid, oldprio, prioinv = 0;

	oldprio = rt->rt_priority;
	rt->rt_priority = newprio;

	/* same prio, no change needed */
	if (oldprio == newprio)
		return;
	if (rn_mpath_next(rn, 1) == NULL) {
		/* no need to move node, route is alone */
		if (prev->rn_mask != rn->rn_mask)
			return;
		/* ... or route is last and prio gets bigger */
		if (oldprio < newprio)
			return;
	}

	/* remove node from dupedkey list and reinsert at correct place */
	if (prev->rn_dupedkey == rn) {
		prev->rn_dupedkey = next;
		if (next)
			next->rn_p = prev;
		else
			next = prev;
	} else {
		if (next == NULL)
			panic("next == NULL");
		next->rn_p = prev;
		if (prev->rn_l == rn)
			prev->rn_l = next;
		else
			prev->rn_r = next;
	}

	/* re-insert rn at the right spot, so first rewind to the head */
	for (tt = next; tt->rn_p->rn_dupedkey == tt; tt = tt->rn_p)
		;
	saved_tt = tt;

	/*
	 * Stolen from radix.c rn_addroute().
	 * This is nasty code with a certain amount of magic and dragons.
	 * t is the element where the re-priorized rn is inserted -- before
	 * or after depending on prioinv. saved_tt points to the head of the
	 * dupedkey chain and tt is a bit of a helper
	 *
	 * First we skip with tt to the start of the mpath group then we
	 * search the right spot to enter our node.
	 */
	for (; tt; tt = tt->rn_dupedkey)
		if (rn->rn_mask == tt->rn_mask)
			break;
	head = tt; /* store current head entry for rn_mklist check */

	tt = rn_mpath_prio(tt, newprio);
	if (((struct rtentry *)tt)->rt_priority != newprio) {
		if (((struct rtentry *)tt)->rt_priority > newprio)
			prioinv = 1;
		t = tt;
	} else {
		mid = rn_mpath_count(tt) / 2;
		do {
			t = tt;
			tt = rn_mpath_next(tt, 0);
		} while (tt && --mid > 0);
	}

	/* insert rn before or after t depending on prioinv, tt and saved_tt */
	if (tt == saved_tt && prioinv) {
		/* link in at head of list */
		rn->rn_dupedkey = tt;
		rn->rn_p = tt->rn_p;
		tt->rn_p = rn;
		if (rn->rn_p->rn_l == tt)
			rn->rn_p->rn_l = rn;
		else
			rn->rn_p->rn_r = rn;
	} else if (prioinv == 1) {
		rn->rn_dupedkey = t;
		t->rn_p->rn_dupedkey = rn;
		rn->rn_p = t->rn_p;
		t->rn_p = rn;
	} else {
		rn->rn_dupedkey = t->rn_dupedkey;
		t->rn_dupedkey = rn;
		rn->rn_p = t;
		if (rn->rn_dupedkey)
			rn->rn_dupedkey->rn_p = rn;
	}

#ifdef RN_DEBUG
	/* readd at head of creation list */
	for (t = rn_clist; t && t->rn_ybro != rn; t = t->rn_ybro)
		;
	if (t)
		t->rn_ybro = rn->rn_ybro;
	rn->rn_ybro = rn_clist;
	rn_clist = rn;
#endif

	if (rn->rn_mklist && rn->rn_flags & RNF_NORMAL) {
		/* the rn_mklist needs to be fixed if the best route changed */
		if (rn->rn_mklist->rm_leaf != rn) {
			if (rn->rn_mklist->rm_leaf->rn_p == rn)
				/* changed route is now best */
				rn->rn_mklist->rm_leaf = rn;
		} else {
			if (rn->rn_dupedkey != head)
				/* rn moved behind head, so head is new head */
				rn->rn_mklist->rm_leaf = head;
		}
	}
}