Module Name:    src
Committed By:   roy
Date:           Thu Feb 26 09:54:46 UTC 2015

Modified Files:
        src/sys/net: route.c route.h
        src/sys/netinet: if_arp.c in.c ip_carp.c
        src/sys/netinet6: in6.c in6_var.h

Log Message:
Introduce the routing flag RTF_LOCAL to track local address routes.
Add functions rt_ifa_addlocal() and rt_ifa_remlocal() to add and remove
local routes for the address and announce the new address and route
to the routing socket.

Add in_ifaddlocal() and in_ifremlocal() to use these functions.
Rename in6_if{add,rem}loop() to in6_if{add,rem}local() and use these
functions.

rtinit() no longer announces the address, just the network route for the
address. As such, calls to rt_newaddrmsg() have been removed from
in_addprefix() and in_scrubprefix().

This solves the problem of potentially more than one announcement, or no
announcement at all for the address in certain situations.


To generate a diff of this commit:
cvs rdiff -u -r1.135 -r1.136 src/sys/net/route.c
cvs rdiff -u -r1.86 -r1.87 src/sys/net/route.h
cvs rdiff -u -r1.160 -r1.161 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.149 -r1.150 src/sys/netinet/in.c
cvs rdiff -u -r1.59 -r1.60 src/sys/netinet/ip_carp.c
cvs rdiff -u -r1.183 -r1.184 src/sys/netinet6/in6.c
cvs rdiff -u -r1.71 -r1.72 src/sys/netinet6/in6_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/route.c
diff -u src/sys/net/route.c:1.135 src/sys/net/route.c:1.136
--- src/sys/net/route.c:1.135	Wed Feb 25 12:45:34 2015
+++ src/sys/net/route.c	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.c,v 1.135 2015/02/25 12:45:34 roy Exp $	*/
+/*	$NetBSD: route.c,v 1.136 2015/02/26 09:54:46 roy Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -90,10 +90,11 @@
  *	@(#)route.c	8.3 (Berkeley) 1/9/95
  */
 
+#include "opt_inet.h"
 #include "opt_route.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.135 2015/02/25 12:45:34 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.136 2015/02/26 09:54:46 roy Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -960,7 +961,7 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 		;
 	else switch (cmd) {
 	case RTM_DELETE:
-		rt_newaddrmsg(cmd, ifa, error, nrt);
+		rt_newmsg(cmd, nrt);
 		if (rt->rt_refcnt <= 0) {
 			rt->rt_refcnt++;
 			rtfree(rt);
@@ -984,7 +985,7 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 
 		if (cmd == RTM_LLINFO_UPD && ifa->ifa_rtrequest != NULL)
 			ifa->ifa_rtrequest(RTM_LLINFO_UPD, rt, &info);
-		rt_newaddrmsg(RTM_CHANGE, ifa, error, nrt);
+		rt_newmsg(RTM_CHANGE, nrt);
 		break;
 	case RTM_ADD:
 		rt->rt_refcnt--;
@@ -1000,12 +1001,132 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 			if (ifa->ifa_rtrequest != NULL)
 				ifa->ifa_rtrequest(RTM_ADD, rt, &info);
 		}
-		rt_newaddrmsg(cmd, ifa, error, nrt);
+		rt_newmsg(cmd, nrt);
 		break;
 	}
 	return error;
 }
 
+static const struct in_addr inmask32 = {.s_addr = INADDR_BROADCAST};
+
+/* Subroutine for rt_ifa_addlocal() and rt_ifa_remlocal() */
+static int
+rt_ifa_localrequest(int cmd, struct ifaddr *ifa)
+{
+	struct sockaddr *all1_sa;
+	struct sockaddr_in all1_sin;
+#ifdef INET6
+	struct sockaddr_in6 all1_sin6;
+#endif
+	struct rtentry *nrt = NULL;
+	int flags, e;
+
+	switch(ifa->ifa_addr->sa_family) {
+	case AF_INET:
+		sockaddr_in_init(&all1_sin, &inmask32, 0);
+		all1_sa = (struct sockaddr *)&all1_sin;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		sockaddr_in6_init(&all1_sin6, &in6mask128, 0, 0, 0);
+		all1_sa = (struct sockaddr *)&all1_sin6;
+		break;
+#endif
+	default:
+		return 0;
+	}
+
+	flags = RTF_UP | RTF_HOST | RTF_LOCAL;
+	if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
+		flags |= RTF_LLINFO;
+	e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, all1_sa, flags, &nrt);
+
+	/* Make sure rt_ifa be equal to IFA, the second argument of the
+	 * function. */
+	if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa)
+		rt_replace_ifa(nrt, ifa);
+
+	rt_newaddrmsg(cmd, ifa, e, nrt);
+	if (nrt) {
+		if (cmd == RTM_DELETE) {
+			if (nrt->rt_refcnt <= 0) {
+				/* XXX: we should free the entry ourselves. */
+				nrt->rt_refcnt++;
+				rtfree(nrt);
+			}
+		} else {
+			/* the cmd must be RTM_ADD here */
+			nrt->rt_refcnt--;
+		}
+	}
+	return e;
+}
+
+/*
+ * Create a local route entry for the address.
+ * Announce the addition of the address and the route to the routing socket.
+ */
+int
+rt_ifa_addlocal(struct ifaddr *ifa)
+{
+	struct rtentry *rt;
+	int e;
+
+	/* If there is no loopback entry, allocate one. */
+	rt = rtalloc1(ifa->ifa_addr, 0);
+	if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
+	    (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+		e = rt_ifa_localrequest(RTM_ADD, ifa);
+	else {
+		e = 0;
+		rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+	}
+	if (rt != NULL)
+		rt->rt_refcnt--;
+	return e;
+}
+
+/*
+ * Remove the local route entry for the address.
+ * Announce the removal of the address and the route to the routing socket.
+ */
+int
+rt_ifa_remlocal(struct ifaddr *ifa, struct ifaddr *alt_ifa)
+{
+	struct rtentry *rt;
+	int e = 0;
+
+	rt = rtalloc1(ifa->ifa_addr, 0);
+
+	/*
+	 * Before deleting, check if a corresponding loopbacked
+	 * host route surely exists.  With this check, we can avoid
+	 * deleting an interface direct route whose destination is
+	 * the same as the address being removed.  This can happen
+	 * when removing a subnet-router anycast address on an
+	 * interface attached to a shared medium.
+	 */
+	if (rt != NULL &&
+	    (rt->rt_flags & RTF_HOST) &&
+	    (rt->rt_ifp->if_flags & IFF_LOOPBACK))
+	{
+		/* If we cannot replace the route's ifaddr with the equivalent
+		 * ifaddr of another interface, I believe it is safest to
+		 * delete the route.
+		 */
+		if (alt_ifa == NULL)
+			e = rt_ifa_localrequest(RTM_DELETE, ifa);
+		else {
+			rt_replace_ifa(rt, alt_ifa);
+			rt_newmsg(RTM_CHANGE, rt);
+		}
+	} else
+		rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
+	if (rt != NULL)
+		rt->rt_refcnt--;
+	return e;
+}
+
 /*
  * Route timer routines.  These routes allow functions to be called
  * for various routes at any time.  This is useful in supporting

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.86 src/sys/net/route.h:1.87
--- src/sys/net/route.h:1.86	Wed Feb 25 12:45:34 2015
+++ src/sys/net/route.h	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.86 2015/02/25 12:45:34 roy Exp $	*/
+/*	$NetBSD: route.h,v 1.87 2015/02/26 09:54:46 roy Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -155,6 +155,7 @@ struct ortentry {
 #define RTF_PROTO1	0x8000		/* protocol specific routing flag */
 #define RTF_SRC		0x10000		/* route has fixed source address */
 #define RTF_ANNOUNCE	0x20000		/* announce new ARP or NDP entry */
+#define RTF_LOCAL	0x40000		/* route represents a local address */
 
 /*
  * Routing statistics.
@@ -504,6 +505,8 @@ struct rtentry *rt_lookup(rtbl_t *, cons
 struct rtentry *rt_deladdr(rtbl_t *, const struct sockaddr *,
     const struct sockaddr *);
 void rtbl_init(void);
+int rt_ifa_addlocal(struct ifaddr *);
+int rt_ifa_remlocal(struct ifaddr *, struct ifaddr *);
 rtbl_t *rt_gettable(sa_family_t);
 void rt_assert_inactive(const struct rtentry *);
 

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.160 src/sys/netinet/if_arp.c:1.161
--- src/sys/netinet/if_arp.c:1.160	Thu Nov 13 16:11:18 2014
+++ src/sys/netinet/if_arp.c	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.160 2014/11/13 16:11:18 christos Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.161 2015/02/26 09:54:46 roy Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.160 2014/11/13 16:11:18 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.161 2015/02/26 09:54:46 roy Exp $");
 
 #include "opt_ddb.h"
 #include "opt_inet.h"
@@ -453,7 +453,9 @@ arp_setgate(struct rtentry *rt, struct s
 	if ((rt->rt_flags & RTF_HOST) == 0 && netmask != NULL &&
 	    satocsin(netmask)->sin_addr.s_addr != 0xffffffff)
 		rt->rt_flags |= RTF_CLONING;
-	if (rt->rt_flags & RTF_CLONING) {
+	if (rt->rt_flags & RTF_CLONING ||
+	    ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !rt->rt_llinfo))
+	{
 		union {
 			struct sockaddr sa;
 			struct sockaddr_storage ss;
@@ -554,7 +556,9 @@ arp_rtrequest(int req, struct rtentry *r
 		break;
 	case RTM_ADD:
 		gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]);
-		if (rt->rt_flags & RTF_CLONING) {
+		if (rt->rt_flags & RTF_CLONING ||
+		    ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la))
+		{
 			/*
 			 * Give this route an expiration time, even though
 			 * it's a "permanent" route, so that routes cloned
@@ -592,7 +596,8 @@ arp_rtrequest(int req, struct rtentry *r
 			    }
 #endif
 			}
-			break;
+			if (rt->rt_flags & RTF_CLONING)
+				break;
 		}
 		/* Announce a new entry if requested. */
 		if (rt->rt_flags & RTF_ANNOUNCE) {

Index: src/sys/netinet/in.c
diff -u src/sys/netinet/in.c:1.149 src/sys/netinet/in.c:1.150
--- src/sys/netinet/in.c:1.149	Mon Dec  1 17:07:43 2014
+++ src/sys/netinet/in.c	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in.c,v 1.149 2014/12/01 17:07:43 christos Exp $	*/
+/*	$NetBSD: in.c,v 1.150 2015/02/26 09:54:46 roy Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.149 2014/12/01 17:07:43 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.150 2015/02/26 09:54:46 roy Exp $");
 
 #include "opt_inet.h"
 #include "opt_inet_conf.h"
@@ -602,6 +602,40 @@ in_control(struct socket *so, u_long cmd
 	return error;
 }
 
+/* Add ownaddr as loopback rtentry. */
+static void
+in_ifaddlocal(struct ifaddr *ifa)
+{
+
+	rt_ifa_addlocal(ifa);
+}
+
+/* Rempve loopback entry of ownaddr */
+static void
+in_ifremlocal(struct ifaddr *ifa)
+{
+	struct in_ifaddr *ia, *p;
+	struct ifaddr *alt_ifa = NULL;
+	int ia_count = 0;
+
+	ia = (struct in_ifaddr *)ifa;
+	/* Delete the entry if exactly one ifaddr matches the
+	 * address, ifa->ifa_addr. */
+	TAILQ_FOREACH(p, &in_ifaddrhead, ia_list) {
+		if (!in_hosteq(p->ia_addr.sin_addr, ia->ia_addr.sin_addr))
+			continue;
+		if (p->ia_ifp != ia->ia_ifp)
+			alt_ifa = &p->ia_ifa;
+		if (++ia_count > 1 && alt_ifa != NULL)
+			break;
+	}
+
+	if (ia_count == 0)
+		return;
+
+	rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
+}
+
 void
 in_purgeaddr(struct ifaddr *ifa)
 {
@@ -609,6 +643,7 @@ in_purgeaddr(struct ifaddr *ifa)
 	struct in_ifaddr *ia = (void *) ifa;
 
 	in_ifscrub(ifp, ia);
+	in_ifremlocal(ifa);
 	LIST_REMOVE(ia, ia_hash);
 	ifa_remove(ifp, &ia->ia_ifa);
 	TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list);
@@ -857,6 +892,9 @@ in_ifinit(struct ifnet *ifp, struct in_i
 		ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
 	}
 
+	/* Add the local route to the address */
+	in_ifaddlocal(&ia->ia_ifa);
+
 	i = ia->ia_addr.sin_addr.s_addr;
 	if (IN_CLASSA(i))
 		ia->ia_netmask = IN_CLASSA_NET;
@@ -958,13 +996,9 @@ in_addprefix(struct in_ifaddr *target, i
 		 * interface address, we don't need to bother
 		 *
 		 * XXX RADIX_MPATH implications here? -dyoung
-		 *
-		 * But we should still notify userland of the new address
 		 */
-		if (ia->ia_flags & IFA_ROUTE) {
-			rt_newaddrmsg(RTM_NEWADDR, &target->ia_ifa, 0, NULL);
+		if (ia->ia_flags & IFA_ROUTE)
 			return 0;
-		}
 	}
 
 	/*
@@ -974,9 +1008,9 @@ in_addprefix(struct in_ifaddr *target, i
 	if (error == 0)
 		target->ia_flags |= IFA_ROUTE;
 	else if (error == EEXIST) {
-		/* 
+		/*
 		 * the fact the route already exists is not an error.
-		 */ 
+		 */
 		error = 0;
 	}
 	return error;
@@ -995,10 +1029,8 @@ in_scrubprefix(struct in_ifaddr *target)
 	int error;
 
 	/* If we don't have IFA_ROUTE we should still inform userland */
-	if ((target->ia_flags & IFA_ROUTE) == 0) {
-		rt_newaddrmsg(RTM_DELADDR, &target->ia_ifa, 0, NULL);
+	if ((target->ia_flags & IFA_ROUTE) == 0)
 		return 0;
-	}
 
 	if (rtinitflags(target))
 		prefix = target->ia_dstaddr.sin_addr;

Index: src/sys/netinet/ip_carp.c
diff -u src/sys/netinet/ip_carp.c:1.59 src/sys/netinet/ip_carp.c:1.60
--- src/sys/netinet/ip_carp.c:1.59	Thu Jul 31 02:37:25 2014
+++ src/sys/netinet/ip_carp.c	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_carp.c,v 1.59 2014/07/31 02:37:25 ozaki-r Exp $	*/
+/*	$NetBSD: ip_carp.c,v 1.60 2015/02/26 09:54:46 roy Exp $	*/
 /*	$OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
 #include "opt_mbuftrace.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.59 2014/07/31 02:37:25 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.60 2015/02/26 09:54:46 roy Exp $");
 
 /*
  * TODO:
@@ -446,9 +446,9 @@ carp_setroute(struct carp_softc *sc, int
 #ifdef INET6
 		case AF_INET6:
 			if (cmd == RTM_ADD)
-				in6_ifaddloop(ifa);
+				in6_ifaddlocal(ifa);
 			else
-				in6_ifremloop(ifa);
+				in6_ifremlocal(ifa);
 			break;
 #endif /* INET6 */
 		default:

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.183 src/sys/netinet6/in6.c:1.184
--- src/sys/netinet6/in6.c:1.183	Wed Feb 25 00:26:58 2015
+++ src/sys/netinet6/in6.c	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.183 2015/02/25 00:26:58 roy Exp $	*/
+/*	$NetBSD: in6.c,v 1.184 2015/02/26 09:54:46 roy Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.183 2015/02/25 00:26:58 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.184 2015/02/26 09:54:46 roy Exp $");
 
 #include "opt_inet.h"
 #include "opt_compat_netbsd.h"
@@ -145,70 +145,6 @@ static int in6_ifinit(struct ifnet *, st
 static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
 
 /*
- * Subroutine for in6_ifaddloop() and in6_ifremloop().
- * This routine does actual work.
- */
-static void
-in6_ifloop_request(int cmd, struct ifaddr *ifa)
-{
-	struct sockaddr_in6 all1_sa;
-	struct rtentry *nrt = NULL;
-	int e;
-
-	sockaddr_in6_init(&all1_sa, &in6mask128, 0, 0, 0);
-
-	/*
-	 * We specify the address itself as the gateway, and set the
-	 * RTF_LLINFO flag, so that the corresponding host route would have
-	 * the flag, and thus applications that assume traditional behavior
-	 * would be happy.  Note that we assume the caller of the function
-	 * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
-	 * which changes the outgoing interface to the loopback interface.
-	 */
-	e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
-	    (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
-	if (e != 0) {
-		log(LOG_ERR, "in6_ifloop_request: "
-		    "%s operation failed for %s (errno=%d)\n",
-		    cmd == RTM_ADD ? "ADD" : "DELETE",
-		    ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
-		    e);
-	}
-
-	/*
-	 * Make sure rt_ifa be equal to IFA, the second argument of the
-	 * function.
-	 * We need this because when we refer to rt_ifa->ia6_flags in
-	 * ip6_input, we assume that the rt_ifa points to the address instead
-	 * of the loopback address.
-	 */
-	if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa)
-		rt_replace_ifa(nrt, ifa);
-
-	/*
-	 * Report the addition/removal of the address to the routing socket
-	 * unless the address is marked tentative, where it will be reported
-	 * once DAD completes.
-	 * XXX: since we called rtinit for a p2p interface with a destination,
-	 *      we end up reporting twice in such a case.  Should we rather
-	 *      omit the second report?
-	 */
-	if (nrt) {
-		rt_newaddrmsg(cmd, ifa, e, nrt);
-		if (cmd == RTM_DELETE) {
-			if (nrt->rt_refcnt <= 0) {
-				/* XXX: we should free the entry ourselves. */
-				nrt->rt_refcnt++;
-				rtfree(nrt);
-			}
-		} else {
-			/* the cmd must be RTM_ADD here */
-			nrt->rt_refcnt--;
-		}
-	}
-}
-
-/*
  * Add ownaddr as loopback rtentry.  We previously add the route only if
  * necessary (ex. on a p2p link).  However, since we now manage addresses
  * separately from prefixes, we should always add the route.  We can't
@@ -216,28 +152,21 @@ in6_ifloop_request(int cmd, struct ifadd
  * any more.
  */
 void
-in6_ifaddloop(struct ifaddr *ifa)
+in6_ifaddlocal(struct ifaddr *ifa)
 {
-	struct rtentry *rt;
 
-	/* If there is no loopback entry, allocate one. */
-	rt = rtalloc1(ifa->ifa_addr, 0);
-	if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
-	    (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
-		in6_ifloop_request(RTM_ADD, ifa);
-	if (rt != NULL)
-		rt->rt_refcnt--;
+	rt_ifa_addlocal(ifa);
 }
 
 /*
- * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
+ * Remove loopback rtentry of ownaddr generated by in6_ifaddlocal(),
  * if it exists.
  */
 void
-in6_ifremloop(struct ifaddr *ifa)
+in6_ifremlocal(struct ifaddr *ifa)
 {
-	struct in6_ifaddr *alt_ia = NULL, *ia;
-	struct rtentry *rt;
+	struct in6_ifaddr *ia;
+	struct ifaddr *alt_ifa = NULL;
 	int ia_count = 0;
 
 	/*
@@ -272,38 +201,15 @@ in6_ifremloop(struct ifaddr *ifa)
 		if (!IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr))
 			continue;
 		if (ia->ia_ifp != ifa->ifa_ifp)
-			alt_ia = ia;
-		if (++ia_count > 1 && alt_ia != NULL)
+			alt_ifa = &ia->ia_ifa;
+		if (++ia_count > 1 && alt_ifa != NULL)
 			break;
 	}
 
 	if (ia_count == 0)
 		return;
 
-	if ((rt = rtalloc1(ifa->ifa_addr, 0)) == NULL)
-		return;
-	rt->rt_refcnt--;
-
-	/*
-	 * Before deleting, check if a corresponding loopbacked
-	 * host route surely exists.  With this check, we can avoid
-	 * deleting an interface direct route whose destination is
-	 * the same as the address being removed.  This can happen
-	 * when removing a subnet-router anycast address on an
-	 * interface attached to a shared medium.
-	 */
-	if ((rt->rt_flags & RTF_HOST) == 0 ||
-	    (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
-		return;
-
-	/* If we cannot replace the route's ifaddr with the equivalent
-	 * ifaddr of another interface, I believe it is safest to
-	 * delete the route.
-	 */
-	if (ia_count == 1 || alt_ia == NULL)
-		in6_ifloop_request(RTM_DELETE, ifa);
-	else
-		rt_replace_ifa(rt, &alt_ia->ia_ifa);
+	rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
 }
 
 int
@@ -1383,7 +1289,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	}
 
 	/* Remove ownaddr's loopback rtentry, if it exists. */
-	in6_ifremloop(&(ia->ia_ifa));
+	in6_ifremlocal(&(ia->ia_ifa));
 
 	/*
 	 * leave from multicast groups we have joined for the interface
@@ -1781,8 +1687,9 @@ in6_ifinit(struct ifnet *ifp, struct in6
 	/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
 	if (newhost) {
 		/* set the rtrequest function to create llinfo */
-		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
-		in6_ifaddloop(&ia->ia_ifa);
+		if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+			ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+		in6_ifaddlocal(&ia->ia_ifa);
 	} else {
 		/* Inform the routing socket of new flags/timings */
 		rt_newaddrmsg(RTM_NEWADDR, &ia->ia_ifa, 0, NULL);

Index: src/sys/netinet6/in6_var.h
diff -u src/sys/netinet6/in6_var.h:1.71 src/sys/netinet6/in6_var.h:1.72
--- src/sys/netinet6/in6_var.h:1.71	Fri Sep  5 06:06:31 2014
+++ src/sys/netinet6/in6_var.h	Thu Feb 26 09:54:46 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_var.h,v 1.71 2014/09/05 06:06:31 matt Exp $	*/
+/*	$NetBSD: in6_var.h,v 1.72 2015/02/26 09:54:46 roy Exp $	*/
 /*	$KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $	*/
 
 /*
@@ -693,8 +693,8 @@ int	in6_if2idlen  (struct ifnet *);
 void	*in6_domifattach(struct ifnet *);
 void	in6_domifdetach(struct ifnet *, void *);
 void	in6_restoremkludge(struct in6_ifaddr *, struct ifnet *);
-void	in6_ifremloop(struct ifaddr *);
-void	in6_ifaddloop(struct ifaddr *);
+void	in6_ifremlocal(struct ifaddr *);
+void	in6_ifaddlocal(struct ifaddr *);
 void	in6_createmkludge(struct ifnet *);
 void	in6_purgemkludge(struct ifnet *);
 struct in6_ifaddr *in6ifa_ifpforlinklocal(const struct ifnet *, int);

Reply via email to