benno@ reported a kernel bug that makes ospfd(8) exit.  When a L2
entry is removed the message sent to userland no longer contains the
RTF_LLINFO flag.  This is inconsistent with what userland listeners
expect because the same entry has the flag when it is added.

The problem comes to the fact that routines resolving L2 caches:
arpresolve() and nd6_resolve() check for the RTF_LLINFO flag to
decide if they use or not an entry.  

Diff below makes them use rtisvalid(9) instead which check for the
RTF_UP flag.  This should make many "route contains no arp information"
messages disappear.

But I'm afraid this can expose another weird driver/NFS setup were non
UP routes are used, so I'd like a lot of testing especially in NFS
build clusters.

Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.231
diff -u -p -r1.231 if_ether.c
--- netinet/if_ether.c  11 Aug 2017 21:24:19 -0000      1.231
+++ netinet/if_ether.c  4 Nov 2017 14:00:09 -0000
@@ -212,7 +212,6 @@ arp_rtrequest(struct ifnet *ifp, int req
                        break;
                LIST_REMOVE(la, la_list);
                rt->rt_llinfo = NULL;
-               rt->rt_flags &= ~RTF_LLINFO;
                la_hold_total -= ml_purge(&la->la_ml);
                pool_put(&arp_pool, la);
                break;
@@ -323,6 +322,8 @@ arpresolve(struct ifnet *ifp, struct rte
        }
 
        rt = rt_getll(rt0);
+       if (!rtisvalid(rt))
+               return (EINVAL);
 
        if (ISSET(rt->rt_flags, RTF_REJECT) &&
            (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) {
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.221
diff -u -p -r1.221 nd6.c
--- netinet6/nd6.c      31 Oct 2017 22:05:13 -0000      1.221
+++ netinet6/nd6.c      4 Nov 2017 14:00:08 -0000
@@ -970,7 +970,6 @@ nd6_rtrequest(struct ifnet *ifp, int req
                TAILQ_REMOVE(&nd6_list, ln, ln_list);
                nd6_llinfo_settimer(ln, -1);
                rt->rt_llinfo = NULL;
-               rt->rt_flags &= ~RTF_LLINFO;
                m_freem(ln->ln_hold);
                pool_put(&nd6_pool, ln);
                break;
@@ -1308,6 +1307,8 @@ nd6_resolve(struct ifnet *ifp, struct rt
        }
 
        rt = rt_getll(rt0);
+       if (!rtisvalid(rt))
+               return (EINVAL);
 
        if (ISSET(rt->rt_flags, RTF_REJECT) &&
            (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) {

Reply via email to