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
This commit is contained in:
Hajimu UMEMOTO 2002-06-13 16:59:31 +00:00
parent f9dc2a8b93
commit 0a5f3ef410
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=98172
8 changed files with 166 additions and 45 deletions

View File

@ -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

View File

@ -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 *));

View File

@ -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");
}
}

View File

@ -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

View File

@ -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 */

View File

@ -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));

View File

@ -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)) {

View File

@ -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 **));