summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2002-06-13 16:59:31 +0000
committerume <ume@FreeBSD.org>2002-06-13 16:59:31 +0000
commita748c142252522c9e5c2e11945e8245cc9871e46 (patch)
tree7d4549a8306821ec107a61d4cbb9e7353e39fc92 /usr.sbin
parent041d0fbbd905c0e30b4155f0bbdfbafd459b50d8 (diff)
downloadFreeBSD-src-a748c142252522c9e5c2e11945e8245cc9871e46.zip
FreeBSD-src-a748c142252522c9e5c2e11945e8245cc9871e46.tar.gz
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
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rtadvd/config.c109
-rw-r--r--usr.sbin/rtadvd/config.h4
-rw-r--r--usr.sbin/rtadvd/dump.c9
-rw-r--r--usr.sbin/rtadvd/rtadvd.836
-rw-r--r--usr.sbin/rtadvd/rtadvd.c14
-rw-r--r--usr.sbin/rtadvd/rtadvd.h8
-rw-r--r--usr.sbin/rtadvd/timer.c27
-rw-r--r--usr.sbin/rtadvd/timer.h4
8 files changed, 166 insertions, 45 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index de817a8..8269913 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 9000461..0bb137b 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 4e4be1a..cb451f6 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 1d083896..519d735 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 88a0a3d..9e8c81e 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 2bf3647..674ab12 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 439cbb2..646b5ee 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 3baf0d0..2eebf15 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 **));
OpenPOWER on IntegriCloud