summaryrefslogtreecommitdiff
path: root/usr.sbin/mrouted/route.c
diff options
context:
space:
mode:
authorBill Fenner <fenner@FreeBSD.org>1999-01-20 07:44:18 +0000
committerBill Fenner <fenner@FreeBSD.org>1999-01-20 07:44:18 +0000
commit1f25327484733d0bec3b33044da7bd5d82ad007f (patch)
tree19c94eeb7ba2b59b0ad53ae0864ebf06723a8afa /usr.sbin/mrouted/route.c
parentce595def0708b60ce4dde9002ac206fae20be240 (diff)
Notes
Diffstat (limited to 'usr.sbin/mrouted/route.c')
-rw-r--r--usr.sbin/mrouted/route.c894
1 files changed, 604 insertions, 290 deletions
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
index c2b6b9e8b932a..e43dac68f1042 100644
--- a/usr.sbin/mrouted/route.c
+++ b/usr.sbin/mrouted/route.c
@@ -7,12 +7,16 @@
* Leland Stanford Junior University.
*
*
- * $Id: route.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
+ * route.c,v 3.8.4.41 1998/01/15 00:08:34 fenner Exp
*/
#include "defs.h"
+#ifndef lint
+static char rcsid[] = "@(#) $Id: \
+route.c,v 3.8.4.41 1998/01/15 00:08:34 fenner Exp $";
+#endif
/*
* This define statement saves a lot of space later
@@ -42,13 +46,89 @@ unsigned int nroutes; /* current number of route entries */
* Private functions.
*/
static int init_children_and_leaves __P((struct rtentry *r,
- vifi_t parent));
+ vifi_t parent, int first));
static int find_route __P((u_int32 origin, u_int32 mask));
static void create_route __P((u_int32 origin, u_int32 mask));
static void discard_route __P((struct rtentry *prev_r));
static int compare_rts __P((const void *rt1, const void *rt2));
-static int report_chunk __P((struct rtentry *start_rt, vifi_t vifi,
+static int report_chunk __P((int, struct rtentry *start_rt, vifi_t vifi,
u_int32 dst));
+static void queue_blaster_report __P((vifi_t, u_int32, u_int32, char *,
+ int, u_int32));
+static void process_blaster_report __P((void *));
+
+#ifdef SNMP
+#include <sys/types.h>
+#include "snmp.h"
+
+/*
+ * Return pointer to a specific route entry. This must be a separate
+ * function from find_route() which modifies rtp.
+ */
+struct rtentry *
+snmp_find_route(src, mask)
+ register u_int32 src, mask;
+{
+ register struct rtentry *rt;
+
+ for (rt = routing_table; rt; rt = rt->rt_next) {
+ if (src == rt->rt_origin && mask == rt->rt_originmask)
+ return rt;
+ }
+ return NULL;
+}
+
+/*
+ * Find next route entry > specification
+ */
+int
+next_route(rtpp, src, mask)
+ struct rtentry **rtpp;
+ u_int32 src;
+ u_int32 mask;
+{
+ struct rtentry *rt, *rbest = NULL;
+
+ /* Among all entries > spec, find "lowest" one in order */
+ for (rt = routing_table; rt; rt=rt->rt_next) {
+ if ((ntohl(rt->rt_origin) > ntohl(src)
+ || (ntohl(rt->rt_origin) == ntohl(src)
+ && ntohl(rt->rt_originmask) > ntohl(mask)))
+ && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
+ || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
+ && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
+ rbest = rt;
+ }
+ (*rtpp) = rbest;
+ return (*rtpp)!=0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next vifi/entry
+ */
+int
+next_route_child(rtpp, src, mask, vifi)
+ struct rtentry **rtpp;
+ u_int32 src;
+ u_int32 mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ /* Get (S,M) entry */
+ if (!((*rtpp) = snmp_find_route(src,mask)))
+ if (!next_route(rtpp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
+ return 1;
+ *vifi = 0;
+ } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) );
+
+ return 0;
+}
+#endif
/*
* Initialize the routing table and associated variables.
@@ -65,54 +145,50 @@ init_routes()
/*
- * Initialize the children and leaf bits for route 'r', along with the
- * associated dominant, subordinate, and leaf timing data structures.
- * Return TRUE if this changes the value of either the children or
- * leaf bitmaps for 'r'.
+ * Initialize the children bits for route 'r', along with the
+ * associated dominant and subordinate data structures.
+ * If first is set, initialize dominants, otherwise keep old
+ * dominants on non-parent interfaces.
+ * XXX Does this need a return value?
*/
static int
-init_children_and_leaves(r, parent)
+init_children_and_leaves(r, parent, first)
register struct rtentry *r;
register vifi_t parent;
+ int first;
{
register vifi_t vifi;
register struct uvif *v;
- vifbitmap_t old_children, old_leaves;
+ vifbitmap_t old_children;
+ nbrbitmap_t old_subords;
VIFM_COPY(r->rt_children, old_children);
- VIFM_COPY(r->rt_leaves, old_leaves );
+ NBRM_COPY(r->rt_subordinates, old_subords);
VIFM_CLRALL(r->rt_children);
- VIFM_CLRALL(r->rt_leaves);
- r->rt_flags &= ~RTF_LEAF_TIMING;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- r->rt_dominants [vifi] = 0;
- r->rt_subordinates[vifi] = 0;
-
- if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ if (first || vifi == parent)
+ r->rt_dominants [vifi] = 0;
+ if (vifi == parent || uvifs[vifi].uv_flags & VIFF_NOFLOOD ||
+ AVOID_TRANSIT(vifi, r) || (!first && r->rt_dominants[vifi]))
+ NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ else
+ NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+
+ if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) &&
+ !(!first && r->rt_dominants[vifi])) {
VIFM_SET(vifi, r->rt_children);
- if (v->uv_neighbors == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = 0;
- }
- else {
- r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
- }
- }
- else {
- r->rt_leaf_timers[vifi] = 0;
}
}
return (!VIFM_SAME(r->rt_children, old_children) ||
- !VIFM_SAME(r->rt_leaves, old_leaves));
+ !NBRM_SAME(r->rt_subordinates, old_subords));
}
/*
- * A new vif has come up -- update the children and leaf bitmaps in all route
+ * A new vif has come up -- update the children bitmaps in all route
* entries to take that into account.
*/
void
@@ -128,17 +204,9 @@ add_vif_to_routes(vifi)
!VIFM_ISSET(vifi, r->rt_children)) {
VIFM_SET(vifi, r->rt_children);
r->rt_dominants [vifi] = 0;
- r->rt_subordinates[vifi] = 0;
- if (v->uv_neighbors == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = 0;
- }
- else {
- VIFM_CLR(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
- }
- update_table_entry(r);
+ /*XXX isn't uv_nbrmap going to be empty?*/
+ NBRM_CLRMASK(r->rt_subordinates, v->uv_nbrmap);
+ update_table_entry(r, r->rt_gateway);
}
}
}
@@ -166,10 +234,8 @@ delete_vif_from_routes(vifi)
}
else if (VIFM_ISSET(vifi, r->rt_children)) {
VIFM_CLR(vifi, r->rt_children);
- VIFM_CLR(vifi, r->rt_leaves);
- r->rt_subordinates[vifi] = 0;
- r->rt_leaf_timers [vifi] = 0;
- update_table_entry(r);
+ NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ update_table_entry(r, r->rt_gateway);
}
else {
r->rt_dominants[vifi] = 0;
@@ -180,14 +246,42 @@ delete_vif_from_routes(vifi)
/*
+ * A new neighbor has come up. If we're flooding on the neighbor's
+ * vif, mark that neighbor as subordinate for all routes whose parent
+ * is not this vif.
+ */
+void
+add_neighbor_to_routes(vifi, index)
+ register vifi_t vifi;
+ register int index;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ if (v->uv_flags & VIFF_NOFLOOD)
+ return;
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE && r->rt_parent != vifi &&
+ !AVOID_TRANSIT(vifi, r)) {
+ NBRM_SET(index, r->rt_subordinates);
+ update_table_entry(r, r->rt_gateway);
+ }
+ }
+}
+
+
+/*
* A neighbor has failed or become unreachable. If that neighbor was
* considered a dominant or subordinate router in any route entries,
- * take appropriate action.
+ * take appropriate action. Expire all routes this neighbor advertised
+ * to us.
*/
void
-delete_neighbor_from_routes(addr, vifi)
+delete_neighbor_from_routes(addr, vifi, index)
register u_int32 addr;
register vifi_t vifi;
+ int index;
{
register struct rtentry *r;
register struct uvif *v;
@@ -195,37 +289,24 @@ delete_neighbor_from_routes(addr, vifi)
v = &uvifs[vifi];
for (r = routing_table; r != NULL; r = r->rt_next) {
if (r->rt_metric != UNREACHABLE) {
- if (r->rt_dominants[vifi] == addr) {
+ if (r->rt_parent == vifi && r->rt_gateway == addr) {
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ } else if (r->rt_dominants[vifi] == addr) {
VIFM_SET(vifi, r->rt_children);
- r->rt_dominants [vifi] = 0;
- r->rt_subordinates[vifi] = 0;
- if (v->uv_neighbors == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = 0;
- }
- else {
- VIFM_CLR(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
- }
- update_table_entry(r);
- }
- else if (r->rt_subordinates[vifi] == addr) {
- r->rt_subordinates[vifi] = 0;
- if (v->uv_neighbors == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- update_table_entry(r);
- }
- else {
- r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
- }
- }
- else if (v->uv_neighbors == NULL &&
- r->rt_leaf_timers[vifi] != 0) {
- VIFM_SET(vifi, r->rt_leaves);
- r->rt_leaf_timers[vifi] = 0;
- update_table_entry(r);
+ r->rt_dominants[vifi] = 0;
+ if ((uvifs[vifi].uv_flags & VIFF_NOFLOOD) ||
+ AVOID_TRANSIT(vifi, r))
+ NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ else
+ NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ update_table_entry(r, r->rt_gateway);
+ } else if (NBRM_ISSET(index, r->rt_subordinates)) {
+ NBRM_CLR(index, r->rt_subordinates);
+ update_table_entry(r, r->rt_gateway);
}
}
}
@@ -296,8 +377,7 @@ create_route(origin, mask)
register struct rtentry *r;
if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
- (2 * numvifs * sizeof(u_int32)) +
- (numvifs * sizeof(u_int)))) == NULL) {
+ (numvifs * sizeof(u_int32)))) == NULL) {
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
}
r->rt_origin = origin;
@@ -308,9 +388,11 @@ create_route(origin, mask)
else r->rt_originwidth = 1;
r->rt_flags = 0;
r->rt_dominants = (u_int32 *)(r + 1);
- r->rt_subordinates = (u_int32 *)(r->rt_dominants + numvifs);
- r->rt_leaf_timers = (u_int *)(r->rt_subordinates + numvifs);
+ bzero(r->rt_dominants, numvifs * sizeof(u_int32));
r->rt_groups = NULL;
+ VIFM_CLRALL(r->rt_children);
+ NBRM_CLRALL(r->rt_subordinates);
+ NBRM_CLRALL(r->rt_subordadv);
r->rt_next = rtp->rt_next;
rtp->rt_next = r;
@@ -334,6 +416,8 @@ discard_route(prev_r)
register struct rtentry *r;
r = prev_r->rt_next;
+ uvifs[r->rt_parent].uv_nroutes--;
+ /*???nbr???.al_nroutes--;*/
prev_r->rt_next = r->rt_next;
if (prev_r->rt_next != NULL)
(prev_r->rt_next)->rt_prev = prev_r;
@@ -351,11 +435,12 @@ discard_route(prev_r)
* to indicate a change of status of one of our own interfaces.
*/
void
-update_route(origin, mask, metric, src, vifi)
+update_route(origin, mask, metric, src, vifi, n)
u_int32 origin, mask;
u_int metric;
u_int32 src;
vifi_t vifi;
+ struct listaddr *n;
{
register struct rtentry *r;
u_int adj_metric;
@@ -393,18 +478,17 @@ update_route(origin, mask, metric, src, vifi)
return;
}
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s advertises new route %s",
+ inet_fmt(src, s1), inet_fmts(origin, mask, s2));
+
/*
* OK, create the new routing entry. 'rtp' will be left pointing
* to the new entry.
*/
create_route(origin, mask);
-
- /*
- * Now "steal away" any sources that belong under this route
- * by deleting any cache entries they might have created
- * and allowing the kernel to re-request them.
- */
- steal_sources(rtp);
+ uvifs[vifi].uv_nroutes++;
+ /*n->al_nroutes++;*/
rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
}
@@ -422,15 +506,32 @@ update_route(origin, mask, metric, src, vifi)
if (adj_metric == UNREACHABLE)
return;
- r->rt_parent = vifi;
- init_children_and_leaves(r, vifi);
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s advertises %s with adj_metric %d (ours was %d)",
+ inet_fmt(src, s1), inet_fmts(origin, mask, s2),
+ adj_metric, r->rt_metric);
+ /*
+ * Now "steal away" any sources that belong under this route
+ * by deleting any cache entries they might have created
+ * and allowing the kernel to re-request them.
+ *
+ * If we haven't performed final initialization yet and are
+ * just collecting the routing table, we can't have any
+ * sources so we don't perform this step.
+ */
+ if (did_final_init)
+ steal_sources(rtp);
+
+ r->rt_parent = vifi;
r->rt_gateway = src;
+ init_children_and_leaves(r, vifi, 1);
+
r->rt_timer = 0;
r->rt_metric = adj_metric;
r->rt_flags |= RTF_CHANGED;
routes_changed = TRUE;
- update_table_entry(r);
+ update_table_entry(r, r->rt_gateway);
}
else if (src == r->rt_gateway) {
/*
@@ -442,6 +543,12 @@ update_route(origin, mask, metric, src, vifi)
* our entry accordingly.
*/
r->rt_timer = 0;
+
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s (current parent) advertises %s with adj_metric %d (ours was %d)",
+ inet_fmt(src, s1), inet_fmts(origin, mask, s2),
+ adj_metric, r->rt_metric);
+
if (adj_metric == r->rt_metric)
return;
@@ -449,11 +556,6 @@ update_route(origin, mask, metric, src, vifi)
del_table_entry(r, 0, DEL_ALL_ROUTES);
r->rt_timer = ROUTE_EXPIRE_TIME;
}
- else if (adj_metric < r->rt_metric) {
- if (init_children_and_leaves(r, vifi)) {
- update_table_entry(r);
- }
- }
r->rt_metric = adj_metric;
r->rt_flags |= RTF_CHANGED;
routes_changed = TRUE;
@@ -479,16 +581,29 @@ update_route(origin, mask, metric, src, vifi)
* IP address than the gateway associated with the route entry.
* Did you get all that?
*/
- if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
- /*
- * XXX Why do we do this if we are just changing the metric?
- */
- r->rt_parent = vifi;
- if (init_children_and_leaves(r, vifi)) {
- update_table_entry(r);
- }
+ u_int32 old_gateway;
+ vifi_t old_parent;
+ old_gateway = r->rt_gateway;
+ old_parent = r->rt_parent;
+ r->rt_gateway = src;
+ r->rt_parent = vifi;
+
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s (new parent) on vif %d advertises %s with adj_metric %d (old parent was %s on vif %d, metric %d)",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ adj_metric, inet_fmt(old_gateway, s3), old_parent,
+ r->rt_metric);
+
+ if (old_parent != vifi) {
+ init_children_and_leaves(r, vifi, 0);
+ uvifs[old_parent].uv_nroutes--;
+ uvifs[vifi].uv_nroutes++;
+ }
+ if (old_gateway != src) {
+ update_table_entry(r, old_gateway);
+ /*???old_gateway???->al_nroutes--;*/
+ /*n->al_nroutes++;*/
}
- r->rt_gateway = src;
r->rt_timer = 0;
r->rt_metric = adj_metric;
r->rt_flags |= RTF_CHANGED;
@@ -497,9 +612,18 @@ update_route(origin, mask, metric, src, vifi)
else if (vifi != r->rt_parent) {
/*
* The report came from a vif other than the route's parent vif.
- * Update the children and leaf info, if necessary.
+ * Update the children info, if necessary.
*/
- if (VIFM_ISSET(vifi, r->rt_children)) {
+ if (AVOID_TRANSIT(vifi, r)) {
+ /*
+ * The route's parent is a vif from which we're not supposed
+ * to transit onto this vif. Simply ignore the update.
+ */
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored due to NOTRANSIT)",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric);
+ } else if (VIFM_ISSET(vifi, r->rt_children)) {
/*
* Vif is a child vif for this route.
*/
@@ -512,42 +636,51 @@ update_route(origin, mask, metric, src, vifi)
* and vif is no longer a child for me.
*/
VIFM_CLR(vifi, r->rt_children);
- VIFM_CLR(vifi, r->rt_leaves);
r->rt_dominants [vifi] = src;
- r->rt_subordinates[vifi] = 0;
- r->rt_leaf_timers [vifi] = 0;
- update_table_entry(r);
+ /* XXX
+ * We don't necessarily want to forget about subordinateness
+ * so that we can become the dominant quickly if the current
+ * dominant fails.
+ */
+ NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ update_table_entry(r, r->rt_gateway);
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d becomes dominant for %s with metric %d",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric);
}
else if (metric > UNREACHABLE) { /* "poisoned reverse" */
/*
* Neighbor considers this vif to be on path to route's
- * origin; if no subordinate recorded, record this neighbor
- * as subordinate and clear the leaf flag.
+ * origin; record this neighbor as subordinate
*/
- if (r->rt_subordinates[vifi] == 0) {
- VIFM_CLR(vifi, r->rt_leaves);
- r->rt_subordinates[vifi] = src;
- r->rt_leaf_timers [vifi] = 0;
- update_table_entry(r);
+ if (!NBRM_ISSET(n->al_index, r->rt_subordinates)) {
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d becomes subordinate for %s with poison-reverse metric %d",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric - UNREACHABLE);
+ NBRM_SET(n->al_index, r->rt_subordinates);
+ update_table_entry(r, r->rt_gateway);
+ } else {
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d confirms subordinateness for %s with poison-reverse metric %d",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric - UNREACHABLE);
}
+ NBRM_SET(n->al_index, r->rt_subordadv);
}
- else if (src == r->rt_subordinates[vifi]) {
+ else if (NBRM_ISSET(n->al_index, r->rt_subordinates)) {
/*
* Current subordinate no longer considers this vif to be on
* path to route's origin; it is no longer a subordinate
- * router, and we set the leaf confirmation timer to give
- * us time to hear from other subordinates.
+ * router.
*/
- r->rt_subordinates[vifi] = 0;
- if (uvifs[vifi].uv_neighbors == NULL ||
- uvifs[vifi].uv_neighbors->al_next == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- update_table_entry(r);
- }
- else {
- r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
- }
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d is no longer a subordinate for %s with metric %d",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric);
+ NBRM_CLR(n->al_index, r->rt_subordinates);
+ update_table_entry(r, r->rt_gateway);
}
}
@@ -560,20 +693,26 @@ update_route(origin, mask, metric, src, vifi)
* (or same metric and lower IP address); we adopt the vif
* as our own child.
*/
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s (current dominant) on vif %d is no longer dominant for %s with metric %d",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric);
VIFM_SET(vifi, r->rt_children);
- r->rt_dominants [vifi] = 0;
+ r->rt_dominants[vifi] = 0;
+ if (uvifs[vifi].uv_flags & VIFF_NOFLOOD)
+ NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
+ else
+ NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
if (metric > UNREACHABLE) {
- r->rt_subordinates[vifi] = src;
- }
- else if (uvifs[vifi].uv_neighbors == NULL ||
- uvifs[vifi].uv_neighbors->al_next == NULL) {
- VIFM_SET(vifi, r->rt_leaves);
- }
- else {
- r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
- r->rt_flags |= RTF_LEAF_TIMING;
+ NBRM_SET(n->al_index, r->rt_subordinates);
+ NBRM_SET(n->al_index, r->rt_subordadv);
}
- update_table_entry(r);
+ update_table_entry(r, r->rt_gateway);
+ } else {
+ IF_DEBUG(DEBUG_RTDETAIL)
+ log(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored)",
+ inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2),
+ metric);
}
}
}
@@ -587,47 +726,13 @@ age_routes()
{
register struct rtentry *r;
register struct rtentry *prev_r;
- register vifi_t vifi;
+ extern u_long virtual_time; /* from main.c */
for (prev_r = RT_ADDR, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next) {
- if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) {
- /*
- * Route is still good; see if any leaf timers need to be
- * advanced.
- */
- if (r->rt_flags & RTF_LEAF_TIMING) {
- r->rt_flags &= ~RTF_LEAF_TIMING;
- for (vifi = 0; vifi < numvifs; ++vifi) {
- if (r->rt_leaf_timers[vifi] != 0) {
- /*
- * Unlike other timers, leaf timers decrement.
- */
- if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
-#ifdef NOTYET
- /* If the vif is a physical leaf but has neighbors,
- * it is not a tree leaf. If I am a leaf, then no
- * interface with neighbors is a tree leaf. */
- if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
- (vifs_with_neighbors == 1)) &&
- (uvifs[vifi].uv_neighbors != NULL))) {
-#endif
- VIFM_SET(vifi, r->rt_leaves);
- update_table_entry(r);
-#ifdef NOTYET
- }
-#endif
- }
- else {
- r->rt_flags |= RTF_LEAF_TIMING;
- }
- }
- }
- }
- }
- else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
+ if ((r->rt_timer += TIMER_INTERVAL) >= ROUTE_DISCARD_TIME) {
/*
* Time to garbage-collect the route entry.
*/
@@ -635,7 +740,8 @@ age_routes()
discard_route(prev_r);
r = prev_r;
}
- else if (r->rt_metric != UNREACHABLE) {
+ else if (r->rt_timer >= ROUTE_EXPIRE_TIME &&
+ r->rt_metric != UNREACHABLE) {
/*
* Time to expire the route entry. If the gateway is zero,
* i.e., it is a route to a directly-connected subnet, just
@@ -652,6 +758,22 @@ age_routes()
routes_changed = TRUE;
}
}
+ else if (virtual_time % (ROUTE_REPORT_INTERVAL * 2) == 0) {
+ /*
+ * Time out subordinateness that hasn't been reported in
+ * the last 2 intervals.
+ */
+ if (!NBRM_SAME(r->rt_subordinates, r->rt_subordadv)) {
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "rt %s sub 0x%08x%08x subadv 0x%08x%08x metric %d",
+ RT_FMT(r, s1),
+ r->rt_subordinates.hi, r->rt_subordinates.lo,
+ r->rt_subordadv.hi, r->rt_subordadv.lo, r->rt_metric);
+ NBRM_MASK(r->rt_subordinates, r->rt_subordadv);
+ update_table_entry(r, r->rt_gateway);
+ }
+ NBRM_CLRALL(r->rt_subordadv);
+ }
}
}
@@ -704,10 +826,41 @@ accept_probe(src, dst, p, datalen, level)
u_int32 level;
{
vifi_t vifi;
+ static struct listaddr *unknowns = NULL;
if ((vifi = find_vif(src, dst)) == NO_VIF) {
- log(LOG_INFO, 0,
- "ignoring probe from non-neighbor %s", inet_fmt(src, s1));
+ struct listaddr *a, **prev;
+ struct listaddr *match = NULL;
+ time_t now = time(0);
+
+ for (prev = &unknowns, a = *prev; a; a = *prev) {
+ if (a->al_addr == src)
+ match = a;
+ if (a->al_ctime + 2 * a->al_timer < now) {
+ /* We haven't heard from it in a long time */
+ *prev = a->al_next;
+ free(a);
+ } else {
+ prev = &a->al_next;
+ }
+ }
+ if (match == NULL) {
+ match = *prev = (struct listaddr *)malloc(sizeof(struct listaddr));
+ match->al_next = NULL;
+ match->al_addr = src;
+ match->al_timer = OLD_NEIGHBOR_EXPIRE_TIME;
+ match->al_ctime = now - match->al_timer;
+ }
+
+ if (match->al_ctime + match->al_timer <= now) {
+ log(LOG_WARNING, 0,
+ "ignoring probe from non-neighbor %s, check for misconfigured tunnel or routing on %s",
+ inet_fmt(src, s1), s1);
+ match->al_timer *= 2;
+ } else
+ IF_DEBUG(DEBUG_PEER)
+ log(LOG_DEBUG, 0,
+ "ignoring probe from non-neighbor %s (%d seconds until next warning)", inet_fmt(src, s1), match->al_ctime + match->al_timer - now);
return;
}
@@ -747,8 +900,137 @@ compare_rts(rt1, rt2)
return (0);
}
+void
+blaster_alloc(vifi)
+ vifi_t vifi;
+{
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ if (v->uv_blasterbuf)
+ free(v->uv_blasterbuf);
+
+ v->uv_blasterlen = 64*1024;
+ v->uv_blasterbuf = malloc(v->uv_blasterlen);
+ v->uv_blastercur = v->uv_blasterend = v->uv_blasterbuf;
+ if (v->uv_blastertimer)
+ timer_clearTimer(v->uv_blastertimer);
+ v->uv_blastertimer = 0;
+}
+
+struct blaster_hdr {
+ u_int32 bh_src;
+ u_int32 bh_dst;
+ u_int32 bh_level;
+ int bh_datalen;
+};
+
+/*
+ * Queue a route report from a route-blaster.
+ * If the timer isn't running to process these reports,
+ * start it.
+ */
+static void
+queue_blaster_report(vifi, src, dst, p, datalen, level)
+ vifi_t vifi;
+ u_int32 src, dst, level;
+ register char *p;
+ register int datalen;
+{
+ register struct blaster_hdr *bh;
+ register struct uvif *v;
+ int bblen = sizeof(*bh) + ((datalen + 3) & ~3);
+
+ v = &uvifs[vifi];
+ if (v->uv_blasterend - v->uv_blasterbuf +
+ bblen > v->uv_blasterlen) {
+ int end = v->uv_blasterend - v->uv_blasterbuf;
+ int cur = v->uv_blastercur - v->uv_blasterbuf;
+
+ v->uv_blasterlen *= 2;
+ IF_DEBUG(DEBUG_IF)
+ log(LOG_DEBUG, 0, "increasing blasterbuf to %d bytes",
+ v->uv_blasterlen);
+ v->uv_blasterbuf = realloc(v->uv_blasterbuf,
+ v->uv_blasterlen);
+ if (v->uv_blasterbuf == NULL) {
+ log(LOG_WARNING, ENOMEM, "turning off blaster on vif %d", vifi);
+ v->uv_blasterlen = 0;
+ v->uv_blasterend = v->uv_blastercur = NULL;
+ v->uv_flags &= ~VIFF_BLASTER;
+ return;
+ }
+ v->uv_blasterend = v->uv_blasterbuf + end;
+ v->uv_blastercur = v->uv_blasterbuf + cur;
+ }
+ bh = (struct blaster_hdr *)v->uv_blasterend;
+ bh->bh_src = src;
+ bh->bh_dst = dst;
+ bh->bh_level = level;
+ bh->bh_datalen = datalen;
+ bcopy(p, (char *)(bh + 1), datalen);
+ v->uv_blasterend += bblen;
+
+ if (v->uv_blastertimer == 0) {
+ int *i = (int *)malloc(sizeof(int *));
+
+ if (i == NULL)
+ log(LOG_ERR, 0, "out of memory");
+
+ *i = vifi;
+
+ v->uv_blastertimer = timer_setTimer(5,
+ process_blaster_report, i);
+ }
+}
+
+/*
+ * Periodic process; process up to 5 of the routes in the route-blaster
+ * queue. If there are more routes remaining, reschedule myself to run
+ * in 1 second.
+ */
+static void
+process_blaster_report(vifip)
+ void *vifip;
+{
+ vifi_t vifi = *(int *)vifip;
+ register struct uvif *v;
+ register struct blaster_hdr *bh;
+ int i;
+
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "processing vif %d blasted routes", vifi);
+ v = &uvifs[vifi];
+ for (i = 0; i < 5; i++) {
+ if (v->uv_blastercur >= v->uv_blasterend)
+ break;
+ bh = (struct blaster_hdr *)v->uv_blastercur;
+ v->uv_blastercur += sizeof(*bh) + ((bh->bh_datalen + 3) & ~3);
+ accept_report(bh->bh_src, bh->bh_dst, (char *)(bh + 1),
+ -bh->bh_datalen, bh->bh_level);
+ }
+
+ if (v->uv_blastercur >= v->uv_blasterend) {
+ v->uv_blastercur = v->uv_blasterbuf;
+ v->uv_blasterend = v->uv_blasterbuf;
+ v->uv_blastertimer = 0;
+ free(vifip);
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "finish processing vif %d blaster", vifi);
+ } else {
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "more blasted routes to come on vif %d", vifi);
+ v->uv_blastertimer = timer_setTimer(1,
+ process_blaster_report, vifip);
+ }
+}
+
/*
* Process an incoming route report message.
+ * If the report arrived on a vif marked as a "blaster", then just
+ * queue it and return; queue_blaster_report() will schedule it for
+ * processing later. If datalen is negative, then this is actually
+ * a queued report so actually process it instead of queueing it.
*/
void
accept_report(src, dst, p, datalen, level)
@@ -762,6 +1044,7 @@ accept_report(src, dst, p, datalen, level)
u_int32 mask;
u_int32 origin;
struct newrt rt[4096];
+ struct listaddr *nbr;
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
@@ -769,7 +1052,15 @@ accept_report(src, dst, p, datalen, level)
return;
}
- if (!update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level))
+ if (uvifs[vifi].uv_flags & VIFF_BLASTER)
+ if (datalen > 0) {
+ queue_blaster_report(vifi, src, dst, p, datalen, level);
+ return;
+ } else {
+ datalen = -datalen;
+ }
+
+ if (!(nbr = update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level)))
return;
if (datalen > 2*4096) {
@@ -826,6 +1117,7 @@ accept_report(src, dst, p, datalen, level)
if (rt[nrt-1].origin == 0)
rt[nrt-1].mask = 0;
+ IF_DEBUG(DEBUG_ROUTE)
log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
inet_fmt(src, s1), inet_fmt(dst, s2));
for (i = 0; i < nrt; ++i) {
@@ -835,8 +1127,43 @@ accept_report(src, dst, p, datalen, level)
inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2));
continue;
}
+ /* Only filter non-poisoned updates. */
+ if (uvifs[vifi].uv_filter && rt[i].metric < UNREACHABLE) {
+ struct vf_element *vfe;
+ int match = 0;
+
+ for (vfe = uvifs[vifi].uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) {
+ if (vfe->vfe_flags & VFEF_EXACT) {
+ if ((vfe->vfe_addr == rt[i].origin) &&
+ (vfe->vfe_mask == rt[i].mask)) {
+ match = 1;
+ break;
+ }
+ } else {
+ if ((rt[i].origin & vfe->vfe_mask) == vfe->vfe_addr) {
+ match = 1;
+ break;
+ }
+ }
+ }
+ if ((uvifs[vifi].uv_filter->vf_type == VFT_ACCEPT && match == 0) ||
+ (uvifs[vifi].uv_filter->vf_type == VFT_DENY && match == 1)) {
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "%s skipped on vif %d because it %s %s",
+ inet_fmts(rt[i].origin, rt[i].mask, s1),
+ vifi,
+ match ? "matches" : "doesn't match",
+ match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2) :
+ "the filter");
+#if 0
+ rt[i].metric += vfe->vfe_addmetric;
+ if (rt[i].metric > UNREACHABLE)
+#endif
+ rt[i].metric = UNREACHABLE;
+ }
+ }
update_route(rt[i].origin, rt[i].mask, rt[i].metric,
- src, vifi);
+ src, vifi, nbr);
}
if (routes_changed && !delay_change_reports)
@@ -855,80 +1182,13 @@ report(which_routes, vifi, dst)
u_int32 dst;
{
register struct rtentry *r;
- register char *p;
register int i;
- int datalen = 0;
- int width = 0;
- u_int32 mask = 0;
- u_int32 src;
- u_int32 nflags;
-
- src = uvifs[vifi].uv_lcl_addr;
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
-#ifdef NOTYET
- /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
- if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
- *p++ = 0; /* 0xff000000 mask */
- *p++ = 0;
- *p++ = 0;
- *p++ = 0; /* class A net 0.0.0.0 == default */
- *p++ = 0x81; /*XXX metric 1, is this safe? */
- datalen += 5;
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL), datalen);
- return;
- }
-#endif
-
- nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
-
- for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
-
- if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
- continue;
-
- /*
- * If there is no room for this route in the current message,
- * send the message and start a new one.
- */
- if (datalen + ((r->rt_originmask == mask) ?
- (width + 1) :
- (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
- *(p-1) |= 0x80;
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL | nflags), datalen);
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
- mask = 0;
- }
-
- if (r->rt_originmask != mask || datalen == 0) {
- mask = r->rt_originmask;
- width = r->rt_originwidth;
- if (datalen != 0) *(p-1) |= 0x80;
- *p++ = ((char *)&mask)[1];
- *p++ = ((char *)&mask)[2];
- *p++ = ((char *)&mask)[3];
- datalen += 3;
- }
-
- for (i = 0; i < width; ++i)
- *p++ = ((char *)&(r->rt_origin))[i];
-
- *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
- (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
- (char)(r->rt_metric);
-
- datalen += width + 1;
- }
-
- if (datalen != 0) {
- *(p-1) |= 0x80;
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL | nflags), datalen);
+ r = rt_end;
+ while (r != RT_ADDR) {
+ i = report_chunk(which_routes, r, vifi, dst);
+ while (i-- > 0)
+ r = r->rt_prev;
}
}
@@ -955,10 +1215,8 @@ report_to_all_neighbors(which_routes)
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if (v->uv_neighbors != NULL) {
- report(which_routes, vifi,
- (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
- : dvmrp_group);
+ if (!NBRM_ISEMPTY(v->uv_nbrmap)) {
+ report(which_routes, vifi, v->uv_dst_addr);
}
}
@@ -987,7 +1245,8 @@ report_to_all_neighbors(which_routes)
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
static int
-report_chunk(start_rt, vifi, dst)
+report_chunk(which_routes, start_rt, vifi, dst)
+ int which_routes;
register struct rtentry *start_rt;
vifi_t vifi;
u_int32 dst;
@@ -996,27 +1255,63 @@ report_chunk(start_rt, vifi, dst)
register char *p;
register int i;
register int nrt = 0;
+ struct uvif *v = &uvifs[vifi];
int datalen = 0;
int width = 0;
u_int32 mask = 0;
u_int32 src;
- u_int32 nflags;
+ int admetric = v->uv_admetric;
+ int metric;
- src = uvifs[vifi].uv_lcl_addr;
+ src = v->uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
-
for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
+ if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) {
+ nrt++;
+ continue;
+ }
-#ifdef NOTYET
- /* Don't send poisoned routes back to parents if I am a leaf */
- if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
- && (r->rt_metric > 1)) {
- ++nrt;
+ /*
+ * Do not poison-reverse a route for a directly-connected
+ * subnetwork on that subnetwork. This can cause loops when
+ * some router on the subnetwork is misconfigured.
+ */
+ if (r->rt_gateway == 0 && r->rt_parent == vifi) {
+ nrt++;
continue;
}
-#endif
+
+ if (v->uv_filter && v->uv_filter->vf_flags & VFF_BIDIR) {
+ struct vf_element *vfe;
+ int match = 0;
+
+ for (vfe = v->uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) {
+ if (vfe->vfe_flags & VFEF_EXACT) {
+ if ((vfe->vfe_addr == r->rt_origin) &&
+ (vfe->vfe_mask == r->rt_originmask)) {
+ match = 1;
+ break;
+ }
+ } else {
+ if ((r->rt_origin & vfe->vfe_mask) == vfe->vfe_addr) {
+ match = 1;
+ break;
+ }
+ }
+ }
+ if ((v->uv_filter->vf_type == VFT_ACCEPT && match == 0) ||
+ (v->uv_filter->vf_type == VFT_DENY && match == 1)) {
+ IF_DEBUG(DEBUG_ROUTE)
+ log(LOG_DEBUG, 0, "%s not reported on vif %d because it %s %s",
+ RT_FMT(r, s1), vifi,
+ match ? "matches" : "doesn't match",
+ match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2) :
+ "the filter");
+ nrt++;
+ continue;
+ }
+ }
/*
* If there is no room for this route in the current message,
@@ -1026,10 +1321,10 @@ report_chunk(start_rt, vifi, dst)
(width + 1) :
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL | nflags), datalen);
+ send_on_vif(v, 0, DVMRP_REPORT, datalen);
return (nrt);
}
+
if (r->rt_originmask != mask || datalen == 0) {
mask = r->rt_originmask;
width = r->rt_originwidth;
@@ -1042,16 +1337,20 @@ report_chunk(start_rt, vifi, dst)
for (i = 0; i < width; ++i)
*p++ = ((char *)&(r->rt_origin))[i];
- *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
- (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
- (char)(r->rt_metric);
+ metric = r->rt_metric + admetric;
+ if (metric > UNREACHABLE)
+ metric = UNREACHABLE;
+ if (r->rt_parent != vifi && AVOID_TRANSIT(vifi, r))
+ metric = UNREACHABLE;
+ *p++ = (r->rt_parent == vifi && metric != UNREACHABLE) ?
+ (char)(metric + UNREACHABLE) : /* "poisoned reverse" */
+ (char)(metric);
++nrt;
datalen += width + 1;
}
if (datalen != 0) {
*(p-1) |= 0x80;
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL | nflags), datalen);
+ send_on_vif(v, 0, DVMRP_REPORT, datalen);
}
return (nrt);
}
@@ -1086,14 +1385,8 @@ report_next_chunk()
* all our neighbors.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if ((v->uv_neighbors != NULL)
-#ifdef NOTYET
- && !(v->uv_flags & VIFF_LEAF)
-#endif
- ) {
- n = report_chunk(sr, vifi,
- (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
- : dvmrp_group);
+ if (!NBRM_ISEMPTY(v->uv_nbrmap)) {
+ n = report_chunk(ALL_ROUTES, sr, vifi, v->uv_dst_addr);
if (n < min)
min = n;
}
@@ -1102,6 +1395,7 @@ report_next_chunk()
min = 0; /* Neighborless router didn't send any routes */
n = min;
+ IF_DEBUG(DEBUG_ROUTE)
log(LOG_INFO, 0, "update %d starting at %d of %d",
n, (nroutes - start_rt), nroutes);
@@ -1124,7 +1418,7 @@ dump_routes(fp)
fprintf(fp,
"Multicast Routing Table (%u %s)\n%s\n",
nroutes, (nroutes == 1) ? "entry" : "entries",
- " Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs");
+ " Origin-Subnet From-Gateway Metric Tmr Fl In-Vif Out-Vifs");
for (r = routing_table; r != NULL; r = r->rt_next) {
@@ -1135,12 +1429,31 @@ dump_routes(fp)
fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
r->rt_metric);
- fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent);
+ fprintf(fp, " %3u %c%c %3u ", r->rt_timer,
+ (r->rt_flags & RTF_CHANGED) ? 'C' : '.',
+ (r->rt_flags & RTF_HOLDDOWN) ? 'H' : '.',
+ r->rt_parent);
for (i = 0; i < numvifs; ++i) {
+ struct listaddr *n;
+ char l = '[';
+
if (VIFM_ISSET(i, r->rt_children)) {
- fprintf(fp, " %u%c",
- i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
+ if ((uvifs[i].uv_flags & VIFF_TUNNEL) &&
+ !NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
+ /* Don't print out parenthood of a leaf tunnel. */
+ continue;
+ fprintf(fp, " %u", i);
+ if (!NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
+ fprintf(fp, "*");
+ for (n = uvifs[i].uv_neighbors; n; n = n->al_next) {
+ if (NBRM_ISSET(n->al_index, r->rt_subordinates)) {
+ fprintf(fp, "%c%d", l, n->al_index);
+ l = ',';
+ }
+ }
+ if (l == ',')
+ fprintf(fp, "]");
}
}
fprintf(fp, "\n");
@@ -1155,7 +1468,8 @@ determine_route(src)
struct rtentry *rt;
for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
- if (rt->rt_origin == (src & rt->rt_originmask))
+ if (rt->rt_origin == (src & rt->rt_originmask) &&
+ rt->rt_metric != UNREACHABLE)
break;
}
return rt;