OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sctp/sctp_route.c


File /code/strss7/drivers/sctp/sctp_route.c



#ident "@(#) $RCSfile: sctp_route.c,v $ $Name:  $($Revision: 0.8.2.10 $) $Date: 2003/05/30 21:15:53 $"

static char const ident[] =
    "$RCSfile: sctp_route.c,v $ $Name:  $($Revision: 0.8.2.10 $) $Date: 2003/05/30 21:15:53 $";

#define __NO_VERSION__

#include <linux/config.h>
#include <linux/version.h>
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/module.h>

#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/cmn_err.h>
#include <sys/dki.h>

#include "../debug.h"
#include "../bufq.h"

#include "sctp.h"
#include "sctp_defs.h"
#include "sctp_cache.h"
#include "sctp_route.h"
#include "sctp_output.h"

#undef min			/* LiS should not have defined these */
#undef max			/* LiS should not have defined these */

#define sctp_daddr sctp_daddr__
#define sctp_saddr sctp_saddr__
#define sctp_strm  sctp_strm__
#define sctp_dup   sctp_dup__
#ifdef ASSERT
#undef ASSERT
#endif

#include <net/ip.h>
#include <net/icmp.h>
#include <net/route.h>

#undef sctp_daddr
#undef sctp_saddr
#undef sctp_strm
#undef sctp_dup
#ifdef ASSERT
#undef ASSERT
#endif

/*
 *  =========================================================================
 *
 *  IP OUTPUT: ROUTING FUNCTIONS
 *
 *  =========================================================================
 *
 *  MULTI-HOMED IP ROUTING FUNCTIONS
 *
 *  -------------------------------------------------------------------------
 *
 *  CHOSE BEST
 *  -------------------------------------------------------------------------
 *  This function is called by sctp_update_routes to choose the best primary
 *  and secondary addresses.  We alway return a usable address if possible,
 *  even if the secondary is not different from the primary.  This is called
 *  only when a route fails or a destination goes inactive due to too many
 *  timeouts, so destinations that are timing out are not so large a factor.
 */
STATIC sctp_daddr_t *sctp_choose_best(sp, not)
	sctp_t *sp;
	sctp_daddr_t *not;
{
	sctp_daddr_t *best, *sd;

	assert(sp);

	if ((best = sp->daddr))
		for (sd = best->next; sd; sd = sd->next) {
			/* choose usable over unusable */
			if (!best->dst_cache && sd->dst_cache) {
				best = sd;
				continue;
			}
			/* choose active routes */
			if (best->retransmits > best->max_retrans && sd->retransmits <= sd->max_retrans) {
				best = sd;
				continue;
			}
			/* choose routes without timeouts */
			if (best->retransmits && !(sd->retransmits)) {
				best = sd;
				continue;
			}
			/* choose routes without dups */
			if (best->dups && !(sd->dups)) {
				best = sd;
				continue;
			}
			/* choose usable alternate if possible */
			if (best == not && sd != not) {
				best = sd;
				continue;
			}
			/* choose routes with least excessive timeouts */
			if (best->retransmits + sd->max_retrans > sd->retransmits + best->max_retrans) {
				best = sd;
				continue;
			}
			/* choose routes with the least duplicates */
			if (best->dups > sd->dups) {
				best = sd;
				continue;
			}
			/* choose lowest rto */
			if (best->rto > sd->rto) {
				best = sd;
				continue;
			}
			/* choose not to slow start */
			if (best->cwnd <= best->ssthresh && sd->cwnd > sd->ssthresh) {
				best = sd;
				continue;
			}
			/* choose largest available window */
			if (best->cwnd + best->mtu - 1 - best->in_flight < sd->cwnd + sd->mtu - 1 - sd->in_flight) {
				best = sd;
				continue;
			}
		}
	return (best);
}

/*
 *  UPDATE ROUTES
 *  -------------------------------------------------------------------------
 *  This function is called whenever there is a routing problem or whenever a
 *  timeout occurs on a destination.  It's purpose is to perform a complete
 *  re-analysis of the available destination addresses and IP routing and
 *  establish new routes as required and set the (primary) and (secondary)
 *  destination addresses.
 */
#ifndef sysctl_ip_dynaddr
#define sysctl_ip_dynaddr 0
#else
extern int sysctl_ip_dynaddr;
#endif
/*
 *  sysctl_ip_dynaddr: this symbol is normally not exported, but we exported
 *  for the Linux Native version of SCTP, so we may have to treat it as extern
 *  here...
 */
int sctp_update_routes(sp, force_reselect)
	sctp_t *sp;
	int force_reselect;
{
	int err = -EHOSTUNREACH;
	int mtu_changed = 0;
	int viable_route = 0;
	int route_changed = 0;

	sctp_daddr_t *sd;
	sctp_daddr_t *taddr, *raddr;

	int old_pmtu;

	assert(sp);
	ensure(sp->daddr, return (-EFAULT));

	old_pmtu = xchg(&sp->pmtu, INT_MAX);	/* big enough? */
	taddr = sp->taddr;
	raddr = sp->raddr;
	/* 
	 *  First we check our cached routes..
	 */
	for (sd = sp->daddr; sd; sd = sd->next) {
		struct rtable *rt = (struct rtable *) sd->dst_cache;

		if (rt && (rt->u.dst.obsolete || rt->u.dst.ops->check(&rt->u.dst, 0))) {
			rare();
			sd->dst_cache = NULL;
			ip_rt_put(rt);
			sd->saddr = 0;

			route_changed = 1;
		}
		if (!rt) {
			if (sd->dif)
				sd->saddr = 0;
			if ((err =
			     ip_route_connect(&rt, sd->daddr, sd->saddr,
					      RT_TOS(sp->ip_tos) | RTO_CONN | sp->ip_dontroute, sd->dif)) < 0) {
				rare();
				continue;
			}
			if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST) && !sp->ip_broadcast) {
				rare();
				ip_rt_put(rt);
				err = -ENETUNREACH;
				continue;
			}
			sd->saddr = rt->rt_src;
			if (!sctp_find_saddr(sp, sd->saddr)) {
				rare();
				if (!sp->saddr) {
					rare();
					ip_rt_put(rt);
					assure(sp->saddr);
					err = -EADDRNOTAVAIL;
					continue;
				}
				sd->saddr = sp->saddr->saddr;
			}
			/* always revert to initial settings when rerouting */
			sd->rto = sp->rto_ini;
			sd->rttvar = 0;
			sd->srtt = 0;
			sd->mtu = rt->u.dst.pmtu;
			sd->ssthresh = 2 * rt->u.dst.pmtu;
			sd->cwnd = rt->u.dst.pmtu;
			sd->dst_cache = &rt->u.dst;

			route_changed = 1;
		}
		/* You're welcome diald! */
		if (sysctl_ip_dynaddr && sp->s_state == SCTP_COOKIE_WAIT && sd == sp->daddr) {
			/* see if route changed on primary as result of INIT that was discarded */
			struct rtable *rt2 = NULL;
			if (!ip_route_connect
			    (&rt2, rt->rt_dst, 0, RT_TOS(sp->ip_tos) | sp->ip_dontroute, sd->dif)) {
				if (rt2->rt_src != rt->rt_src) {
					rare();
					rt2 = xchg(&rt, rt2);

					sd->rto = sp->rto_ini;
					sd->rttvar = 0;
					sd->srtt = 0;
					sd->mtu = rt->u.dst.pmtu;
					sd->ssthresh = 2 * rt->u.dst.pmtu;
					sd->cwnd = rt->u.dst.pmtu;
					sd->dst_cache = &rt->u.dst;

					route_changed = 1;
				}
				ip_rt_put(rt2);
			}
		}
		viable_route = 1;

		/* always update MTU if we have a viable route */

		if (sd->mtu != rt->u.dst.pmtu) {
			sd->mtu = rt->u.dst.pmtu;
			mtu_changed = 1;
			rare();
		}
		if (sp->pmtu > sd->mtu)
			sp->pmtu = sd->mtu;
	}
	if (!viable_route) {
		rare();

		/* set defaults */
		sp->taddr = sp->daddr;
		sp->raddr = sp->daddr->next ? sp->daddr->next : sp->daddr;

		sp->pmtu = 576;

		return (err);
	}
	/* if we have made or need changes then we want to reanalyze routes */
	if (force_reselect || route_changed || mtu_changed || sp->pmtu != old_pmtu || !sp->taddr || !sp->raddr) {
#ifdef _DEBUG
#ifdef ERROR_GENERATOR
		int bad_choice = 0;
#endif
#endif
		sp->taddr = sctp_choose_best(sp, NULL);
		usual(sp->taddr);

#ifdef _DEBUG
#ifdef ERROR_GENERATOR
		if ((sp->options & SCTP_OPTION_BREAK)
		    && (sp->taddr == sp->daddr || sp->taddr == sp->daddr->next)
		    && sp->taddr->packets > BREAK_GENERATOR_LEVEL) {
			ptrace(("Primary sp->taddr %03d.%03d.%03d.%03d chosen poorly on %x\n",
				(sp->taddr->daddr >> 0) & 0xff, (sp->taddr->daddr >> 8) & 0xff,
				(sp->taddr->daddr >> 16) & 0xff, (sp->taddr->daddr >> 24) & 0xff, (uint) sp));
			bad_choice = 1;
		}
#endif
#endif

#if 0
		if (sp->taddr && sp->taddr != taddr)
			ptrace(("sp = %u, New primary route: %d.%d.%d.%d\n", (uint) sp,
				(sp->taddr->daddr >> 0) & 0xff, (sp->taddr->daddr >> 8) & 0xff,
				(sp->taddr->daddr >> 16) & 0xff, (sp->taddr->daddr >> 24) & 0xff));
#endif

		sp->raddr = sctp_choose_best(sp, sp->taddr);
		usual(sp->raddr);

#ifdef _DEBUG
#ifdef ERROR_GENERATOR
		if ((sp->options & SCTP_OPTION_BREAK)
		    && (sp->raddr == sp->daddr || sp->raddr == sp->daddr->next)
		    && sp->raddr->packets > BREAK_GENERATOR_LEVEL) {
			ptrace(("Secondary sp->raddr %03d.%03d.%03d.%03d chosen poorly on %x\n",
				(sp->raddr->daddr >> 0) & 0xff, (sp->raddr->daddr >> 8) & 0xff,
				(sp->raddr->daddr >> 16) & 0xff, (sp->raddr->daddr >> 24) & 0xff, (uint) sp));
			bad_choice = 1;
		}
		if (bad_choice) {
			for (sd = sp->daddr; sd; sd = sd->next) {
				printk(KERN_INFO "%03d.%03d.%03d.%03d: %x, %u:%u, %u, %lu, %u:%u, %u, %u\n",
				       (sd->daddr >> 0) & 0xff, (sd->daddr >> 8) & 0xff, (sd->daddr >> 16) & 0xff,
				       (sd->daddr >> 24) & 0xff, (uint) sd->dst_cache, sd->retransmits,
				       sd->max_retrans, sd->dups, sd->rto, sd->cwnd, sd->ssthresh, sd->mtu,
				       sd->in_flight);
			}
		}
#endif
#endif

#if 0
		if (sp->raddr && sp->raddr != raddr)
			ptrace(("sp = %u, New secondary route: %d.%d.%d.%d\n", (uint) sp,
				(sp->raddr->daddr >> 0) & 0xff, (sp->raddr->daddr >> 8) & 0xff,
				(sp->raddr->daddr >> 16) & 0xff, (sp->raddr->daddr >> 24) & 0xff));
#endif

	}
	return (0);
}


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sctp/sctp_route.c

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: