On Sat, Jan 21, 2017 at 07:31:20AM +0100, Claudio Jeker wrote:
> On Sat, Jan 21, 2017 at 01:28:02AM +0100, Claudio Jeker wrote:
> > On Fri, Jan 20, 2017 at 02:51:52AM +0100, Claudio Jeker wrote:
> > > I sent this diff out some time ago and would really like to get this in.
> > > This is one step on makeing rtsock.c less of a hornets nest.
> > > This reduces the side effects in route_output and simplifies some other
> > > bits as well. For example route_input is less variadic and simpler.
> > > 
> > 
> > Here is just the route_input change. Which should be easier to OK.
> > Changed a few things based on input from bluhm@
> > 
> 
> Next piece of the puzzle. Cleanup the error handling a bit.
> If the route message is not valid (syntactically or also because it
> references bad things) fail without broadcasting this message to all
> listeners. So make sure that until the info struct has been checked we only
> use goto fail instead of goto flush.
> While there remove some redundant checks which are not needed.
> 

Last bit for now. This is changing the reporting madness. It moves it in
its own function which is called after the big switch statement.
If you hit a bad error in the switch the code should eiter goto fail or
flush. 
The new function rt_report is actually constructing the rt message out of
a rtentry. It does not magically update the message that was passed in
from userland. I think this is much safer and works better.

The diff is maybe hard to read because big chunks of code got moved
around.

With this the side effects happening in route_output are mostly gone I
think.
-- 
:wq Claudio

Index: net/rtsock.c
===================================================================
RCS file: /cvs/src/sys/net/rtsock.c,v
retrieving revision 1.216
diff -u -p -r1.216 rtsock.c
--- net/rtsock.c        22 Jan 2017 04:31:02 -0000      1.216
+++ net/rtsock.c        22 Jan 2017 05:02:42 -0000
@@ -459,30 +459,94 @@ route_input(struct mbuf *m0, sa_family_t
                m_freem(m);
 }
 
+struct rt_msghdr *
+rt_report(struct rtentry *rt, u_char type, int seq, int tableid)
+{
+       struct rt_msghdr        *rtm;
+       struct rt_addrinfo       info;
+       struct sockaddr_rtlabel  sa_rl;
+       struct sockaddr_in6      sa_mask;
+#ifdef BFD
+       struct sockaddr_bfd      sa_bfd;
+#endif
+#ifdef MPLS
+       struct sockaddr_mpls     sa_mpls;
+#endif
+       struct ifnet            *ifp = NULL;
+       int                      len;
+
+       bzero(&info, sizeof(info));
+       info.rti_info[RTAX_DST] = rt_key(rt);
+       info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+       info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
+       info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl);
+#ifdef BFD
+       if (rt->rt_flags & RTF_BFD)
+               info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd);
+#endif
+#ifdef MPLS
+       if (rt->rt_flags & RTF_MPLS) {
+               bzero(&sa_mpls, sizeof(sa_mpls));
+               sa_mpls.smpls_family = AF_MPLS;
+               sa_mpls.smpls_len = sizeof(sa_mpls);
+               sa_mpls.smpls_label = ((struct rt_mpls *)
+                   rt->rt_llinfo)->mpls_label;
+               info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls;
+               info.rti_mpls = ((struct rt_mpls *)
+                   rt->rt_llinfo)->mpls_operation;
+       }
+#endif
+       ifp = if_get(rt->rt_ifidx);
+       if (ifp != NULL) {
+               info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
+               info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
+               if (ifp->if_flags & IFF_POINTOPOINT)
+                       info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr;
+       }
+       if_put(ifp);
+       /* RTAX_GENMASK, RTAX_AUTHOR, RTAX_SRCMASK ignored */
+
+       /* build new route message */
+       len = rt_msg2(type, RTM_VERSION, &info, NULL, NULL);
+       /* XXX why can't we wait? Should be process context... */
+       rtm = malloc(len, M_RTABLE, M_NOWAIT | M_ZERO);
+       if (rtm == NULL)
+               return NULL;
+
+       rt_msg2(type, RTM_VERSION, &info, (caddr_t)rtm, NULL);
+       rtm->rtm_type = type;
+       rtm->rtm_index = rt->rt_ifidx;
+       rtm->rtm_tableid = tableid;
+       rtm->rtm_priority = rt->rt_priority & RTP_MASK;
+       rtm->rtm_flags = rt->rt_flags;
+       rtm->rtm_pid = curproc->p_p->ps_pid;
+       rtm->rtm_seq = seq;
+       rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
+       rtm->rtm_addrs = info.rti_addrs;
+#ifdef MPLS
+       rtm->rtm_mpls = info.rti_mpls;
+#endif
+       return rtm;
+}
+
 int
 route_output(struct mbuf *m, ...)
 {
        struct rt_msghdr        *rtm = NULL;
        struct rtentry          *rt = NULL;
-       struct rtentry          *saved_nrt = NULL;
        struct rt_addrinfo       info;
-       int                      plen, len, newgate = 0, error = 0;
+       int                      plen, len, seq, newgate = 0, error = 0;
        struct ifnet            *ifp = NULL;
        struct ifaddr           *ifa = NULL;
        struct socket           *so;
        struct rawcb            *rp = NULL;
-       struct sockaddr_rtlabel  sa_rl;
-       struct sockaddr_in6      sa_mask;
-#ifdef BFD
-       struct sockaddr_bfd      sa_bfd;
-#endif
 #ifdef MPLS
-       struct sockaddr_mpls     sa_mpls, *psa_mpls;
+       struct sockaddr_mpls    *psa_mpls;
 #endif
        va_list                  ap;
        u_int                    tableid;
        u_int8_t                 prio;
-       u_char                   vers;
+       u_char                   vers, type;
 
        va_start(ap, m);
        so = va_arg(ap, struct socket *);
@@ -639,16 +703,12 @@ route_output(struct mbuf *m, ...)
                rtfree(rt);
                rt = NULL;
 
-               error = rtrequest(RTM_ADD, &info, prio, &saved_nrt, tableid);
-               if (error == 0) {
+               error = rtrequest(RTM_ADD, &info, prio, &rt, tableid);
+               if (error == 0)
                        rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
-                           &saved_nrt->rt_rmx);
-                       /* write back the priority the kernel used */
-                       rtm->rtm_priority = saved_nrt->rt_priority & RTP_MASK;
-                       rtm->rtm_index = saved_nrt->rt_ifidx;
-                       rtm->rtm_flags = saved_nrt->rt_flags;
-                       rtfree(saved_nrt);
-               }
+                           &rt->rt_rmx);
+               else
+                       goto flush;
                break;
        case RTM_DELETE:
                rt = rtable_lookup(tableid, info.rti_info[RTAX_DST],
@@ -668,7 +728,7 @@ route_output(struct mbuf *m, ...)
                        /* Reset the MTU of the gateway route. */
                        rtable_walk(tableid, rt_key(rt)->sa_family,
                            route_cleargateway, rt);
-                       goto report;
+                       break;
                }
 
                /*
@@ -678,84 +738,15 @@ route_output(struct mbuf *m, ...)
                if ((rt != NULL) &&
                    ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) {
                        error = EINVAL;
-                       goto report;
+                       break;
                }
 
                rtfree(rt);
                rt = NULL;
 
                error = rtrequest(RTM_DELETE, &info, prio, &rt, tableid);
-               if (error == 0)
-                       goto report;
-               break;
-       case RTM_GET:
-               rt = rtable_lookup(tableid, info.rti_info[RTAX_DST],
-                   info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY],
-                   prio);
-               if (rt == NULL) {
-                       error = ESRCH;
+               if (error != 0)
                        goto flush;
-               }
-
-report:
-               info.rti_info[RTAX_DST] = rt_key(rt);
-               info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
-               info.rti_info[RTAX_NETMASK] =
-                   rt_plen2mask(rt, &sa_mask);
-               info.rti_info[RTAX_LABEL] =
-                   rtlabel_id2sa(rt->rt_labelid, &sa_rl);
-#ifdef BFD
-               if (rt->rt_flags & RTF_BFD)
-                       info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd);
-#endif
-#ifdef MPLS
-               if (rt->rt_flags & RTF_MPLS) {
-                       bzero(&sa_mpls, sizeof(sa_mpls));
-                       sa_mpls.smpls_family = AF_MPLS;
-                       sa_mpls.smpls_len = sizeof(sa_mpls);
-                       sa_mpls.smpls_label = ((struct rt_mpls *)
-                           rt->rt_llinfo)->mpls_label;
-                       info.rti_info[RTAX_SRC] =
-                           (struct sockaddr *)&sa_mpls;
-                       info.rti_mpls = ((struct rt_mpls *)
-                           rt->rt_llinfo)->mpls_operation;
-                       rtm->rtm_mpls = info.rti_mpls;
-               }
-#endif
-               info.rti_info[RTAX_IFP] = NULL;
-               info.rti_info[RTAX_IFA] = NULL;
-               ifp = if_get(rt->rt_ifidx);
-               if (ifp != NULL && rtm->rtm_addrs & (RTA_IFP|RTA_IFA)) {
-                       info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
-                       info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
-                       if (ifp->if_flags & IFF_POINTOPOINT)
-                               info.rti_info[RTAX_BRD] =
-                                   rt->rt_ifa->ifa_dstaddr;
-                       else
-                               info.rti_info[RTAX_BRD] = NULL;
-               }
-               if_put(ifp);
-               len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL,
-                   NULL);
-               if (len > rtm->rtm_msglen) {
-                       struct rt_msghdr        *new_rtm;
-                       new_rtm = malloc(len, M_RTABLE, M_NOWAIT);
-                       if (new_rtm == NULL) {
-                               error = ENOBUFS;
-                               goto flush;
-                       }
-                       memcpy(new_rtm, rtm, rtm->rtm_msglen);
-                       free(rtm, M_RTABLE, 0);
-                       rtm = new_rtm;
-               }
-               rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm,
-                   NULL);
-               rtm->rtm_flags = rt->rt_flags;
-               rtm->rtm_use = 0;
-               rtm->rtm_priority = rt->rt_priority & RTP_MASK;
-               rtm->rtm_index = rt->rt_ifidx;
-               rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
-               rtm->rtm_addrs = info.rti_addrs;
                break;
        case RTM_CHANGE:
        case RTM_LOCK:
@@ -907,9 +898,6 @@ change:
 
                        rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
                            &rt->rt_rmx);
-                       rtm->rtm_index = rt->rt_ifidx;
-                       rtm->rtm_priority = rt->rt_priority & RTP_MASK;
-                       rtm->rtm_flags = rt->rt_flags;
 
                        ifp = if_get(rt->rt_ifidx);
                        KASSERT(ifp != NULL);
@@ -929,13 +917,43 @@ change:
                        rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
                        rt->rt_rmx.rmx_locks |=
                            (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
-                       rtm->rtm_priority = rt->rt_priority & RTP_MASK;
                        break;
                }
                break;
+       case RTM_GET:
+               rt = rtable_lookup(tableid, info.rti_info[RTAX_DST],
+                   info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY],
+                   prio);
+               if (rt == NULL) {
+                       error = ESRCH;
+                       goto flush;
+               }
+               break;
+       }
+
+       /*
+        * From here on these vars need to be valid
+        * rt, rtm, error, so, m, tableid, sa_family
+        *
+        * Other notes:
+        * - to end up here previous calls passed OK, error is most probably 0
+        * - error cases take the flush route or in bad cases fail
+        * - fail does not report the message back but just fails the call
+        *   if the message is not valid then fail should be used
+        */
+
+       type = rtm->rtm_type;
+       seq = rtm->rtm_seq;
+       free(rtm, M_RTABLE, 0);
+       rtm = rt_report(rt, type, seq, tableid);
+       if (rtm == NULL) {
+               error = ENOBUFS;
+               goto fail;
        }
 
 flush:
+       if (rt)
+               rtfree(rt);
        if (rtm) {
                if (error)
                        rtm->rtm_errno = error;
@@ -943,14 +961,13 @@ flush:
                        rtm->rtm_flags |= RTF_DONE;
                }
        }
-       if (rt)
-               rtfree(rt);
 
        /*
         * Check to see if we don't want our own messages.
         */
        if (!(so->so_options & SO_USELOOPBACK)) {
                if (route_cb.any_count <= 1) {
+                       /* no other listener and no loopback of messages */
 fail:
                        free(rtm, M_RTABLE, 0);
                        m_freem(m);

Reply via email to