|
OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
| Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
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);
}
|
|||||||||||||||||||||||||||
|
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
|
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
|||||||||||||||||||||||||||