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. |