summaryrefslogtreecommitdiffstats
path: root/sbin/routed/output.c
diff options
context:
space:
mode:
authormarkm <markm@FreeBSD.org>1999-05-02 13:14:16 +0000
committermarkm <markm@FreeBSD.org>1999-05-02 13:14:16 +0000
commitc74fc4e83b599157005f6adfcfebde46851bd0d4 (patch)
treee8f3c95ddb4dcfbbc332816196635e042e72873b /sbin/routed/output.c
parenta60c9cfa3a8359247f7ca33b3ebc8574c5c7194a (diff)
downloadFreeBSD-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.c276
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;
OpenPOWER on IntegriCloud