route: Seperate route messages from creation/lookup.
authorRoy Marples <roy@marples.name>
Sun, 8 Sep 2019 10:56:18 +0000 (11:56 +0100)
committerRoy Marples <roy@marples.name>
Sun, 8 Sep 2019 10:56:18 +0000 (11:56 +0100)
This allows a more fine grained choice about whether to announce
messsages via route(4) or not.

For example, a freshly added clone route is useless without the
resolved hardware address it's talking to.
Instead, announce the route when the hardware address has
been resolved, changed or if it's not resolvable.

For IPv6 destinations, we can now interpret RTM_MISS as unreachable.
This allows listening software to take action, such as soliciting
a new router if the destination missed was originally a router.

Reviewed-by: sephe
sys/net/route.c
sys/net/route.h
sys/net/rtsock.c
sys/netinet/if_ether.c
sys/netinet6/nd6.c

index e2e007b..763bf98 100644 (file)
@@ -220,7 +220,7 @@ rtalloc_ign(struct route *ro, u_long ignoreflags)
                rtfree(ro->ro_rt);
                ro->ro_rt = NULL;
        }
-       ro->ro_rt = _rtlookup(&ro->ro_dst, RTL_REPORTMSG, ignoreflags);
+       ro->ro_rt = _rtlookup(&ro->ro_dst, ignoreflags);
 }
 
 /*
@@ -233,7 +233,7 @@ rtalloc_ign(struct route *ro, u_long ignoreflags)
  * Any route returned has its reference count incremented.
  */
 struct rtentry *
-_rtlookup(struct sockaddr *dst, boolean_t generate_report, u_long ignore)
+_rtlookup(struct sockaddr *dst, u_long ignore)
 {
        struct radix_node_head *rnh = rt_tables[mycpuid][dst->sa_family];
        struct rtentry *rt;
@@ -261,18 +261,12 @@ _rtlookup(struct sockaddr *dst, boolean_t generate_report, u_long ignore)
                error = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0,
                                  &clonedroute);        /* clone the route */
                if (error != 0) {       /* cloning failed */
-                       if (generate_report)
-                               rt_dstmsg(RTM_MISS, dst, error);
+                       rt_dstmsg(RTM_MISS, dst, error);
                        rt->rt_refcnt++;
                        return (rt);    /* return the uncloned route */
                }
-               if (generate_report) {
-                       if (clonedroute->rt_flags & RTF_XRESOLVE)
-                               rt_dstmsg(RTM_RESOLVE, dst, 0);
-                       else
-                               rt_rtmsg(RTM_ADD, clonedroute,
-                                        clonedroute->rt_ifp, 0);
-               }
+               if (clonedroute->rt_flags & RTF_XRESOLVE)
+                       rt_dstmsg(RTM_RESOLVE, dst, 0);
                return (clonedroute);   /* return cloned route */
        }
 
@@ -284,8 +278,7 @@ _rtlookup(struct sockaddr *dst, boolean_t generate_report, u_long ignore)
 
 unreach:
        rtstat.rts_unreach++;
-       if (generate_report)
-               rt_dstmsg(RTM_MISS, dst, 0);
+       rt_dstmsg(RTM_MISS, dst, 0);
        return (NULL);
 }
 
@@ -429,8 +422,9 @@ create:
                flags |= RTF_MODIFIED;
 
                /* We only need to report rtmsg on CPU0 */
-               rt_setgate(rt, rt_key(rt), gateway,
-                          mycpuid == 0 ? RTL_REPORTMSG : RTL_DONTREPORT);
+               rt_setgate(rt, rt_key(rt), gateway);
+               if (mycpuid == 0)
+                       rt_rtmsg(RTM_CHANGE, rt, rt->rt_ifp, 0);
                error = 0;
                stat = &rtstat.rts_newgateway;
        }
@@ -744,7 +738,6 @@ rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
        struct radix_node_head *rnh;
        struct ifaddr *ifa;
        struct sockaddr *ndst;
-       boolean_t reportmsg;
        int error = 0;
 
        ASSERT_NETISR_NCPUS(mycpuid);
@@ -873,18 +866,7 @@ makeroute:
                rt->rt_flags = RTF_UP | rtinfo->rti_flags;
                rt->rt_cpuid = mycpuid;
 
-               if (mycpuid != 0 && req == RTM_ADD) {
-                       /* For RTM_ADD, we have already sent rtmsg on CPU0. */
-                       reportmsg = RTL_DONTREPORT;
-               } else {
-                       /*
-                        * For RTM_ADD, we only send rtmsg on CPU0.
-                        * For RTM_RESOLVE, we always send rtmsg. XXX
-                        */
-                       reportmsg = RTL_REPORTMSG;
-               }
-               error = rt_setgate(rt, dst, rtinfo->rti_info[RTAX_GATEWAY],
-                                  reportmsg);
+               error = rt_setgate(rt, dst, rtinfo->rti_info[RTAX_GATEWAY]);
                if (error != 0) {
                        Free(rt);
                        gotoerr(error);
@@ -1153,8 +1135,7 @@ rt_fixchange(struct radix_node *rn, void *vp)
 }
 
 int
-rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate,
-          boolean_t generate_report)
+rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate)
 {
        char *space, *oldspace;
        int dlen = RT_ROUNDUP(dst->sa_len), glen = RT_ROUNDUP(gate->sa_len);
@@ -1237,8 +1218,7 @@ rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate,
                 *
                 * This breaks TTCP for hosts outside the gateway!  XXX JH
                 */
-               rt->rt_gwroute = _rtlookup(gate, generate_report,
-                                          RTF_PRCLONING);
+               rt->rt_gwroute = _rtlookup(gate, RTF_PRCLONING);
                if (rt->rt_gwroute == rt) {
                        rt->rt_gwroute = NULL;
                        --rt->rt_refcnt;
index 363ee5a..27660f5 100644 (file)
@@ -354,15 +354,12 @@ void       rt_missmsg (int, struct rt_addrinfo *, int, int);
 void    rt_newaddrmsg (int, struct ifaddr *, int, struct rtentry *);
 void    rt_newmaddrmsg (int, struct ifmultiaddr *);
 void    rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error);
-int     rt_setgate (struct rtentry *,
-           struct sockaddr *, struct sockaddr *, boolean_t);
+int     rt_setgate (struct rtentry *, struct sockaddr *, struct sockaddr *);
 void    rtalloc (struct route *);
 void    rtalloc_ign (struct route *, u_long);
 
 struct rtentry *
-        _rtlookup (struct sockaddr *, __boolean_t, u_long);
-#define                RTL_REPORTMSG   TRUE
-#define                RTL_DONTREPORT  FALSE
+        _rtlookup (struct sockaddr *, u_long);
 
 /* flags to ignore */
 #define                RTL_DOCLONE     0UL
@@ -374,7 +371,7 @@ struct rtentry *
 static __inline struct rtentry *
 rtpurelookup(struct sockaddr *dst)
 {
-       return _rtlookup(dst, RTL_DONTREPORT, RTL_DONTCLONE);
+       return _rtlookup(dst, RTL_DONTCLONE);
 }
 
 /*
@@ -383,7 +380,7 @@ rtpurelookup(struct sockaddr *dst)
 static __inline struct rtentry *
 rtlookup(struct sockaddr *dst)
 {
-       return _rtlookup(dst, RTL_REPORTMSG, RTL_DOCLONE);
+       return _rtlookup(dst, RTL_DOCLONE);
 }
 
 typedef void (*rtrequest1_callback_func_t)(int, int, struct rt_addrinfo *,
index 232cd74..43d48c1 100644 (file)
@@ -823,8 +823,7 @@ route_output_change_callback(int cmd, struct rt_addrinfo *rtinfo,
                 * We only need to generate rtmsg upon the
                 * first route to be changed.
                 */
-               error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway,
-                       found_cnt == 1 ? RTL_REPORTMSG : RTL_DONTREPORT);
+               error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway);
                if (error != 0)
                        goto done;
        }
@@ -855,6 +854,8 @@ route_output_change_callback(int cmd, struct rt_addrinfo *rtinfo,
                }
        }
        rtm->rtm_index = rt->rt_ifp->if_index;
+       if (found_cnt == 1)
+               rt_rtmsg(RTM_CHANGE, rt, rt->rt_ifp, 0);
 done:
        return error;
 }
@@ -1176,7 +1177,8 @@ rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error)
                rtinfo.rti_ifpaddr =
                TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
        }
-       rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
+       if (rt->rt_ifa != NULL)
+               rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
 
        m = rt_msg_mbuf(cmd, &rtinfo);
        if (m == NULL)
index c6a4b5a..9881500 100644 (file)
@@ -162,7 +162,7 @@ static void arpintr(netmsg_t msg);
 static void    arptfree(struct llinfo_arp *);
 static void    arptimer(void *);
 static struct llinfo_arp *
-               arplookup(in_addr_t, boolean_t, boolean_t, boolean_t);
+               arplookup(in_addr_t, boolean_t, boolean_t);
 #ifdef INET
 static void    in_arpinput(struct mbuf *);
 static void    in_arpreply(struct mbuf *m, in_addr_t, in_addr_t);
@@ -246,8 +246,7 @@ arp_rtrequest(int req, struct rtentry *rt)
                         * Case 1: This route should come from a route to iface.
                         */
                        rt_setgate(rt, rt_key(rt),
-                                  (struct sockaddr *)&null_sdl,
-                                  RTL_DONTREPORT);
+                                  (struct sockaddr *)&null_sdl);
                        gate = rt->rt_gateway;
                        SDL(gate)->sdl_type = rt->rt_ifp->if_type;
                        SDL(gate)->sdl_index = rt->rt_ifp->if_index;
@@ -529,8 +528,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
                la = rt->rt_llinfo;
        }
        if (la == NULL) {
-               la = arplookup(SIN(dst)->sin_addr.s_addr,
-                              TRUE, RTL_REPORTMSG, FALSE);
+               la = arplookup(SIN(dst)->sin_addr.s_addr, TRUE, FALSE);
                if (la != NULL)
                        rt = la->la_rt;
        }
@@ -599,6 +597,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
                                rt->rt_expire += arpt_down;
                                la->la_asked = 0;
                                la->la_preempt = arp_maxtries;
+                               rt_rtmsg(RTM_MISS, rt, rt->rt_ifp, 0);
                        }
                }
        }
@@ -691,7 +690,7 @@ SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_creation_failure, CTLFLAG_RW,
  */
 static int
 arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
-                boolean_t generate_report, boolean_t dologging)
+                boolean_t dologging)
 {
        struct arphdr *ah = mtod(m, struct arphdr *);
        struct ifnet *ifp = m->m_pkthdr.rcvif;
@@ -705,9 +704,11 @@ arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
        KASSERT(curthread->td_type == TD_TYPE_NETISR,
            ("arp update not in netisr"));
 
-       la = arplookup(saddr, create, generate_report, FALSE);
+       la = arplookup(saddr, create, FALSE);
        if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
                struct in_addr isaddr = { saddr };
+               int rt_cmd = sdl->sdl_alen == 0 ? RTM_ADD : RTM_CHANGE;
+               bool do_rtmsg = false;
 
                /*
                 * Normally arps coming in on the wrong interface are ignored,
@@ -760,10 +761,12 @@ arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
                        if (sdl->sdl_type != ifp->if_type) {
                                sdl->sdl_type = ifp->if_type;
                                changed = 1;
+                               do_rtmsg = true;
                        }
                        if (sdl->sdl_index != ifp->if_index) {
                                sdl->sdl_index = ifp->if_index;
                                changed = 1;
+                               do_rtmsg = true;
                        }
                }
                if (sdl->sdl_alen &&
@@ -791,6 +794,7 @@ arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
                                }
                                return changed;
                        }
+                       do_rtmsg = true;
                }
                /*
                 * sanity check for the address length.
@@ -815,6 +819,8 @@ arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
                        }
                        return changed;
                }
+               if (sdl->sdl_alen == 0)
+                       do_rtmsg = true;
                memcpy(LLADDR(sdl), ar_sha(ah), sdl->sdl_alen = ah->ar_hln);
                if (rt->rt_expire != 0) {
                        if (rt->rt_expire != time_uptime + arpt_keep &&
@@ -848,6 +854,9 @@ arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
                        ifp->if_output(ifp, m, rt_key(rt), rt);
                        changed = 1;
                }
+
+               if (do_rtmsg && mycpuid == 0)
+                       rt_rtmsg(rt_cmd, rt, rt->rt_ifp, 0);
        }
        return changed;
 }
@@ -1056,7 +1065,7 @@ match:
        ASSERT_NETISR0;
        changed = arp_update_oncpu(m, isaddr.s_addr,
                                   itaddr.s_addr == myaddr.s_addr,
-                                  RTL_REPORTMSG, TRUE);
+                                  TRUE);
 
        if (netisr_ncpus > 1 && changed) {
                struct netmsg_inarp *msg = &m->m_hdr.mh_arpmsg;
@@ -1106,7 +1115,7 @@ arp_update_msghandler(netmsg_t msg)
        KASSERT(mycpuid > 0, ("arp update msg on cpu%d", mycpuid));
        arp_update_oncpu(rmsg->m, rmsg->saddr,
                         rmsg->taddr == rmsg->myaddr,
-                        RTL_DONTREPORT, FALSE);
+                        FALSE);
 
        nextcpu = mycpuid + 1;
        if (nextcpu < netisr_ncpus) {
@@ -1161,7 +1170,7 @@ in_arpreply(struct mbuf *m, in_addr_t taddr, in_addr_t myaddr)
                struct llinfo_arp *la;
                struct rtentry *rt;
 
-               la = arplookup(taddr, FALSE, RTL_DONTREPORT, SIN_PROXY);
+               la = arplookup(taddr, FALSE, SIN_PROXY);
                if (la == NULL) {
                        struct sockaddr_in sin;
 #ifdef DEBUG_PROXY
@@ -1248,8 +1257,9 @@ in_arpreply(struct mbuf *m, in_addr_t taddr, in_addr_t myaddr)
 static void
 arptfree(struct llinfo_arp *la)
 {
-       struct rtentry *rt = la->la_rt;
+       struct rtentry *rt = la->la_rt, *nrt;
        struct sockaddr_dl *sdl;
+       int error;
 
        if (rt == NULL)
                panic("arptfree");
@@ -1262,14 +1272,18 @@ arptfree(struct llinfo_arp *la)
                rt->rt_flags &= ~RTF_REJECT;
                return;
        }
-       rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL);
+       error = rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, &nrt);
+       if (error == 0 && nrt != NULL) {
+               rt_rtmsg(RTM_DELETE, nrt, nrt->rt_ifp, 0);
+               rtfree(nrt);
+       }
 }
 
 /*
  * Lookup or enter a new address in arptab.
  */
 static struct llinfo_arp *
-arplookup(in_addr_t addr, boolean_t create, boolean_t generate_report,
+arplookup(in_addr_t addr, boolean_t create,
          boolean_t proxy)
 {
        struct rtentry *rt;
@@ -1283,8 +1297,7 @@ arplookup(in_addr_t addr, boolean_t create, boolean_t generate_report,
        sin.sin_addr.s_addr = addr;
        sin.sin_other = proxy ? SIN_PROXY : 0;
        if (create) {
-               rt = _rtlookup((struct sockaddr *)&sin,
-                              generate_report, RTL_DOCLONE);
+               rt = rtlookup((struct sockaddr *)&sin);
        } else {
                rt = rtpurelookup((struct sockaddr *)&sin);
        }
index fbf2d52..845ec67 100644 (file)
@@ -499,6 +499,7 @@ nd6_timer_dispatch(netmsg_t nmsg)
                                                    ICMP6_DST_UNREACH_ADDR, 0);
                                        ln->ln_hold = NULL;
                                }
+                               rt_rtmsg(RTM_MISS, rt, rt->rt_ifp, 0);
                                next = nd6_free(rt);
                        }
                        break;
@@ -1004,6 +1005,8 @@ nd6_free(struct rtentry *rt)
        struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
        struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
        struct nd_defrouter *dr;
+       int error;
+       struct rtentry *nrt = NULL;
 
        /*
         * we used to have kpfctlinput(PRC_HOSTDEAD) here.
@@ -1079,7 +1082,15 @@ nd6_free(struct rtentry *rt)
         * caches, and disable the route entry not to be used in already
         * cached routes.
         */
-       rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL);
+       error = rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, &nrt);
+       if (error == 0 && nrt != NULL) {
+               struct sockaddr_dl *sdl;
+
+               sdl = (struct sockaddr_dl *)nrt->rt_gateway;
+               if (sdl->sdl_alen != 0)
+                       rt_rtmsg(RTM_DELETE, nrt, nrt->rt_ifp, 0);
+               rtfree(nrt);
+       }
 
        return (next);
 }
@@ -1194,8 +1205,7 @@ nd6_rtrequest(int req, struct rtentry *rt)
                         * treated as on-link.
                         */
                        rt_setgate(rt, rt_key(rt),
-                                  (struct sockaddr *)&null_sdl,
-                                  RTL_DONTREPORT);
+                                  (struct sockaddr *)&null_sdl);
                        gate = rt->rt_gateway;
                        SDL(gate)->sdl_type = ifp->if_type;
                        SDL(gate)->sdl_index = ifp->if_index;
@@ -1814,6 +1824,9 @@ fail:
                break;
        }
 
+       if (llchange || lladdr)
+               rt_rtmsg(llchange ? RTM_CHANGE : RTM_ADD, rt, rt->rt_ifp, 0);
+
        /*
         * When the link-layer address of a router changes, select the
         * best router again.  In particular, when the neighbor entry is newly