diff options
author | markm <markm@FreeBSD.org> | 1999-05-02 13:14:16 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 1999-05-02 13:14:16 +0000 |
commit | c74fc4e83b599157005f6adfcfebde46851bd0d4 (patch) | |
tree | e8f3c95ddb4dcfbbc332816196635e042e72873b /sbin/routed/output.c | |
parent | a60c9cfa3a8359247f7ca33b3ebc8574c5c7194a (diff) | |
download | FreeBSD-src-c74fc4e83b599157005f6adfcfebde46851bd0d4.zip FreeBSD-src-c74fc4e83b599157005f6adfcfebde46851bd0d4.tar.gz |
Merge-o-matic and add a bunch of $Id's
Diffstat (limited to 'sbin/routed/output.c')
-rw-r--r-- | sbin/routed/output.c | 276 |
1 files changed, 149 insertions, 127 deletions
diff --git a/sbin/routed/output.c b/sbin/routed/output.c index 546a350..b1593b8 100644 --- a/sbin/routed/output.c +++ b/sbin/routed/output.c @@ -11,7 +11,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: + * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors @@ -29,20 +29,21 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)output.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + -int update_seqno; +u_int update_seqno; /* walk the tree of routes with this for output @@ -63,10 +64,9 @@ struct { #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ #define WS_ST_AG 0x004 /* ok to aggregate subnets */ #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ -#define WS_ST_SUB_AG 0x010 /* aggregate subnets in odd case */ -#define WS_ST_QUERY 0x020 /* responding to a query */ -#define WS_ST_TO_ON_NET 0x040 /* sending onto one of our nets */ -#define WS_ST_DEFAULT 0x080 /* faking a default */ +#define WS_ST_QUERY 0x010 /* responding to a query */ +#define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ +#define WS_ST_DEFAULT 0x040 /* faking a default */ } ws; /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ @@ -104,7 +104,7 @@ output(enum output_type type, { struct sockaddr_in sin; int flags; - char *msg; + const char *msg; int res; naddr tgt_mcast; int soc; @@ -233,7 +233,7 @@ find_auth(struct interface *ifp) /* stop looking after the last key */ if (ap->type == RIP_AUTH_NONE) break; - + /* ignore keys that are not ready yet */ if ((u_long)ap->start > (u_long)clk.tv_sec) continue; @@ -261,25 +261,26 @@ clr_ws_buf(struct ws_buf *wb, wb->lim = wb->base + NETS_LEN; wb->n = wb->base; - bzero(wb->n, NETS_LEN*sizeof(*wb->n)); + memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); - /* install authentication if appropriate + /* (start to) install authentication if appropriate */ if (ap == 0) return; + na = (struct netauth*)wb->n; if (ap->type == RIP_AUTH_PW) { na->a_family = RIP_AF_AUTH; na->a_type = RIP_AUTH_PW; - bcopy(ap->key, na->au.au_pw, sizeof(na->au.au_pw)); + memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); wb->n++; } else if (ap->type == RIP_AUTH_MD5) { na->a_family = RIP_AF_AUTH; na->a_type = RIP_AUTH_MD5; na->au.a_md5.md5_keyid = ap->keyid; - na->au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; - na->au.a_md5.md5_seqno = clk.tv_sec; + na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; + na->au.a_md5.md5_seqno = htonl(clk.tv_sec); wb->n++; wb->lim--; /* make room for trailer */ } @@ -292,17 +293,18 @@ end_md5_auth(struct ws_buf *wb, { struct netauth *na, *na2; MD5_CTX md5_ctx; + int len; na = (struct netauth*)wb->base; na2 = (struct netauth*)wb->n; + len = (char *)na2-(char *)wb->buf; na2->a_family = RIP_AF_AUTH; - na2->a_type = 1; - bcopy(ap->key, na2->au.au_pw, sizeof(na2->au.au_pw)); - na->au.a_md5.md5_pkt_len = (char *)na2-(char *)(na+1); + na2->a_type = htons(1); + na->au.a_md5.md5_pkt_len = htons(len); MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)na, - (char *)(na2+1) - (char *)na); + MD5Update(&md5_ctx, (u_char *)wb->buf, len); + MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); MD5Final(na2->au.au_pw, &md5_ctx); wb->n++; } @@ -356,11 +358,6 @@ supply_out(struct ag_info *ag) && (ws.state & WS_ST_FLASH)) return; - /* Skip this route if required by split-horizon. - */ - if (ag->ag_state & AGS_SPLIT_HZ) - return; - dst_h = ag->ag_dst_h; mask = ag->ag_mask; v1_mask = ripv1_mask_host(htonl(dst_h), @@ -396,13 +393,14 @@ supply_out(struct ag_info *ag) /* Punt if we would have to generate an * unreasonable number of routes. */ -#ifdef DEBUG - msglog("sending %s to %s as 1 instead" - " of %d routes", - addrname(htonl(dst_h),mask,1), - naddr_ntoa(ws.to.sin_addr.s_addr), - i+1); -#endif + if (TRACECONTENTS) + trace_misc("sending %s-->%s as 1" + " instead of %d routes", + addrname(htonl(dst_h), mask, + 1), + naddr_ntoa(ws.to.sin_addr + .s_addr), + i+1); i = 0; } else { @@ -451,12 +449,14 @@ supply_out(struct ag_info *ag) /* ARGSUSED */ static int walk_supply(struct radix_node *rn, - struct walkarg *w) + struct walkarg *argp UNUSED) { #define RT ((struct rt_entry *)rn) u_short ags; char metric, pref; naddr dst, nhop; + struct rt_spare *rts; + int i; /* Do not advertise external remote interfaces or passive interfaces. @@ -512,6 +512,7 @@ walk_supply(struct radix_node *rn, /* Advertise the next hop if this is not a route for one * of our interfaces and the next hop is on the same * network as the target. + * The final determination is made by supply_out(). */ if (!(RT->rt_state & RS_IF) && RT->rt_gate != myaddr @@ -529,23 +530,30 @@ walk_supply(struct radix_node *rn, ; } else if (RT_ISHOST(RT)) { - /* We should always aggregate the host routes - * for the local end of our point-to-point links. + /* We should always suppress (into existing network routes) + * the host routes for the local end of our point-to-point + * links. * If we are suppressing host routes in general, then do so. * Avoid advertising host routes onto their own network, * where they should be handled by proxy-ARP. */ if ((RT->rt_state & RS_LOCAL) || ridhosts - || (ws.state & WS_ST_SUPER_AG) || on_net(dst, ws.to_net, ws.to_mask)) ags |= AGS_SUPPRESS; - if (ws.state & WS_ST_SUPER_AG) - ags |= AGS_PROMOTE; + /* Aggregate stray host routes into network routes if allowed. + * We cannot aggregate host routes into small network routes + * without confusing RIPv1 listeners into thinking the + * network routes are host routes. + */ + if ((ws.state & WS_ST_AG) + && !(ws.state & WS_ST_RIP2_ALL)) + ags |= AGS_AGGREGATE; - } else if (ws.state & WS_ST_AG) { - /* Aggregate network routes, if we are allowed. + } else { + /* Always suppress network routes into other, existing + * network routes */ ags |= AGS_SUPPRESS; @@ -554,10 +562,10 @@ walk_supply(struct radix_node *rn, * later convert back to ordinary nets. * This unifies dealing with received supernets. */ - if ((RT->rt_state & RS_SUBNET) - || (ws.state & WS_ST_SUPER_AG)) - ags |= AGS_PROMOTE; - + if ((ws.state & WS_ST_AG) + && ((RT->rt_state & RS_SUBNET) + || (ws.state & WS_ST_SUPER_AG))) + ags |= AGS_AGGREGATE; } /* Do not send RIPv1 advertisements of subnets to other @@ -565,11 +573,9 @@ walk_supply(struct radix_node *rn, */ if ((RT->rt_state & RS_SUBNET) && !(ws.state & WS_ST_RIP2_ALL) - && !on_net(dst, ws.to_std_net, ws.to_std_mask)) { - ags |= AGS_RIPV2 | AGS_PROMOTE; - if (ws.state & WS_ST_SUB_AG) - ags |= AGS_SUPPRESS; - } + && !on_net(dst, ws.to_std_net, ws.to_std_mask)) + ags |= AGS_RIPV2 | AGS_AGGREGATE; + /* Do not send a route back to where it came from, except in * response to a query. This is "split-horizon". That means not @@ -578,61 +584,72 @@ walk_supply(struct radix_node *rn, * We want to suppress routes that might have been fragmented * from this route by a RIPv1 router and sent back to us, and so we * cannot forget this route here. Let the split-horizon route - * aggregate (suppress) the fragmented routes and then itself be - * forgotten. + * suppress the fragmented routes and then itself be forgotten. * * Include the routes for both ends of point-to-point interfaces * among those suppressed by split-horizon, since the other side * should knows them as well as we do. + * + * Notice spare routes with the same metric that we are about to + * advertise, to split the horizon on redundant, inactive paths. */ - if (RT->rt_ifp == ws.ifp && ws.ifp != 0 + if (ws.ifp != 0 && !(ws.state & WS_ST_QUERY) && (ws.state & WS_ST_TO_ON_NET) && (!(RT->rt_state & RS_IF) || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { - /* If we do not mark the route with AGS_SPLIT_HZ here, - * it will be poisoned-reverse, or advertised back toward - * its source with an infinite metric. If we have recently - * advertised the route with a better metric than we now - * have, then we should poison-reverse the route before - * suppressing it for split-horizon. - * - * In almost all cases, if there is no spare for the route - * then it is either old and dead or a brand new route. - * If it is brand new, there is no need for poison-reverse. - * If it is old and dead, it is already poisoned. - */ - if (RT->rt_poison_time < now_expire - || RT->rt_poison_metric >= metric - || RT->rt_spares[1].rts_gate == 0) { - ags |= AGS_SPLIT_HZ; - ags &= ~(AGS_PROMOTE | AGS_SUPPRESS); + for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { + if (rts->rts_metric > metric + || rts->rts_ifp != ws.ifp) + continue; + + /* If we do not mark the route with AGS_SPLIT_HZ here, + * it will be poisoned-reverse, or advertised back + * toward its source with an infinite metric. + * If we have recently advertised the route with a + * better metric than we now have, then we should + * poison-reverse the route before suppressing it for + * split-horizon. + * + * In almost all cases, if there is no spare for the + * route then it is either old and dead or a brand + * new route. If it is brand new, there is no need + * for poison-reverse. If it is old and dead, it + * is already poisoned. + */ + if (RT->rt_poison_time < now_expire + || RT->rt_poison_metric >= metric + || RT->rt_spares[1].rts_gate == 0) { + ags |= AGS_SPLIT_HZ; + ags &= ~AGS_SUPPRESS; + } + metric = HOPCNT_INFINITY; + break; } - metric = HOPCNT_INFINITY; } - /* Adjust the outgoing metric by the cost of the link. + /* Keep track of the best metric with which the + * route has been advertised recently. */ - pref = metric + ws.metric; - if (pref < HOPCNT_INFINITY) { - /* Keep track of the best metric with which the - * route has been advertised recently. - */ - if (RT->rt_poison_metric >= metric - || RT->rt_poison_time < now_expire) { - RT->rt_poison_time = now.tv_sec; - RT->rt_poison_metric = metric; - } - metric = pref; + if (RT->rt_poison_metric >= metric + || RT->rt_poison_time < now_expire) { + RT->rt_poison_time = now.tv_sec; + RT->rt_poison_metric = metric; + } - } else { - /* Do not advertise stable routes that will be ignored, - * unless we are answering a query. - * If the route recently was advertised with a metric that - * would have been less than infinity through this interface, - * we need to continue to advertise it in order to poison it. - */ - pref = RT->rt_poison_metric + ws.metric; + /* Adjust the outgoing metric by the cost of the link. + * Avoid aggregation when a route is counting to infinity. + */ + pref = RT->rt_poison_metric + ws.metric; + metric += ws.metric; + + /* Do not advertise stable routes that will be ignored, + * unless we are answering a query. + * If the route recently was advertised with a metric that + * would have been less than infinity through this interface, + * we need to continue to advertise it in order to poison it. + */ + if (metric >= HOPCNT_INFINITY) { if (!(ws.state & WS_ST_QUERY) && (pref >= HOPCNT_INFINITY || RT->rt_poison_time < now_garbage)) @@ -687,8 +704,6 @@ supply(struct sockaddr_in *dst, ws.npackets = 0; if (flash) ws.state |= WS_ST_FLASH; - if (type == OUT_QUERY) - ws.state |= WS_ST_QUERY; if ((ws.ifp = ifp) == 0) { ws.metric = 1; @@ -702,44 +717,42 @@ supply(struct sockaddr_in *dst, ripv12_buf.rip.rip_vers = vers; switch (type) { - case OUT_BROADCAST: - v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); - v12buf.type = OUT_BROADCAST; - break; case OUT_MULTICAST: - v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); + if (ifp->int_if_flags & IFF_MULTICAST) + v2buf.type = OUT_MULTICAST; + else + v2buf.type = NO_OUT_MULTICAST; v12buf.type = OUT_BROADCAST; break; - case OUT_UNICAST: + case OUT_QUERY: + ws.state |= WS_ST_QUERY; + /* fall through */ + case OUT_BROADCAST: + case OUT_UNICAST: v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; v12buf.type = type; break; - default: - v2buf.type = type; - v12buf.type = type; - break; + + case NO_OUT_MULTICAST: + case NO_OUT_RIPV2: + break; /* no output */ } if (vers == RIPv2) { /* full RIPv2 only if cannot be heard by RIPv1 listeners */ if (type != OUT_BROADCAST) ws.state |= WS_ST_RIP2_ALL; - if (!(ws.state & WS_ST_TO_ON_NET)) { + if ((ws.state & WS_ST_QUERY) + || !(ws.state & WS_ST_TO_ON_NET)) { ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { ws.state |= WS_ST_AG; if (type != OUT_BROADCAST - && (ifp == 0 || !(ifp->int_state&IS_NO_SUPER_AG))) + && (ifp == 0 + || !(ifp->int_state & IS_NO_SUPER_AG))) ws.state |= WS_ST_SUPER_AG; } - - } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { - ws.state |= WS_ST_SUB_AG; } ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; @@ -835,7 +848,7 @@ rip_bcast(int flash) continue; /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) + if (!iff_up(ifp->int_if_flags)) continue; vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; @@ -844,11 +857,8 @@ rip_bcast(int flash) /* ordinary, hardware interface */ dst.sin_addr.s_addr = ifp->int_brdaddr; - /* If RIPv1 is not turned off, then broadcast so - * that RIPv1 listeners can hear. - */ if (vers == RIPv2 - && (ifp->int_state & IS_NO_RIPV1_OUT)) { + && !(ifp->int_state & IS_NO_RIP_MCAST)) { type = OUT_MULTICAST; } else { type = OUT_BROADCAST; @@ -896,7 +906,7 @@ rip_query(void) if (rip_sock < 0) return; - bzero(&buf, sizeof(buf)); + memset(&buf, 0, sizeof(buf)); for (ifp = ifnet; ifp; ifp = ifp->int_next) { /* Skip interfaces those already queried. @@ -910,7 +920,7 @@ rip_query(void) continue; /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) + if (!iff_up(ifp->int_if_flags)) continue; buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; @@ -918,14 +928,26 @@ rip_query(void) buf.rip_nets[0].n_family = RIP_AF_UNSPEC; buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); + /* Send a RIPv1 query only if allowed and if we will + * listen to RIPv1 routers. + */ + if ((ifp->int_state & IS_NO_RIPV1_OUT) + || (ifp->int_state & IS_NO_RIPV1_IN)) { + buf.rip_vers = RIPv2; + } else { + buf.rip_vers = RIPv1; + } + if (ifp->int_if_flags & IFF_BROADCAST) { /* ordinary, hardware interface */ dst.sin_addr.s_addr = ifp->int_brdaddr; - /* if RIPv1 is not turned off, then broadcast so - * that RIPv1 listeners can hear. + + /* Broadcast RIPv1 queries and RIPv2 queries + * when the hardware cannot multicast. */ if (buf.rip_vers == RIPv2 - && (ifp->int_state & IS_NO_RIPV1_OUT)) { + && (ifp->int_if_flags & IFF_MULTICAST) + && !(ifp->int_state & IS_NO_RIP_MCAST)) { type = OUT_MULTICAST; } else { type = OUT_BROADCAST; |