diff options
author | Bill Fenner <fenner@FreeBSD.org> | 1999-01-20 07:44:18 +0000 |
---|---|---|
committer | Bill Fenner <fenner@FreeBSD.org> | 1999-01-20 07:44:18 +0000 |
commit | 1f25327484733d0bec3b33044da7bd5d82ad007f (patch) | |
tree | 19c94eeb7ba2b59b0ad53ae0864ebf06723a8afa /usr.sbin/mrouted/vif.c | |
parent | ce595def0708b60ce4dde9002ac206fae20be240 (diff) |
Import mrouted version 3.9-beta3+IOS12 . This is a version of 3.9-beta3vendor/mrouted
with minor changes to work around a bug in Cisco's IOS version 12.0 .
3.9-beta3 is much improved over 3.8, and is only labelled "beta" because
of missing features, as opposed to instability or known bugs.
Notes
Notes:
svn path=/cvs2svn/branches/XEROX/; revision=42888
Diffstat (limited to 'usr.sbin/mrouted/vif.c')
-rw-r--r-- | usr.sbin/mrouted/vif.c | 999 |
1 files changed, 689 insertions, 310 deletions
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c index 3716292d1cab..1cebd0ec0014 100644 --- a/usr.sbin/mrouted/vif.c +++ b/usr.sbin/mrouted/vif.c @@ -7,13 +7,18 @@ * Leland Stanford Junior University. * * - * $Id: vif.c,v 3.8 1995/11/29 22:36:57 fenner Rel $ + * vif.c,v 3.8.4.56.2.1 1999/01/20 05:18:50 fenner Exp */ #include "defs.h" #include <fcntl.h> +#ifndef lint +static char rcsid[] = "@(#) $Id: \ +vif.c,v 3.8.4.56.2.1 1999/01/20 05:18:50 fenner Exp $"; +#endif + /* * Exported variables. */ @@ -27,6 +32,11 @@ 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; @@ -41,7 +51,8 @@ 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 int info_version __P((char *p)); +static void send_query __P((struct uvif *v)); +static int info_version __P((u_char *p)); static void DelVif __P((void *arg)); static int SetTimer __P((int vifi, struct listaddr *g)); static int DeleteTimer __P((int id)); @@ -70,10 +81,15 @@ 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.) + * (Open a UDP socket for ioctl use in the config procedures if + * the kernel can't handle IOCTL's on the IGMP socket.) */ +#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); @@ -123,6 +139,47 @@ 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. */ @@ -163,8 +220,18 @@ check_vif_state() register vifi_t vifi; register struct uvif *v; struct ifreq ifr; + static int checking_vifs = 0; + + /* + * If we get an error while checking, (e.g. two interfaces go down + * at once, and we decide to send a prune out one of the failed ones) + * then don't go into an infinite loop! + */ + if (checking_vifs) + return; vifs_down = FALSE; + checking_vifs = 1; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_flags & VIFF_DISABLED) continue; @@ -176,27 +243,59 @@ check_vif_state() if (v->uv_flags & VIFF_DOWN) { if (ifr.ifr_flags & IFF_UP) { - v->uv_flags &= ~VIFF_DOWN; - start_vif(vifi); - log(LOG_INFO, 0, + log(LOG_NOTICE, 0, "%s has come up; vif #%u now in service", v->uv_name, vifi); + v->uv_flags &= ~VIFF_DOWN; + start_vif(vifi); } else vifs_down = TRUE; } else { if (!(ifr.ifr_flags & IFF_UP)) { - stop_vif(vifi); - v->uv_flags |= VIFF_DOWN; - log(LOG_INFO, 0, + log(LOG_NOTICE, 0, "%s has gone down; vif #%u taken out of service", v->uv_name, vifi); + stop_vif(vifi); + v->uv_flags |= VIFF_DOWN; vifs_down = TRUE; } } } + checking_vifs = 0; +} + +/* + * 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 */ @@ -209,6 +308,10 @@ 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++) @@ -227,13 +330,21 @@ send_probe_on_vif(v) nbr = nbr->al_next; } - 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); + 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); } /* @@ -293,10 +404,10 @@ start_vif2(vifi) * the interface is connected. */ start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi); + update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL); for (p = v->uv_addrs; p; p = p->pa_next) { start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi); + update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL); } /* @@ -305,10 +416,9 @@ start_vif2(vifi) * query. */ v->uv_flags |= VIFF_QUERIER; - 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(); + IF_DEBUG(DEBUG_IGMP) + log(LOG_DEBUG, 0, "assuming querier duties on vif %d", vifi); + send_query(v); } v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; @@ -349,10 +459,10 @@ stop_vif(vifi) * failure. */ start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi); + update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL); for (p = v->uv_addrs; p; p = p->pa_next) { start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi); + update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL); } /* @@ -365,6 +475,8 @@ 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; } @@ -381,14 +493,16 @@ stop_vif(vifi) /* * Discard all neighbor addresses. */ - if (v->uv_neighbors) + if (!NBRM_ISEMPTY(v->uv_nbrmap)) 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); } @@ -413,6 +527,7 @@ 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) { @@ -440,7 +555,8 @@ 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) + if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr || + dst == dvmrp_group)) return(vifi); } else { @@ -479,7 +595,13 @@ age_old_hosts() /* - * Send group membership queries to all subnets for which I am querier. + * 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) */ void query_groups() @@ -489,17 +611,16 @@ query_groups() for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { if (v->uv_flags & VIFF_QUERIER) { - 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); + send_query(v); } } age_old_hosts(); } /* - * Process an incoming host membership query + * 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. */ void accept_membership_query(src, dst, group, tmo) @@ -519,20 +640,97 @@ 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; + } + } + /* - * 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! + * Reset the timer since we've received a query. */ - if ((v->uv_flags & VIFF_QUERIER) && - (ntohl(src) < ntohl(v->uv_lcl_addr))) { - v->uv_flags &= ~VIFF_QUERIER; + if (v->uv_querier && src == v->uv_querier->al_addr) + v->uv_querier->al_timer = 0; + /* + * 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; + } + } } } @@ -563,14 +761,13 @@ 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_HOST_MEMBERSHIP_REPORT) + if (r_type == IGMP_V1_MEMBERSHIP_REPORT) g->al_old = OLD_AGE_THRESHOLD; -#ifdef SNMP - g->al_genid = src; -#endif /* SNMP */ + + g->al_reporter = src; /** delete old timers, set a timer for expiration **/ - g->al_timer = GROUP_EXPIRE_TIME; + g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; if (g->al_query) g->al_query = DeleteTimer(g->al_query); if (g->al_timerid) @@ -589,21 +786,19 @@ 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_HOST_NEW_MEMBERSHIP_REPORT) - g->al_old = 0; - else + if (r_type == IGMP_V1_MEMBERSHIP_REPORT) g->al_old = OLD_AGE_THRESHOLD; -#ifdef SNMP - g->al_genid = src; -#endif + else + g->al_old = 0; /** set a timer for expiration **/ - g->al_query = 0; - g->al_timer = GROUP_EXPIRE_TIME; + 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; time(&g->al_ctime); - g->al_timerid = SetTimer(vifi, g); - g->al_next = v->uv_groups; - v->uv_groups = g; update_lclgrp(vifi, group); } @@ -614,7 +809,9 @@ 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; @@ -642,6 +839,7 @@ 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); @@ -658,14 +856,20 @@ 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 = LEAVE_EXPIRE_TIME; + g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL * + (IGMP_LAST_MEMBER_QUERY_COUNT + 1); send_igmp(v->uv_lcl_addr, g->al_addr, - 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); + 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); g->al_timerid = SetTimer(vifi, g); break; } @@ -704,33 +908,7 @@ accept_neighbor_request(src, dst) u_char *p, *ncount; struct listaddr *la; int datalen; - u_int32 temp_addr, us, them = src; - - /* Determine which of our addresses to use as the source of our response - * to this query. - */ - if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ - int udp; /* find best interface to reply on */ - struct sockaddr_in addr; - int addrlen = sizeof(addr); - - addr.sin_family = AF_INET; -#if (defined(BSD) && (BSD >= 199103)) - addr.sin_len = sizeof addr; -#endif - addr.sin_addr.s_addr = dst; - addr.sin_port = htons(2000); /* any port over 1024 will do... */ - if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 - || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 - || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { - log(LOG_WARNING, errno, "Determining local address"); - close(udp); - return; - } - close(udp); - us = addr.sin_addr.s_addr; - } else /* query sent to us alone */ - us = dst; + u_int32 temp_addr, them = src; #define PUT_ADDR(a) temp_addr = ntohl(a); \ *p++ = temp_addr >> 24; \ @@ -751,7 +929,7 @@ accept_neighbor_request(src, dst) /* Make sure that there's room for this neighbor... */ if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { - send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, + send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL), datalen); p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; @@ -775,8 +953,8 @@ accept_neighbor_request(src, dst) } if (datalen != 0) - send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL), - datalen); + send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, + htonl(MROUTED_LEVEL), datalen); } /* @@ -791,33 +969,7 @@ accept_neighbor_request2(src, dst) u_char *p, *ncount; struct listaddr *la; int datalen; - u_int32 us, them = src; - - /* Determine which of our addresses to use as the source of our response - * to this query. - */ - if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ - int udp; /* find best interface to reply on */ - struct sockaddr_in addr; - int addrlen = sizeof(addr); - - addr.sin_family = AF_INET; -#if (defined(BSD) && (BSD >= 199103)) - addr.sin_len = sizeof addr; -#endif - addr.sin_addr.s_addr = dst; - addr.sin_port = htons(2000); /* any port over 1024 will do... */ - if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 - || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 - || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { - log(LOG_WARNING, errno, "Determining local address"); - close(udp); - return; - } - close(udp); - us = addr.sin_addr.s_addr; - } else /* query sent to us alone */ - us = dst; + u_int32 them = src; p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; @@ -847,7 +999,7 @@ accept_neighbor_request2(src, dst) if (rflags & DVMRP_NF_TUNNEL) rflags |= DVMRP_NF_DOWN; if (datalen > MAX_DVMRP_DATA_LEN - 12) { - send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, + send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), datalen); p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; @@ -865,7 +1017,7 @@ accept_neighbor_request2(src, dst) for ( ; la; la = la->al_next) { /* Make sure that there's room for this neighbor... */ if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { - send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, + send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), datalen); p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; @@ -873,6 +1025,9 @@ 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; @@ -882,16 +1037,25 @@ 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) - send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), - datalen); + send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, + htonl(MROUTED_LEVEL), datalen); } void @@ -942,7 +1106,7 @@ accept_info_request(src, dst, p, datalen) */ static int info_version(p) - char *p; + u_char *p; { int len; extern char versionstring[]; @@ -951,7 +1115,7 @@ info_version(p) p++; /* skip over length */ *p++ = 0; /* zero out */ *p++ = 0; /* reserved fields */ - strcpy(p, versionstring); /* XXX strncpy!!! */ + strcpy((char *)p, versionstring); /* XXX strncpy!!! */ len = strlen(versionstring); return ((len + 3) / 4); @@ -980,7 +1144,8 @@ accept_neighbors2(src, dst, p, datalen, level) u_char *p; int datalen; { - log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", + IF_DEBUG(DEBUG_PKT) + log(LOG_DEBUG, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", inet_fmt(src, s1), inet_fmt(dst, s2)); } @@ -993,7 +1158,8 @@ accept_info_reply(src, dst, p, datalen) u_char *p; int datalen; { - log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s", + IF_DEBUG(DEBUG_PKT) + log(LOG_DEBUG, 0, "ignoring spurious DVMRP info reply from %s to %s", inet_fmt(src, s1), inet_fmt(dst, s2)); } @@ -1001,9 +1167,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 TRUE if 'addr' is a valid neighbor, FALSE otherwise. + * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise. */ -int +struct listaddr * update_neighbor(vifi, addr, msgtype, p, datalen, level) vifi_t vifi; u_int32 addr; @@ -1014,14 +1180,17 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level) { register struct uvif *v; register struct listaddr *n; - u_int32 genid = 0; - u_int32 router; + 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 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'. @@ -1038,11 +1207,66 @@ 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 'the unknown host' or self: %s", + "received DVMRP message from %s: %s", + (addr == v->uv_lcl_addr) ? "self (check device loopback)" : + "'the unknown host'", inet_fmt(addr, s1)); - return (FALSE); + return NULL; + } + + /* + * Ignore all neighbors on vifs forced into leaf mode + */ + if (v->uv_flags & VIFF_FORCE_LEAF) { + return NULL; + } + + /* + * 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. */ @@ -1052,157 +1276,217 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level) } } - /* - * Found it. Reset its timer, and check for a version change - */ - if (n) { - n->al_timer = 0; - + if (n == NULL) { /* - * update the neighbors version and protocol number - * if changed => router went down and came up, - * so take action immediately. + * 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. */ - if ((n->al_pv != (level & 0xff)) || - (n->al_mv != ((level >> 8) & 0xff))) { + if (dvmrpspec && (msgtype != DVMRP_PROBE)) + return NULL; - 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; + 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*/ } - } else { + /* - * If not found, add it to the list. If the neighbor has a lower - * IP address than me, yield querier duties to it. + * Add it to our list of neighbors. */ - log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x", + IF_DEBUG(DEBUG_PEER) + log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d", inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, - (level >> 16) & 0xff); + (level >> 16) & 0xff, i); 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 = level & 0xff; - n->al_mv = (level >> 8) & 0xff; - n->al_genid = 0; + n->al_pv = pv; + n->al_mv = mv; + n->al_genid = has_genid ? genid : 0; + n->al_index = i; + nbrs[i] = n; 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 (v->uv_neighbors == NULL) { - send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group; + if (NBRM_ISEMPTY(v->uv_nbrmap)) { + send_tables = v->uv_dst_addr; vifs_with_neighbors++; } else { send_tables = addr; } - v->uv_neighbors = n; - if (!(v->uv_flags & VIFF_TUNNEL) && - ntohl(addr) < ntohl(v->uv_lcl_addr)) - v->uv_flags &= ~VIFF_QUERIER; - } - - /* - * 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))) { + NBRM_SET(i, v->uv_nbrmap); + add_neighbor_to_routes(vifi, i); + } else { + /* + * Found it. Reset its timer. + */ + n->al_timer = 0; - int i; + 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); + } + } - if (datalen < 4) { - log(LOG_WARNING, 0, - "received truncated probe message from %s (len %d)", - inet_fmt(addr, s1), datalen); - return (FALSE); + 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); } + } - for (i = 0; i < 4; i++) - ((char *)&genid)[i] = *p++; - datalen -= 4; + /* + * 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; + } - 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); + /* + * 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)) { - n->al_genid = genid; - do_reset = TRUE; - } - - /* - * loop through router list and check for one-way ifs. - */ - - v->uv_flags |= VIFF_ONEWAY; + 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); - 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; + 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--; } + 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 != 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; + + 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; } + + /* check "leaf" flag */ } if (do_reset) { reset_neighbor_state(vifi, addr); if (!send_tables) send_tables = addr; } - if (send_tables) + if (send_tables) { + send_probe_on_vif(v); report(ALL_ROUTES, vifi, send_tables); + } + v->uv_leaf_timer = 0; + v->uv_flags &= ~VIFF_LEAF; - return (TRUE); + return n; } @@ -1215,7 +1499,7 @@ age_vifs() { register vifi_t vifi; register struct uvif *v; - register struct listaddr *a, *prev_a, *n; + register struct listaddr *a, *prev_a; register u_int32 addr; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { @@ -1227,39 +1511,58 @@ 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) < NEIGHBOR_EXPIRE_TIME) + if ((a->al_timer += TIMER_INTERVAL) < exp_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 and assume querier duties unless there is - * another neighbor with a lower IP address than mine. + * any route entries. */ + 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; + a = prev_a;/*XXX use ** */ - delete_neighbor_from_routes(addr, vifi); + delete_neighbor_from_routes(addr, vifi, idx); + reset_neighbor_state(vifi, addr); - if (v->uv_neighbors == NULL) + if (NBRM_ISEMPTY(v->uv_nbrmap)) vifs_with_neighbors--; v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; + } - 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; - } - } - } + 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); } } } @@ -1281,6 +1584,36 @@ 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'. */ @@ -1292,8 +1625,13 @@ 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) @@ -1321,65 +1659,106 @@ dump_vifs(fp) v->uv_threshold, v->uv_rate_limit); - 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"); + 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); + 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); - 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", + label = "alternate subnets:"; + for (p = v->uv_addrs; p; p = p->pa_next) { + fprintf(fp, " %18s %s\n", label, inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); - } + 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 = "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_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 = "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_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", + label = "boundaries:"; + for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) { + fprintf(fp, " %11s %-18s\n", label, inet_fmts(acl->acl_addr, acl->acl_mask, s1)); - } + label = ""; } - v_req.vifi = vifi; - if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { - log(LOG_WARNING, 0, - "SIOCGETVIFCNT fails"); + 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 = ""; + } } - else { - fprintf(fp, " pkts in : %ld\n", - v_req.icount); - fprintf(fp, " pkts out: %ld\n", - v_req.ocount); + 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); + } fprintf(fp, "\n"); } fprintf(fp, "\n"); @@ -1432,7 +1811,7 @@ SetTimer(vifi, g) cbk = (cbk_t *) malloc(sizeof(cbk_t)); cbk->g = g; cbk->vifi = vifi; - return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk); + return timer_setTimer(g->al_timer, DelVif, cbk); } /* @@ -1457,7 +1836,7 @@ SendQuery(arg) register struct uvif *v = &uvifs[cbk->vifi]; send_igmp(v->uv_lcl_addr, cbk->g->al_addr, - IGMP_HOST_MEMBERSHIP_QUERY, + IGMP_MEMBERSHIP_QUERY, cbk->q_time, cbk->g->al_addr, 0); cbk->g->al_query = 0; free(cbk); @@ -1478,5 +1857,5 @@ SetQueryTimer(g, vifi, to_expire, q_time) cbk->g = g; cbk->q_time = q_time; cbk->vifi = vifi; - return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk); + return timer_setTimer(to_expire, SendQuery, cbk); } |