So, I'm resending this diff since the previous bug has been fixed,
still looking for oks.

On 09/04/14(Wed) 11:22, Martin Pieuchot wrote:
> 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  

Here's an updated diff that addresses some points raised by claudio@:
  - Support all the p2p interfaces but mpe(4) (should I include it?)
  - Add comment about lo0 vs rdomain in {p2p,arp,nd6}_rtrequest().

Index: net/if.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if.c,v
retrieving revision 1.286
diff -u -p -r1.286 if.c
--- net/if.c    22 Apr 2014 12:35:00 -0000      1.286
+++ net/if.c    29 Apr 2014 14:22:28 -0000
@@ -990,6 +990,71 @@ link_rtrequest(int cmd, struct rtentry *
 }
 
 /*
+ * Default action when installing a local route on a point-to-point
+ * interface.
+ */
+void
+p2p_rtrequest(int req, struct rtentry *rt)
+{
+       struct ifnet *ifp = rt->rt_ifp;
+       struct ifaddr *ifa, *lo0ifa;
+
+       switch (req) {
+       case RTM_ADD:
+               /*
+                * XXX Here we abuse RTF_LLINFO to add a route to
+                * loopback.  We do that to always have a route
+                * pointing to our address.
+                */
+               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;
+
+               /*
+                * XXX Since lo0 is in the default rdomain we should not
+                * (ab)use it for any route related to an interface of a
+                * different rdomain.
+                */
+               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;
+       }
+}
+
+
+/*
  * Bring down all interfaces
  */
 void
Index: net/if_gif.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_gif.c,v
retrieving revision 1.66
diff -u -p -r1.66 if_gif.c
--- net/if_gif.c        21 Apr 2014 12:22:25 -0000      1.66
+++ net/if_gif.c        29 Apr 2014 14:22:28 -0000
@@ -354,7 +354,8 @@ int
 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
        struct gif_softc *sc  = (struct gif_softc*)ifp;
-       struct ifreq     *ifr = (struct ifreq*)data;
+       struct ifreq     *ifr = (struct ifreq *)data;
+       struct ifaddr    *ifa = (struct ifaddr *)data;
        int error = 0, size;
        struct sockaddr *dst, *src;
        struct sockaddr *sa;
@@ -363,6 +364,7 @@ gif_ioctl(struct ifnet *ifp, u_long cmd,
 
        switch (cmd) {
        case SIOCSIFADDR:
+               ifa->ifa_rtrequest = p2p_rtrequest;
                break;
 
        case SIOCSIFDSTADDR:
Index: net/if_gre.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_gre.c,v
retrieving revision 1.67
diff -u -p -r1.67 if_gre.c
--- net/if_gre.c        21 Apr 2014 12:22:25 -0000      1.67
+++ net/if_gre.c        29 Apr 2014 14:22:28 -0000
@@ -441,7 +441,8 @@ int
 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
 
-       struct ifreq *ifr = (struct ifreq *) data;
+       struct ifreq *ifr = (struct ifreq *)data;
+       struct ifaddr *ifa = (struct ifaddr *)data;
        struct if_laddrreq *lifr = (struct if_laddrreq *)data;
        struct ifkalivereq *ikar = (struct ifkalivereq *)data;
        struct gre_softc *sc = ifp->if_softc;
@@ -455,6 +456,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
        switch(cmd) {
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
+               ifa->ifa_rtrequest = p2p_rtrequest;
                break;
        case SIOCSIFDSTADDR:
                break;
Index: net/if_ppp.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_ppp.c,v
retrieving revision 1.73
diff -u -p -r1.73 if_ppp.c
--- net/if_ppp.c        19 Apr 2014 12:08:10 -0000      1.73
+++ net/if_ppp.c        29 Apr 2014 14:22:28 -0000
@@ -619,6 +619,7 @@ pppsioctl(struct ifnet *ifp, u_long cmd,
     case SIOCSIFADDR:
        if (ifa->ifa_addr->sa_family != AF_INET)
            error = EAFNOSUPPORT;
+       ifa->ifa_rtrequest = p2p_rtrequest;
        break;
 
     case SIOCSIFDSTADDR:
Index: net/if_pppx.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_pppx.c,v
retrieving revision 1.29
diff -u -p -r1.29 if_pppx.c
--- net/if_pppx.c       8 Apr 2014 04:26:53 -0000       1.29
+++ net/if_pppx.c       29 Apr 2014 14:22:28 -0000
@@ -1094,10 +1094,14 @@ pppx_if_ioctl(struct ifnet *ifp, u_long 
 {
        struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
        struct ifreq *ifr = (struct ifreq *)addr;
+       struct ifaddr *ifa = (struct ifaddr *)addr;
        int error = 0;
 
        switch (cmd) {
        case SIOCSIFADDR:
+               ifa->ifa_rtrequest = p2p_rtrequest;
+               break;
+
        case SIOCSIFFLAGS:
                break;
 
Index: net/if_spppsubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.121
diff -u -p -r1.121 if_spppsubr.c
--- net/if_spppsubr.c   19 Apr 2014 12:12:02 -0000      1.121
+++ net/if_spppsubr.c   29 Apr 2014 14:22:28 -0000
@@ -996,7 +996,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;
 
@@ -1009,6 +1010,7 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
 
        case SIOCSIFADDR:
                if_up(ifp);
+               ifa->ifa_rtrequest = p2p_rtrequest;
                /* FALLTHROUGH */
 
        case SIOCSIFFLAGS:
Index: net/if_tun.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_tun.c,v
retrieving revision 1.124
diff -u -p -r1.124 if_tun.c
--- net/if_tun.c        22 Apr 2014 14:41:03 -0000      1.124
+++ net/if_tun.c        29 Apr 2014 14:22:28 -0000
@@ -469,6 +469,7 @@ tun_ioctl(struct ifnet *ifp, u_long cmd,
 {
        struct tun_softc        *tp = (struct tun_softc *)(ifp->if_softc);
        struct ifreq            *ifr = (struct ifreq *)data;
+       struct ifaddr           *ifa = (struct ifaddr *)data;
        int                      error = 0, s;
 
        s = splnet();
@@ -477,16 +478,19 @@ tun_ioctl(struct ifnet *ifp, u_long cmd,
        case SIOCSIFADDR:
                tuninit(tp);
                TUNDEBUG(("%s: address set\n", ifp->if_xname));
-               if (tp->tun_flags & TUN_LAYER2)
-                       switch (((struct ifaddr *)data)->ifa_addr->sa_family) {
+               if (tp->tun_flags & TUN_LAYER2) {
+                       switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
                        case AF_INET:
-                               arp_ifinit(&tp->arpcom, (struct ifaddr *)data);
+                               arp_ifinit(&tp->arpcom, ifa);
                                break;
 #endif
                        default:
                                break;
                        }
+               } else {
+                       ifa->ifa_rtrequest = p2p_rtrequest;
+               }
                break;
        case SIOCSIFDSTADDR:
                tuninit(tp);
Index: net/if_var.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_var.h,v
retrieving revision 1.9
diff -u -p -r1.9 if_var.h
--- net/if_var.h        23 Apr 2014 09:30:57 -0000      1.9
+++ net/if_var.h        29 Apr 2014 14:22:28 -0000
@@ -428,6 +428,7 @@ struct      ifaddr *ifa_ifwithnet(struct sock
 struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);
 void   ifafree(struct ifaddr *);
 void   link_rtrequest(int, struct rtentry *);
+void   p2p_rtrequest(int, struct rtentry *);
 
 void   if_clone_attach(struct if_clone *);
 void   if_clone_detach(struct if_clone *);
Index: netinet/if_ether.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.125
diff -u -p -r1.125 if_ether.c
--- netinet/if_ether.c  14 Apr 2014 09:06:42 -0000      1.125
+++ netinet/if_ether.c  29 Apr 2014 14:22:28 -0000
@@ -254,6 +254,12 @@ arp_rtrequest(int req, struct rtentry *r
                        SDL(gate)->sdl_alen = ETHER_ADDR_LEN;
                        memcpy(LLADDR(SDL(gate)),
                            ((struct arpcom *)ifp)->ac_enaddr, ETHER_ADDR_LEN);
+
+                       /*
+                        * XXX Since lo0 is in the default rdomain we
+                        * should not (ab)use it for any route related
+                        * to an interface of a different rdomain.
+                        */
                        if (useloopback)
                                rt->rt_ifp = lo0ifp;
                        /*
Index: netinet6/in6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
retrieving revision 1.135
diff -u -p -r1.135 in6.c
--- netinet6/in6.c      10 Apr 2014 13:47:21 -0000      1.135
+++ netinet6/in6.c      29 Apr 2014 14:22:28 -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);
@@ -1398,7 +1399,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));
        }
 
Index: netinet6/nd6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.114
diff -u -p -r1.114 nd6.c
--- netinet6/nd6.c      14 Apr 2014 09:06:42 -0000      1.114
+++ netinet6/nd6.c      29 Apr 2014 14:22:28 -0000
@@ -1157,8 +1157,14 @@ nd6_rtrequest(int req, struct rtentry *r
                                memcpy(LLADDR(SDL(gate)), macp, 
ifp->if_addrlen);
                                SDL(gate)->sdl_alen = ifp->if_addrlen;
                        }
+
+                       /*
+                        * XXX Since lo0 is in the default rdomain we
+                        * should not (ab)use it for any route related
+                        * to an interface of a different rdomain.
+                        */
                        if (nd6_useloopback) {
-                               rt->rt_ifp = lo0ifp;    /*XXX*/
+                               rt->rt_ifp = lo0ifp;
                                /*
                                 * Make sure rt_ifa be equal to the ifaddr
                                 * corresponding to the address.

Reply via email to