From 0a5f3ef41099551283ddc027c5186203389711f6 Mon Sep 17 00:00:00 2001 From: Hajimu UMEMOTO Date: Thu, 13 Jun 2002 16:59:31 +0000 Subject: Changed the behavior when an interface-direct prefix being advertised was removed from the kernel; Advertise the prefix with zero lifetimes rather than to remove the prefix from the prefix list to be advertised. This will help renumber a receiving host by deprecating the address derived from the old prefix. Obtained from: KAME MFC after: 2 weeks --- usr.sbin/rtadvd/config.c | 109 ++++++++++++++++++++++++++++++++++++++++------- usr.sbin/rtadvd/config.h | 4 +- usr.sbin/rtadvd/dump.c | 9 ++++ usr.sbin/rtadvd/rtadvd.8 | 36 +++++++++++++--- usr.sbin/rtadvd/rtadvd.c | 14 ++++-- usr.sbin/rtadvd/rtadvd.h | 8 +++- usr.sbin/rtadvd/timer.c | 27 ++++++------ usr.sbin/rtadvd/timer.h | 4 +- 8 files changed, 166 insertions(+), 45 deletions(-) diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index de817a80a7d5..82699133052f 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -71,12 +71,15 @@ #include "if.h" #include "config.h" +static time_t prefix_timo = (60 * 120); /* 2 hours. + * XXX: should be configurable. */ +extern struct rainfo *ralist; + +static struct rtadvd_timer *prefix_timeout __P((void *)); static void makeentry __P((char *, size_t, int, char *, int)); static void get_prefix __P((struct rainfo *)); static int getinet6sysctl __P((int)); -extern struct rainfo *ralist; - void getconfig(intface) char *intface; @@ -309,6 +312,7 @@ getconfig(intface) /* link into chain */ insque(pfx, &tmp->prefix); + pfx->rainfo = tmp; pfx->origin = PREFIX_FROM_CONFIG; @@ -681,6 +685,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) prefix->origin = PREFIX_FROM_DYNAMIC; insque(prefix, &rai->prefix); + prefix->rainfo = rai; syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, @@ -709,18 +714,82 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) * The prefix must be in the list. */ void -delete_prefix(struct rainfo *rai, struct prefix *prefix) +delete_prefix(struct prefix *prefix) { u_char ntopbuf[INET6_ADDRSTRLEN]; + struct rainfo *rai = prefix->rainfo; remque(prefix); syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); + if (prefix->timer) + rtadvd_remove_timer(&prefix->timer); free(prefix); rai->pfxs--; - make_packet(rai); +} + +void +invalidate_prefix(struct prefix *prefix) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + struct timeval timo; + struct rainfo *rai = prefix->rainfo; + + if (prefix->timer) { /* sanity check */ + syslog(LOG_ERR, + "<%s> assumption failure: timer already exists", + __FUNCTION__); + exit(1); + } + + syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " + "will expire in %ld seconds", __FUNCTION__, + inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), + prefix->prefixlen, rai->ifname, (long)prefix_timo); + + /* set the expiration timer */ + prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); + if (prefix->timer == NULL) { + syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " + "remove the prefix", __FUNCTION__); + delete_prefix(prefix); + } + timo.tv_sec = prefix_timo; + timo.tv_usec = 0; + rtadvd_set_timer(&timo, prefix->timer); +} + +static struct rtadvd_timer * +prefix_timeout(void *arg) +{ + struct prefix *prefix = (struct prefix *)arg; + + delete_prefix(prefix); + + return(NULL); +} + +void +update_prefix(struct prefix * prefix) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + struct rainfo *rai = prefix->rainfo; + + if (prefix->timer == NULL) { /* sanity check */ + syslog(LOG_ERR, + "<%s> assumption failure: timer does not exist", + __FUNCTION__); + exit(1); + } + + syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", + __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, + INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); + + /* stop the expiration timer */ + rtadvd_remove_timer(&prefix->timer); } /* @@ -934,18 +1003,26 @@ make_packet(struct rainfo *rainfo) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ROUTER; #endif - if (pfx->vltimeexpire || pfx->pltimeexpire) - gettimeofday(&now, NULL); - if (pfx->vltimeexpire == 0) - vltime = pfx->validlifetime; - else - vltime = (pfx->vltimeexpire > now.tv_sec) ? - pfx->vltimeexpire - now.tv_sec : 0; - if (pfx->pltimeexpire == 0) - pltime = pfx->preflifetime; - else - pltime = (pfx->pltimeexpire > now.tv_sec) ? - pfx->pltimeexpire - now.tv_sec : 0; + if (pfx->timer) + vltime = 0; + else { + if (pfx->vltimeexpire || pfx->pltimeexpire) + gettimeofday(&now, NULL); + if (pfx->vltimeexpire == 0) + vltime = pfx->validlifetime; + else + vltime = (pfx->vltimeexpire > now.tv_sec) ? + pfx->vltimeexpire - now.tv_sec : 0; + } + if (pfx->timer) + pltime = 0; + else { + if (pfx->pltimeexpire == 0) + pltime = pfx->preflifetime; + else + pltime = (pfx->pltimeexpire > now.tv_sec) ? + pfx->pltimeexpire - now.tv_sec : 0; + } if (vltime < pltime) { /* * this can happen if vltime is decrement but pltime diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index 90004619d02f..0bb137b1f313 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -31,6 +31,8 @@ */ extern void getconfig __P((char *)); -extern void delete_prefix __P((struct rainfo *, struct prefix *)); +extern void delete_prefix __P((struct prefix *)); +extern void invalidate_prefix __P((struct prefix *)); +extern void update_prefix __P((struct prefix *)); extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); extern void make_packet __P((struct rainfo *)); diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c index 4e4be1a9bf97..cb451f60adb0 100644 --- a/usr.sbin/rtadvd/dump.c +++ b/usr.sbin/rtadvd/dump.c @@ -221,6 +221,15 @@ if_dump() pfx->routeraddr ? "R" : #endif ""); + if (pfx->timer) { + struct timeval *rest; + + rest = rtadvd_timer_rest(pfx->timer); + if (rest) { /* XXX: what if not? */ + fprintf(fp, ", expire in: %ld", + (long)rest->tv_sec); + } + } fprintf(fp, ")\n"); } } diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8 index 1d0838969c85..519d73515765 100644 --- a/usr.sbin/rtadvd/rtadvd.8 +++ b/usr.sbin/rtadvd/rtadvd.8 @@ -63,20 +63,42 @@ them as on-link prefixes. .Pp .Nm also watches the routing table. -By default, if an interface direct route is -added/deleted on an advertising interface and no static prefixes are +If an interface direct route is +added on an advertising interface and no static prefixes are specified by the configuration file, .Nm -adds/deletes the corresponding prefix to/from its advertising list, -respectively. -The -.Fl s -option may be used to disable this behavior. +adds the corresponding prefix to its advertising list. +.Pp +Similarly, when an interface direct route is deleted, +.Nm +will start advertising the prefixes with zero valid and preferred +lifetimes to help the receiving hosts switch to a new prefix when +renumbering. +Note, however, that the zero valid lifetime cannot invalidate the +autoconfigured addresses at a receiving host immediately. +According to the specification, the host will retain the address +for a certain period, which will typically be two hours. +The zero lifetimes rather intend to make the address deprecated, +indicating that a new non-deprecated address should be used as the +source address of a new connection. +This behavior will last for two hours. +Then +.Nm +will completely remove the prefix from the advertising list, +and succeeding advertisements will not contain the prefix information. +.Pp Moreover, if the status of an advertising interface changes, .Nm will start or stop sending router advertisements according to the latest status. .Pp +The +.Fl s +option may be used to disable this behavior; +.Nm +will not watch the routing table and the whole functionality described +above will be suppressed. +.Pp Basically, hosts MUST NOT send Router Advertisement messages at any time (RFC 2461, Section 6.2.3). However, it would sometimes be useful to allow hosts to advertise some diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index 88a0a3dbeca6..9e8c81eaaf77 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -450,7 +450,13 @@ rtmsg_input() } prefix = find_prefix(rai, addr, plen); if (prefix) { - if (dflag > 1) { + if (prefix->timer) { + /* + * If the prefix has been invalidated, + * make it available again. + */ + update_prefix(prefix); + } else if (dflag > 1) { syslog(LOG_DEBUG, "<%s> new prefix(%s/%d) " "added on %s, " @@ -497,7 +503,7 @@ rtmsg_input() } break; } - delete_prefix(rai, prefix); + invalidate_prefix(prefix); break; case RTM_NEWADDR: case RTM_DELADDR: @@ -1550,7 +1556,7 @@ struct rainfo *rainfo; } /* process RA timer */ -void +struct rtadvd_timer * ra_timeout(void *data) { struct rainfo *rai = (struct rainfo *)data; @@ -1564,6 +1570,8 @@ ra_timeout(void *data) __FUNCTION__, rai->ifname); ra_output(rai); + + return(rai->timer); } /* update RA timer */ diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 2bf3647a18ad..674ab122afab 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -74,6 +74,12 @@ struct prefix { struct prefix *next; /* forward link */ struct prefix *prev; /* previous link */ + struct rainfo *rainfo; /* back pointer to the interface */ + + struct rtadvd_timer *timer; /* expiration timer. used when a prefix + * derived from the kernel is deleted. + */ + u_int32_t validlifetime; /* AdvValidLifetime */ long vltimeexpire; /* expiration of vltime; decrement case only */ u_int32_t preflifetime; /* AdvPreferredLifetime */ @@ -159,7 +165,7 @@ struct rainfo { struct soliciter *soliciter; /* recent solication source */ }; -void ra_timeout __P((void *)); +struct rtadvd_timer *ra_timeout __P((void *)); void ra_timer_update __P((void *, struct timeval *)); int prefix_match __P((struct in6_addr *, int, struct in6_addr *, int)); diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c index 439cbb2b5523..646b5eeb8af2 100644 --- a/usr.sbin/rtadvd/timer.c +++ b/usr.sbin/rtadvd/timer.c @@ -59,9 +59,9 @@ rtadvd_timer_init() } struct rtadvd_timer * -rtadvd_add_timer(void (*timeout) __P((void *)), - void (*update) __P((void *, struct timeval *)), - void *timeodata, void *updatedata) +rtadvd_add_timer(struct rtadvd_timer *(*timeout) __P((void *)), + void (*update) __P((void *, struct timeval *)), + void *timeodata, void *updatedata) { struct rtadvd_timer *newtimer; @@ -78,11 +78,6 @@ rtadvd_add_timer(void (*timeout) __P((void *)), "<%s> timeout function unspecfied", __FUNCTION__); exit(1); } - if (update == NULL) { - syslog(LOG_ERR, - "<%s> update function unspecfied", __FUNCTION__); - exit(1); - } newtimer->expire = timeout; newtimer->update = update; newtimer->expire_data = timeodata; @@ -121,7 +116,7 @@ rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) } /* - * Check expiration for each timer. If a timer is expired, + * Check expiration for each timer. If a timer expires, * call the expire function for the timer and update the timer. * Return the next interval for select() call. */ @@ -130,23 +125,25 @@ rtadvd_check_timer() { static struct timeval returnval; struct timeval now; - struct rtadvd_timer *tm = timer_head.next; + struct rtadvd_timer *tm = timer_head.next, *tm_next; gettimeofday(&now, NULL); timer_head.tm = tm_max; - while(tm != &timer_head) { + for (tm = timer_head.next; tm != &timer_head; tm = tm_next) { + tm_next = tm->next; + if (TIMEVAL_LEQ(tm->tm, now)) { - (*tm->expire)(tm->expire_data); - (*tm->update)(tm->update_data, &tm->tm); + if (((*tm->expire)(tm->expire_data) == NULL)) + continue; /* the timer was removed */ + if (tm->update) + (*tm->update)(tm->update_data, &tm->tm); TIMEVAL_ADD(&tm->tm, &now, &tm->tm); } if (TIMEVAL_LT(tm->tm, timer_head.tm)) timer_head.tm = tm->tm; - - tm = tm->next; } if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h index 3baf0d09b41c..2eebf150faa2 100644 --- a/usr.sbin/rtadvd/timer.h +++ b/usr.sbin/rtadvd/timer.h @@ -46,14 +46,14 @@ struct rtadvd_timer { struct rainfo *rai; struct timeval tm; - void (*expire) __P((void *)); /* expiration function */ + struct rtadvd_timer *(*expire) __P((void *)); /* expiration function */ void *expire_data; void (*update) __P((void *, struct timeval *)); /* update function */ void *update_data; }; void rtadvd_timer_init __P((void)); -struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), +struct rtadvd_timer *rtadvd_add_timer __P((struct rtadvd_timer *(*) __P((void *)), void (*) __P((void *, struct timeval *)), void *, void *)); void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); void rtadvd_remove_timer __P((struct rtadvd_timer **)); -- cgit v1.2.3