When an IPv6 address is configured on a point-to-point interface, it
is associated to nd6_rtrequest().  This is because nd6_request()
contains a hack to automatically create a route to loopback for p2p
interfaces.

The resulting route looks like this:

fe80::300:245f:fedc:22f8%pppoe0    link#12                        HL         0  
      0     -     4 lo0  


I'd like to stop abusing nd6_rtrequest() for point-to-point interfaces
because I want to introduce a similar behavior for IPv4.  So the diff
below adds a sppp_rtrequest() function that works for both IPv4 and
IPv6 and creates a local route if the loopback interface has an address
of the same family.  This diff introduce a difference in the routing
table, see below, but it shouldn't matter.  The RTF_LLINFO flags is
necessary for ND6 or ARP, not for p2p interfaces.


-fe80::300:245f:fedc:22f8%pppoe0    link#12                        HL         0 
       0     -     4 lo0  
-2011:4b10:1003:ff::1               link#12                        HL         0 
       0     -     4 lo0  
+fe80::300:245f:fedc:22f8%pppoe0    ::1                            H          0 
       0     -     4 lo0  
+2011:4b10:1003:ff::1               ::1                            H          0 
       0     -     4 lo0  


ok?


Index: net/if_spppsubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.119
diff -u -p -r1.119 if_spppsubr.c
--- net/if_spppsubr.c   3 Apr 2014 06:06:56 -0000       1.119
+++ net/if_spppsubr.c   9 Apr 2014 09:03:05 -0000
@@ -242,6 +242,7 @@ static struct timeout keepalive_ch;
        struct ifnet *ifp = &sp->pp_if;                         \
        int debug = ifp->if_flags & IFF_DEBUG
 
+void sppp_rtrequest(int, struct rtentry *);
 int sppp_output(struct ifnet *ifp, struct mbuf *m,
                       struct sockaddr *dst, struct rtentry *rt);
 
@@ -1010,7 +1011,8 @@ sppp_pick(struct ifnet *ifp)
 int
 sppp_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
-       struct ifreq *ifr = (struct ifreq*) data;
+       struct ifreq *ifr = data;
+       struct ifaddr *ifa = data;
        struct sppp *sp = (struct sppp*) ifp;
        int s, rv, going_up, going_down, newmode;
 
@@ -1023,6 +1025,7 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
 
        case SIOCSIFADDR:
                if_up(ifp);
+               ifa->ifa_rtrequest = sppp_rtrequest;
                /* FALLTHROUGH */
 
        case SIOCSIFFLAGS:
@@ -1108,6 +1111,61 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
        return rv;
 }
 
+void
+sppp_rtrequest(int req, struct rtentry *rt)
+{
+       struct ifnet *ifp = rt->rt_ifp;
+       struct ifaddr *ifa, *lo0ifa;
+
+       switch (req) {
+       case RTM_ADD:
+               /*
+                * Here RTF_LLINFO means we're adding a route to
+                * loopback to always have an entry pointing to
+                * the address of the interface as destination.
+                */
+               if ((rt->rt_flags & RTF_LLINFO) == 0)
+                       break;
+
+               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+                       if (memcmp(rt_key(rt), ifa->ifa_addr,
+                           rt_key(rt)->sa_len) == 0)
+                               break;
+               }
+
+               if (ifa == NULL)
+                       break;
+
+               TAILQ_FOREACH(lo0ifa, &lo0ifp->if_addrlist, ifa_list)
+                       if (lo0ifa->ifa_addr->sa_family ==
+                           ifa->ifa_addr->sa_family)
+                               break;
+
+               if (lo0ifa == NULL)
+                       break;
+
+               rt_setgate(rt, rt_key(rt), lo0ifa->ifa_addr, ifp->if_rdomain);
+               rt->rt_ifp = lo0ifp;
+               rt->rt_flags &= ~RTF_LLINFO;
+
+               /*
+                * make sure to set rt->rt_ifa to the interface
+                * address we are using, otherwise we will have trouble
+                * with source address selection.
+                */
+               if (ifa != rt->rt_ifa) {
+                       ifafree(rt->rt_ifa);
+                       ifa->ifa_refcnt++;
+                       rt->rt_ifa = ifa;
+               }
+               break;
+
+       case RTM_DELETE:
+       case RTM_RESOLVE:
+       default:
+               break;
+       }
+}
 
 /*
  * Cisco framing implementation.
Index: netinet6/in6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
retrieving revision 1.134
diff -u -p -r1.134 in6.c
--- netinet6/in6.c      3 Apr 2014 08:22:10 -0000       1.134
+++ netinet6/in6.c      9 Apr 2014 09:03:05 -0000
@@ -1369,7 +1369,8 @@ in6_ifinit(struct ifnet *ifp, struct in6
                ifacount++;
        }
 
-       if ((ifacount <= 1 || ifp->if_type == IFT_CARP) && ifp->if_ioctl &&
+       if ((ifacount <= 1 || ifp->if_type == IFT_CARP ||
+           (ifp->if_flags & IFF_POINTOPOINT)) && ifp->if_ioctl &&
            (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia6))) {
                splx(s);
                return (error);
@@ -1396,7 +1397,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 */
-               ia6->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+                       ia6->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+
                rt_ifa_addloop(&(ia6->ia_ifa));
        }
 

Reply via email to