route: Replicate mask_rnhead to each CPU; unbreak genmask support.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 7 Feb 2009 04:51:35 +0000 (12:51 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 17 Feb 2009 10:35:57 +0000 (18:35 +0800)
- mask_rnhead stores netmask and is read-write accessed by the per-cpu
  routing functions, so its replication is necessary.
- Unbreak genmask support by always adding genmask at the beginning of
  the route_output() and searching for the per-cpu genmask before
  assigning it to the per-cpu rtentry.

sys/net/radix.c
sys/net/route.c
sys/net/route.h
sys/net/rtsock.c

index b84ce77..5fa3ae8 100644 (file)
@@ -43,6 +43,8 @@
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/domain.h>
+#include <sys/globaldata.h>
+#include <sys/thread.h>
 #else
 #include <stdlib.h>
 #endif
@@ -67,7 +69,7 @@ static struct radix_node
     *rn_search_m(const char *, struct radix_node *, const char *);
 
 static struct radix_mask *rn_mkfreelist;
-static struct radix_node_head *mask_rnhead;
+static struct radix_node_head *mask_rnheads[MAXCPU];
 
 static int max_keylen;
 static char *rn_zeros, *rn_ones;
@@ -435,13 +437,14 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        boolean_t maskduplicated, isnormal;
        static int last_zeroed = 0;
        char *addmask_key;
+       struct radix_node_head *mask_rnh = mask_rnheads[mycpuid];
 
        if ((mlen = clen(netmask)) > max_keylen)
                mlen = max_keylen;
        if (skip == 0)
                skip = 1;
        if (mlen <= skip)
-               return (mask_rnhead->rnh_nodes);
+               return (mask_rnh->rnh_nodes);
        R_Malloc(addmask_key, char *, max_keylen);
        if (addmask_key == NULL)
                return NULL;
@@ -459,12 +462,12 @@ rn_addmask(char *netmask, boolean_t search, int skip)
                if (m0 >= last_zeroed)
                        last_zeroed = mlen;
                Free(addmask_key);
-               return (mask_rnhead->rnh_nodes);
+               return (mask_rnh->rnh_nodes);
        }
        if (m0 < last_zeroed)
                bzero(addmask_key + m0, last_zeroed - m0);
        *addmask_key = last_zeroed = mlen;
-       x = rn_search(addmask_key, mask_rnhead->rnh_treetop);
+       x = rn_search(addmask_key, mask_rnh->rnh_treetop);
        if (bcmp(addmask_key, x->rn_key, mlen) != 0)
                x = NULL;
        if (x != NULL || search)
@@ -475,7 +478,7 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        bzero(x, max_keylen + 2 * (sizeof *x));
        netmask = cp = (char *)(x + 2);
        bcopy(addmask_key, cp, mlen);
-       x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
+       x = rn_insert(cp, mask_rnh, &maskduplicated, x);
        if (maskduplicated) {
                log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
                Free(saved_x);
@@ -1054,6 +1057,7 @@ void
 rn_init(void)
 {
        char *cp, *cplim;
+       int cpu;
 #ifdef _KERNEL
        struct domain *dom;
 
@@ -1074,6 +1078,9 @@ rn_init(void)
        cplim = rn_ones + max_keylen;
        while (cp < cplim)
                *cp++ = -1;
-       if (rn_inithead((void **)&mask_rnhead, 0) == 0)
-               panic("rn_init 2");
+
+       for (cpu = 0; cpu < ncpus; ++cpu) {
+               if (rn_inithead((void **)&mask_rnheads[cpu], 0) == 0)
+                       panic("rn_init 2");
+       }
 }
index adefcfb..e1bd3e0 100644 (file)
@@ -119,6 +119,8 @@ static void rtrequest1_msghandler(struct netmsg *netmsg);
 #endif
 static void rtsearch_msghandler(struct netmsg *netmsg);
 
+static void rtmask_add_msghandler(struct netmsg *netmsg);
+
 static int rt_setshims(struct rtentry *, struct sockaddr **);
 
 SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RW, 0, "Routing");
@@ -1749,5 +1751,52 @@ rtsearch_msghandler(struct netmsg *netmsg)
        }
 }
 
+int
+rtmask_add_global(struct sockaddr *mask)
+{
+       struct netmsg nmsg;
+
+       netmsg_init(&nmsg, &curthread->td_msgport, 0,
+                   rtmask_add_msghandler);
+       nmsg.nm_lmsg.u.ms_resultp = mask;
+
+       return lwkt_domsg(rtable_portfn(0), &nmsg.nm_lmsg, 0);
+}
+
+struct sockaddr *
+_rtmask_lookup(struct sockaddr *mask, boolean_t search)
+{
+       struct radix_node *n;
+
+#define        clen(s) (*(u_char *)(s))
+       n = rn_addmask((char *)mask, search, 1);
+       if (n != NULL &&
+           mask->sa_len >= clen(n->rn_key) &&
+           bcmp((char *)mask + 1,
+                (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0) {
+               return (struct sockaddr *)n->rn_key;
+       } else {
+               return NULL;
+       }
+#undef clen
+}
+
+static void
+rtmask_add_msghandler(struct netmsg *nmsg)
+{
+       struct lwkt_msg *lmsg = &nmsg->nm_lmsg;
+       struct sockaddr *mask = lmsg->u.ms_resultp;
+       int error = 0, nextcpu;
+
+       if (rtmask_lookup(mask) == NULL)
+               error = ENOBUFS;
+
+       nextcpu = mycpuid + 1;
+       if (!error && nextcpu < ncpus)
+               lwkt_forwardmsg(rtable_portfn(nextcpu), lmsg);
+       else
+               lwkt_replymsg(lmsg, error);
+}
+
 /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */
 SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0);
index 587661d..4acc68d 100644 (file)
@@ -397,6 +397,22 @@ int         rtrequest1_global (int, struct rt_addrinfo *, rtrequest1_callback_func_t, v
 int     rtsearch_global(int, struct rt_addrinfo *,
            rtsearch_callback_func_t, void *, boolean_t);
 
+int     rtmask_add_global(struct sockaddr *);
+
+struct sockaddr *_rtmask_lookup(struct sockaddr *, boolean_t);
+
+static __inline struct sockaddr *
+rtmask_lookup(struct sockaddr *_mask)
+{
+       return _rtmask_lookup(_mask, FALSE);
+}
+
+static __inline struct sockaddr *
+rtmask_purelookup(struct sockaddr *_mask)
+{
+       return _rtmask_lookup(_mask, TRUE);
+}
+
 void   rtfree_oncpu(struct rtentry *);
 void   rtfree_remote(struct rtentry *, int);
 void   rt_print(struct rt_addrinfo *, struct rtentry *);
index fd48105..ae2750d 100644 (file)
@@ -514,17 +514,9 @@ route_output(struct mbuf *m, struct socket *so, ...)
                gotoerr(EINVAL);
 
        if (rtinfo.rti_genmask != NULL) {
-               struct radix_node *n;
-
-#define        clen(s) (*(u_char *)(s))
-               n = rn_addmask((char *)rtinfo.rti_genmask, TRUE, 1);
-               if (n != NULL &&
-                   rtinfo.rti_genmask->sa_len >= clen(n->rn_key) &&
-                   bcmp((char *)rtinfo.rti_genmask + 1,
-                        (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0)
-                       rtinfo.rti_genmask = (struct sockaddr *)n->rn_key;
-               else
-                       gotoerr(ENOBUFS);
+               error = rtmask_add_global(rtinfo.rti_genmask);
+               if (error)
+                       goto flush;
        }
 
        /*
@@ -621,7 +613,19 @@ route_output_add_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
                rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
                rt->rt_rmx.rmx_locks |=
                    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
-               rt->rt_genmask = rtinfo->rti_genmask;
+               if (rtinfo->rti_genmask != NULL) {
+                       rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
+                       if (rt->rt_genmask == NULL) {
+                               /*
+                                * This should not happen, since we
+                                * have already installed genmask
+                                * on each CPU before we reach here.
+                                */
+                               panic("genmask is gone!?");
+                       }
+               } else {
+                       rt->rt_genmask = NULL;
+               }
                rtm->rtm_index = rt->rt_ifp->if_index;
        }
 }
@@ -706,8 +710,17 @@ route_output_change_callback(int cmd, struct rt_addrinfo *rtinfo,
        rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx);
        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
                rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, rtinfo);
-       if (rtinfo->rti_genmask != NULL)
-               rt->rt_genmask = rtinfo->rti_genmask;
+       if (rtinfo->rti_genmask != NULL) {
+               rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
+               if (rt->rt_genmask == NULL) {
+                       /*
+                        * This should not happen, since we
+                        * have already installed genmask
+                        * on each CPU before we reach here.
+                        */
+                       panic("genmask is gone!?\n");
+               }
+       }
        rtm->rtm_index = rt->rt_ifp->if_index;
 done:
        return error;