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:
parent
f9dc2a8b93
commit
0a5f3ef410
@ -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
|
||||
|
@ -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 *));
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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)) {
|
||||
|
@ -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 **));
|
||||
|
Loading…
Reference in New Issue
Block a user