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.282
diff -u -p -r1.282 if.c
--- net/if.c 20 Mar 2014 13:19:06 -0000 1.282
+++ net/if.c 9 Apr 2014 13:31:06 -0000
@@ -1009,6 +1009,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.64
diff -u -p -r1.64 if_gif.c
--- net/if_gif.c 19 Oct 2013 14:46:30 -0000 1.64
+++ net/if_gif.c 9 Apr 2014 13:31:06 -0000
@@ -356,7 +356,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;
@@ -365,6 +366,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.64
diff -u -p -r1.64 if_gre.c
--- net/if_gre.c 19 Oct 2013 14:46:30 -0000 1.64
+++ net/if_gre.c 9 Apr 2014 13:31:06 -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.71
diff -u -p -r1.71 if_ppp.c
--- net/if_ppp.c 23 Oct 2013 15:12:42 -0000 1.71
+++ net/if_ppp.c 9 Apr 2014 13:31:06 -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 9 Apr 2014 13:31:06 -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.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 13:31:06 -0000
@@ -1010,7 +1010,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 +1024,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.121
diff -u -p -r1.121 if_tun.c
--- net/if_tun.c 30 Mar 2014 21:54:48 -0000 1.121
+++ net/if_tun.c 9 Apr 2014 13:31:06 -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.6
diff -u -p -r1.6 if_var.h
--- net/if_var.h 27 Mar 2014 10:39:23 -0000 1.6
+++ net/if_var.h 9 Apr 2014 13:31:06 -0000
@@ -501,6 +501,7 @@ struct ifaddr *ifa_ifwithroute(int, stru
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.123
diff -u -p -r1.123 if_ether.c
--- netinet/if_ether.c 27 Mar 2014 10:39:23 -0000 1.123
+++ netinet/if_ether.c 9 Apr 2014 13:31:06 -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.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 13:31:06 -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));
}
Index: netinet6/nd6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.113
diff -u -p -r1.113 nd6.c
--- netinet6/nd6.c 27 Mar 2014 10:39:23 -0000 1.113
+++ netinet6/nd6.c 9 Apr 2014 13:31:06 -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.