Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Jul 2011 09:20:23 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r224087 - in user/hrs/ipv6/usr.sbin: rtadvctl rtadvd
Message-ID:  <201107160920.p6G9KNGi018881@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hrs
Date: Sat Jul 16 09:20:22 2011
New Revision: 224087
URL: http://svn.freebsd.org/changeset/base/224087

Log:
  - Implement burst unsolicited RA sending by using the ra_timer framework when
    AdvSendAdvertisements and/or configuration entries are changed as described
    in RFC 4861 6.2.4.  This fixes issues that make termination of the rtadvd
    daemon take very long time and rtadvctl(8) utility become unresponsive after
    reloading the configuration file.
  
    An interface now has three states, UNCONFIGURED, TRANSITIVE, or CONFIGURED,
    and the burst unsolicited sending happens only in TRANSITIVE.  See rtadvd.h
    for the details.
  
  - Remove extra make_packet().
  
  - rtadvctl(8) now displays the RA timers.

Modified:
  user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.8
  user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.c
  user/hrs/ipv6/usr.sbin/rtadvd/config.c
  user/hrs/ipv6/usr.sbin/rtadvd/config.h
  user/hrs/ipv6/usr.sbin/rtadvd/control_server.c
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.h
  user/hrs/ipv6/usr.sbin/rtadvd/timer.c
  user/hrs/ipv6/usr.sbin/rtadvd/timer_subr.c

Modified: user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.8
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.8	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.8	Sat Jul 16 09:20:22 2011	(r224087)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 15, 2011
+.Dd July 16, 2011
 .Dt RTADVCTL 8
 .Os
 .Sh NAME
@@ -80,12 +80,17 @@ Specifies to mark the interface as disab
 .It shutdown
 Makes the
 .Xr rtadvd 8
-daemon shut down immediately.
+daemon shut down.
+Note that the
+.Xr rtadvd 8
+daemon will send several RAs with zero lifetime to invalidate the old
+information on each interface.
+It will take at most nine seconds.
 .It show Op interfaces...
 Displays information on Router Advertisement messages being sent
 on each interface.
 .Sh SEE ALSO
-.Xr rtadv 8 ,
+.Xr rtadvd 8 ,
 .Xr rtadvd.conf 5
 .Sh HISTORY
 The
@@ -96,16 +101,3 @@ command first appeared in
 .Nm
 was written by
 .An "Hiroki Sato" Aq hrs@FreeBSD.org .
-.Sh BUGS
-The
-.Xr rtadvd 8
-daemon stops responding to
-.Nm
-for a while just after reloading the configuration file by the reload
-subcommand.
-This is because in the current implementation it cannot communicate
-with
-.Nm
-while sending some additional RAs for graceful transition from one
-configuration to another.
-It will take at most nine seconds for each interface.

Modified: user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.c	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvctl/rtadvctl.c	Sat Jul 16 09:20:22 2011	(r224087)
@@ -61,6 +61,7 @@
 #include "rtadvd.h"
 #include "if.h"
 #include "timer_subr.h"
+#include "timer.h"
 #include "control.h"
 #include "control_client.h"
 
@@ -115,6 +116,9 @@ static struct dispatch_table {
 	{ NULL, NULL },
 };
 
+static char errmsgbuf[1024];
+static char *errmsg = NULL;
+
 static void
 mysyslog(int priority, const char * restrict fmt, ...)
 {
@@ -176,13 +180,17 @@ main(int argc, char *argv[])
 		}
 	}
 
-	if (action != NULL) {
-		error = (dtable[i].dt_act)(--argc, ++argv);
-		if (error)
-			fprintf(stderr, "%s failed.\n", dtable[i].dt_comm);
-	} else
+	if (action == NULL)
 		usage();
 
+	error = (dtable[i].dt_act)(--argc, ++argv);
+	if (error) {
+		fprintf(stderr, "%s failed", dtable[i].dt_comm);
+		if (errmsg != NULL)
+			fprintf(stderr, ": %s", errmsg);
+		fprintf(stderr, ".\n");
+	}
+
 	return (error);
 }
 
@@ -312,7 +320,7 @@ action_disable(int argc, char **argv)
 		error += action_propset(action_argv);
 	}
 
-	return(error);
+	return (error);
 }
 
 static int
@@ -333,7 +341,7 @@ action_enable(int argc, char **argv)
 		error += action_propset(action_argv);
 	}
 
-	return(error);
+	return (error);
 }
 
 static int
@@ -346,7 +354,7 @@ action_reload(int argc, char **argv)
 
 	if (argc == 0) {
 		action_argv = strdup(":reload=");
-		return(action_propset(action_argv));
+		return (action_propset(action_argv));
 	}
 
 	error = 0;
@@ -356,7 +364,7 @@ action_reload(int argc, char **argv)
 		error += action_propset(action_argv);
 	}
 
-	return(error);
+	return (error);
 }
 
 static int
@@ -365,7 +373,7 @@ action_echo(int argc __unused, char **ar
 	char *action_argv;
 
 	action_argv = strdup("echo");
-	return(action_propset(action_argv));
+	return (action_propset(action_argv));
 }
 
 static int
@@ -374,7 +382,7 @@ action_shutdown(int argc __unused, char 
 	char *action_argv;
 
 	action_argv = strdup("shutdown");
-	return(action_propset(action_argv));
+	return (action_propset(action_argv));
 }
 
 /* XXX */
@@ -403,6 +411,7 @@ action_show(int argc, char **argv)
 	char argv_rai[IFNAMSIZ + sizeof(":rai=")];
 	char argv_rti[IFNAMSIZ + sizeof(":rti=")];
 	char argv_pfx[IFNAMSIZ + sizeof(":pfx=")];
+	char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")];
 	char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
 	char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
 	char ssbuf[SSBUFLEN];
@@ -427,7 +436,7 @@ action_show(int argc, char **argv)
 		while (p < endp) {
 			ifi = malloc(sizeof(*ifi));
 			if (ifi == NULL)
-				exit(1);
+				return (1);
 			memset(ifi, 0, sizeof(*ifi));
 
 			strcpy(ifi->ifi_ifname, p);
@@ -439,19 +448,25 @@ action_show(int argc, char **argv)
 		for (i = 0; i < argc; i++) {
 			ifi = malloc(sizeof(*ifi));
 			if (ifi == NULL)
-				exit(1);
+				return (1);
 			memset(ifi, 0, sizeof(*ifi));
 
 			strcpy(ifi->ifi_ifname, argv[i]);
 			ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
-			if (ifi->ifi_ifindex == 0)
-				exit(1);
+			if (ifi->ifi_ifindex == 0) {
+				sprintf(errmsgbuf, "invalid interface %s",
+				    ifi->ifi_ifname);
+				errmsg = errmsgbuf;
+				return (1);
+			}
+
 			TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
 		}
 	}
 
 	TAILQ_FOREACH(ifi, &ifl, ifi_next) {
 		struct ifinfo *ifi_s;
+		struct rtadvd_timer *rat;
 		struct rainfo *rai;
 		struct rtinfo *rti;
 		struct prefix *pfx;
@@ -470,28 +485,33 @@ action_show(int argc, char **argv)
 
 		printf("%s: flags=<", ifi->ifi_ifname);
 
-		/*
-		 * RA_RECV = UP + CONFIGURED + ACCEPT_RTADV
-		 * RA_SEND = UP + CONFIGURED + IPV6FORWARDING
-		 */
-
 		c = 0;
 		if (ifi_s->ifi_ifindex == 0)
 			c += printf("NONEXISTENT");
 		else
 			c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
 			    "UP" : "DOWN");
-		if (ifi_s->ifi_state == IFI_STATE_CONFIGURED)
+		switch (ifi_s->ifi_state) {
+		case IFI_STATE_CONFIGURED:
 			c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
-
+			break;
+		case IFI_STATE_TRANSITIVE:
+			c += printf("%s%s", (c) ? "," : "", "TRANSITIVE");
+			break;
+		}
 		if (ifi_s->ifi_persist)
 			c += printf("%s%s", (c) ? "," : "", "PERSIST");
 		printf(">");
 
 		ra_ifstatus = RA_IFSTATUS_INACTIVE;
 		if ((ifi_s->ifi_flags & IFF_UP) &&
-		    (ifi_s->ifi_state == IFI_STATE_CONFIGURED)) {
+		    ((ifi_s->ifi_state == IFI_STATE_CONFIGURED) ||
+			(ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) {
 #if (__FreeBSD_version < 900000)
+			/*
+			 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv
+			 * RA_SEND: ip6.forwarding
+			 */
 			if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
 				if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
 					ra_ifstatus = RA_IFSTATUS_RA_RECV;
@@ -500,6 +520,10 @@ action_show(int argc, char **argv)
 			} else
 				ra_ifstatus = RA_IFSTATUS_RA_SEND;
 #else
+			/*
+			 * RA_RECV: ND6_IFF_ACCEPT_RTADV
+			 * RA_SEND: ip6.forwarding
+			 */
 			if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
 				ra_ifstatus = RA_IFSTATUS_RA_RECV;
 			else if (getinet6sysctl(IPV6CTL_FORWARDING))
@@ -519,7 +543,11 @@ action_show(int argc, char **argv)
 			printf("%s%s", (c) ? "," : "", "RA_SEND");
 		printf("> ");
 
-		if (ifi_s->ifi_state != IFI_STATE_CONFIGURED) {
+		switch (ifi_s->ifi_state) {
+		case IFI_STATE_CONFIGURED:
+		case IFI_STATE_TRANSITIVE:
+			break;
+		default:
 			printf("\n");
 			continue;
 		}
@@ -574,6 +602,26 @@ action_show(int argc, char **argv)
 		    rai->rai_hoplimit);
 		printf("\tAdvIfPrefixes: %s\n",
 		    rai->rai_advifprefix ? "yes" : "no");
+
+		/* RA timer */
+		rat = NULL;
+		if (ifi_s->ifi_ra_timer != NULL) {
+			sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
+			    ifi->ifi_ifname);
+			action_argv = argv_ifi_ra_timer;
+
+			error = action_propget(action_argv, &cp);
+			if (error)
+				return (error);
+
+			rat = (struct rtadvd_timer *)cp.cp_val;
+		}
+		printf("\tNext RA send: %s",
+		    (rat == NULL) ? "never\n" :
+		    ctime((time_t *)&rat->rat_tm.tv_sec));
+		printf("\tLast RA sent: %s",
+		    (ifi_s->ifi_ra_lastsent.tv_sec == 0) ? "never\n" :
+		    ctime((time_t *)&ifi_s->ifi_ra_lastsent.tv_sec));
 		if (rai->rai_clockskew)
 			printf("\tClock skew: %" PRIu16 "sec\n",
 			    rai->rai_clockskew);
@@ -650,18 +698,22 @@ action_show(int argc, char **argv)
 
 		printf("\n");
 
-		printf("\tLast RA sent: %s",
-		    (rai->rai_lastsent.tv_sec == 0) ? "never\n" :
-		    ctime((time_t *)&rai->rai_lastsent.tv_sec));
-		printf("\tRA initcounts/waits: %d/%d\n",
-		    rai->rai_initcounter,
-		    rai->rai_waiting);
-		printf("\tRA out/in/inconsistent: "
-		    "%" PRIu64 "/%" PRIu64 "/%" PRIu64 "\n",
-		    ifi_s->ifi_raoutput,
+		printf("\tCounters\n"
+		    "\t RA burst counts: %" PRIu16 " (interval: %s)\n"
+		    "\t RS wait counts: %" PRIu16 "\n",
+		    ifi_s->ifi_burstcount,
+		    sec2str(ifi_s->ifi_burstinterval, ssbuf),
+		    ifi_s->ifi_rs_waitcount);
+
+		printf("\tOutputs\n"
+		    "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
+
+		printf("\tInputs\n"
+		    "\t RA: %" PRIu64 " (normal)\n"
+		    "\t RA: %" PRIu64 " (inconsistent)\n"
+		    "\t RS: %" PRIu64 "\n",
 		    ifi_s->ifi_rainput,
-		    ifi_s->ifi_rainconsistent);
-		printf("\tRS in: %" PRIu64 "\n",
+		    ifi_s->ifi_rainconsistent,
 		    ifi_s->ifi_rsinput);
 
 		printf("\n");

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sat Jul 16 09:20:22 2011	(r224087)
@@ -149,7 +149,6 @@ int
 loadconfig_ifname(char *ifname)
 {
 	struct ifinfo *ifi;
-	int error;
 
 	syslog(LOG_DEBUG, "<%s> enter", __func__);
 
@@ -175,37 +174,21 @@ loadconfig_ifname(char *ifname)
 			    ifi->ifi_ifname);
 			continue;
 		}
-		if (getconfig(ifi->ifi_ifindex) == NULL) {
+		if (getconfig(ifi) == NULL) {
 			syslog(LOG_ERR,
 			    "<%s> invalid configuration for %s.  "
 			    "Ignored at this moment.", __func__,
 			    ifi->ifi_ifname);
 			continue;
 		}
-		ifi->ifi_state = IFI_STATE_CONFIGURED;
-		syslog(LOG_DEBUG,
-		    "<%s> ifname=%s marked as configured.",
-		    __func__, ifi->ifi_ifname);
-
-		error = sock_mc_join(&sock, ifi->ifi_ifindex);
-		if (error)
-			exit(1);
 	}
 	return (0);
 }
 
 int
-rmconfig(int idx)
+rm_ifinfo_index(int idx)
 {
-	struct rainfo *rai;
-	struct prefix *pfx;
-	struct soliciter *sol;
-	struct rdnss *rdn;
-	struct rdnss_addr *rdna;
-	struct dnssl *dns;
-	struct rtinfo *rti;
 	struct ifinfo *ifi;
-	int error;
 
 	ifi = if_indextoifinfo(idx);
 	if (ifi == NULL) {
@@ -213,24 +196,39 @@ rmconfig(int idx)
 		    __func__, idx);
 		return (-1);
 	}
-	rai = ifi->ifi_rainfo;
 
-	if (ifi->ifi_state == IFI_STATE_CONFIGURED) {
+	return (rm_ifinfo(ifi));
+}
+
+int
+rm_ifinfo(struct ifinfo *ifi)
+{
+	int error;
+
+	syslog(LOG_DEBUG, "<%s> enter (%s).", __func__, ifi->ifi_ifname);
+	switch (ifi->ifi_state) {
+	case IFI_STATE_UNCONFIGURED:
+		return (0);
+		break;
+	default:
 		ifi->ifi_state = IFI_STATE_UNCONFIGURED;
 		syslog(LOG_DEBUG,
-		    "<%s> ifname=%s marked as unconfigured.",
+		    "<%s> ifname=%s marked as UNCONFIGURED.",
 		    __func__, ifi->ifi_ifname);
 
-		error = sock_mc_leave(&sock, ifi->ifi_ifindex);
-		if (error)
-			exit(1);
+		/* XXX: No MC leaving here becasue index is disappeared */
+
+		/* Inactivate timer */
+		rtadvd_remove_timer(ifi->ifi_ra_timer);
+		ifi->ifi_ra_timer = NULL;
+		break;
 	}
 
 	/* clean up ifi */
 	if (!ifi->ifi_persist) {
 		TAILQ_REMOVE(&ifilist, ifi, ifi_next);
 		syslog(LOG_DEBUG, "<%s>: ifinfo (idx=%d) removed.",
-		    __func__, idx);
+		    __func__, ifi->ifi_ifindex);
 		free(ifi);
 	} else {
 		/* recreate an empty entry */
@@ -238,16 +236,62 @@ rmconfig(int idx)
 		syslog(LOG_DEBUG, "<%s>: ifname=%s is persistent.",
 		    __func__, ifi->ifi_ifname);
 	}
+
 	/* clean up rai if any */
-	if (rai == NULL)
-		return (0);
+	switch (ifi->ifi_state) {
+	case IFI_STATE_CONFIGURED:
+		if (ifi->ifi_rainfo != NULL) {
+			error = rm_rainfo(ifi->ifi_rainfo);
+			if (error)
+				return (error);
+			ifi->ifi_rainfo = NULL;
+		}
+		break;
+	case IFI_STATE_TRANSITIVE:
+		if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) {
+			if (ifi->ifi_rainfo != NULL) {
+				error = rm_rainfo(ifi->ifi_rainfo);
+				if (error)
+					return (error);
+				ifi->ifi_rainfo = NULL;
+				ifi->ifi_rainfo_trans = NULL;
+			}
+		} else {
+			if (ifi->ifi_rainfo != NULL) {
+				error = rm_rainfo(ifi->ifi_rainfo);
+				if (error)
+					return (error);
+				ifi->ifi_rainfo = NULL;
+			}
+			if (ifi->ifi_rainfo_trans != NULL) {
+				error = rm_rainfo(ifi->ifi_rainfo_trans);
+				if (error)
+					return (error);
+				ifi->ifi_rainfo_trans = NULL;
+			}
+		}
+	}
 
-	TAILQ_REMOVE(&railist, rai, rai_next);
-	syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
-	    __func__, idx);
+	syslog(LOG_DEBUG, "<%s> leave (%s).", __func__, ifi->ifi_ifname);
+	return (0);
+}
+
+int
+rm_rainfo(struct rainfo *rai)
+{
+	struct prefix *pfx;
+	struct soliciter *sol;
+	struct rdnss *rdn;
+	struct rdnss_addr *rdna;
+	struct dnssl *dns;
+	struct rtinfo *rti;
 
-	/* Free all of allocated memories for this entry. */
-	rtadvd_remove_timer(rai->rai_timer);
+	syslog(LOG_DEBUG, "<%s>: enter",  __func__);
+
+	TAILQ_REMOVE(&railist, rai, rai_next);
+	if (rai->rai_ifinfo != NULL)
+		syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
+		    __func__, rai->rai_ifinfo->ifi_ifindex);
 
 	if (rai->rai_ra_data != NULL)
 		free(rai->rai_ra_data);
@@ -277,34 +321,34 @@ rmconfig(int idx)
 		free(rti);
 	}
 	free(rai);
+	syslog(LOG_DEBUG, "<%s>: leave",  __func__);
 
 	return (0);
 }
 
 struct ifinfo *
-getconfig(int idx)
+getconfig(struct ifinfo *ifi)
 {
 	int stat, i;
+	int error;
 	char tbuf[BUFSIZ];
 	struct rainfo *rai;
 	struct rainfo *rai_old;
-	struct ifinfo *ifi;
 	int32_t val;
 	int64_t val64;
 	char buf[BUFSIZ];
 	char *bp = buf;
 	char *addr, *flagstr;
 
-	if (idx == 0)
-		return (NULL);
-	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
-		if (ifi->ifi_ifindex == idx)
-			break;
-	}
 	if (ifi == NULL)	/* if does not exist */
 		return (NULL);
 
-	rai_old = ifi->ifi_rainfo;
+	if (ifi->ifi_state == IFI_STATE_TRANSITIVE &&
+	    ifi->ifi_rainfo == NULL) {
+		syslog(LOG_INFO, "<%s> %s is shutting down.  Skipped.",
+		    __func__, ifi->ifi_ifname);
+		return (NULL);
+	}
 
 	if ((stat = agetent(tbuf, ifi->ifi_ifname)) <= 0) {
 		memset(tbuf, 0, sizeof(tbuf));
@@ -857,26 +901,102 @@ getconfig_free_dns:
 	 * Before the removal, RDNSS and DNSSL options with
 	 * zero-lifetime will be sent.
 	 */
-	if (rai_old != NULL) {
-		const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
-		struct rdnss *rdn;
-		struct dnssl *dns;
+	switch (ifi->ifi_state) {
+	case IFI_STATE_UNCONFIGURED:
+		/* UNCONFIGURED -> TRANSITIVE */
 
-		rai_old->rai_lifetime = 0;
-		TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next)
-			rdn->rd_ltime = 0;
-		TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next)
-			dns->dn_ltime = 0;
-
-		make_packet(rai_old);
-		for (i = 0; i < retrans; i++) {
-			ra_output(rai_old);
-			sleep(MIN_DELAY_BETWEEN_RAS);
+		error = sock_mc_join(&sock, ifi->ifi_ifindex);
+		if (error)
+			exit(1);
+
+		ifi->ifi_state = IFI_STATE_TRANSITIVE;
+		ifi->ifi_burstcount = MAX_INITIAL_RTR_ADVERTISEMENTS;
+		ifi->ifi_burstinterval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
+
+		/* The same two rai mean initial burst */
+		ifi->ifi_rainfo = rai;
+		ifi->ifi_rainfo_trans = rai;
+		TAILQ_INSERT_TAIL(&railist, rai, rai_next);
+
+		if (ifi->ifi_ra_timer == NULL)
+			ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout,
+			    ra_timer_update, ifi, ifi);
+		ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+		rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+		    ifi->ifi_ra_timer);
+
+		syslog(LOG_DEBUG,
+		    "<%s> ifname=%s marked as TRANSITIVE (initial burst).",
+		    __func__, ifi->ifi_ifname);
+		break;
+	case IFI_STATE_CONFIGURED:
+		/* CONFIGURED -> TRANSITIVE */
+		rai_old = ifi->ifi_rainfo;
+		if (rai_old == NULL) {
+			syslog(LOG_ERR,
+			    "<%s> ifi_rainfo is NULL"
+			    " in IFI_STATE_CONFIGURED.", __func__);
+			ifi = NULL;
+			break;
+		} else {
+			struct rdnss *rdn;
+			struct dnssl *dns;
+
+			rai_old->rai_lifetime = 0;
+			TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next)
+			    rdn->rd_ltime = 0;
+			TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next)
+			    dns->dn_ltime = 0;
+
+			ifi->ifi_rainfo_trans = rai_old;
+			ifi->ifi_state = IFI_STATE_TRANSITIVE;
+			ifi->ifi_burstcount = MAX_FINAL_RTR_ADVERTISEMENTS;
+			ifi->ifi_burstinterval = MIN_DELAY_BETWEEN_RAS;
+
+			ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+			rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+			    ifi->ifi_ra_timer);
+
+			syslog(LOG_DEBUG,
+			    "<%s> ifname=%s marked as TRANSITIVE"
+			    " (transitional burst)",
+			    __func__, ifi->ifi_ifname);
+		}
+		ifi->ifi_rainfo = rai;
+		TAILQ_INSERT_TAIL(&railist, rai, rai_next);
+		break;
+	case IFI_STATE_TRANSITIVE:
+		if (ifi->ifi_rainfo != NULL) {
+			if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) {
+				/* Reinitialize initial burst */
+				rm_rainfo(ifi->ifi_rainfo);
+				ifi->ifi_rainfo = rai;
+				ifi->ifi_rainfo_trans = rai;
+				ifi->ifi_burstcount =
+				    MAX_INITIAL_RTR_ADVERTISEMENTS;
+				ifi->ifi_burstinterval =
+				    MAX_INITIAL_RTR_ADVERT_INTERVAL;
+			} else {
+				/* Replace ifi_rainfo with the new one */
+				rm_rainfo(ifi->ifi_rainfo);
+				ifi->ifi_rainfo = rai;
+			}
+			TAILQ_INSERT_TAIL(&railist, rai, rai_next);
+
+			ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+			rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+			    ifi->ifi_ra_timer);
+		} else {
+			/* XXX: NOTREACHED.  Being shut down. */
+			syslog(LOG_ERR,
+			    "<%s> %s is shutting down.  Skipped.",
+			    __func__, ifi->ifi_ifname);
+			rm_rainfo(rai);
+
+			return (NULL);
 		}
-		rmconfig(idx);
+		break;
 	}
-	ifi->ifi_rainfo = rai;
-	TAILQ_INSERT_TAIL(&railist, rai, rai_next);
 
 	return (ifi);
 
@@ -913,6 +1033,7 @@ get_prefix(struct rainfo *rai)
 		a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
 		if (IN6_IS_ADDR_LINKLOCAL(a))
 			continue;
+
 		/* get prefix length */
 		m = (char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
 		lim = (char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
@@ -1011,9 +1132,7 @@ add_prefix(struct rainfo *rai, struct in
 	    inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
 		sizeof(ntopbuf)), ipr->ipr_plen, ifi->ifi_ifname);
 
-	/* reconstruct the packet */
 	rai->rai_pfxs++;
-	make_packet(rai);
 }
 
 /*
@@ -1038,8 +1157,8 @@ delete_prefix(struct prefix *pfx)
 	if (pfx->pfx_timer)
 		rtadvd_remove_timer(pfx->pfx_timer);
 	free(pfx);
+
 	rai->rai_pfxs--;
-	make_packet(rai);
 }
 
 void

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.h
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sat Jul 16 09:20:22 2011	(r224087)
@@ -30,8 +30,10 @@
  * SUCH DAMAGE.
  */
 
-extern struct ifinfo *getconfig(int);
-extern int rmconfig(int);
+extern struct ifinfo *getconfig(struct ifinfo *);
+extern int rm_ifinfo(struct ifinfo *);
+extern int rm_ifinfo_index(int);
+extern int rm_rainfo(struct rainfo *);
 extern int loadconfig_ifname(char *);
 extern int loadconfig_index(int);
 extern void delete_prefix(struct prefix *);

Modified: user/hrs/ipv6/usr.sbin/rtadvd/control_server.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/control_server.c	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvd/control_server.c	Sat Jul 16 09:20:22 2011	(r224087)
@@ -74,8 +74,8 @@ static int cmsg_getprop_echo(struct ctrl
 static int cmsg_getprop_version(struct ctrl_msg_pl *);
 static int cmsg_getprop_ifilist(struct ctrl_msg_pl *);
 static int cmsg_getprop_ifi(struct ctrl_msg_pl *);
+static int cmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
 static int cmsg_getprop_rai(struct ctrl_msg_pl *);
-static int cmsg_getprop_rai_timer(struct ctrl_msg_pl *);
 static int cmsg_getprop_pfx(struct ctrl_msg_pl *);
 static int cmsg_getprop_rdnss(struct ctrl_msg_pl *);
 static int cmsg_getprop_dnssl(struct ctrl_msg_pl *);
@@ -94,8 +94,8 @@ static struct dispatch_table {
 	DEF_PL_HANDLER(version),
 	DEF_PL_HANDLER(ifilist),
 	DEF_PL_HANDLER(ifi),
+	DEF_PL_HANDLER(ifi_ra_timer),
 	DEF_PL_HANDLER(rai),
-	DEF_PL_HANDLER(rai_timer),
 	DEF_PL_HANDLER(rti),
 	DEF_PL_HANDLER(pfx),
 	DEF_PL_HANDLER(rdnss),
@@ -235,7 +235,7 @@ cmsg_getprop_rai(struct ctrl_msg_pl *cp)
 }
 
 static int
-cmsg_getprop_rai_timer(struct ctrl_msg_pl *cp)
+cmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
 {
 	struct ifinfo *ifi;
 	struct rainfo *rai;
@@ -259,8 +259,8 @@ cmsg_getprop_rai_timer(struct ctrl_msg_p
 		    cp->cp_ifname);
 		return (1);
 	}
-	if ((rtimer = rai->rai_timer) == NULL) {
-		syslog(LOG_ERR, "<%s> %s has no rai_timer", __func__,
+	if ((rtimer = ifi->ifi_ra_timer) == NULL) {
+		syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
 		    cp->cp_ifname);
 		return (1);
 	}

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sat Jul 16 08:51:09 2011	(r224086)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sat Jul 16 09:20:22 2011	(r224087)
@@ -96,6 +96,7 @@ static const char *pidfilename = _PATH_R
 const char *conffile = _PATH_RTADVDCONF;
 static struct pidfh *pfh;
 int dflag = 0, sflag = 0;
+static int wait_shutdown;
 
 #define	PFD_RAWSOCK	0
 #define	PFD_RTSOCK	1
@@ -162,7 +163,7 @@ static int	nd6_options(struct nd_opt_hdr
 		    union nd_opt *, uint32_t);
 static void	free_ndopts(union nd_opt *);
 static void	rtmsg_input(struct sockinfo *);
-static void	set_short_delay(struct rainfo *);
+static void	set_short_delay(struct ifinfo *);
 static int	check_accept_rtadv(int);
 
 int
@@ -313,7 +314,7 @@ main(int argc, char *argv[])
 
 		/* timeout handler update for active interfaces */
 		rtadvd_update_timeout_handler();
-		
+
 		/* timer expiration check and reset the timer */
 		timeout = rtadvd_check_timer();
 
@@ -347,7 +348,7 @@ main(int argc, char *argv[])
 
 		if (set[PFD_CSOCK].revents & POLLIN) {
 			int fd;
-			
+
 			fd = csock_accept(&ctrlsock);
 			if (fd == -1)
 				syslog(LOG_ERR, "<%s> accept", __func__);
@@ -361,38 +362,66 @@ main(int argc, char *argv[])
 static void
 rtadvd_shutdown(void)
 {
+	struct ifinfo *ifi;
 	struct rainfo *rai;
 	struct rdnss *rdn;
 	struct dnssl *dns;
-	int i;
-	const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
+
+	if (wait_shutdown) {
+		syslog(LOG_INFO,
+		    "waiting expiration of the all RA timers\n");
+
+		TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+			if (ifi->ifi_ra_timer != NULL)
+				break;
+		}
+		if (ifi == NULL) {
+			syslog(LOG_INFO, "gracefully terminated.\n");
+			exit(0);
+		}
+
+		sleep(1);
+		return;
+	}
 
 	syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n",
 	    __func__);
 
+	wait_shutdown = 1;
+
 	TAILQ_FOREACH(rai, &railist, rai_next) {
 		rai->rai_lifetime = 0;
 		TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next)
 			rdn->rd_ltime = 0;
 		TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next)
 			dns->dn_ltime = 0;
-		make_packet(rai);
 	}
-	for (i = 0; i < retrans; i++) {
-		syslog(LOG_INFO, "<%s> final RA transmission #%d/%d\n",
-		    __func__, i, retrans - i);
-		TAILQ_FOREACH(rai, &railist, rai_next)
-			if (rai->rai_ifinfo->ifi_state
-			    == IFI_STATE_CONFIGURED)
-				ra_output(rai);
-		syslog(LOG_INFO, "<%s> waiting for %d sec.\n",
-		    __func__, MIN_DELAY_BETWEEN_RAS);
-		sleep(MIN_DELAY_BETWEEN_RAS);
+	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+		if (!ifi->ifi_persist)
+			continue;
+		if (ifi->ifi_state == IFI_STATE_UNCONFIGURED)
+			continue;
+		if (ifi->ifi_ra_timer == NULL)
+			continue;
+
+		ifi->ifi_state = IFI_STATE_TRANSITIVE;
+
+		/* Mark as the shut-down state. */
+		ifi->ifi_rainfo_trans = ifi->ifi_rainfo;
+		ifi->ifi_rainfo = NULL;
+
+		ifi->ifi_burstcount = MAX_FINAL_RTR_ADVERTISEMENTS;
+		ifi->ifi_burstinterval = MIN_DELAY_BETWEEN_RAS;
+
+		ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+		rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+		    ifi->ifi_ra_timer);
 	}
+	syslog(LOG_INFO,
+	    "<%s> final RA transmission started.\n", __func__);
+
 	pidfile_remove(pfh);
 	csock_close(&ctrlsock);
-	
-	exit(0);
 }
 
 static void
@@ -489,7 +518,16 @@ rtmsg_input(struct sockinfo *s)
 				syslog(LOG_INFO,
 				    "<%s>: interface removed (idx=%d)",
 				    __func__, ifan->ifan_index);
-				rmconfig(ifan->ifan_index);
+				rm_ifinfo_index(ifan->ifan_index);
+
+				/* Clear ifi_ifindex */
+				TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+					if (ifi->ifi_ifindex
+					    == ifan->ifan_index) {
+						ifi->ifi_ifindex = 0;
+						break;
+					}
+				}
 				update_ifinfo(&ifilist, ifan->ifan_index);
 				break;
 			}
@@ -526,7 +564,7 @@ rtmsg_input(struct sockinfo *s)
 		case RTM_ADD:
 			if (sflag)
 				break;	/* we aren't interested in prefixes  */
-		       
+
 			addr = get_addr(msg);
 			plen = get_prefixlen(msg);
 			/* sanity check for plen */
@@ -608,29 +646,32 @@ rtmsg_input(struct sockinfo *s)
 			syslog(LOG_INFO,
 			    "<%s> interface %s becomes down. stop timer.",
 			    __func__, ifi->ifi_ifname);
-			rtadvd_remove_timer(rai->rai_timer);
-			rai->rai_timer = NULL;
+			rtadvd_remove_timer(ifi->ifi_ra_timer);
+			ifi->ifi_ra_timer = NULL;
 		} else if (!(oldifflags & IFF_UP) && /* DOWN to UP */
 		    (ifi->ifi_flags & IFF_UP)) {
 			syslog(LOG_INFO,
 			    "<%s> interface %s becomes up. restart timer.",
 			    __func__, ifi->ifi_ifname);
 
-			rai->rai_initcounter = 0; /* reset the counter */
-			rai->rai_waiting = 0; /* XXX */
-			rai->rai_timer = rtadvd_add_timer(ra_timeout,
-			    ra_timer_update, rai, rai);
-			ra_timer_update(rai, &rai->rai_timer->rat_tm);
-			rtadvd_set_timer(&rai->rai_timer->rat_tm,
-			    rai->rai_timer);
+			ifi->ifi_state = IFI_STATE_TRANSITIVE;
+			ifi->ifi_burstcount =
+			    MAX_INITIAL_RTR_ADVERTISEMENTS;
+			ifi->ifi_burstinterval =
+			    MAX_INITIAL_RTR_ADVERT_INTERVAL;
+
+			ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout,
+			    ra_timer_update, ifi, ifi);
+			ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+			rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+			    ifi->ifi_ra_timer);
 		} else if (prefixchange &&
 		    (ifi->ifi_flags & IFF_UP)) {
 			/*
 			 * An advertised prefix has been added or invalidated.
 			 * Will notice the change in a short delay.
 			 */
-			rai->rai_initcounter = 0;
-			set_short_delay(rai);
+			set_short_delay(ifi);
 		}
 	}
 
@@ -654,7 +695,7 @@ rtadvd_input(struct sockinfo *s)
 	struct ifinfo *ifi;
 
 	syslog(LOG_DEBUG, "<%s> enter", __func__);
-	
+
 	if (s == NULL) {
 		syslog(LOG_ERR, "<%s> internal error", __func__);
 		exit(1);
@@ -922,10 +963,10 @@ rs_input(int len, struct nd_router_solic
 	 * If there is already a waiting RS packet, don't
 	 * update the timer.
 	 */
-	if (rai->rai_waiting++)
+	if (ifi->ifi_rs_waitcount++)
 		goto done;
 
-	set_short_delay(rai);
+	set_short_delay(ifi);
 
   done:
 	free_ndopts(&ndopts);
@@ -933,7 +974,7 @@ rs_input(int len, struct nd_router_solic
 }
 
 static void
-set_short_delay(struct rainfo *rai)
+set_short_delay(struct ifinfo *ifi)
 {
 	long delay;	/* must not be greater than 1000000 */
 	struct timeval interval, now, min_delay, tm_tmp, *rest;
@@ -952,7 +993,7 @@ set_short_delay(struct rainfo *rai)
 #endif
 	interval.tv_sec = 0;
 	interval.tv_usec = delay;
-	rest = rtadvd_timer_rest(rai->rai_timer);
+	rest = rtadvd_timer_rest(ifi->ifi_ra_timer);
 	if (TIMEVAL_LT(rest, &interval)) {
 		syslog(LOG_DEBUG, "<%s> random delay is larger than "
 		    "the rest of the current timer", __func__);
@@ -967,21 +1008,21 @@ set_short_delay(struct rainfo *rai)
 	 * previous advertisement was sent.
 	 */
 	gettimeofday(&now, NULL);
-	TIMEVAL_SUB(&now, &rai->rai_lastsent, &tm_tmp);
+	TIMEVAL_SUB(&now, &ifi->ifi_ra_lastsent, &tm_tmp);
 	min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
 	min_delay.tv_usec = 0;
 	if (TIMEVAL_LT(&tm_tmp, &min_delay)) {
 		TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
 		TIMEVAL_ADD(&min_delay, &interval, &interval);
 	}
-	rtadvd_set_timer(&interval, rai->rai_timer);
+	rtadvd_set_timer(&interval, ifi->ifi_ra_timer);
 }
 
 static int
 check_accept_rtadv(int idx)
 {
 	struct ifinfo *ifi;
-	
+
 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
 		if (ifi->ifi_ifindex == idx)
 			break;
@@ -992,7 +1033,18 @@ check_accept_rtadv(int idx)
 		    __func__, idx);
 		return (0);
 	}
-#if (__FreeBSD_version > 900000)
+#if (__FreeBSD_version < 900000)
+	/*
+	 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv
+	 * RA_SEND: ip6.forwarding
+	 */
+	return ((getinet6sysctl(IPV6CTL_FORWARDING) == 0) &&

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107160920.p6G9KNGi018881>