svn commit: r222708 - user/hrs/ipv6/usr.sbin/rtadvd

Hiroki Sato hrs at FreeBSD.org
Sun Jun 5 07:55:52 UTC 2011


Author: hrs
Date: Sun Jun  5 07:55:51 2011
New Revision: 222708
URL: http://svn.freebsd.org/changeset/base/222708

Log:
  Support dynamically-added/removed interfaces.  The rtadvd(8) daemon detects an
  interface addition/removal via RTM_IFANNOUNCE message and update the internal
  structure.
  
  TO BE FIXED:
   The advertising interface list still depends on the command line argument.
   The configuration file cannot be reloaded.

Modified:
  user/hrs/ipv6/usr.sbin/rtadvd/config.c
  user/hrs/ipv6/usr.sbin/rtadvd/config.h
  user/hrs/ipv6/usr.sbin/rtadvd/if.c
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
  user/hrs/ipv6/usr.sbin/rtadvd/timer.c

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sun Jun  5 03:33:46 2011	(r222707)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sun Jun  5 07:55:51 2011	(r222708)
@@ -143,8 +143,68 @@ dname_labelenc(char *dst, const char *sr
 		memset(p, 0, sizeof(*p));				\
 	} while(0)
 
-void
-getconfig(char *intface)
+int
+rmconfig(int idx)
+{
+	struct rainfo *rai;
+	struct prefix *pfx;
+	struct soliciter *sol;
+	struct rdnss *rdn;
+	struct rdnss_addr *rdna;
+	struct dnssl *dns;
+	struct rtinfo *rti;
+
+	rai = if_indextorainfo(idx);
+	if (rai == NULL) {
+		syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)",
+		    __func__, idx);
+		return (-1);
+	}
+
+	TAILQ_REMOVE(&railist, rai, rai_next);
+	syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
+	    __func__, idx);
+
+	/* Free all of allocated memories for this entry. */
+	rtadvd_remove_timer(rai->rai_timer);
+
+	if (rai->rai_ra_data != NULL)
+		free(rai->rai_ra_data);
+
+	if (rai->rai_sdl != NULL)
+		free(rai->rai_sdl);
+
+	while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) {
+		TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
+		free(pfx);
+	}
+	while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) {
+		TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next);
+		free(sol);
+	}
+	while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) {
+		TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next);
+		while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) {
+			TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next);
+			free(rdna);
+		}
+		free(rdn);
+	}
+	while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) {
+		TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next);
+		free(dns);
+	}
+	while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) {
+		TAILQ_REMOVE(&rai->rai_route, rti, rti_next);
+		free(rti);
+	}
+	free(rai);
+	
+	return (0);
+}
+
+int
+getconfig(int idx)
 {
 	int stat, i;
 	char tbuf[BUFSIZ];
@@ -154,8 +214,15 @@ getconfig(char *intface)
 	char buf[BUFSIZ];
 	char *bp = buf;
 	char *addr, *flagstr;
+	char intface[IFNAMSIZ];
 	static int forwarding = -1;
 
+	if (if_indextoname(idx, intface) == NULL) {
+		syslog(LOG_ERR, "<%s> invalid index number (%d)",
+		    __func__, idx);
+		return (-1);
+	}
+
 	if ((stat = agetent(tbuf, intface)) <= 0) {
 		memset(tbuf, 0, sizeof(tbuf));
 		syslog(LOG_INFO,
@@ -201,7 +268,7 @@ getconfig(char *intface)
 			syslog(LOG_ERR,
 			    "<%s> can't get information of %s",
 			    __func__, intface);
-			exit(1);
+			return (-1);
 		}
 		rai->rai_ifindex = rai->rai_sdl->sdl_index;
 	} else
@@ -227,7 +294,7 @@ getconfig(char *intface)
 		    "<%s> maxinterval (%ld) on %s is invalid "
 		    "(must be between %u and %u)", __func__, val,
 		    intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_maxinterval = (u_int)val;
 
@@ -239,7 +306,7 @@ getconfig(char *intface)
 		    "(must be between %d and %d)",
 		    __func__, val, intface, MIN_MININTERVAL,
 		    (rai->rai_maxinterval * 3) / 4);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_mininterval = (u_int)val;
 
@@ -258,7 +325,7 @@ getconfig(char *intface)
 			if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
 				syslog(LOG_ERR, "<%s> the \'h\' and \'l\'"
 				    " router flags are exclusive", __func__);
-				exit(1);
+				return (-1);
 			}
 			val |= ND_RA_FLAG_RTPREF_LOW;
 		}
@@ -275,7 +342,7 @@ getconfig(char *intface)
 	if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) {
 		syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
 		    __func__, rai->rai_rtpref, intface);
-		exit(1);
+		return (-1);
 	}
 
 	MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
@@ -286,7 +353,7 @@ getconfig(char *intface)
 		    "(must be 0 or between %d and %d)",
 		    __func__, val, intface, rai->rai_maxinterval,
 		    MAXROUTERLIFETIME);
-		exit(1);
+		return (-1);
 	}
 	/*
 	 * Basically, hosts MUST NOT send Router Advertisement messages at any
@@ -302,7 +369,7 @@ getconfig(char *intface)
 		    "which must not be allowed for hosts.  you must "
 		    "change router lifetime or enable IPv6 forwarding.",
 		    __func__, intface);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_lifetime = val & 0xffff;
 
@@ -312,7 +379,7 @@ getconfig(char *intface)
 		    "<%s> reachable time (%ld) on %s is invalid "
 		    "(must be no greater than %d)",
 		    __func__, val, intface, MAXREACHABLETIME);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_reachabletime = (u_int32_t)val;
 
@@ -320,7 +387,7 @@ getconfig(char *intface)
 	if (val64 < 0 || val64 > 0xffffffff) {
 		syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
 		    __func__, (long long)val64, intface);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_retranstimer = (u_int32_t)val64;
 
@@ -328,7 +395,7 @@ getconfig(char *intface)
 		syslog(LOG_ERR,
 		    "<%s> mobile-ip6 configuration not supported",
 		    __func__);
-		exit(1);
+		return (-1);
 	}
 	/* prefix information */
 
@@ -361,14 +428,14 @@ getconfig(char *intface)
 			syslog(LOG_ERR,
 			    "<%s> inet_pton failed for %s",
 			    __func__, addr);
-			exit(1);
+			return (-1);
 		}
 		if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) {
 			syslog(LOG_ERR,
 			    "<%s> multicast prefix (%s) must "
 			    "not be advertised on %s",
 			    __func__, addr, intface);
-			exit(1);
+			return (-1);
 		}
 		if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix))
 			syslog(LOG_NOTICE,
@@ -382,7 +449,7 @@ getconfig(char *intface)
 			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s "
 			    "on %s out of range",
 			    __func__, val, addr, intface);
-			exit(1);
+			return (-1);
 		}
 		pfx->pfx_prefixlen = (int)val;
 
@@ -407,7 +474,7 @@ getconfig(char *intface)
 			    "%s/%d on %s is out of range",
 			    __func__, (long long)val64,
 			    addr, pfx->pfx_prefixlen, intface);
-			exit(1);
+			return (-1);
 		}
 		pfx->pfx_validlifetime = (u_int32_t)val64;
 
@@ -427,7 +494,7 @@ getconfig(char *intface)
 			    "is out of range",
 			    __func__, (long long)val64,
 			    addr, pfx->pfx_prefixlen, intface);
-			exit(1);
+			return (-1);
 		}
 		pfx->pfx_preflifetime = (u_int32_t)val64;
 
@@ -447,7 +514,7 @@ getconfig(char *intface)
 		syslog(LOG_ERR,
 		    "<%s> mtu (%ld) on %s out of range",
 		    __func__, val, intface);
-		exit(1);
+		return (-1);
 	}
 	rai->rai_linkmtu = (u_int32_t)val;
 	if (rai->rai_linkmtu == 0) {
@@ -464,7 +531,7 @@ getconfig(char *intface)
 		    "be between least MTU (%d) and physical link MTU (%d)",
 		    __func__, (unsigned long)rai->rai_linkmtu, intface,
 		    IPV6_MMTU, rai->rai_phymtu);
-		exit(1);
+		return (-1);
 	}
 
 #ifdef SIOCSIFINFO_IN6
@@ -523,7 +590,7 @@ getconfig(char *intface)
 		if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) {
 			syslog(LOG_ERR, "<%s> inet_pton failed for %s",
 			    __func__, addr);
-			exit(1);
+			return (-1);
 		}
 #if 0
 		/*
@@ -538,14 +605,14 @@ getconfig(char *intface)
 			    "<%s> multicast route (%s) must "
 			    "not be advertised on %s",
 			    __func__, addr, intface);
-			exit(1);
+			return (-1);
 		}
 		if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
 			syslog(LOG_NOTICE,
 			    "<%s> link-local route (%s) will "
 			    "be advertised on %s",
 			    __func__, addr, intface);
-			exit(1);
+			return (-1);
 		}
 #endif
 
@@ -565,7 +632,7 @@ getconfig(char *intface)
 			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
 			    "out of range",
 			    __func__, val, addr, intface);
-			exit(1);
+			return (-1);
 		}
 		rti->rti_prefixlen = (int)val;
 
@@ -601,7 +668,7 @@ getconfig(char *intface)
 			    "for %s/%d on %s",
 			    __func__, rti->rti_rtpref, addr,
 			    rti->rti_prefixlen, intface);
-			exit(1);
+			return (-1);
 		}
 
 		/*
@@ -628,7 +695,7 @@ getconfig(char *intface)
 			syslog(LOG_ERR, "<%s> route lifetime (%lld) for "
 			    "%s/%d on %s out of range", __func__,
 			    (long long)val64, addr, rti->rti_prefixlen, intface);
-			exit(1);
+			return (-1);
 		}
 		rti->rti_ltime = (u_int32_t)val64;
 	}
@@ -656,7 +723,8 @@ getconfig(char *intface)
 			if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
 				syslog(LOG_ERR, "<%s> inet_pton failed for %s",
 				    __func__, abuf);
-				exit(1);
+				free(rdna);
+				return (-1);
 			}
 			TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next);
 		}
@@ -669,7 +737,7 @@ getconfig(char *intface)
 			    "(must be between %d and %d)",
 			    entbuf, val, intface, rai->rai_maxinterval,
 			    rai->rai_maxinterval * 2);
-			exit(1);
+			return (-1);
 		}
 		rdn->rd_ltime = val;
 
@@ -711,7 +779,7 @@ getconfig(char *intface)
 			    "(must be between %d and %d)",
 			    entbuf, val, intface, rai->rai_maxinterval,
 			    rai->rai_maxinterval * 2);
-			exit(1);
+			return (-1);
 		}
 		dns->dn_ltime = val;
 
@@ -727,6 +795,8 @@ getconfig(char *intface)
 				      rai, rai);
 	ra_timer_update((void *)rai, &rai->rai_timer->rat_tm);
 	rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer);
+
+	return (0);
 }
 
 void

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.h
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sun Jun  5 03:33:46 2011	(r222707)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sun Jun  5 07:55:51 2011	(r222708)
@@ -30,7 +30,8 @@
  * SUCH DAMAGE.
  */
 
-extern void getconfig(char *);
+extern int getconfig(int);
+extern int rmconfig(int);
 extern void delete_prefix(struct prefix *);
 extern void invalidate_prefix(struct prefix *);
 extern void update_prefix(struct prefix *);

Modified: user/hrs/ipv6/usr.sbin/rtadvd/if.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/if.c	Sun Jun  5 03:33:46 2011	(r222707)
+++ user/hrs/ipv6/usr.sbin/rtadvd/if.c	Sun Jun  5 07:55:51 2011	(r222708)
@@ -271,10 +271,17 @@ get_next_msg(char *buf, char *lim, int i
 			    buf, lim, rtm);
 			break;
 		}
-		if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
+		if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
+			syslog(LOG_WARNING,
+			    "<%s> routing message version mismatch "
+			    "(buf=%p lim=%p rtm=%p)", __func__,
+			    buf, lim, rtm);
 			continue;
 		}
 
+		if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
+			continue;
+
 		switch (rtm->rtm_type) {
 		case RTM_GET:
 		case RTM_ADD:
@@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int i
 			return (char *)rtm;
 			/* NOTREACHED */
 		case RTM_IFINFO:
+		case RTM_IFANNOUNCE:
 			/* found */
 			*lenp = rtm->rtm_msglen;
 			return (char *)rtm;
@@ -566,6 +574,9 @@ parse_iflist(struct if_msghdr ***ifmlist
 void
 init_iflist(void)
 {
+	syslog(LOG_DEBUG,
+	    "<%s> generate iflist.", __func__);
+
 	if (ifblock) {
 		free(ifblock);
 		ifblock_size = 0;

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sun Jun  5 03:33:46 2011	(r222707)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sun Jun  5 07:55:51 2011	(r222708)
@@ -90,6 +90,8 @@ int sock;
 int rtsock = -1;
 int accept_rr = 0;
 int dflag = 0, sflag = 0;
+static int ifl_len;
+static char **ifl_names;
 
 struct railist_head_t railist =
     TAILQ_HEAD_INITIALIZER(railist);
@@ -171,6 +173,7 @@ static void	ra_output(struct rainfo *);
 static void	rtmsg_input(void);
 static void	rtadvd_set_dump_file(int);
 static void	set_short_delay(struct rainfo *);
+static int	ifl_lookup(char *, char **, int);
 
 int
 main(int argc, char *argv[])
@@ -186,6 +189,7 @@ main(int argc, char *argv[])
 	int i, ch;
 	int fflag = 0, logopt;
 	pid_t pid, otherpid;
+	int error;
 
 	/* get command line options and arguments */
 	while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) {
@@ -258,9 +262,25 @@ main(int argc, char *argv[])
 #endif
 	/* get iflist block from kernel */
 	init_iflist();
+	ifl_names = argv;
+	ifl_len = argc;
+
+	for (i = 0; i < ifl_len; i++) {
+		int idx;
 
-	while (argc--)
-		getconfig(*argv++);
+		idx = if_nametoindex(ifl_names[i]);
+		if (idx == 0) {
+			syslog(LOG_INFO,
+			    "<%s> interface %s not found."
+			    "Ignored at this moment.", __func__, ifl_names[i]);
+			continue;
+		}
+		error = getconfig(idx);
+		if (error)
+			syslog(LOG_INFO,
+			    "<%s> invalid configuration for %s."
+			    "Ignored at this moment.", __func__, ifl_names[i]);
+	}
 
 	pfh = pidfile_open(pidfilename, 0600, &otherpid);
 	if (pfh == NULL) {
@@ -376,6 +396,15 @@ main(int argc, char *argv[])
 	exit(0);		/* NOTREACHED */
 }
 
+static int
+ifl_lookup(char *ifn, char **names, int len)
+{
+	while (len--)
+		if (strncmp(names[len], ifn, IFNAMSIZ) == 0)
+			return (0);
+	return (-1);
+}
+
 static void
 rtadvd_set_dump_file(int sig __unused)
 {
@@ -426,12 +455,14 @@ rtmsg_input(void)
 	int n, type, ifindex = 0, plen;
 	size_t len;
 	char msg[2048], *next, *lim;
-	u_char ifname[IF_NAMESIZE];
+	u_char ifname[IFNAMSIZ];
+	struct if_announcemsghdr *ifan;
 	struct prefix *pfx;
 	struct rainfo *rai;
 	struct in6_addr *addr;
 	char addrbuf[INET6_ADDRSTRLEN];
 	int prefixchange = 0;
+	int error;
 
 	n = read(rtsock, msg, sizeof(msg));
 	syslog(LOG_DEBUG, "<%s> received a routing message "
@@ -462,7 +493,8 @@ rtmsg_input(void)
 		    RTADV_TYPE2BITMASK(RTM_DELETE) |
 		    RTADV_TYPE2BITMASK(RTM_NEWADDR) |
 		    RTADV_TYPE2BITMASK(RTM_DELADDR) |
-		    RTADV_TYPE2BITMASK(RTM_IFINFO));
+		    RTADV_TYPE2BITMASK(RTM_IFINFO) |
+		    RTADV_TYPE2BITMASK(RTM_IFANNOUNCE));
 		if (len == 0)
 			break;
 		type = rtmsg_type(next);
@@ -478,6 +510,50 @@ rtmsg_input(void)
 		case RTM_IFINFO:
 			ifindex = get_ifm_ifindex(next);
 			break;
+		case RTM_IFANNOUNCE:
+			ifan = (struct if_announcemsghdr *)next;
+			switch (ifan->ifan_what) {
+			case IFAN_ARRIVAL:
+			case IFAN_DEPARTURE:
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "<%s:%d> unknown ifan msg (ifan_what=%d)",
+				   __func__, __LINE__, ifan->ifan_what);
+				continue;
+			}
+
+			syslog(LOG_INFO, "<%s>: if_announcemsg (idx=%d:%d)",
+			       __func__, ifan->ifan_index, ifan->ifan_what);
+			init_iflist();
+			error = ifl_lookup(ifan->ifan_name,
+			    ifl_names, ifl_len);
+			if (error) {
+				syslog(LOG_INFO, "<%s>: not a target "
+				    "interface (idx=%d)", __func__,
+				    ifan->ifan_index);
+				continue;
+			}
+
+			switch (ifan->ifan_what) {
+			case IFAN_ARRIVAL:
+				error = getconfig(ifan->ifan_index);
+				if (error)
+					syslog(LOG_ERR,
+					    "<%s>: getconfig failed (idx=%d)"
+					    "  Ignored.", __func__,
+					    ifan->ifan_index);
+				break;
+			case IFAN_DEPARTURE:
+				error = rmconfig(ifan->ifan_index);
+				if (error)
+					syslog(LOG_ERR,
+					    "<%s>: rmconfig failed (idx=%d)"
+					    "  Ignored.", __func__,
+					    ifan->ifan_index);
+				break;
+			}
+			continue;
 		default:
 			/* should not reach here */
 			syslog(LOG_DEBUG,

Modified: user/hrs/ipv6/usr.sbin/rtadvd/timer.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/timer.c	Sun Jun  5 03:33:46 2011	(r222707)
+++ user/hrs/ipv6/usr.sbin/rtadvd/timer.c	Sun Jun  5 07:55:51 2011	(r222708)
@@ -92,6 +92,9 @@ void
 rtadvd_remove_timer(struct rtadvd_timer *rat)
 {
 
+	if (rat == NULL)
+		return;
+
 	TAILQ_REMOVE(&ra_timer, rat, rat_next);
 	free(rat);
 }


More information about the svn-src-user mailing list