diff options
Diffstat (limited to 'usr.sbin/mrouted/vif.c')
-rw-r--r-- | usr.sbin/mrouted/vif.c | 898 |
1 files changed, 240 insertions, 658 deletions
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c index 98c11ceb2ee26..4ce99edf49dde 100644 --- a/usr.sbin/mrouted/vif.c +++ b/usr.sbin/mrouted/vif.c @@ -5,14 +5,11 @@ * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. - * - * - * vif.c,v 3.8.4.56.2.1 1999/01/20 05:18:50 fenner Exp */ #ifndef lint static const char rcsid[] = - "$Id: vif.c,v 1.13 1998/06/09 05:01:38 imp Exp $"; + "$Id: vif.c,v 1.12 1998/01/16 07:17:45 charnier Exp $"; #endif /* not lint */ #include "defs.h" @@ -31,11 +28,6 @@ int udp_socket; /* Since the honkin' kernel doesn't support */ /* How dumb. */ int vifs_with_neighbors; /* == 1 if I am a leaf */ -/* - * Private variables. - */ -struct listaddr *nbrs[MAXNBRS]; /* array of neighbors */ - typedef struct { vifi_t vifi; struct listaddr *g; @@ -50,7 +42,6 @@ static void start_vif2 __P((vifi_t vifi)); static void stop_vif __P((vifi_t vifi)); static void age_old_hosts __P((void)); static void send_probe_on_vif __P((struct uvif *v)); -static void send_query __P((struct uvif *v)); static int info_version __P((char *p, int plen)); static void DelVif __P((void *arg)); static int SetTimer __P((int vifi, struct listaddr *g)); @@ -80,15 +71,10 @@ init_vifs() /* * Configure the vifs based on the interface configuration of the * the kernel and the contents of the configuration file. - * (Open a UDP socket for ioctl use in the config procedures if - * the kernel can't handle IOCTL's on the IGMP socket.) + * (Open a UDP socket for ioctl use in the config procedures.) */ -#ifdef IOCTL_OK_ON_RAW_SOCKET - udp_socket = igmp_socket; -#else if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) log(LOG_ERR, errno, "UDP socket"); -#endif log(LOG_INFO,0,"Getting vifs from kernel interfaces"); config_vifs_from_kernel(); log(LOG_INFO,0,"Getting vifs from %s",configfilename); @@ -138,47 +124,6 @@ init_vifs() } /* - * Initialize the passed vif with all appropriate default values. - * "t" is true if a tunnel, or false if a phyint. - */ -void -zero_vif(v, t) - struct uvif *v; - int t; -{ - v->uv_flags = 0; - v->uv_metric = DEFAULT_METRIC; - v->uv_admetric = 0; - v->uv_threshold = DEFAULT_THRESHOLD; - v->uv_rate_limit = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT; - v->uv_lcl_addr = 0; - v->uv_rmt_addr = 0; - v->uv_dst_addr = t ? 0 : dvmrp_group; - v->uv_subnet = 0; - v->uv_subnetmask = 0; - v->uv_subnetbcast = 0; - v->uv_name[0] = '\0'; - v->uv_groups = NULL; - v->uv_neighbors = NULL; - NBRM_CLRALL(v->uv_nbrmap); - v->uv_querier = NULL; - v->uv_igmpv1_warn = 0; - v->uv_prune_lifetime = 0; - v->uv_leaf_timer = 0; - v->uv_acl = NULL; - v->uv_addrs = NULL; - v->uv_filter = NULL; - v->uv_blasterbuf = NULL; - v->uv_blastercur = NULL; - v->uv_blasterend = NULL; - v->uv_blasterlen = 0; - v->uv_blastertimer = 0; - v->uv_nbrup = 0; - v->uv_icmp_warn = 0; - v->uv_nroutes = 0; -} - -/* * Start routing on all virtual interfaces that are not down or * administratively disabled. */ @@ -265,37 +210,6 @@ check_vif_state() } /* - * Send a DVMRP message on the specified vif. If DVMRP messages are - * to be encapsulated and sent "inside" the tunnel, use the special - * encapsulator. If it's not a tunnel or DVMRP messages are to be - * sent "beside" the tunnel, as required by earlier versions of mrouted, - * then just send the message. - */ -void -send_on_vif(v, dst, code, datalen) - register struct uvif *v; - u_int32 dst; - int code; - int datalen; -{ - u_int32 group = htonl(MROUTED_LEVEL | - ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)); - - /* - * The UNIX kernel will not decapsulate unicasts. - * Therefore, we don't send encapsulated unicasts. - */ - if ((v->uv_flags & (VIFF_TUNNEL|VIFF_OTUNNEL)) == VIFF_TUNNEL && - ((dst == 0) || IN_MULTICAST(ntohl(dst)))) - send_ipip(v->uv_lcl_addr, dst ? dst : dvmrp_group, IGMP_DVMRP, - code, group, datalen, v); - else - send_igmp(v->uv_lcl_addr, dst ? dst : v->uv_dst_addr, IGMP_DVMRP, - code, group, datalen); -} - - -/* * Send a probe message on vif v */ static void @@ -307,10 +221,6 @@ send_probe_on_vif(v) struct listaddr *nbr; int i; - if ((v->uv_flags & VIFF_PASSIVE && v->uv_neighbors == NULL) || - (v->uv_flags & VIFF_FORCE_LEAF)) - return; - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; for (i = 0; i < 4; i++) @@ -329,21 +239,13 @@ send_probe_on_vif(v) nbr = nbr->al_next; } - send_on_vif(v, 0, DVMRP_PROBE, datalen); -} - -static void -send_query(v) - register struct uvif *v; -{ - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "sending %squery on vif %d", - (v->uv_flags & VIFF_IGMPV1) ? "v1 " : "", - v - uvifs); - send_igmp(v->uv_lcl_addr, allhosts_group, - IGMP_MEMBERSHIP_QUERY, - (v->uv_flags & VIFF_IGMPV1) ? 0 : - IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); + send_igmp(v->uv_lcl_addr, + (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr + : dvmrp_group, + IGMP_DVMRP, DVMRP_PROBE, + htonl(MROUTED_LEVEL | + ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)), + datalen); } /* @@ -403,10 +305,10 @@ start_vif2(vifi) * the interface is connected. */ start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL); + update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi); for (p = v->uv_addrs; p; p = p->pa_next) { start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL); + update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi); } /* @@ -415,9 +317,10 @@ start_vif2(vifi) * query. */ v->uv_flags |= VIFF_QUERIER; - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "assuming querier duties on vif %d", vifi); - send_query(v); + send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, + (v->uv_flags & VIFF_IGMPV1) ? 0 : + IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); + age_old_hosts(); } v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; @@ -458,10 +361,10 @@ stop_vif(vifi) * failure. */ start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL); + update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi); for (p = v->uv_addrs; p; p = p->pa_next) { start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL); + update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi); } /* @@ -474,8 +377,6 @@ stop_vif(vifi) free((char *)a); } - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "releasing querier duties on vif %d", vifi); v->uv_flags &= ~VIFF_QUERIER; } @@ -492,16 +393,14 @@ stop_vif(vifi) /* * Discard all neighbor addresses. */ - if (!NBRM_ISEMPTY(v->uv_nbrmap)) + if (v->uv_neighbors) vifs_with_neighbors--; while (v->uv_neighbors != NULL) { a = v->uv_neighbors; v->uv_neighbors = a->al_next; - nbrs[a->al_index] = NULL; free((char *)a); } - NBRM_CLRALL(v->uv_nbrmap); } @@ -526,7 +425,6 @@ stop_all_vifs() while (v->uv_neighbors != NULL) { a = v->uv_neighbors; v->uv_neighbors = a->al_next; - nbrs[a->al_index] = NULL; free((char *)a); } while (v->uv_acl != NULL) { @@ -554,8 +452,7 @@ find_vif(src, dst) for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { if (v->uv_flags & VIFF_TUNNEL) { - if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr || - dst == dvmrp_group)) + if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr) return(vifi); } else { @@ -594,13 +491,7 @@ age_old_hosts() /* - * Send group membership queries on each interface for which I am querier. - * Note that technically, there should be a timer per interface, as the - * dynamics of querier election can cause the "right" time to send a - * query to be different on different interfaces. However, this simple - * implementation only ever sends queries sooner than the "right" time, - * so can not cause loss of membership (but can send more packets than - * necessary) + * Send group membership queries to all subnets for which I am querier. */ void query_groups() @@ -610,16 +501,17 @@ query_groups() for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { if (v->uv_flags & VIFF_QUERIER) { - send_query(v); + send_igmp(v->uv_lcl_addr, allhosts_group, + IGMP_HOST_MEMBERSHIP_QUERY, + (v->uv_flags & VIFF_IGMPV1) ? 0 : + IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); } } age_old_hosts(); } /* - * Process an incoming host membership query. Warn about - * IGMP version mismatches, perform querier election, and - * handle group-specific queries when we're not the querier. + * Process an incoming host membership query */ void accept_membership_query(src, dst, group, tmo) @@ -639,97 +531,20 @@ accept_membership_query(src, dst, group, tmo) v = &uvifs[vifi]; - if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) || - (tmo != 0 && (v->uv_flags & VIFF_IGMPV1))) { - int i; - - /* - * Exponentially back-off warning rate - */ - i = ++v->uv_igmpv1_warn; - while (i && !(i & 1)) - i >>= 1; - if (i == 1) - log(LOG_WARNING, 0, "%s %s on vif %d, %s", - tmo == 0 ? "Received IGMPv1 report from" - : "Received IGMPv2 report from", - inet_fmt(src, s1), - vifi, - tmo == 0 ? "please configure vif for IGMPv1" - : "but I am configured for IGMPv1"); - } - - if (v->uv_querier == NULL || v->uv_querier->al_addr != src) { - /* - * This might be: - * - A query from a new querier, with a lower source address - * than the current querier (who might be me) - * - A query from a new router that just started up and doesn't - * know who the querier is. - */ - if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr) - : ntohl(v->uv_lcl_addr))) { - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "new querier %s (was %s) on vif %d", - inet_fmt(src, s1), - v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) : - "me", vifi); - if (!v->uv_querier) { - v->uv_querier = (struct listaddr *) - malloc(sizeof(struct listaddr)); - v->uv_flags &= ~VIFF_QUERIER; - } - time(&v->uv_querier->al_ctime); - v->uv_querier->al_addr = src; - } else { - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "ignoring query from %s; querier on vif %d is still %s", - inet_fmt(src, s1), vifi, - v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) : - "me"); - - return; - } - } - /* - * Reset the timer since we've received a query. + * If we consider ourselves the querier for this vif, but hear a + * query from a router with a lower IP address, yield to them. + * + * This is done here as well as in the neighbor discovery in case + * there is a querier that doesn't speak DVMRP. + * + * XXX If this neighbor doesn't speak DVMRP, then we need to create + * some neighbor state for him so that we can time him out! */ - if (v->uv_querier && src == v->uv_querier->al_addr) - v->uv_querier->al_timer = 0; + if ((v->uv_flags & VIFF_QUERIER) && + (ntohl(src) < ntohl(v->uv_lcl_addr))) { + v->uv_flags &= ~VIFF_QUERIER; - /* - * If this is a Group-Specific query which we did not source, - * we must set our membership timer to [Last Member Query Count] * - * the [Max Response Time] in the packet. - */ - if (!(v->uv_flags & (VIFF_IGMPV1|VIFF_QUERIER)) && group != 0 && - src != v->uv_lcl_addr) { - register struct listaddr *g; - - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, - "%s for %s from %s on vif %d, timer %d", - "Group-specific membership query", - inet_fmt(group, s2), inet_fmt(src, s1), vifi, tmo); - - for (g = v->uv_groups; g != NULL; g = g->al_next) { - if (group == g->al_addr && g->al_query == 0) { - /* setup a timeout to remove the group membership */ - if (g->al_timerid) - g->al_timerid = DeleteTimer(g->al_timerid); - g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT * - tmo / IGMP_TIMER_SCALE; - /* use al_query to record our presence in last-member state */ - g->al_query = -1; - g->al_timerid = SetTimer(vifi, g); - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, - "timer for grp %s on vif %d set to %d", - inet_fmt(group, s2), vifi, g->al_timer); - break; - } - } } } @@ -760,13 +575,14 @@ accept_group_report(src, dst, group, r_type) */ for (g = v->uv_groups; g != NULL; g = g->al_next) { if (group == g->al_addr) { - if (r_type == IGMP_V1_MEMBERSHIP_REPORT) + if (r_type == IGMP_HOST_MEMBERSHIP_REPORT) g->al_old = OLD_AGE_THRESHOLD; - - g->al_reporter = src; +#ifdef SNMP + g->al_genid = src; +#endif /* SNMP */ /** delete old timers, set a timer for expiration **/ - g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; + g->al_timer = GROUP_EXPIRE_TIME; if (g->al_query) g->al_query = DeleteTimer(g->al_query); if (g->al_timerid) @@ -785,19 +601,21 @@ accept_group_report(src, dst, group, r_type) log(LOG_ERR, 0, "ran out of memory"); /* fatal */ g->al_addr = group; - if (r_type == IGMP_V1_MEMBERSHIP_REPORT) - g->al_old = OLD_AGE_THRESHOLD; - else + if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) g->al_old = 0; + else + g->al_old = OLD_AGE_THRESHOLD; +#ifdef SNMP + g->al_genid = src; +#endif /** set a timer for expiration **/ - g->al_query = 0; - g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; - g->al_reporter = src; - g->al_timerid = SetTimer(vifi, g); - g->al_next = v->uv_groups; - v->uv_groups = g; + g->al_query = 0; + g->al_timer = GROUP_EXPIRE_TIME; time(&g->al_ctime); + g->al_timerid = SetTimer(vifi, g); + g->al_next = v->uv_groups; + v->uv_groups = g; update_lclgrp(vifi, group); } @@ -808,9 +626,7 @@ accept_group_report(src, dst, group, r_type) chkgrp_graft(vifi, group); } -/* - * Process an incoming IGMPv2 Leave Group message. - */ + void accept_leave_message(src, dst, group) u_int32 src, dst, group; @@ -838,7 +654,6 @@ accept_leave_message(src, dst, group) */ for (g = v->uv_groups; g != NULL; g = g->al_next) { if (group == g->al_addr) { - IF_DEBUG(DEBUG_IGMP) log(LOG_DEBUG, 0, "[vif.c, _accept_leave_message] %d %d \n", g->al_old, g->al_query); @@ -855,20 +670,14 @@ accept_leave_message(src, dst, group) if (g->al_timerid) g->al_timerid = DeleteTimer(g->al_timerid); -#if IGMP_LAST_MEMBER_QUERY_COUNT != 2 -This code needs to be updated to keep a counter of the number -of queries remaining. -#endif /** send a group specific querry **/ - g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL * - (IGMP_LAST_MEMBER_QUERY_COUNT + 1); + g->al_timer = LEAVE_EXPIRE_TIME; send_igmp(v->uv_lcl_addr, g->al_addr, - IGMP_MEMBERSHIP_QUERY, - IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE, - g->al_addr, 0); - g->al_query = SetQueryTimer(g, vifi, - IGMP_LAST_MEMBER_QUERY_INTERVAL, - IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE); + IGMP_HOST_MEMBERSHIP_QUERY, + LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE, + g->al_addr, 0); + g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3, + LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE); g->al_timerid = SetTimer(vifi, g); break; } @@ -1024,9 +833,6 @@ accept_neighbor_request2(src, dst) } /* Put out the header for this neighbor list... */ if (ncount == 0) { - /* If it's a one-way tunnel, mark it down. */ - if (rflags & DVMRP_NF_TUNNEL && la->al_flags & NBRF_ONEWAY) - rflags |= DVMRP_NF_DOWN; *(u_int*)p = v->uv_lcl_addr; p += 4; *p++ = v->uv_metric; @@ -1036,20 +842,11 @@ accept_neighbor_request2(src, dst) *p++ = 0; datalen += 4 + 4; } - /* Don't report one-way peering on phyint at all */ - if (!(rflags & DVMRP_NF_TUNNEL) && la->al_flags & NBRF_ONEWAY) - continue; *(u_int*)p = la->al_addr; p += 4; datalen += 4; (*ncount)++; } - if (*ncount == 0) { - *(u_int*)p = v->uv_rmt_addr; - p += 4; - datalen += 4; - (*ncount)++; - } } } if (datalen != 0) @@ -1145,8 +942,7 @@ accept_neighbors2(src, dst, p, datalen, level) u_char *p; int datalen; { - IF_DEBUG(DEBUG_PKT) - log(LOG_DEBUG, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", + log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", inet_fmt(src, s1), inet_fmt(dst, s2)); } @@ -1159,8 +955,7 @@ accept_info_reply(src, dst, p, datalen) u_char *p; int datalen; { - IF_DEBUG(DEBUG_PKT) - log(LOG_DEBUG, 0, "ignoring spurious DVMRP info reply from %s to %s", + log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s", inet_fmt(src, s1), inet_fmt(dst, s2)); } @@ -1168,9 +963,9 @@ accept_info_reply(src, dst, p, datalen) /* * Update the neighbor entry for neighbor 'addr' on vif 'vifi'. * 'msgtype' is the type of DVMRP message received from the neighbor. - * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise. + * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise. */ -struct listaddr * +int update_neighbor(vifi, addr, msgtype, p, datalen, level) vifi_t vifi; u_int32 addr; @@ -1181,17 +976,14 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level) { register struct uvif *v; register struct listaddr *n; - int pv = level & 0xff; - int mv = (level >> 8) & 0xff; - int has_genid = 0; - int in_router_list = 0; - int dvmrpspec = 0; - u_int32 genid; + u_int32 genid = 0; + u_int32 router; u_int32 send_tables = 0; - int i; int do_reset = FALSE; + int nflags; v = &uvifs[vifi]; + nflags = (level >> 16) & 0xff; /* * Confirm that 'addr' is a valid neighbor address on vif 'vifi'. @@ -1208,67 +1000,12 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level) (addr == v->uv_lcl_addr || addr == v->uv_subnet )) { log(LOG_WARNING, 0, - "received DVMRP message from %s: %s", - (addr == v->uv_lcl_addr) ? "self (check device loopback)" : - "'the unknown host'", + "received DVMRP message from 'the unknown host' or self: %s", inet_fmt(addr, s1)); - return NULL; - } - - /* - * Ignore all neighbors on vifs forced into leaf mode - */ - if (v->uv_flags & VIFF_FORCE_LEAF) { - return NULL; + return (FALSE); } /* - * mrouted's version 3.3 and later include the generation ID - * and the list of neighbors on the vif in their probe messages. - */ - if (msgtype == DVMRP_PROBE && ((pv == 3 && mv > 2) || - (pv > 3 && pv < 10))) { - u_int32 router; - - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "checking probe from %s (%d.%d) on vif %d", - inet_fmt(addr, s1), pv, mv, vifi); - - if (datalen < 4) { - log(LOG_WARNING, 0, - "received truncated probe message from %s (len %d)", - inet_fmt(addr, s1), datalen); - return NULL; - } - - has_genid = 1; - - for (i = 0; i < 4; i++) - ((char *)&genid)[i] = *p++; - datalen -= 4; - - while (datalen > 0) { - if (datalen < 4) { - log(LOG_WARNING, 0, - "received truncated probe message from %s (len %d)", - inet_fmt(addr, s1), datalen); - return NULL; - } - for (i = 0; i < 4; i++) - ((char *)&router)[i] = *p++; - datalen -= 4; - - if (router == v->uv_lcl_addr) { - in_router_list = 1; - break; - } - } - } - - if ((pv == 3 && mv == 255) || (pv > 3 && pv < 10)) - dvmrpspec = 1; - - /* * Look for addr in list of neighbors. */ for (n = v->uv_neighbors; n != NULL; n = n->al_next) { @@ -1277,217 +1014,157 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level) } } - if (n == NULL) { + /* + * Found it. Reset its timer, and check for a version change + */ + if (n) { + n->al_timer = 0; + /* - * New neighbor. - * - * If this neighbor follows the DVMRP spec, start the probe - * handshake. If not, then it doesn't require the probe - * handshake, so establish the peering immediately. + * update the neighbors version and protocol number + * if changed => router went down and came up, + * so take action immediately. */ - if (dvmrpspec && (msgtype != DVMRP_PROBE)) - return NULL; + if ((n->al_pv != (level & 0xff)) || + (n->al_mv != ((level >> 8) & 0xff))) { - for (i = 0; i < MAXNBRS; i++) - if (nbrs[i] == NULL) - break; - - if (i == MAXNBRS) { - /* XXX This is a severe new restriction. */ - /* XXX want extensible bitmaps! */ - log(LOG_ERR, 0, "Can't handle %dth neighbor %s on vif %d!", - MAXNBRS, inet_fmt(addr, s1), vifi); - /*NOTREACHED*/ + do_reset = TRUE; + log(LOG_DEBUG, 0, + "version change neighbor %s [old:%d.%d, new:%d.%d]", + inet_fmt(addr, s1), + n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff); + + n->al_pv = level & 0xff; + n->al_mv = (level >> 8) & 0xff; } - + } else { /* - * Add it to our list of neighbors. + * If not found, add it to the list. If the neighbor has a lower + * IP address than me, yield querier duties to it. */ - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d", + log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x", inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, - (level >> 16) & 0xff, i); + (level >> 16) & 0xff); n = (struct listaddr *)malloc(sizeof(struct listaddr)); if (n == NULL) log(LOG_ERR, 0, "ran out of memory"); /* fatal */ n->al_addr = addr; - n->al_pv = pv; - n->al_mv = mv; - n->al_genid = has_genid ? genid : 0; - n->al_index = i; - nbrs[i] = n; + n->al_pv = level & 0xff; + n->al_mv = (level >> 8) & 0xff; + n->al_genid = 0; time(&n->al_ctime); n->al_timer = 0; - n->al_flags = has_genid ? NBRF_GENID : 0; n->al_next = v->uv_neighbors; - v->uv_neighbors = n; - - /* - * If we are not configured to peer with non-pruning routers, - * check the deprecated "I-know-how-to-prune" bit. This bit - * was MBZ in early mrouted implementations (<3.5) and is required - * to be set by the DVMRPv3 specification. - */ - if (!(v->uv_flags & VIFF_ALLOW_NONPRUNERS) && - !((level & 0x020000) || (pv == 3 && mv < 5))) { - n->al_flags |= NBRF_TOOOLD; - } - - /* - * If this router implements the DVMRPv3 spec, then don't peer - * with him if we haven't yet established a bidirectional connection. - */ - if (dvmrpspec) { - if (!in_router_list) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "waiting for probe from %s with my addr", - inet_fmt(addr, s1)); - n->al_flags |= NBRF_WAITING; - return NULL; - } - } - - if (n->al_flags & NBRF_DONTPEER) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "not peering with %s on vif %d because %x", - inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER); - return NULL; - } /* * If we thought that we had no neighbors on this vif, send a route * report to the vif. If this is just a new neighbor on the same * vif, send the route report just to the new neighbor. */ - if (NBRM_ISEMPTY(v->uv_nbrmap)) { - send_tables = v->uv_dst_addr; + if (v->uv_neighbors == NULL) { + send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group; vifs_with_neighbors++; } else { send_tables = addr; } + v->uv_neighbors = n; - NBRM_SET(i, v->uv_nbrmap); - add_neighbor_to_routes(vifi, i); - } else { - /* - * Found it. Reset its timer. - */ - n->al_timer = 0; + if (!(v->uv_flags & VIFF_TUNNEL) && + ntohl(addr) < ntohl(v->uv_lcl_addr)) + v->uv_flags &= ~VIFF_QUERIER; + } - if (n->al_flags & NBRF_WAITING && msgtype == DVMRP_PROBE) { - n->al_flags &= ~NBRF_WAITING; - if (!in_router_list) { - log(LOG_WARNING, 0, "possible one-way peering with %s on vif %d", - inet_fmt(addr, s1), vifi); - n->al_flags |= NBRF_ONEWAY; - return NULL; - } else { - if (NBRM_ISEMPTY(v->uv_nbrmap)) { - send_tables = v->uv_dst_addr; - vifs_with_neighbors++; - } else { - send_tables = addr; - } - NBRM_SET(n->al_index, v->uv_nbrmap); - add_neighbor_to_routes(vifi, n->al_index); - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "%s on vif %d exits WAITING", - inet_fmt(addr, s1), vifi); - } - } + /* + * Check if the router gen-ids are the same. + * Need to reset the prune state of the router if not. + * Also check for one-way interfaces by seeing if we are in our + * neighbor's list of known routers. + */ + if (msgtype == DVMRP_PROBE) { + + /* Check genid neighbor flag. Also check version number; 3.3 and + * 3.4 didn't set this flag. */ + if ((((level >> 16) & 0xff) & NF_GENID) || + (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) { + + int i; - if (n->al_flags & NBRF_ONEWAY && msgtype == DVMRP_PROBE) { - if (in_router_list) { - if (NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors++; - NBRM_SET(n->al_index, v->uv_nbrmap); - add_neighbor_to_routes(vifi, n->al_index); - log(LOG_NOTICE, 0, "peering with %s on vif %d is no longer one-way", - inet_fmt(addr, s1), vifi); - n->al_flags &= ~NBRF_ONEWAY; - } else { - /* XXX rate-limited warning message? */ - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "%s on vif %d is still ONEWAY", - inet_fmt(addr, s1), vifi); + if (datalen < 4) { + log(LOG_WARNING, 0, + "received truncated probe message from %s (len %d)", + inet_fmt(addr, s1), datalen); + return (FALSE); } - } - /* - * When peering with a genid-capable but pre-DVMRP spec peer, - * we might bring up the peering with a route report and not - * remember his genid. Assume that he doesn't send a route - * report and then reboot before sending a probe. - */ - if (has_genid && !(n->al_flags & NBRF_GENID)) { - n->al_flags |= NBRF_GENID; - n->al_genid = genid; - } + for (i = 0; i < 4; i++) + ((char *)&genid)[i] = *p++; + datalen -= 4; - /* - * update the neighbors version and protocol number and genid - * if changed => router went down and came up, - * so take action immediately. - */ - if ((n->al_pv != pv) || - (n->al_mv != mv) || - (has_genid && n->al_genid != genid)) { + if (n->al_genid == 0) + n->al_genid = genid; + else if (n->al_genid != genid) { + log(LOG_DEBUG, 0, + "new genid neigbor %s on vif %d [old:%x, new:%x]", + inet_fmt(addr, s1), vifi, n->al_genid, genid); - do_reset = TRUE; - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, - "version/genid change neighbor %s [old:%d.%d/%8x, new:%d.%d/%8x]", - inet_fmt(addr, s1), - n->al_pv, n->al_mv, n->al_genid, pv, mv, genid); + n->al_genid = genid; + do_reset = TRUE; + } - n->al_pv = pv; - n->al_mv = mv; - n->al_genid = genid; - time(&n->al_ctime); - } - - if ((pv == 3 && mv > 2) || (pv > 3 && pv < 10)) { - if (!(n->al_flags & VIFF_ONEWAY) && has_genid && !in_router_list && - (time(NULL) - n->al_ctime > 20)) { - if (NBRM_ISSET(n->al_index, v->uv_nbrmap)) { - NBRM_CLR(n->al_index, v->uv_nbrmap); - if (NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors--; + /* + * loop through router list and check for one-way ifs. + */ + + v->uv_flags |= VIFF_ONEWAY; + + while (datalen > 0) { + if (datalen < 4) { + log(LOG_WARNING, 0, + "received truncated probe message from %s (len %d)", + inet_fmt(addr, s1), datalen); + return (FALSE); + } + for (i = 0; i < 4; i++) + ((char *)&router)[i] = *p++; + datalen -= 4; + if (router == v->uv_lcl_addr) { + v->uv_flags &= ~VIFF_ONEWAY; + break; } - delete_neighbor_from_routes(addr, vifi, n->al_index); - reset_neighbor_state(vifi, addr); - log(LOG_WARNING, 0, "peering with %s on vif %d is one-way", - inet_fmt(addr, s1), vifi); - n->al_flags |= NBRF_ONEWAY; } } - - if (n->al_flags & NBRF_DONTPEER) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "not peering with %s on vif %d because %x", - inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER); - return NULL; + } + if (n->al_flags != nflags) { + n->al_flags = nflags; + + if (n->al_flags & NF_LEAF) { + /*XXX If we have non-leaf neighbors then we know we shouldn't + * mark this vif as a leaf. For now we just count on other + * probes and/or reports resetting the timer. */ + if (!v->uv_leaf_timer) + v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; + } else { + /* If we get a leaf to non-leaf transition, we *must* update + * the routing table. */ + if (v->uv_flags & VIFF_LEAF && send_tables == 0) + send_tables = addr; + v->uv_flags &= ~VIFF_LEAF; + v->uv_leaf_timer = 0; } - - /* check "leaf" flag */ } if (do_reset) { reset_neighbor_state(vifi, addr); if (!send_tables) send_tables = addr; } - if (send_tables) { - send_probe_on_vif(v); + if (send_tables) report(ALL_ROUTES, vifi, send_tables); - } - v->uv_leaf_timer = 0; - v->uv_flags &= ~VIFF_LEAF; - return n; + return (TRUE); } @@ -1500,7 +1177,7 @@ age_vifs() { register vifi_t vifi; register struct uvif *v; - register struct listaddr *a, *prev_a; + register struct listaddr *a, *prev_a, *n; register u_int32 addr; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { @@ -1512,58 +1189,39 @@ age_vifs() a = v->uv_neighbors; a != NULL; prev_a = a, a = a->al_next) { - int exp_time; - int idx; - if (((a->al_pv == 3) && (a->al_mv >= 3)) || - ((a->al_pv > 3) && (a->al_pv < 10))) - exp_time = NEIGHBOR_EXPIRE_TIME; - else - exp_time = OLD_NEIGHBOR_EXPIRE_TIME; - - if ((a->al_timer += TIMER_INTERVAL) < exp_time) + if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME) continue; - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "Neighbor %s (%d.%d) expired after %d seconds", - inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, exp_time); - /* * Neighbor has expired; delete it from the neighbor list, * delete it from the 'dominants' and 'subordinates arrays of - * any route entries. + * any route entries and assume querier duties unless there is + * another neighbor with a lower IP address than mine. */ - NBRM_CLR(a->al_index, v->uv_nbrmap); - nbrs[a->al_index] = NULL; /* XXX is it a good idea to reuse indxs? */ - idx = a->al_index; addr = a->al_addr; prev_a->al_next = a->al_next; free((char *)a); - a = prev_a;/*XXX use ** */ + a = prev_a; - delete_neighbor_from_routes(addr, vifi, idx); - reset_neighbor_state(vifi, addr); + delete_neighbor_from_routes(addr, vifi); - if (NBRM_ISEMPTY(v->uv_nbrmap)) + if (v->uv_neighbors == NULL) vifs_with_neighbors--; v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; - } - if (v->uv_querier && - (v->uv_querier->al_timer += TIMER_INTERVAL) > - IGMP_OTHER_QUERIER_PRESENT_INTERVAL) { - /* - * The current querier has timed out. We must become the - * querier. - */ - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "querier %s timed out", - inet_fmt(v->uv_querier->al_addr, s1)); - free(v->uv_querier); - v->uv_querier = NULL; - v->uv_flags |= VIFF_QUERIER; - send_query(v); + if (!(v->uv_flags & VIFF_TUNNEL)) { + v->uv_flags |= VIFF_QUERIER; + for (n = v->uv_neighbors; n != NULL; n = n->al_next) { + if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) { + v->uv_flags &= ~VIFF_QUERIER; + } + if (!(n->al_flags & NF_LEAF)) { + v->uv_leaf_timer = 0; + } + } + } } } } @@ -1585,36 +1243,6 @@ neighbor_info(vifi, addr) return NULL; } -static struct vnflags { - int vn_flag; - char *vn_name; -} vifflags[] = { - { VIFF_DOWN, "down" }, - { VIFF_DISABLED, "disabled" }, - { VIFF_QUERIER, "querier" }, - { VIFF_ONEWAY, "one-way" }, - { VIFF_LEAF, "leaf" }, - { VIFF_IGMPV1, "IGMPv1" }, - { VIFF_REXMIT_PRUNES, "rexmit_prunes" }, - { VIFF_PASSIVE, "passive" }, - { VIFF_ALLOW_NONPRUNERS,"allow_nonpruners" }, - { VIFF_NOFLOOD, "noflood" }, - { VIFF_NOTRANSIT, "notransit" }, - { VIFF_BLASTER, "blaster" }, - { VIFF_FORCE_LEAF, "force_leaf" }, - { VIFF_OTUNNEL, "old-tunnel" }, -}; - -static struct vnflags nbrflags[] = { - { NBRF_LEAF, "leaf" }, - { NBRF_GENID, "have-genid" }, - { NBRF_WAITING, "waiting" }, - { NBRF_ONEWAY, "one-way" }, - { NBRF_TOOOLD, "too old" }, - { NBRF_TOOMANYROUTES, "too many routes" }, - { NBRF_NOTPRUNING, "not pruning?" }, -}; - /* * Print the contents of the uvifs array on file 'fp'. */ @@ -1626,13 +1254,8 @@ dump_vifs(fp) register struct uvif *v; register struct listaddr *a; register struct phaddr *p; - register struct vif_acl *acl; - int i; struct sioc_vif_req v_req; - time_t now; - char *label; - time(&now); fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors); if (vifs_with_neighbors == 1) @@ -1660,106 +1283,65 @@ dump_vifs(fp) v->uv_threshold, v->uv_rate_limit); - for (i = 0; i < sizeof(vifflags) / sizeof(struct vnflags); i++) - if (v->uv_flags & vifflags[i].vn_flag) - fprintf(fp, " %s", vifflags[i].vn_name); - + if (v->uv_flags & VIFF_ONEWAY) fprintf(fp, " one-way"); + if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down"); + if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled"); + if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier"); + if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt"); + if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf"); + if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1"); fprintf(fp, "\n"); - /* - fprintf(fp, " #routes: %d\n", v->uv_nroutes); - */ - if (v->uv_admetric != 0) - fprintf(fp, " advert-metric %2u\n", - v->uv_admetric); - label = "alternate subnets:"; - for (p = v->uv_addrs; p; p = p->pa_next) { - fprintf(fp, " %18s %s\n", label, + if (v->uv_addrs != NULL) { + fprintf(fp, " alternate subnets: %s\n", + inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1)); + for (p = v->uv_addrs->pa_next; p; p = p->pa_next) { + fprintf(fp, " %s\n", inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); - label = ""; + } } - label = "peers:"; - for (a = v->uv_neighbors; a != NULL; a = a->al_next) { - fprintf(fp, " %6s %s (%d.%d) [%d]", - label, inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, - a->al_index); - for (i = 0; i < sizeof(nbrflags) / sizeof(struct vnflags); i++) - if (a->al_flags & nbrflags[i].vn_flag) - fprintf(fp, " %s", nbrflags[i].vn_name); - fprintf(fp, " up %s\n", scaletime(now - a->al_ctime)); - /*fprintf(fp, " #routes %d\n", a->al_nroutes);*/ - label = ""; + if (v->uv_neighbors != NULL) { + fprintf(fp, " peers: %s (%d.%d) (0x%x)\n", + inet_fmt(v->uv_neighbors->al_addr, s1), + v->uv_neighbors->al_pv, v->uv_neighbors->al_mv, + v->uv_neighbors->al_flags); + for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) { + fprintf(fp, " %s (%d.%d) (0x%x)\n", + inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, + a->al_flags); + } } - label = "group host (time left):"; - for (a = v->uv_groups; a != NULL; a = a->al_next) { - fprintf(fp, " %23s %-15s %-15s (%s)\n", - label, - inet_fmt(a->al_addr, s1), - inet_fmt(a->al_reporter, s2), - scaletime(timer_leftTimer(a->al_timerid))); - label = ""; + if (v->uv_groups != NULL) { + fprintf(fp, " groups: %-15s\n", + inet_fmt(v->uv_groups->al_addr, s1)); + for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) { + fprintf(fp, " %-15s\n", + inet_fmt(a->al_addr, s1)); + } } - label = "boundaries:"; - for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) { - fprintf(fp, " %11s %-18s\n", label, + if (v->uv_acl != NULL) { + struct vif_acl *acl; + + fprintf(fp, " boundaries: %-18s\n", + inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1)); + for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) { + fprintf(fp, " : %-18s\n", inet_fmts(acl->acl_addr, acl->acl_mask, s1)); - label = ""; - } - if (v->uv_filter) { - struct vf_element *vfe; - char lbuf[100]; - - sprintf(lbuf, "%5s %7s filter:", - v->uv_filter->vf_flags & VFF_BIDIR ? "bidir" - : " ", - v->uv_filter->vf_type == VFT_ACCEPT ? "accept" - : "deny"); - label = lbuf; - for (vfe = v->uv_filter->vf_filter; - vfe != NULL; vfe = vfe->vfe_next) { - fprintf(fp, " %23s %-18s%s\n", - label, - inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s1), - vfe->vfe_flags & VFEF_EXACT ? " (exact)" : ""); - label = ""; } } - if (!(v->uv_flags & (VIFF_TUNNEL|VIFF_DOWN|VIFF_DISABLED))) { - fprintf(fp, " IGMP querier: "); - if (v->uv_querier == NULL) - if (v->uv_flags & VIFF_QUERIER) - fprintf(fp, "%-18s (this system)\n", - inet_fmt(v->uv_lcl_addr, s1)); - else - fprintf(fp, "NONE - querier election failure?\n"); - else - fprintf(fp, "%-18s up %s last heard %s ago\n", - inet_fmt(v->uv_querier->al_addr, s1), - scaletime(now - v->uv_querier->al_ctime), - scaletime(v->uv_querier->al_timer)); - } - if (v->uv_flags & VIFF_BLASTER) - fprintf(fp, " blasterbuf size: %dk\n", - v->uv_blasterlen / 1024); - fprintf(fp, " Nbr bitmaps: 0x%08lx%08lx\n",/*XXX*/ - v->uv_nbrmap.hi, v->uv_nbrmap.lo); - if (v->uv_prune_lifetime != 0) - fprintf(fp, " Prune Lifetime: %d seconds\n", - v->uv_prune_lifetime); - v_req.vifi = vifi; - if (did_final_init) - if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { - log(LOG_WARNING, errno, - "SIOCGETVIFCNT fails on vif %d", vifi); - } else { - fprintf(fp, " pkts/bytes in : %lu/%lu\n", - v_req.icount, v_req.ibytes); - fprintf(fp, " pkts/bytes out: %lu/%lu\n", - v_req.ocount, v_req.obytes); - } + if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { + log(LOG_WARNING, 0, + "SIOCGETVIFCNT fails"); + } + else { + fprintf(fp, " pkts in : %ld\n", + v_req.icount); + fprintf(fp, " pkts out: %ld\n", + v_req.ocount); + } fprintf(fp, "\n"); } fprintf(fp, "\n"); @@ -1812,7 +1394,7 @@ SetTimer(vifi, g) cbk = (cbk_t *) malloc(sizeof(cbk_t)); cbk->g = g; cbk->vifi = vifi; - return timer_setTimer(g->al_timer, DelVif, cbk); + return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk); } /* @@ -1837,7 +1419,7 @@ SendQuery(arg) register struct uvif *v = &uvifs[cbk->vifi]; send_igmp(v->uv_lcl_addr, cbk->g->al_addr, - IGMP_MEMBERSHIP_QUERY, + IGMP_HOST_MEMBERSHIP_QUERY, cbk->q_time, cbk->g->al_addr, 0); cbk->g->al_query = 0; free(cbk); @@ -1858,5 +1440,5 @@ SetQueryTimer(g, vifi, to_expire, q_time) cbk->g = g; cbk->q_time = q_time; cbk->vifi = vifi; - return timer_setTimer(to_expire, SendQuery, cbk); + return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk); } |