Diff below splits in_addprefix() into two functions, one for adding a
route to host (for point-to-point interfaces) and one for adding a
route prefix.

This simplifies a lot the RTF_* flags logic and will make it easier
to create routes to loopback in a near future.  The only difference
it introduces is that the (new) code to add a route to host no longer
check for an associated carp interface to move the route from/to it.

I'd also like to remove the magic to check if there's already a route
to the same destination, but that'll be for another diff.

ok?

Index: netinet/in.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in.c,v
retrieving revision 1.91
diff -u -p -r1.91 in.c
--- netinet/in.c        21 Jan 2014 10:18:26 -0000      1.91
+++ netinet/in.c        10 Mar 2014 12:38:20 -0000
@@ -94,8 +94,10 @@ int in_lifaddr_ioctl(struct socket *, u_
        struct ifnet *);
 
 void in_purgeaddr(struct ifaddr *);
-int in_addprefix(struct in_ifaddr *, int);
+int in_addprefix(struct in_ifaddr *);
 int in_scrubprefix(struct in_ifaddr *);
+int in_addhost(struct in_ifaddr *);
+int in_scrubhost(struct in_ifaddr *);
 
 /* Return 1 if an internet address is for a directly connected host */
 int
@@ -608,7 +610,10 @@ in_lifaddr_ioctl(struct socket *so, u_lo
 void
 in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
 {
-       in_scrubprefix(ia);
+       if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+               in_scrubprefix(ia);
+       else
+               in_scrubhost(ia);
 }
 
 /*
@@ -621,7 +626,7 @@ in_ifinit(struct ifnet *ifp, struct in_i
 {
        u_int32_t i = sin->sin_addr.s_addr;
        struct sockaddr_in oldaddr;
-       int s = splnet(), flags = RTF_UP, error = 0;
+       int s = splnet(), error = 0;
 
        if (newaddr)
                TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
@@ -681,13 +686,15 @@ in_ifinit(struct ifnet *ifp, struct in_i
                }
        } else if (ifp->if_flags & IFF_LOOPBACK) {
                ia->ia_dstaddr = ia->ia_addr;
-               flags |= RTF_HOST;
        } else if (ifp->if_flags & IFF_POINTOPOINT) {
                if (ia->ia_dstaddr.sin_family != AF_INET)
                        goto out;
-               flags |= RTF_HOST;
        }
-       error = in_addprefix(ia, flags);
+
+       if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+               error = in_addprefix(ia);
+       else
+               error = in_addhost(ia);
 
        /*
         * If the interface supports multicast, join the "all hosts"
@@ -739,51 +746,118 @@ in_purgeaddr(struct ifaddr *ifa)
        ifafree(&ia->ia_ifa);
 }
 
-#define rtinitflags(x) \
-       ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
-           ? RTF_HOST : 0)
+int
+in_addhost(struct in_ifaddr *ia0)
+{
+       struct in_ifaddr *ia;
+       struct in_addr dst;
+       int error;
+
+       dst = ia0->ia_dstaddr.sin_addr;
+
+       /*
+        * If an interface already have a route to the same
+        * destination don't do anything.
+        */
+       TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
+               if (ia->ia_ifp->if_rdomain != ia0->ia_ifp->if_rdomain)
+                       continue;
+
+               if (dst.s_addr != ia->ia_dstaddr.sin_addr.s_addr)
+                       continue;
+
+               if ((ia->ia_flags & IFA_ROUTE) == 0)
+                       continue;
+
+               return (0);
+       }
+
+       error = rtinit(&ia0->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST);
+       if (!error)
+               ia0->ia_flags |= IFA_ROUTE;
+
+       return (error);
+}
+
+int
+in_scrubhost(struct in_ifaddr *ia0)
+{
+       struct in_ifaddr *ia;
+       struct in_addr dst;
+       int error;
+
+       if ((ia0->ia_flags & IFA_ROUTE) == 0)
+               return (0);
+
+       dst = ia0->ia_dstaddr.sin_addr;
+
+       /*
+        * Because we only add one route for a given destination at
+        * a time, here we need to do some magic to move this route
+        * to another interface if it has the same destination.
+        */
+       TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
+               if (ia->ia_ifp->if_rdomain != ia0->ia_ifp->if_rdomain)
+                       continue;
+
+               if (dst.s_addr != ia->ia_dstaddr.sin_addr.s_addr)
+                       continue;
+
+               if ((ia->ia_flags & IFA_ROUTE) != 0)
+                       continue;
+
+               rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_HOST);
+               ia0->ia_flags &= ~IFA_ROUTE;
+               error = rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST);
+               if (!error)
+                       ia->ia_flags |= IFA_ROUTE;
+
+               return (error);
+       }
+
+       rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_HOST);
+       ia0->ia_flags &= ~IFA_ROUTE;
+
+       return (0);
+}
 
 /*
  * add a route to prefix ("connected route" in cisco terminology).
  * does nothing if there's some interface address with the same prefix already.
  */
 int
-in_addprefix(struct in_ifaddr *target, int flags)
+in_addprefix(struct in_ifaddr *ia0)
 {
        struct in_ifaddr *ia;
-       struct in_addr prefix, mask, p;
+       struct in_addr prefix, mask, p, m;
        int error;
 
-       if ((flags & RTF_HOST) != 0)
-               prefix = target->ia_dstaddr.sin_addr;
-       else {
-               prefix = target->ia_addr.sin_addr;
-               mask = target->ia_sockmask.sin_addr;
-               prefix.s_addr &= mask.s_addr;
-       }
+       prefix = ia0->ia_addr.sin_addr;
+       mask = ia0->ia_sockmask.sin_addr;
+       prefix.s_addr &= mask.s_addr;
 
        TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
-               if (ia->ia_ifp->if_rdomain != target->ia_ifp->if_rdomain)
+               if (ia->ia_ifp->if_rdomain != ia0->ia_ifp->if_rdomain)
                        continue;
-               if (rtinitflags(ia)) {
-                       p = ia->ia_dstaddr.sin_addr;
-                       if (prefix.s_addr != p.s_addr)
-                               continue;
-               } else {
-                       p = ia->ia_addr.sin_addr;
-                       p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
-                       if (prefix.s_addr != p.s_addr ||
-                           mask.s_addr != ia->ia_sockmask.sin_addr.s_addr)
-                               continue;
-               }
+
+               if ((ia->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
+                       continue;
+
                if ((ia->ia_flags & IFA_ROUTE) == 0)
                        continue;
+
+               p = ia->ia_addr.sin_addr;
+               m = ia->ia_sockmask.sin_addr;
+               p.s_addr &= m.s_addr;
+
+               if (prefix.s_addr != p.s_addr || mask.s_addr != m.s_addr)
+                       continue;
+
 #if NCARP > 0
                /* move to a real interface instead of carp interface */
                if (ia->ia_ifp->if_type == IFT_CARP &&
-                   target->ia_ifp->if_type != IFT_CARP) {
-                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE,
-                           rtinitflags(ia));
+                   ia0->ia_ifp->if_type != IFT_CARP) {
+                       rtinit(&ia->ia_ifa, RTM_DELETE, 0);
                        ia->ia_flags &= ~IFA_ROUTE;
                        break;
                }
@@ -798,9 +872,9 @@ in_addprefix(struct in_ifaddr *target, i
        /*
         * noone seem to have prefix route.  insert it.
         */
-       error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
+       error = rtinit(&ia0->ia_ifa, RTM_ADD, RTF_UP);
        if (!error)
-               target->ia_flags |= IFA_ROUTE;
+               ia0->ia_flags |= IFA_ROUTE;
        return error;
 }
 
@@ -810,64 +884,54 @@ in_addprefix(struct in_ifaddr *target, i
  * with the same prefix (otherwise we lose the route mistakenly).
  */
 int
-in_scrubprefix(struct in_ifaddr *target)
+in_scrubprefix(struct in_ifaddr *ia0)
 {
        struct in_ifaddr *ia;
        struct in_addr prefix, mask, p, m;
        int error;
 
-       if ((target->ia_flags & IFA_ROUTE) == 0)
+       if ((ia0->ia_flags & IFA_ROUTE) == 0)
                return 0;
 
-       if (rtinitflags(target)) {
-               prefix = target->ia_dstaddr.sin_addr;
-               mask.s_addr = INADDR_BROADCAST;
-       } else {
-               prefix = target->ia_addr.sin_addr;
-               mask = target->ia_sockmask.sin_addr;
-               prefix.s_addr &= mask.s_addr;
-       }
+       prefix = ia0->ia_addr.sin_addr;
+       mask = ia0->ia_sockmask.sin_addr;
+       prefix.s_addr &= mask.s_addr;
 
        TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
-               if (rtinitflags(ia)) {
-                       p = ia->ia_dstaddr.sin_addr;
-                       m.s_addr = INADDR_BROADCAST;
-               } else {
-                       p = ia->ia_addr.sin_addr;
-                       m = ia->ia_sockmask.sin_addr;
-                       p.s_addr &= m.s_addr;
-               }
+               if (ia->ia_ifp->if_rdomain != ia0->ia_ifp->if_rdomain)
+                       continue;
 
-               if (ia->ia_ifp->if_rdomain != target->ia_ifp->if_rdomain)
+               if ((ia->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
                        continue;
-               if (prefix.s_addr != p.s_addr ||
-                   mask.s_addr != m.s_addr)
+
+               if ((ia->ia_flags & IFA_ROUTE) != 0)
                        continue;
+
+               p = ia->ia_addr.sin_addr;
+               m = ia->ia_sockmask.sin_addr;
+               p.s_addr &= m.s_addr;
+
+               if (prefix.s_addr != p.s_addr || mask.s_addr != m.s_addr)
+                       continue;
+
                /*
                 * if we got a matching prefix route, move IFA_ROUTE to him
                 */
-               if ((ia->ia_flags & IFA_ROUTE) == 0) {
-                       rtinit(&(target->ia_ifa), (int)RTM_DELETE,
-                           rtinitflags(target));
-                       target->ia_flags &= ~IFA_ROUTE;
-
-                       error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
-                           rtinitflags(ia) | RTF_UP);
-                       if (error == 0)
-                               ia->ia_flags |= IFA_ROUTE;
-                       return error;
-               }
+               rtinit(&ia0->ia_ifa, RTM_DELETE, 0);
+               ia0->ia_flags &= ~IFA_ROUTE;
+               error = rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP);
+               if (error == 0)
+                       ia->ia_flags |= IFA_ROUTE;
+               return error;
        }
 
        /*
         * noone seem to have prefix route.  remove it.
         */
-       rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
-       target->ia_flags &= ~IFA_ROUTE;
+       rtinit(&ia0->ia_ifa, RTM_DELETE, 0);
+       ia0->ia_flags &= ~IFA_ROUTE;
        return 0;
 }
-
-#undef rtinitflags
 
 /*
  * Return 1 if the address might be a local broadcast address.

Reply via email to