Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Introduce the routing flag RTF_LOCAL to track local addr...



details:   https://anonhg.NetBSD.org/src/rev/634d6c2fa097
branches:  trunk
changeset: 336339:634d6c2fa097
user:      roy <roy%NetBSD.org@localhost>
date:      Thu Feb 26 09:54:46 2015 +0000

description:
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.

diffstat:

 sys/net/route.c        |  131 +++++++++++++++++++++++++++++++++++++++++++++++-
 sys/net/route.h        |    5 +-
 sys/netinet/if_arp.c   |   15 +++-
 sys/netinet/in.c       |   56 ++++++++++++++++----
 sys/netinet/ip_carp.c  |    8 +-
 sys/netinet6/in6.c     |  123 +++++----------------------------------------
 sys/netinet6/in6_var.h |    6 +-
 7 files changed, 206 insertions(+), 138 deletions(-)

diffs (truncated from 603 to 300 lines):

diff -r 18dbabe375b9 -r 634d6c2fa097 sys/net/route.c
--- a/sys/net/route.c   Thu Feb 26 09:10:52 2015 +0000
+++ b/sys/net/route.c   Thu Feb 26 09:54:46 2015 +0000
@@ -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 @@
                ;
        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 @@
 
                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 @@
                        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
diff -r 18dbabe375b9 -r 634d6c2fa097 sys/net/route.h
--- a/sys/net/route.h   Thu Feb 26 09:10:52 2015 +0000
+++ b/sys/net/route.h   Thu Feb 26 09:54:46 2015 +0000
@@ -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 @@
 #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_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 *);
 
diff -r 18dbabe375b9 -r 634d6c2fa097 sys/netinet/if_arp.c
--- a/sys/netinet/if_arp.c      Thu Feb 26 09:10:52 2015 +0000
+++ b/sys/netinet/if_arp.c      Thu Feb 26 09:54:46 2015 +0000
@@ -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 @@
        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 @@
                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 @@
                            }
 #endif
                        }
-                       break;
+                       if (rt->rt_flags & RTF_CLONING)
+                               break;
                }
                /* Announce a new entry if requested. */
                if (rt->rt_flags & RTF_ANNOUNCE) {
diff -r 18dbabe375b9 -r 634d6c2fa097 sys/netinet/in.c
--- a/sys/netinet/in.c  Thu Feb 26 09:10:52 2015 +0000
+++ b/sys/netinet/in.c  Thu Feb 26 09:54:46 2015 +0000
@@ -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 @@
        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;
+       }
+



Home | Main Index | Thread Index | Old Index