route.c (mrouted-4.3) | : | route.c (mrouted-4.4) | ||
---|---|---|---|---|
skipping to change at line 39 | skipping to change at line 39 | |||
uint32_t bh_dst; | uint32_t bh_dst; | |||
uint32_t bh_level; | uint32_t bh_level; | |||
int32_t bh_datalen; | int32_t bh_datalen; | |||
}; | }; | |||
/* | /* | |||
* Exported variables. | * Exported variables. | |||
*/ | */ | |||
int routes_changed; /* 1=>some routes have changed */ | int routes_changed; /* 1=>some routes have changed */ | |||
int delay_change_reports; /* 1=>postpone change reports */ | int delay_change_reports; /* 1=>postpone change reports */ | |||
unsigned int nroutes; /* current number of route entries */ | unsigned int nroutes; /* number of routes */ | |||
struct rtentry *routing_table; /* pointer to list of route entries */ | ||||
/* | /* | |||
* Private variables. | * Private variables. | |||
*/ | */ | |||
static struct rtentry *rtp; /* pointer to a route entry */ | static TAILQ_HEAD(rthead, rtentry) rtable; | |||
static struct rtentry *rt_end; /* pointer to last route entry */ | static struct rtentry *rtp; /* pointer to a route entry */ | |||
/* | /* | |||
* Private functions. | * Private functions. | |||
*/ | */ | |||
static int init_children_and_leaves (struct rtentry *r, vifi_t parent, int firs t); | static int init_children_and_leaves (struct rtentry *r, vifi_t parent, int firs t); | |||
static int find_route (uint32_t origin, uint32_t mask); | static int find_route (uint32_t origin, uint32_t mask); | |||
static void create_route (uint32_t origin, uint32_t mask); | static void create_route (uint32_t origin, uint32_t mask); | |||
static void discard_route (struct rtentry *rt); | static void discard_route (struct rtentry *rt); | |||
static int compare_rts (const void *rt1, const void *rt2); | static int compare_rts (const void *rt1, const void *rt2); | |||
static int report_chunk (int, struct rtentry *start_rt, vifi_t vifi , uint32_t dst); | static struct rtentry *report_chunk (int, struct rtentry *, vifi_t, uint32_t, i nt *); | |||
static void queue_blaster_report (vifi_t vifi, uint32_t src, uint32_t dst, c har *p, size_t datalen, uint32_t level); | static void queue_blaster_report (vifi_t vifi, uint32_t src, uint32_t dst, c har *p, size_t datalen, uint32_t level); | |||
static void process_blaster_report (void *vifip); | static void process_blaster_report (void *vifip); | |||
/* | /* | |||
* Initialize the routing table and associated variables. | * Initialize the routing table and associated variables. | |||
*/ | */ | |||
void init_routes(void) | void init_routes(void) | |||
{ | { | |||
routing_table = NULL; | TAILQ_INIT(&rtable); | |||
rt_end = NULL; | ||||
nroutes = 0; | nroutes = 0; | |||
routes_changed = FALSE; | routes_changed = FALSE; | |||
delay_change_reports = FALSE; | delay_change_reports = FALSE; | |||
} | } | |||
/* | /* | |||
* Initialize the children bits for route 'r', along with the | * Initialize the children bits for route 'r', along with the | |||
* associated dominant and subordinate data structures. | * associated dominant and subordinate data structures. | |||
* If first is set, initialize dominants, otherwise keep old | * If first is set, initialize dominants, otherwise keep old | |||
* dominants on non-parent interfaces. | * dominants on non-parent interfaces. | |||
skipping to change at line 122 | skipping to change at line 120 | |||
/* | /* | |||
* A new vif has come up -- update the children bitmaps in all route | * A new vif has come up -- update the children bitmaps in all route | |||
* entries to take that into account. | * entries to take that into account. | |||
*/ | */ | |||
void add_vif_to_routes(vifi_t vifi) | void add_vif_to_routes(vifi_t vifi) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
uv = find_uvif(vifi); | uv = find_uvif(vifi); | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
if (r->rt_metric != UNREACHABLE && | if (r->rt_metric != UNREACHABLE && !VIFM_ISSET(vifi, r->rt_children)) { | |||
!VIFM_ISSET(vifi, r->rt_children)) { | ||||
VIFM_SET(vifi, r->rt_children); | VIFM_SET(vifi, r->rt_children); | |||
r->rt_dominants[vifi] = 0; | r->rt_dominants[vifi] = 0; | |||
/*XXX isn't uv_nbrmap going to be empty?*/ | /*XXX isn't uv_nbrmap going to be empty?*/ | |||
NBRM_CLRMASK(r->rt_subordinates, uv->uv_nbrmap); | NBRM_CLRMASK(r->rt_subordinates, uv->uv_nbrmap); | |||
update_table_entry(r, r->rt_gateway); | update_table_entry(r, r->rt_gateway); | |||
} | } | |||
} | } | |||
} | } | |||
/* | /* | |||
* A vif has gone down -- expire all routes that have that vif as parent, | * A vif has gone down -- expire all routes that have that vif as parent, | |||
* and update the children bitmaps in all other route entries to take into | * and update the children bitmaps in all other route entries to take into | |||
* account the failed vif. | * account the failed vif. | |||
*/ | */ | |||
void delete_vif_from_routes(vifi_t vifi) | void delete_vif_from_routes(vifi_t vifi) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
uv = find_uvif(vifi); | uv = find_uvif(vifi); | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
if (r->rt_metric != UNREACHABLE) { | if (r->rt_metric != UNREACHABLE) { | |||
if (vifi == r->rt_parent) { | if (vifi == r->rt_parent) { | |||
del_table_entry(r, 0, DEL_ALL_ROUTES); | del_table_entry(r, 0, DEL_ALL_ROUTES); | |||
r->rt_timer = ROUTE_EXPIRE_TIME; | r->rt_timer = ROUTE_EXPIRE_TIME; | |||
r->rt_metric = UNREACHABLE; | r->rt_metric = UNREACHABLE; | |||
r->rt_flags |= RTF_CHANGED; | r->rt_flags |= RTF_CHANGED; | |||
routes_changed = TRUE; | routes_changed = TRUE; | |||
} else if (VIFM_ISSET(vifi, r->rt_children)) { | } else if (VIFM_ISSET(vifi, r->rt_children)) { | |||
VIFM_CLR(vifi, r->rt_children); | VIFM_CLR(vifi, r->rt_children); | |||
NBRM_CLRMASK(r->rt_subordinates, uv->uv_nbrmap); | NBRM_CLRMASK(r->rt_subordinates, uv->uv_nbrmap); | |||
skipping to change at line 178 | skipping to change at line 175 | |||
*/ | */ | |||
void add_neighbor_to_routes(vifi_t vifi, uint32_t index) | void add_neighbor_to_routes(vifi_t vifi, uint32_t index) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
uv = find_uvif(vifi); | uv = find_uvif(vifi); | |||
if (uv->uv_flags & VIFF_NOFLOOD) | if (uv->uv_flags & VIFF_NOFLOOD) | |||
return; | return; | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
if (r->rt_metric != UNREACHABLE && r->rt_parent != vifi && !AVOID_TRANSIT (vifi, uv, r)) { | if (r->rt_metric != UNREACHABLE && r->rt_parent != vifi && !AVOID_TRANSIT (vifi, uv, r)) { | |||
NBRM_SET(index, r->rt_subordinates); | NBRM_SET(index, r->rt_subordinates); | |||
update_table_entry(r, r->rt_gateway); | update_table_entry(r, r->rt_gateway); | |||
} | } | |||
} | } | |||
} | } | |||
/* | /* | |||
* A neighbor has failed or become unreachable. If that neighbor was | * A neighbor has failed or become unreachable. If that neighbor was | |||
* considered a dominant or subordinate router in any route entries, | * considered a dominant or subordinate router in any route entries, | |||
* take appropriate action. Expire all routes this neighbor advertised | * take appropriate action. Expire all routes this neighbor advertised | |||
* to us. | * to us. | |||
*/ | */ | |||
void delete_neighbor_from_routes(uint32_t addr, vifi_t vifi, uint32_t index) | void delete_neighbor_from_routes(uint32_t addr, vifi_t vifi, uint32_t index) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
uv = find_uvif(vifi); | uv = find_uvif(vifi); | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
if (r->rt_metric != UNREACHABLE) { | if (r->rt_metric != UNREACHABLE) { | |||
if (r->rt_parent == vifi && r->rt_gateway == addr) { | if (r->rt_parent == vifi && r->rt_gateway == addr) { | |||
del_table_entry(r, 0, DEL_ALL_ROUTES); | del_table_entry(r, 0, DEL_ALL_ROUTES); | |||
r->rt_timer = ROUTE_EXPIRE_TIME; | r->rt_timer = ROUTE_EXPIRE_TIME; | |||
r->rt_metric = UNREACHABLE; | r->rt_metric = UNREACHABLE; | |||
r->rt_flags |= RTF_CHANGED; | r->rt_flags |= RTF_CHANGED; | |||
routes_changed = TRUE; | routes_changed = TRUE; | |||
} else if (r->rt_dominants[vifi] == addr) { | } else if (r->rt_dominants[vifi] == addr) { | |||
VIFM_SET(vifi, r->rt_children); | VIFM_SET(vifi, r->rt_children); | |||
r->rt_dominants[vifi] = 0; | r->rt_dominants[vifi] = 0; | |||
skipping to change at line 253 | skipping to change at line 250 | |||
* If no match is found, return FALSE and leave 'rtp' pointing to the route | * If no match is found, return FALSE and leave 'rtp' pointing to the route | |||
* entry preceding the point at which the new origin should be inserted. | * entry preceding the point at which the new origin should be inserted. | |||
* This code is optimized for the normal case in which the first entry to | * This code is optimized for the normal case in which the first entry to | |||
* be examined is the matching entry. | * be examined is the matching entry. | |||
*/ | */ | |||
static int find_route(uint32_t origin, uint32_t mask) | static int find_route(uint32_t origin, uint32_t mask) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
/* | /* | |||
* If rtp is NULL, we are preceding routing_table, so our first search | * If rtp is NULL, we are preceding rtable, so our first search | |||
* candidate should be the routing_table. | * candidate should be the rtable. | |||
*/ | */ | |||
r = rtp ? rtp : routing_table; | r = rtp ? rtp : TAILQ_FIRST(&rtable); | |||
while (r != NULL) { | while (r != NULL) { | |||
if (origin == r->rt_origin && mask == r->rt_originmask) { | if (origin == r->rt_origin && mask == r->rt_originmask) { | |||
rtp = r; | rtp = r; | |||
return TRUE; | return TRUE; | |||
} | } | |||
if (ntohl(mask) < ntohl(r->rt_originmask) || | if (ntohl(mask) < ntohl(r->rt_originmask) || | |||
(mask == r->rt_originmask && | (mask == r->rt_originmask && | |||
ntohl(origin) < ntohl(r->rt_origin))) { | ntohl(origin) < ntohl(r->rt_origin))) { | |||
rtp = r; | rtp = r; | |||
r = r->rt_next; | r = TAILQ_NEXT(r, rt_link); | |||
} else { | } else | |||
break; | break; | |||
} | ||||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
/* | /* | |||
* Create a new routing table entry for the specified origin and link it into | * Create a new routing table entry for the specified origin and link it into | |||
* the routing table. The shared variable 'rtp' is assumed to point to the | * the routing table. The shared variable 'rtp' is assumed to point to the | |||
* routing entry after which the new one should be inserted. It is left | * routing entry after which the new one should be inserted. It is left | |||
* pointing to the new entry. | * pointing to the new entry. | |||
* | * | |||
* Only the origin, originmask, originwidth and flags fields are initialized | * Only the origin, originmask, originwidth and flags fields are initialized | |||
skipping to change at line 313 | skipping to change at line 311 | |||
else if (((char *)&mask)[2] != 0) rt->rt_originwidth = 3; | else if (((char *)&mask)[2] != 0) rt->rt_originwidth = 3; | |||
else if (((char *)&mask)[1] != 0) rt->rt_originwidth = 2; | else if (((char *)&mask)[1] != 0) rt->rt_originwidth = 2; | |||
else rt->rt_originwidth = 1; | else rt->rt_originwidth = 1; | |||
rt->rt_flags = 0; | rt->rt_flags = 0; | |||
rt->rt_groups = NULL; | rt->rt_groups = NULL; | |||
VIFM_CLRALL(rt->rt_children); | VIFM_CLRALL(rt->rt_children); | |||
NBRM_CLRALL(rt->rt_subordinates); | NBRM_CLRALL(rt->rt_subordinates); | |||
NBRM_CLRALL(rt->rt_subordadv); | NBRM_CLRALL(rt->rt_subordadv); | |||
/* Link in 'rt', where rtp points */ | if (rtp) | |||
if (rtp) { | TAILQ_INSERT_AFTER(&rtable, rtp, rt, rt_link); | |||
rt->rt_prev = rtp; | else | |||
rt->rt_next = rtp->rt_next; | TAILQ_INSERT_HEAD(&rtable, rt, rt_link); | |||
if (rt->rt_next) | ||||
(rt->rt_next)->rt_prev = rt; | ||||
else | ||||
rt_end = rt; | ||||
rtp->rt_next = rt; | ||||
} else { | ||||
if (routing_table) { | ||||
/* Change existing head to rt */ | ||||
rt->rt_next = routing_table; | ||||
routing_table->rt_prev = rt; | ||||
} | ||||
else { | ||||
/* rt is the first route entry that exists */ | ||||
rt_end = rt; | ||||
} | ||||
routing_table = rt; | ||||
} | ||||
rtp = rt; | rtp = rt; | |||
++nroutes; | ++nroutes; | |||
} | } | |||
/* | /* | |||
* Discard the routing table entry following the one to which 'rt' points. | * Discard the routing table entry following the one to which 'rt' points. | |||
* [.|prev|.]--->[.|rt|.]<---[.|next|.] | * [.|prev|.]--->[.|rt|.]<---[.|next|.] | |||
*/ | */ | |||
static void discard_route(struct rtentry *rt) | static void discard_route(struct rtentry *rt) | |||
{ | { | |||
struct rtentry *prev, *next; | ||||
struct uvif *uv; | struct uvif *uv; | |||
if (!rt) | if (!rt) | |||
return; | return; | |||
/* Find previous and next link */ | /* Update meta pointers */ | |||
prev = rt->rt_prev; | if (rtp == rt) | |||
next = rt->rt_next; | rtp = TAILQ_NEXT(rt, rt_link); | |||
/* Unlink 'rt' */ | TAILQ_REMOVE(&rtable, rt, rt_link); | |||
if (prev) | ||||
prev->rt_next = next; /* Handles case when 'rt' is last link. */ | ||||
else | ||||
routing_table = next; /* 'rt' is first link. */ | ||||
if (next) | ||||
next->rt_prev = prev; | ||||
/* Update the books */ | /* Update the books */ | |||
uv = find_uvif(rt->rt_parent); | uv = find_uvif(rt->rt_parent); | |||
uv->uv_nroutes--; | uv->uv_nroutes--; | |||
/*???nbr???.al_nroutes--;*/ | /*???nbr???.al_nroutes--;*/ | |||
--nroutes; | --nroutes; | |||
/* Update meta pointers */ | ||||
if (rtp == rt) | ||||
rtp = next; | ||||
if (rt_end == rt) | ||||
rt_end = next; | ||||
free(rt->rt_dominants); | free(rt->rt_dominants); | |||
free(rt); | free(rt); | |||
} | } | |||
/* | /* | |||
* Process a route report for a single origin, creating or updating the | * Process a route report for a single origin, creating or updating the | |||
* corresponding routing table entry if necessary. 'src' is either the | * corresponding routing table entry if necessary. 'src' is either the | |||
* address of a neighboring router from which the report arrived, or zero | * address of a neighboring router from which the report arrived, or zero | |||
* to indicate a change of status of one of our own interfaces. | * to indicate a change of status of one of our own interfaces. | |||
*/ | */ | |||
skipping to change at line 676 | skipping to change at line 644 | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
/* | /* | |||
* On every timer interrupt, advance the timer in each routing entry. | * On every timer interrupt, advance the timer in each routing entry. | |||
*/ | */ | |||
void age_routes(void) | void age_routes(void) | |||
{ | { | |||
struct rtentry *r, *next; | ||||
extern uint32_t virtual_time; /* from main.c */ | extern uint32_t virtual_time; /* from main.c */ | |||
struct rtentry *r, *tmp; | ||||
r = routing_table; | TAILQ_FOREACH_SAFE(r, &rtable, rt_link, tmp) { | |||
while (r) { | ||||
next = r->rt_next; | ||||
if ((r->rt_timer += TIMER_INTERVAL) >= ROUTE_DISCARD_TIME) { | if ((r->rt_timer += TIMER_INTERVAL) >= ROUTE_DISCARD_TIME) { | |||
/* | /* | |||
* Time to garbage-collect the route entry. | * Time to garbage-collect the route entry. | |||
*/ | */ | |||
del_table_entry(r, 0, DEL_ALL_ROUTES); | del_table_entry(r, 0, DEL_ALL_ROUTES); | |||
discard_route(r); | discard_route(r); | |||
} else if (r->rt_timer >= ROUTE_EXPIRE_TIME && | } else if (r->rt_timer >= ROUTE_EXPIRE_TIME && | |||
r->rt_metric != UNREACHABLE) { | r->rt_metric != UNREACHABLE) { | |||
/* | /* | |||
* Time to expire the route entry. If the gateway is zero, | * Time to expire the route entry. If the gateway is zero, | |||
skipping to change at line 721 | skipping to change at line 686 | |||
IF_DEBUG(DEBUG_ROUTE) { | IF_DEBUG(DEBUG_ROUTE) { | |||
logit(LOG_DEBUG, 0, "rt %s sub 0x%08x%08x subadv 0x%08x%08x m etric %d", | logit(LOG_DEBUG, 0, "rt %s sub 0x%08x%08x subadv 0x%08x%08x m etric %d", | |||
RT_FMT(r, s1), r->rt_subordinates.hi, r->rt_subordinate s.lo, | RT_FMT(r, s1), r->rt_subordinates.hi, r->rt_subordinate s.lo, | |||
r->rt_subordadv.hi, r->rt_subordadv.lo, r->rt_metric); | r->rt_subordadv.hi, r->rt_subordadv.lo, r->rt_metric); | |||
} | } | |||
NBRM_MASK(r->rt_subordinates, r->rt_subordadv); | NBRM_MASK(r->rt_subordinates, r->rt_subordadv); | |||
update_table_entry(r, r->rt_gateway); | update_table_entry(r, r->rt_gateway); | |||
} | } | |||
NBRM_CLRALL(r->rt_subordadv); | NBRM_CLRALL(r->rt_subordadv); | |||
} | } | |||
r = next; | ||||
} | } | |||
} | } | |||
/* | /* | |||
* Mark all routes as unreachable. This function is called only from | * Mark all routes as unreachable. This function is called only from | |||
* hup() in preparation for informing all neighbors that we are going | * hup() in preparation for informing all neighbors that we are going | |||
* off the air. For consistency, we ought also to delete all reachable | * off the air. For consistency, we ought also to delete all reachable | |||
* route entries from the kernel, but since we are about to exit we rely | * route entries from the kernel, but since we are about to exit we rely | |||
* on the kernel to do its own cleanup -- no point in making all those | * on the kernel to do its own cleanup -- no point in making all those | |||
* expensive kernel calls now. | * expensive kernel calls now. | |||
*/ | */ | |||
void expire_all_routes(void) | void expire_all_routes(void) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
r->rt_metric = UNREACHABLE; | r->rt_metric = UNREACHABLE; | |||
r->rt_flags |= RTF_CHANGED; | r->rt_flags |= RTF_CHANGED; | |||
routes_changed = TRUE; | routes_changed = TRUE; | |||
} | } | |||
} | } | |||
/* | /* | |||
* Delete all the routes in the routing table. | * Delete all the routes in the routing table. | |||
*/ | */ | |||
void free_all_routes(void) | void free_all_routes(void) | |||
{ | { | |||
struct rtentry *r, *next; | struct rtentry *r, *tmp; | |||
r = routing_table; | TAILQ_FOREACH_SAFE(r, &rtable, rt_link, tmp) | |||
while (r) { | ||||
next = r->rt_next; | ||||
discard_route(r); | discard_route(r); | |||
r = next; | ||||
} | ||||
} | } | |||
/* | /* | |||
* Process an incoming neighbor probe message. | * Process an incoming neighbor probe message. | |||
*/ | */ | |||
void accept_probe(uint32_t src, uint32_t dst, char *p, size_t datalen, uint32_t level) | void accept_probe(uint32_t src, uint32_t dst, char *p, size_t datalen, uint32_t level) | |||
{ | { | |||
vifi_t vifi; | vifi_t vifi; | |||
vifi = find_vif_direct(src, dst); | vifi = find_vif_direct(src, dst); | |||
skipping to change at line 906 | skipping to change at line 865 | |||
/* | /* | |||
* Process an incoming route report message. | * Process an incoming route report message. | |||
* If the report arrived on a vif marked as a "blaster", then just | * If the report arrived on a vif marked as a "blaster", then just | |||
* queue it and return; queue_blaster_report() will schedule it for | * queue it and return; queue_blaster_report() will schedule it for | |||
* processing later. If datalen is negative, then this is actually | * processing later. If datalen is negative, then this is actually | |||
* a queued report so actually process it instead of queueing it. | * a queued report so actually process it instead of queueing it. | |||
*/ | */ | |||
void accept_report(uint32_t src, uint32_t dst, char *p, size_t datalen, uint32_t level) | void accept_report(uint32_t src, uint32_t dst, char *p, size_t datalen, uint32_t level) | |||
{ | { | |||
static struct newrt rt[MAX_NUM_RT]; /* Use heap instead of stack */ | static struct newrt rt[MAX_NUM_RT]; /* Use heap instead of stack */ /* XXX: fixme */ | |||
struct listaddr *nbr; | struct listaddr *nbr; | |||
struct uvif *uv; | struct uvif *uv; | |||
uint32_t origin; | uint32_t origin; | |||
uint32_t mask; | uint32_t mask; | |||
size_t width, i; | size_t width, i; | |||
size_t nrt = 0; | size_t nrt = 0; | |||
vifi_t vifi; | vifi_t vifi; | |||
int metric; | int metric; | |||
/* | /* | |||
skipping to change at line 1048 | skipping to change at line 1007 | |||
} | } | |||
update_route(rt[i].origin, rt[i].mask, rt[i].metric, src, vifi, nbr); | update_route(rt[i].origin, rt[i].mask, rt[i].metric, src, vifi, nbr); | |||
} | } | |||
if (routes_changed && !delay_change_reports) | if (routes_changed && !delay_change_reports) | |||
report_to_all_neighbors(CHANGED_ROUTES); | report_to_all_neighbors(CHANGED_ROUTES); | |||
} | } | |||
/* | /* | |||
* Send a route report message to destination 'dst', via virtual interface | * Send a route report message to destination 'dst', via virtual interface | |||
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. | * 'vifi'. 'type' specifies ALL_ROUTES or CHANGED_ROUTES. | |||
*/ | */ | |||
void report(int which_routes, vifi_t vifi, uint32_t dst) | void report(int type, vifi_t vifi, uint32_t dst) | |||
{ | { | |||
struct rtentry *rt; | struct rtentry *rt = TAILQ_LAST(&rtable, rthead); | |||
int i; | int dummy; | |||
rt = rt_end; | while (rt) | |||
while (rt && rt != routing_table) { | rt = report_chunk(type, rt, vifi, dst, &dummy); | |||
i = report_chunk(which_routes, rt, vifi, dst); | ||||
while (i-- > 0) | ||||
rt = rt->rt_prev; | ||||
} | ||||
} | } | |||
/* | /* | |||
* Send a route report message to all neighboring routers. | * Send a route report message to all neighboring routers. | |||
* 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. | * 'type' specifies ALL_ROUTES or CHANGED_ROUTES. | |||
*/ | */ | |||
void report_to_all_neighbors(int which_routes) | void report_to_all_neighbors(int type) | |||
{ | { | |||
int routes_changed_before; | int routes_changed_before; | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
vifi_t vifi; | vifi_t vifi; | |||
/* | /* | |||
* Remember the state of the global routes_changed flag before | * Remember the state of the global routes_changed flag before | |||
* generating the reports, and clear the flag. | * generating the reports, and clear the flag. | |||
*/ | */ | |||
routes_changed_before = routes_changed; | routes_changed_before = routes_changed; | |||
routes_changed = FALSE; | routes_changed = FALSE; | |||
UVIF_FOREACH(vifi, uv) { | UVIF_FOREACH(vifi, uv) { | |||
if (!NBRM_ISEMPTY(uv->uv_nbrmap)) | if (!NBRM_ISEMPTY(uv->uv_nbrmap)) | |||
report(which_routes, vifi, uv->uv_dst_addr); | report(type, vifi, uv->uv_dst_addr); | |||
} | } | |||
/* | /* | |||
* If there were changed routes before we sent the reports AND | * If there were changed routes before we sent the reports AND | |||
* if no new changes occurred while sending the reports, clear | * if no new changes occurred while sending the reports, clear | |||
* the change flags in the individual route entries. If changes | * the change flags in the individual route entries. If changes | |||
* did occur while sending the reports, new reports will be | * did occur while sending the reports, new reports will be | |||
* generated at the next timer interrupt. | * generated at the next timer interrupt. | |||
*/ | */ | |||
if (routes_changed_before && !routes_changed) { | if (routes_changed_before && !routes_changed) { | |||
for (r = routing_table; r; r = r->rt_next) | TAILQ_FOREACH(r, &rtable, rt_link) | |||
r->rt_flags &= ~RTF_CHANGED; | r->rt_flags &= ~RTF_CHANGED; | |||
} | } | |||
/* | /* | |||
* Set a flag to inhibit further reports of changed routes until the | * Set a flag to inhibit further reports of changed routes until the | |||
* next timer interrupt. This is to alleviate update storms. | * next timer interrupt. This is to alleviate update storms. | |||
*/ | */ | |||
delay_change_reports = TRUE; | delay_change_reports = TRUE; | |||
} | } | |||
/* | /* | |||
* Send a route report message to destination 'dst', via virtual interface | * Send a route report message to destination 'dst', via virtual interface | |||
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. | * 'vifi'. 'type' specifies ALL_ROUTES or CHANGED_ROUTES. | |||
*/ | */ | |||
static int report_chunk(int which_routes, struct rtentry *start_rt, vifi_t vifi, uint32_t dst) | static struct rtentry *report_chunk(int type, struct rtentry *rt, vifi_t vifi, u int32_t dst, int *nrt) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
uint32_t mask = 0; | uint32_t mask = 0; | |||
int datalen = 0; | int datalen = 0; | |||
size_t nrt = 0; | ||||
int width = 0; | int width = 0; | |||
int admetric; | int admetric; | |||
uint8_t *p; | uint8_t *p; | |||
int metric; | int metric; | |||
int i; | int i; | |||
*nrt = 0; | ||||
uv = find_uvif(vifi); | uv = find_uvif(vifi); | |||
if (!uv) | ||||
return NULL; | ||||
admetric = uv->uv_admetric; | admetric = uv->uv_admetric; | |||
p = send_buf + IP_HEADER_RAOPT_LEN + IGMP_MINLEN; | p = send_buf + IP_HEADER_RAOPT_LEN + IGMP_MINLEN; | |||
for (r = start_rt; r; r = r->rt_prev) { | for (r = rt; r != TAILQ_END(&rtable); r = TAILQ_PREV(r, rthead, rt_link)) { | |||
if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) { | if (type == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) { | |||
nrt++; | (*nrt)++; | |||
continue; | continue; | |||
} | } | |||
/* | /* | |||
* Do not poison-reverse a route for a directly-connected | * Do not poison-reverse a route for a directly-connected | |||
* subnetwork on that subnetwork. This can cause loops when | * subnetwork on that subnetwork. This can cause loops when | |||
* some router on the subnetwork is misconfigured. | * some router on the subnetwork is misconfigured. | |||
*/ | */ | |||
if (r->rt_gateway == 0 && r->rt_parent == vifi) { | if (r->rt_gateway == 0 && r->rt_parent == vifi) { | |||
nrt++; | (*nrt)++; | |||
continue; | continue; | |||
} | } | |||
if (uv->uv_filter && uv->uv_filter->vf_flags & VFF_BIDIR) { | if (uv->uv_filter && uv->uv_filter->vf_flags & VFF_BIDIR) { | |||
struct vf_element *vfe; | struct vf_element *vfe; | |||
int match = 0; | int match = 0; | |||
for (vfe = uv->uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) { | for (vfe = uv->uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) { | |||
if (vfe->vfe_flags & VFEF_EXACT) { | if (vfe->vfe_flags & VFEF_EXACT) { | |||
if ((vfe->vfe_addr == r->rt_origin) && | if ((vfe->vfe_addr == r->rt_origin) && | |||
skipping to change at line 1176 | skipping to change at line 1133 | |||
IF_DEBUG(DEBUG_ROUTE) { | IF_DEBUG(DEBUG_ROUTE) { | |||
logit(LOG_DEBUG, 0, "%s not reported on vif %d because it %s %s", | logit(LOG_DEBUG, 0, "%s not reported on vif %d because it %s %s", | |||
RT_FMT(r, s1), vifi, | RT_FMT(r, s1), vifi, | |||
(match | (match | |||
? "matches" | ? "matches" | |||
: "doesn't match"), | : "doesn't match"), | |||
(match | (match | |||
? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2, sizeof(s 2)) | ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2, sizeof(s 2)) | |||
: "the filter")); | : "the filter")); | |||
} | } | |||
nrt++; | (*nrt)++; | |||
continue; | continue; | |||
} | } | |||
} | } | |||
/* | /* | |||
* If there is no room for this route in the current message, | * If there is no room for this route in the current message, | |||
* send it & return how many routes we sent. | * send it & return how many routes we sent. | |||
*/ | */ | |||
if (datalen + ((r->rt_originmask == mask) | if (datalen + ((r->rt_originmask == mask) | |||
? (width + 1) | ? (width + 1) | |||
: (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { | : (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { | |||
*(p-1) |= 0x80; | *(p-1) |= 0x80; | |||
send_on_vif(uv, 0, DVMRP_REPORT, datalen); | send_on_vif(uv, 0, DVMRP_REPORT, datalen); | |||
return nrt; | return r; | |||
} | } | |||
if (r->rt_originmask != mask || datalen == 0) { | if (r->rt_originmask != mask || datalen == 0) { | |||
mask = r->rt_originmask; | mask = r->rt_originmask; | |||
width = r->rt_originwidth; | width = r->rt_originwidth; | |||
if (datalen != 0) | if (datalen != 0) | |||
*(p - 1) |= 0x80; | *(p - 1) |= 0x80; | |||
*p++ = ((char *)&mask)[1]; | *p++ = ((char *)&mask)[1]; | |||
*p++ = ((char *)&mask)[2]; | *p++ = ((char *)&mask)[2]; | |||
skipping to change at line 1219 | skipping to change at line 1176 | |||
metric = r->rt_metric + admetric; | metric = r->rt_metric + admetric; | |||
if (metric > UNREACHABLE) | if (metric > UNREACHABLE) | |||
metric = UNREACHABLE; | metric = UNREACHABLE; | |||
if (r->rt_parent != vifi && AVOID_TRANSIT(vifi, uv, r)) | if (r->rt_parent != vifi && AVOID_TRANSIT(vifi, uv, r)) | |||
metric = UNREACHABLE; | metric = UNREACHABLE; | |||
*p++ = (r->rt_parent == vifi && metric != UNREACHABLE) | *p++ = (r->rt_parent == vifi && metric != UNREACHABLE) | |||
? (char)(metric + UNREACHABLE) /* "poisoned reverse" */ | ? (char)(metric + UNREACHABLE) /* "poisoned reverse" */ | |||
: (char)(metric); | : (char)(metric); | |||
++nrt; | (*nrt)++; | |||
datalen += width + 1; | datalen += width + 1; | |||
} | } | |||
if (datalen != 0) { | if (datalen != 0) { | |||
*(p-1) |= 0x80; | *(p-1) |= 0x80; | |||
send_on_vif(uv, 0, DVMRP_REPORT, datalen); | send_on_vif(uv, 0, DVMRP_REPORT, datalen); | |||
} | } | |||
return nrt; | return r; | |||
} | } | |||
/* | /* | |||
* send the next chunk of our routing table to all neighbors. | * send the next chunk of our routing table to all neighbors. | |||
* return the length of the smallest chunk we sent out. | * return the length of the smallest chunk we sent out. | |||
*/ | */ | |||
int report_next_chunk(void) | int report_next_chunk(void) | |||
{ | { | |||
static int start_rt; | static int start_rt = 0; | |||
struct rtentry *sr; | struct rtentry *sr; | |||
struct uvif *uv; | struct uvif *uv; | |||
int min = 20000; | int min = 20000; | |||
vifi_t vifi; | vifi_t vifi; | |||
int n = 0; | int n = 0; | |||
int i; | int i; | |||
if (nroutes <= 0) | if (nroutes <= 0) | |||
return 0; | return 0; | |||
/* | /* | |||
* find this round's starting route. | * find this round's starting route. | |||
*/ | */ | |||
for (sr = rt_end, i = start_rt; sr && --i >= 0; ) { | i = start_rt; | |||
sr = sr->rt_prev; | TAILQ_FOREACH_REVERSE(sr, &rtable, rthead, rt_link) { | |||
if (sr == routing_table) | if (--i < 0) | |||
sr = rt_end; | break; | |||
} | } | |||
/* | /* | |||
* send one chunk of routes starting at this round's start to | * send one chunk of routes starting at this round's start to | |||
* all our neighbors. | * all our neighbors. | |||
*/ | */ | |||
UVIF_FOREACH(vifi, uv) { | UVIF_FOREACH(vifi, uv) { | |||
/* sr might turn up NULL above ... */ | /* sr might turn up NULL above ... */ | |||
if (sr && !NBRM_ISEMPTY(uv->uv_nbrmap)) { | if (sr && !NBRM_ISEMPTY(uv->uv_nbrmap)) { | |||
n = report_chunk(ALL_ROUTES, sr, vifi, uv->uv_dst_addr); | report_chunk(ALL_ROUTES, sr, vifi, uv->uv_dst_addr, &n); | |||
if (n < min) | if (n < min) | |||
min = n; | min = n; | |||
} | } | |||
} | } | |||
if (min == 20000) | if (min == 20000) | |||
min = 0; /* Neighborless router didn't send any routes */ | min = 0; /* Neighborless router didn't send any routes */ | |||
n = min; | n = min; | |||
IF_DEBUG(DEBUG_ROUTE) { | IF_DEBUG(DEBUG_ROUTE) { | |||
logit(LOG_INFO, 0, "update %d starting at %d of %d", | logit(LOG_INFO, 0, "update %d starting at %d of %d", | |||
skipping to change at line 1296 | skipping to change at line 1253 | |||
void dump_routes(FILE *fp, int detail) | void dump_routes(FILE *fp, int detail) | |||
{ | { | |||
struct rtentry *r; | struct rtentry *r; | |||
struct uvif *uv; | struct uvif *uv; | |||
vifi_t vifi; | vifi_t vifi; | |||
if (detail) | if (detail) | |||
fprintf(fp, "Multicast Routing Table (%u entr%s)\n", nroutes, nroutes == 1 ? "y" : "ies"); | fprintf(fp, "Multicast Routing Table (%u entr%s)\n", nroutes, nroutes == 1 ? "y" : "ies"); | |||
fputs(" Origin-Subnet From-Gateway Metric Tmr Fl In-Vif Out-Vifs=\n ", fp); | fputs(" Origin-Subnet From-Gateway Metric Tmr Fl In-Vif Out-Vifs=\n ", fp); | |||
for (r = routing_table; r; r = r->rt_next) { | TAILQ_FOREACH(r, &rtable, rt_link) { | |||
fprintf(fp, " %-18s %-15s ", | fprintf(fp, " %-18s %-15s ", | |||
inet_fmts(r->rt_origin, r->rt_originmask, s1, sizeof(s1)), | inet_fmts(r->rt_origin, r->rt_originmask, s1, sizeof(s1)), | |||
(r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2, sizeof(s2 ))); | (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2, sizeof(s2 ))); | |||
if (r->rt_metric == UNREACHABLE) | if (r->rt_metric == UNREACHABLE) | |||
fprintf(fp, " NR "); | fprintf(fp, " NR "); | |||
else | else | |||
fprintf(fp, "%4u ", r->rt_metric); | fprintf(fp, "%4u ", r->rt_metric); | |||
fprintf(fp, " %3u %c%c %3u ", r->rt_timer, | fprintf(fp, " %3u %c%c %3u ", r->rt_timer, | |||
skipping to change at line 1345 | skipping to change at line 1302 | |||
} | } | |||
fprintf(fp, "\n"); | fprintf(fp, "\n"); | |||
} | } | |||
fprintf(fp, "\n"); | fprintf(fp, "\n"); | |||
} | } | |||
struct rtentry *determine_route(uint32_t src) | struct rtentry *determine_route(uint32_t src) | |||
{ | { | |||
struct rtentry *rt; | struct rtentry *rt; | |||
for (rt = routing_table; rt; rt = rt->rt_next) { | TAILQ_FOREACH(rt, &rtable, rt_link) { | |||
if (rt->rt_origin == (src & rt->rt_originmask) && | if (rt->rt_origin == (src & rt->rt_originmask) && | |||
rt->rt_metric != UNREACHABLE) | rt->rt_metric != UNREACHABLE) | |||
break; | break; | |||
} | } | |||
return rt; | return rt; | |||
} | } | |||
struct rtentry *route_iter(struct rtentry **rt) | ||||
{ | ||||
if (!*rt) | ||||
*rt = TAILQ_FIRST(&rtable); | ||||
else | ||||
*rt = TAILQ_NEXT(*rt, rt_link); | ||||
return *rt; | ||||
} | ||||
/** | /** | |||
* Local Variables: | * Local Variables: | |||
* indent-tabs-mode: t | * indent-tabs-mode: t | |||
* c-file-style: "ellemtel" | * c-file-style: "cc-mode" | |||
* c-basic-offset: 4 | ||||
* End: | * End: | |||
*/ | */ | |||
End of changes. 53 change blocks. | ||||
108 lines changed or deleted | 74 lines changed or added |