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.