Bring in the parallel route table code and clean up ARP. The
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 31 Jan 2006 19:05:45 +0000 (19:05 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 31 Jan 2006 19:05:45 +0000 (19:05 +0000)
route table is now replicated across all cpus (ncpus, not ncpus2).
Note that cloned routes are not replicated.

This removes one of the few remaining obstacles to being able
to run the network protocol stacks without the BGL.

Primary-Design-by: Jeffrey Hsu
Work-by: Jeffrey Hsu and Matthew Dillon
23 files changed:
sys/i386/include/thread.h
sys/kern/lwkt_thread.c
sys/net/bridge/if_bridge.c
sys/net/if.c
sys/net/netisr.c
sys/net/netisr.h
sys/net/radix.c
sys/net/route.c
sys/net/route.h
sys/net/rtsock.c
sys/netinet/if_ether.c
sys/netinet/in_pcb.c
sys/netinet/in_rmx.c
sys/netinet/ip_input.c
sys/netinet/ip_var.h
sys/netinet6/in6.c
sys/netinet6/in6_pcb.c
sys/netinet6/in6_rmx.c
sys/netinet6/nd6_rtr.c
sys/platform/pc32/include/thread.h
sys/sys/thread.h
sys/vfs/nfs/bootp_subr.c
sys/vfs/nfs/nfs_vfsops.c

index e7d4239..a58b7f2 100644 (file)
@@ -33,7 +33,7 @@
  * 
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.13 2005/06/16 21:12:46 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.14 2006/01/31 19:05:30 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
@@ -83,7 +83,12 @@ _get_mycpu(void)
 }
 
 #define mycpu          _get_mycpu()
-#define mycpuid        _get_mycpu()->gd_cpuid
+
+#ifdef SMP
+#define        mycpuid (_get_mycpu()->gd_cpuid)
+#else
+#define        mycpuid 0
+#endif
 
 /*
  * note: curthread is never NULL, but curproc can be.  Also note that
index acc8d53..11c9066 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.90 2005/12/10 18:50:36 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.91 2006/01/31 19:05:33 dillon Exp $
  */
 
 /*
@@ -1219,6 +1219,17 @@ lwkt_setcpu_self(globaldata_t rgd)
 #endif
 }
 
+void
+lwkt_migratecpu(int cpuid)
+{
+#ifdef SMP
+       globaldata_t rgd;
+
+       rgd = globaldata_find(cpuid);
+       lwkt_setcpu_self(rgd);
+#endif
+}
+
 /*
  * Remote IPI for cpu migration (called while in a critical section so we
  * do not have to enter another one).  The thread has already been moved to
index cc129a6..8977627 100644 (file)
@@ -66,7 +66,7 @@
  * $OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp $
  * $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $
  * $FreeBSD: src/sys/net/if_bridge.c,v 1.26 2005/10/13 23:05:55 thompsa Exp $
- * $DragonFly: src/sys/net/bridge/if_bridge.c,v 1.4 2006/01/14 11:05:17 swildner Exp $
+ * $DragonFly: src/sys/net/bridge/if_bridge.c,v 1.5 2006/01/31 19:05:37 dillon Exp $
  */
 
 /*
@@ -1390,6 +1390,12 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
 
        eh = mtod(m, struct ether_header *);
 
+       /*
+        * Various ifp's are used below, release the serializer for
+        * the bridge ifp so other ifp serializers can be acquired.
+        */
+       lwkt_serialize_exit(ifp->if_serializer);
+
        /*
         * If the interface is learning, and the source
         * address is valid and not multicast, record
@@ -1409,7 +1415,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
        if ((bif->bif_flags & IFBIF_STP) != 0 &&
            bif->bif_state == BSTP_IFSTATE_LEARNING) {
                m_freem(m);
-               return;
+               goto done;
        }
 
        /*
@@ -1425,7 +1431,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
                dst_if = bridge_rtlookup(sc, eh->ether_dhost);
                if (src_if == dst_if) {
                        m_freem(m);
-                       return;
+                       goto done;
                }
        } else {
                /* ...forward it to all interfaces. */
@@ -1440,16 +1446,14 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
 #endif
            ) {
                if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
-                       return;
+                       goto done;
                if (m == NULL)
-                       return;
+                       goto done;
        }
 
        if (dst_if == NULL) {
-               lwkt_serialize_exit(ifp->if_serializer);
                bridge_broadcast(sc, src_if, m, 1);
-               lwkt_serialize_enter(ifp->if_serializer);
-               return;
+               goto done;
        }
 
        /*
@@ -1458,13 +1462,13 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
         */
        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
                m_freem(m);
-               return;
+               goto done;
        }
        bif = bridge_lookup_member_if(sc, dst_if);
        if (bif == NULL) {
                /* Not a member of the bridge (anymore?) */
                m_freem(m);
-               return;
+               goto done;
        }
 
        if (bif->bif_flags & IFBIF_STP) {
@@ -1472,7 +1476,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
                case BSTP_IFSTATE_DISABLED:
                case BSTP_IFSTATE_BLOCKING:
                        m_freem(m);
-                       return;
+                       goto done;
                }
        }
 
@@ -1482,12 +1486,17 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
 #endif
            ) {
                if (bridge_pfil(&m, sc->sc_ifp, dst_if, PFIL_OUT) != 0)
-                       return;
+                       goto done;
                if (m == NULL)
-                       return;
+                       goto done;
        }
-       lwkt_serialize_exit(ifp->if_serializer);
        bridge_enqueue(sc, dst_if, m);
+
+       /*
+        * ifp's serializer was held on entry and is expected to be held
+        * on return.
+        */
+done:
        lwkt_serialize_enter(ifp->if_serializer);
 }
 
index dbde1d7..5cb809e 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)if.c        8.3 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $
- * $DragonFly: src/sys/net/if.c,v 1.43 2005/11/28 17:13:45 dillon Exp $
+ * $DragonFly: src/sys/net/if.c,v 1.44 2006/01/31 19:05:35 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -314,6 +314,7 @@ if_detach(struct ifnet *ifp)
        struct ifaddr *ifa;
        struct radix_node_head  *rnh;
        int i;
+       int cpu, origcpu;
        struct domain *dp;
 
        EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
@@ -388,11 +389,16 @@ if_detach(struct ifnet *ifp)
         * the entire routing table looking for routes which point
         * to this interface...oh well...
         */
-       for (i = 1; i <= AF_MAX; i++) {
-               if ((rnh = rt_tables[i]) == NULL)
-                       continue;
-               rnh->rnh_walktree(rnh, if_rtdel, ifp);
+       origcpu = mycpuid;
+       for (cpu = 0; cpu < ncpus2; cpu++) {
+               lwkt_migratecpu(cpu);
+               for (i = 1; i <= AF_MAX; i++) {
+                       if ((rnh = rt_tables[mycpuid][i]) == NULL)
+                               continue;
+                       rnh->rnh_walktree(rnh, if_rtdel, ifp);
+               }
        }
+       lwkt_migratecpu(origcpu);
 
        /* Announce that the interface is gone. */
        rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
index 22492e7..452d864 100644 (file)
@@ -35,7 +35,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/net/netisr.c,v 1.24 2006/01/14 11:05:17 swildner Exp $
+ * $DragonFly: src/sys/net/netisr.c,v 1.25 2006/01/31 19:05:35 dillon Exp $
  */
 
 /*
@@ -351,6 +351,12 @@ cpu0_portfn(struct mbuf **mptr)
     return (&netisr_cpu[0].td_msgport);
 }
 
+lwkt_port_t
+cpu_portfn(int cpu)
+{
+    return (&netisr_cpu[cpu].td_msgport);
+}
+
 /* ARGSUSED */
 lwkt_port_t
 cpu0_soport(struct socket *so __unused, struct sockaddr *nam __unused,
index 6426bdb..cfbfbeb 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)netisr.h    8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/netisr.h,v 1.21.2.5 2002/02/09 23:02:39 luigi Exp $
- * $DragonFly: src/sys/net/netisr.h,v 1.21 2005/01/19 17:30:52 dillon Exp $
+ * $DragonFly: src/sys/net/netisr.h,v 1.22 2006/01/31 19:05:35 dillon Exp $
  */
 
 #ifndef _NET_NETISR_H_
@@ -211,6 +211,7 @@ struct netisr {
 extern lwkt_port netisr_afree_rport;
 
 lwkt_port_t    cpu0_portfn(struct mbuf **mptr);
+lwkt_port_t    cpu_portfn(int cpu);
 void           netisr_dispatch(int, struct mbuf *);
 int            netisr_queue(int, struct mbuf *);
 void           netisr_register(int, lwkt_portfn_t, netisr_fn_t);
index e501a39..9135745 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)radix.c     8.4 (Berkeley) 11/2/94
  * $FreeBSD: src/sys/net/radix.c,v 1.20.2.3 2002/04/28 05:40:25 suz Exp $
- * $DragonFly: src/sys/net/radix.c,v 1.12 2006/01/14 11:05:17 swildner Exp $
+ * $DragonFly: src/sys/net/radix.c,v 1.13 2006/01/31 19:05:35 dillon Exp $
  */
 
 /*
@@ -71,7 +71,6 @@ static struct radix_node_head *mask_rnhead;
 
 static int max_keylen;
 static char *rn_zeros, *rn_ones;
-static char *addmask_key;
 
 static int rn_lexobetter(char *m, char *n);
 static struct radix_mask *
@@ -435,6 +434,7 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        int b = 0, mlen, m0, j;
        boolean_t maskduplicated, isnormal;
        static int last_zeroed = 0;
+       char *addmask_key;
 
        if ((mlen = clen(netmask)) > max_keylen)
                mlen = max_keylen;
@@ -442,6 +442,9 @@ rn_addmask(char *netmask, boolean_t search, int skip)
                skip = 1;
        if (mlen <= skip)
                return (mask_rnhead->rnh_nodes);
+       R_Malloc(addmask_key, char *, max_keylen);
+       if (addmask_key == NULL)
+               return NULL;
        if (skip > 1)
                bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
        if ((m0 = mlen) > skip)
@@ -455,6 +458,7 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        if (mlen <= skip) {
                if (m0 >= last_zeroed)
                        last_zeroed = mlen;
+               Free(addmask_key);
                return (mask_rnhead->rnh_nodes);
        }
        if (m0 < last_zeroed)
@@ -464,10 +468,10 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        if (bcmp(addmask_key, x->rn_key, mlen) != 0)
                x = NULL;
        if (x != NULL || search)
-               return (x);
+               goto out;
        R_Malloc(x, struct radix_node *, max_keylen + 2 * (sizeof *x));
        if ((saved_x = x) == NULL)
-               return (NULL);
+               goto out;
        bzero(x, max_keylen + 2 * (sizeof *x));
        netmask = cp = (char *)(x + 2);
        bcopy(addmask_key, cp, mlen);
@@ -475,7 +479,7 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        if (maskduplicated) {
                log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
                Free(saved_x);
-               return (x);
+               goto out;
        }
        /*
         * Calculate index of mask, and check for normalcy.
@@ -498,6 +502,8 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        x->rn_bit = -1 - b;
        if (isnormal)
                x->rn_flags |= RNF_NORMAL;
+out:
+       Free(addmask_key);
        return (x);
 }
 
@@ -1060,12 +1066,12 @@ rn_init(void)
                    "rn_init: radix functions require max_keylen be set\n");
                return;
        }
-       R_Malloc(rn_zeros, char *, 3 * max_keylen);
+       R_Malloc(rn_zeros, char *, 2 * max_keylen);
        if (rn_zeros == NULL)
                panic("rn_init");
-       bzero(rn_zeros, 3 * max_keylen);
+       bzero(rn_zeros, 2 * max_keylen);
        rn_ones = cp = rn_zeros + max_keylen;
-       addmask_key = cplim = rn_ones + max_keylen;
+       cplim = rn_ones + max_keylen;
        while (cp < cplim)
                *cp++ = -1;
        if (rn_inithead((void **)&mask_rnhead, 0) == 0)
index e11be3e..478c692 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)route.c     8.3 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.c,v 1.59.2.10 2003/01/17 08:04:00 ru Exp $
- * $DragonFly: src/sys/net/route.c,v 1.23 2006/01/14 11:05:17 swildner Exp $
+ * $DragonFly: src/sys/net/route.c,v 1.24 2006/01/31 19:05:35 dillon Exp $
  */
 
 #include "opt_inet.h"
 #include <sys/globaldata.h>
 #include <sys/thread.h>
 #include <sys/thread2.h>
+#include <sys/msgport2.h>
 
 #include <net/if.h>
 #include <net/route.h>
+#include <net/netisr.h>
 
 #include <netinet/in.h>
 #include <net/ip_mroute/ip_mroute.h>
@@ -112,39 +114,79 @@ static struct rtstatistics rtstatistics_percpu[MAXCPU];
 #define rtstat rtstatistics_percpu[0]
 #endif
 
-struct radix_node_head *rt_tables[AF_MAX+1];
+struct radix_node_head *rt_tables[MAXCPU][AF_MAX+1];
+struct lwkt_port *rt_ports[MAXCPU];
 
 static void    rt_maskedcopy (struct sockaddr *, struct sockaddr *,
                               struct sockaddr *);
-static void    rtable_init (void **);
+static void rtable_init(void);
+static void rtable_service_loop(void *dummy);
+static void rtinit_rtrequest_callback(int, int, struct rt_addrinfo *,
+                                     struct rtentry *, void *);
+
+#ifdef SMP
+static int rtredirect_msghandler(struct lwkt_msg *lmsg);
+static int rtrequest1_msghandler(struct lwkt_msg *lmsg);
+#endif
 
 SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RW, 0, "Routing");
 
+/*
+ * Initialize the route table(s) for protocol domains and
+ * create a helper thread which will be responsible for updating
+ * route table entries on each cpu.
+ */
+void
+route_init(void)
+{
+       int cpu, origcpu;
+       thread_t rtd;
+
+       for (cpu = 0; cpu < ncpus; ++cpu)
+               bzero(&rtstatistics_percpu[cpu], sizeof(struct rtstatistics));
+       rn_init();      /* initialize all zeroes, all ones, mask table */
+       origcpu = mycpuid;
+       for (cpu = 0; cpu < ncpus; cpu++) {
+               lwkt_migratecpu(cpu);
+               rtable_init();
+               lwkt_create(rtable_service_loop, NULL, &rtd, NULL,
+                           TDF_STOPREQ, cpu, "rtable_cpu %d", cpu);
+               rt_ports[cpu] = &rtd->td_msgport;
+               lwkt_schedule(rtd);
+       }
+       lwkt_migratecpu(origcpu);
+}
+
 static void
-rtable_init(void **table)
+rtable_init(void)
 {
        struct domain *dom;
 
-       SLIST_FOREACH(dom, &domains, dom_next)
-               if (dom->dom_rtattach)
-                       dom->dom_rtattach(&table[dom->dom_family],
-                                         dom->dom_rtoffset);
+       SLIST_FOREACH(dom, &domains, dom_next) {
+               if (dom->dom_rtattach) {
+                       dom->dom_rtattach(
+                               (void **)&rt_tables[mycpuid][dom->dom_family],
+                               dom->dom_rtoffset);
+               }
+       }
 }
 
-void
-route_init(void)
+/*
+ * Our per-cpu table management protocol thread.  All route table operations
+ * are chained through all cpus in order starting at cpu #0 in order to
+ * maintain duplicate route tables on each cpu.  Having a spearate route
+ * table management thread allows the protocol and interrupt threads to
+ * issue route table changes.
+ */
+static void
+rtable_service_loop(void *dummy __unused)
 {
-#ifdef SMP
-       int ccpu;
-
-       for (ccpu = 0; ccpu < ncpus; ++ccpu)
-               bzero(&rtstatistics_percpu[ccpu], sizeof(struct rtstatistics));
-#else
-       bzero(&rtstat, sizeof(struct rtstatistics));
-#endif
+       struct lwkt_msg *lmsg;
+       thread_t td = curthread;
 
-       rn_init();      /* initialize all zeroes, all ones, mask table */
-       rtable_init((void **)rt_tables);
+       while ((lmsg = lwkt_waitport(&td->td_msgport, NULL)) != NULL) {
+               lmsg->ms_cmd.cm_func(lmsg);
+       }
 }
 
 /*
@@ -219,7 +261,7 @@ rtalloc_ign(struct route *ro, u_long ignoreflags)
 struct rtentry *
 _rtlookup(struct sockaddr *dst, boolean_t generate_report, u_long ignore)
 {
-       struct radix_node_head *rnh = rt_tables[dst->sa_family];
+       struct radix_node_head *rnh = rt_tables[mycpuid][dst->sa_family];
        struct rtentry *rt;
 
        if (rnh == NULL)
@@ -278,7 +320,8 @@ rtfree(struct rtentry *rt)
 
        --rt->rt_refcnt;
        if (rt->rt_refcnt == 0) {
-               struct radix_node_head *rnh = rt_tables[rt_key(rt)->sa_family];
+               struct radix_node_head *rnh =
+                   rt_tables[mycpuid][rt_key(rt)->sa_family];
 
                if (rnh->rnh_close)
                        rnh->rnh_close((struct radix_node *)rt, rnh);
@@ -294,16 +337,9 @@ rtfree(struct rtentry *rt)
        }
 }
 
-/*
- * Force a routing table entry to the specified destination to go through
- * the given gateway.  Normally called as a result of a routing redirect
- * message from the network layer.
- *
- * N.B.: must be called at splnet
- */
-void
-rtredirect(struct sockaddr *dst, struct sockaddr *gateway,
-          struct sockaddr *netmask, int flags, struct sockaddr *src)
+static int
+rtredirect_oncpu(struct sockaddr *dst, struct sockaddr *gateway,
+                struct sockaddr *netmask, int flags, struct sockaddr *src)
 {
        struct rtentry *rt = NULL;
        struct rt_addrinfo rtinfo;
@@ -396,6 +432,50 @@ out:
        else if (stat != NULL)
                (*stat)++;
 
+       return error;
+}
+
+#ifdef SMP
+
+struct netmsg_rtredirect {
+       struct lwkt_msg lmsg;
+       struct sockaddr *dst;
+       struct sockaddr *gateway;
+       struct sockaddr *netmask;
+       int             flags;
+       struct sockaddr *src;
+};
+
+#endif
+
+/*
+ * Force a routing table entry to the specified
+ * destination to go through the given gateway.
+ * Normally called as a result of a routing redirect
+ * message from the network layer.
+ *
+ * N.B.: must be called at splnet
+ */
+void
+rtredirect(struct sockaddr *dst, struct sockaddr *gateway,
+          struct sockaddr *netmask, int flags, struct sockaddr *src)
+{
+       struct rt_addrinfo rtinfo;
+       int error;
+#ifdef SMP
+       struct netmsg_rtredirect msg;
+
+       lwkt_initmsg(&msg.lmsg, &curthread->td_msgport, 0,
+                    lwkt_cmd_func(rtredirect_msghandler), lwkt_cmd_op_none);
+       msg.dst = dst;
+       msg.gateway = gateway;
+       msg.netmask = netmask;
+       msg.flags = flags;
+       msg.src = src;
+       error = lwkt_domsg(rtable_portfn(0), &msg.lmsg);
+#else
+       error = rtredirect_oncpu(dst, gateway, netmask, flags, src);
+#endif
        bzero(&rtinfo, sizeof(struct rt_addrinfo));
        rtinfo.rti_info[RTAX_DST] = dst;
        rtinfo.rti_info[RTAX_GATEWAY] = gateway;
@@ -404,6 +484,26 @@ out:
        rt_missmsg(RTM_REDIRECT, &rtinfo, flags, error);
 }
 
+#ifdef SMP
+
+static int
+rtredirect_msghandler(struct lwkt_msg *lmsg)
+{
+       struct netmsg_rtredirect *msg = (void *)lmsg;
+       int nextcpu;
+
+       rtredirect_oncpu(msg->dst, msg->gateway, msg->netmask,
+                        msg->flags, msg->src);
+       nextcpu = mycpuid + 1;
+       if (nextcpu < ncpus)
+               lwkt_forwardmsg(rtable_portfn(nextcpu), &msg->lmsg);
+       else
+               lwkt_replymsg(&msg->lmsg, 0);
+       return (0);
+}
+
+#endif
+
 /*
 * Routing table ioctl interface.
 */
@@ -548,6 +648,111 @@ rtrequest(
        return rtrequest1(req, &rtinfo, ret_nrt);
 }
 
+int
+rtrequest_global(
+       int req,
+       struct sockaddr *dst,
+       struct sockaddr *gateway,
+       struct sockaddr *netmask,
+       int flags)
+{
+       struct rt_addrinfo rtinfo;
+
+       bzero(&rtinfo, sizeof(struct rt_addrinfo));
+       rtinfo.rti_info[RTAX_DST] = dst;
+       rtinfo.rti_info[RTAX_GATEWAY] = gateway;
+       rtinfo.rti_info[RTAX_NETMASK] = netmask;
+       rtinfo.rti_flags = flags;
+       return rtrequest1_global(req, &rtinfo, NULL, NULL);
+}
+
+#ifdef SMP
+
+struct netmsg_rtq {
+       struct lwkt_msg         lmsg;
+       int                     req;
+       struct rt_addrinfo      *rtinfo;
+       rtrequest1_callback_func_t callback;
+       void                    *arg;
+};
+
+#endif
+
+int
+rtrequest1_global(int req, struct rt_addrinfo *rtinfo, 
+                 rtrequest1_callback_func_t callback, void *arg)
+{
+       int error;
+#ifdef SMP
+       struct netmsg_rtq msg;
+
+       lwkt_initmsg(&msg.lmsg, &curthread->td_msgport, 0,
+                    lwkt_cmd_func(rtrequest1_msghandler), lwkt_cmd_op_none);
+       msg.lmsg.ms_error = -1;
+       msg.req = req;
+       msg.rtinfo = rtinfo;
+       msg.callback = callback;
+       msg.arg = arg;
+       error = lwkt_domsg(rtable_portfn(0), &msg.lmsg);
+#else
+       struct rtentry *rt = NULL;
+
+       error = rtrequest1(req, rtinfo, &rt);
+       if (rt)
+               --rt->rt_refcnt;
+       if (callback)
+               callback(req, error, rtinfo, rt, arg);
+#endif
+       return (error);
+}
+
+/*
+ * Handle a route table request on the current cpu.  Since the route table's
+ * are supposed to be identical on each cpu, an error occuring later in the
+ * message chain is considered system-fatal.
+ */
+#ifdef SMP
+
+static int
+rtrequest1_msghandler(struct lwkt_msg *lmsg)
+{
+       struct netmsg_rtq *msg = (void *)lmsg;
+       struct rtentry *rt = NULL;
+       int nextcpu;
+       int error;
+
+       error = rtrequest1(msg->req, msg->rtinfo, &rt);
+       if (rt)
+               --rt->rt_refcnt;
+       if (msg->callback)
+               msg->callback(msg->req, error, msg->rtinfo, rt, msg->arg);
+
+       /*
+        * RTM_DELETE's are propogated even if an error occurs, since a
+        * cloned route might be undergoing deletion and cloned routes
+        * are not necessarily replicated.  An overall error is returned
+        * only if no cpus have the route in question.
+        */
+       if (msg->lmsg.ms_error < 0 || error == 0)
+               msg->lmsg.ms_error = error;
+
+       nextcpu = mycpuid + 1;
+       if (error && msg->req != RTM_DELETE) {
+               if (mycpuid != 0) {
+                       panic("rtrequest1_msghandler: rtrequest table "
+                             "error was not on cpu #0: %p", msg);
+               }
+               lwkt_replymsg(&msg->lmsg, error);
+       } else if (nextcpu < ncpus) {
+               lwkt_forwardmsg(rtable_portfn(nextcpu), &msg->lmsg);
+       } else {
+               lwkt_replymsg(&msg->lmsg, msg->lmsg.ms_error);
+       }
+       return (0);
+}
+
+#endif
+
 int
 rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
 {
@@ -565,7 +770,7 @@ rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
        /*
         * Find the correct routing tree to use for this Address Family
         */
-       if ((rnh = rt_tables[dst->sa_family]) == NULL)
+       if ((rnh = rt_tables[mycpuid][dst->sa_family]) == NULL)
                gotoerr(EAFNOSUPPORT);
 
        /*
@@ -589,6 +794,9 @@ rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
                        ("rnh_deladdr returned flags 0x%x", rn->rn_flags));
                rt = (struct rtentry *)rn;
 
+               /* ref to prevent a deletion race */
+               ++rt->rt_refcnt;
+
                /* Free any routes cloned from this one. */
                if ((rt->rt_flags & (RTF_CLONING | RTF_PRCLONING)) &&
                    rt_mask(rt) != NULL) {
@@ -621,9 +829,10 @@ rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
                KASSERT(rt->rt_refcnt >= 0,
                        ("rtrequest1(DELETE): refcnt %ld", rt->rt_refcnt));
                if (ret_nrt != NULL) {
+                       /* leave ref intact for return */
                        *ret_nrt = rt;
-               } else if (rt->rt_refcnt == 0) {
-                       rt->rt_refcnt++;  /* refcnt > 0 required for rtfree() */
+               } else {
+                       /* deref / attempt to destroy */
                        rtfree(rt);
                }
                break;
@@ -900,7 +1109,7 @@ rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate)
        char *space, *oldspace;
        int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
        struct rtentry *rt = rt0;
-       struct radix_node_head *rnh = rt_tables[dst->sa_family];
+       struct radix_node_head *rnh = rt_tables[mycpuid][dst->sa_family];
 
        /*
         * A host route with the destination equal to the gateway
@@ -1062,7 +1271,6 @@ int
 rtinit(struct ifaddr *ifa, int cmd, int flags)
 {
        struct sockaddr *dst, *deldst, *netmask;
-       struct rtentry *rt;
        struct mbuf *m = NULL;
        struct radix_node_head *rnh;
        struct radix_node *rn;
@@ -1099,7 +1307,7 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
                 * Look up an rtentry that is in the routing tree and
                 * contains the correct info.
                 */
-               if ((rnh = rt_tables[dst->sa_family]) == NULL ||
+               if ((rnh = rt_tables[mycpuid][dst->sa_family]) == NULL ||
                    (rn = rnh->rnh_lookup((char *)dst,
                                          (char *)netmask, rnh)) == NULL ||
                    ((struct rtentry *)rn)->rt_ifa != ifa ||
@@ -1129,32 +1337,32 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
        rtinfo.rti_info[RTAX_NETMASK] = netmask;
        rtinfo.rti_flags = flags | ifa->ifa_flags;
        rtinfo.rti_ifa = ifa;
-       error = rtrequest1(cmd, &rtinfo, &rt);
-       if (error == 0 && rt != NULL) {
-               /*
-                * notify any listening routing agents of the change
-                */
-               rt_newaddrmsg(cmd, ifa, error, rt);
+       error = rtrequest1_global(cmd, &rtinfo, rtinit_rtrequest_callback, ifa);
+       if (m != NULL)
+               m_free(m);
+       return (error);
+}
+
+static void
+rtinit_rtrequest_callback(int cmd, int error,
+                         struct rt_addrinfo *rtinfo, struct rtentry *rt,
+                         void *arg)
+{
+       struct ifaddr *ifa = arg;
+
+       if (error == 0 && rt) {
+               if (mycpuid == 0) {
+                       ++rt->rt_refcnt;
+                       rt_newaddrmsg(cmd, ifa, error, rt);
+                       --rt->rt_refcnt;
+               }
                if (cmd == RTM_DELETE) {
-                       /*
-                        * If we are deleting, and we found an entry, then
-                        * it's been removed from the tree.. now throw it away.
-                        */
                        if (rt->rt_refcnt == 0) {
-                               rt->rt_refcnt++; /* make a 1->0 transition */
+                               ++rt->rt_refcnt;
                                rtfree(rt);
                        }
-               } else if (cmd == RTM_ADD) {
-                       /*
-                        * We just wanted to add it.. we don't actually
-                        * need a reference.
-                        */
-                       rt->rt_refcnt--;
                }
        }
-       if (m != NULL)
-               m_free(m);
-       return (error);
 }
 
 /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */
index 6e91833..46e66dd 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)route.h     8.4 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.h,v 1.36.2.5 2002/02/01 11:48:01 ru Exp $
- * $DragonFly: src/sys/net/route.h,v 1.14 2005/05/01 04:05:35 hmp Exp $
+ * $DragonFly: src/sys/net/route.h,v 1.15 2006/01/31 19:05:35 dillon Exp $
  */
 
 #ifndef _NET_ROUTE_H_
@@ -319,7 +319,8 @@ struct rt_addrinfo {
 #define        rti_author      rti_info[RTAX_AUTHOR]
 #define        rti_bcastaddr   rti_info[RTAX_BRD]
 
-extern struct radix_node_head *rt_tables[AF_MAX+1];
+extern struct radix_node_head *rt_tables[MAXCPU][AF_MAX+1];
+extern struct lwkt_port *rt_ports[MAXCPU];
 
 struct ifmultiaddr;
 struct proc;
@@ -367,6 +368,9 @@ rtlookup(struct sockaddr *dst)
        return _rtlookup(dst, RTL_REPORTMSG, RTL_DOCLONE);
 }
 
+typedef void (*rtrequest1_callback_func_t)(int, int, struct rt_addrinfo *,
+                                     struct rtentry *, void *);
+
 void    rtfree (struct rtentry *);
 int     rtinit (struct ifaddr *, int, int);
 int     rtioctl (u_long, caddr_t, struct thread *);
@@ -374,7 +378,10 @@ void        rtredirect (struct sockaddr *, struct sockaddr *,
            struct sockaddr *, int, struct sockaddr *);
 int     rtrequest (int, struct sockaddr *,
            struct sockaddr *, struct sockaddr *, int, struct rtentry **);
+int     rtrequest_global (int, struct sockaddr *,
+           struct sockaddr *, struct sockaddr *, int);
 int     rtrequest1 (int, struct rt_addrinfo *, struct rtentry **);
+int     rtrequest1_global (int, struct rt_addrinfo *, rtrequest1_callback_func_t, void *);
 
 static __inline void
 RTFREE(struct rtentry *rt)
@@ -385,6 +392,13 @@ RTFREE(struct rtentry *rt)
                --rt->rt_refcnt;
 }
 
+static __inline
+struct lwkt_port *
+rtable_portfn(int cpu)
+{  
+        return (rt_ports[cpu]);
+}
+
 int    in_inithead(void **, int);
 #endif
 
index 8343379..4036bd1 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)rtsock.c    8.7 (Berkeley) 10/12/95
  * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
- * $DragonFly: src/sys/net/rtsock.c,v 1.29 2005/07/15 17:54:47 eirikn Exp $
+ * $DragonFly: src/sys/net/rtsock.c,v 1.30 2006/01/31 19:05:35 dillon Exp $
  */
 
 #include "opt_sctp.h"
@@ -405,15 +405,22 @@ fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt,
        return (0);
 }
 
+static void route_output_add_callback(int, int, struct rt_addrinfo *,
+                                       struct rtentry *, void *);
+static void route_output_delete_callback(int, int, struct rt_addrinfo *,
+                                       struct rtentry *, void *);
+static void route_output_change_callback(int, int, struct rt_addrinfo *,
+                                       struct rtentry *, void *);
+static void route_output_lock_callback(int, int, struct rt_addrinfo *, 
+                                       struct rtentry *, void *);
+
 /*ARGSUSED*/
 static int
 route_output(struct mbuf *m, struct socket *so, ...)
 {
        struct rt_msghdr *rtm = NULL;
-       struct rtentry *rt = NULL;
-       struct rtentry *saved_nrt = NULL;
+       struct rtentry *rt;
        struct radix_node_head *rnh;
-       struct ifaddr *ifa = NULL;
        struct rawcb *rp = NULL;
        struct pr_output_info *oi;
        struct rt_addrinfo rtinfo;
@@ -483,99 +490,49 @@ route_output(struct mbuf *m, struct socket *so, ...)
 
        switch (rtm->rtm_type) {
        case RTM_ADD:
-               if (rtinfo.rti_gateway == NULL)
-                       gotoerr(EINVAL);
-               error = rtrequest1(RTM_ADD, &rtinfo, &saved_nrt);
-               if (error == 0 && saved_nrt != NULL) {
-                       rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
-                           &saved_nrt->rt_rmx);
-                       saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
-                       saved_nrt->rt_rmx.rmx_locks |=
-                           (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
-                       --saved_nrt->rt_refcnt;
-                       saved_nrt->rt_genmask = rtinfo.rti_genmask;
+               if (rtinfo.rti_gateway == NULL) {
+                       error = EINVAL;
+               } else {
+                       error = rtrequest1_global(RTM_ADD, &rtinfo, 
+                                         route_output_add_callback, rtm);
                }
                break;
        case RTM_DELETE:
-               error = rtrequest1(RTM_DELETE, &rtinfo, &saved_nrt);
-               if (error == 0) {
-                       if ((rt = saved_nrt))
-                               rt->rt_refcnt++;
-                       if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
-                               gotoerr(ENOBUFS);
-               }
+               /*
+                * note: &rtm passed as argument so 'rtm' can be replaced.
+                */
+               error = rtrequest1_global(RTM_DELETE, &rtinfo,
+                                         route_output_delete_callback, &rtm);
                break;
        case RTM_GET:
-       case RTM_CHANGE:
-       case RTM_LOCK:
-               if ((rnh = rt_tables[rtinfo.rti_dst->sa_family]) == NULL)
-                       gotoerr(EAFNOSUPPORT);
+               rnh = rt_tables[mycpuid][rtinfo.rti_dst->sa_family];
+               if (rnh == NULL) {
+                       error = EAFNOSUPPORT;
+                       break;
+               }
                rt = (struct rtentry *)
                    rnh->rnh_lookup((char *)rtinfo.rti_dst,
                                    (char *)rtinfo.rti_netmask, rnh);
-               if (rt == NULL)
-                       gotoerr(ESRCH);
-               rt->rt_refcnt++;
-
-               switch(rtm->rtm_type) {
-               case RTM_GET:
-                       if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
-                               gotoerr(ENOBUFS);
-                       break;
-               case RTM_CHANGE:
-                       /*
-                        * new gateway could require new ifaddr, ifp;
-                        * flags may also be different; ifp may be specified
-                        * by ll sockaddr when protocol address is ambiguous
-                        */
-                       if (((rt->rt_flags & RTF_GATEWAY) &&
-                            rtinfo.rti_gateway != NULL) ||
-                           rtinfo.rti_ifpaddr != NULL ||
-                           (rtinfo.rti_ifaaddr != NULL &&
-                            sa_equal(rtinfo.rti_ifaaddr,
-                                     rt->rt_ifa->ifa_addr))) {
-                               error = rt_getifa(&rtinfo);
-                               if (error != 0)
-                                       gotoerr(error);
-                       }
-                       if (rtinfo.rti_gateway != NULL) {
-                               error = rt_setgate(rt, rt_key(rt),
-                                                  rtinfo.rti_gateway);
-                               if (error != 0)
-                                       gotoerr(error);
-                       }
-                       if ((ifa = rtinfo.rti_ifa) != NULL) {
-                               struct ifaddr *oifa = rt->rt_ifa;
-
-                               if (oifa != ifa) {
-                                       if (oifa && oifa->ifa_rtrequest)
-                                               oifa->ifa_rtrequest(RTM_DELETE,
-                                                   rt, &rtinfo);
-                                       IFAFREE(rt->rt_ifa);
-                                       IFAREF(ifa);
-                                       rt->rt_ifa = ifa;
-                                       rt->rt_ifp = rtinfo.rti_ifp;
-                               }
-                       }
-                       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;
-                       /*
-                        * Fall into
-                        */
-               case RTM_LOCK:
-                       rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
-                       rt->rt_rmx.rmx_locks |=
-                               (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+               if (rt == NULL) {
+                       error = ESRCH;
                        break;
                }
-
+               rt->rt_refcnt++;
+               if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
+                       gotoerr(ENOBUFS);
+               --rt->rt_refcnt;
+               break;
+       case RTM_CHANGE:
+               error = rtrequest1_global(RTM_GET, &rtinfo,
+                                         route_output_change_callback, rtm);
+               break;
+       case RTM_LOCK:
+               error = rtrequest1_global(RTM_GET, &rtinfo,
+                                         route_output_lock_callback, rtm);
                break;
        default:
-               gotoerr(EOPNOTSUPP);
+               error = EOPNOTSUPP;
+               break;
        }
 
 flush:
@@ -585,8 +542,7 @@ flush:
                else
                        rtm->rtm_flags |= RTF_DONE;
        }
-       if (rt != NULL)
-               rtfree(rt);
+
        /*
         * Check to see if we don't want our own messages.
         */
@@ -618,6 +574,99 @@ flush:
        return (error);
 }
 
+static void
+route_output_add_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
+                         struct rtentry *rt, void *arg)
+{
+       struct rt_msghdr *rtm = arg;
+
+       if (error == 0 && rt != NULL) {
+               rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
+                   &rt->rt_rmx);
+               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;
+       }
+}
+
+static void
+route_output_delete_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
+                         struct rtentry *rt, void *arg)
+{
+       struct rt_msghdr **rtm = arg;
+
+       if (error == 0 && rt) {
+               ++rt->rt_refcnt;
+               if (fillrtmsg(rtm, rt, rtinfo) != 0) {
+                       error = ENOBUFS;
+                       /* XXX no way to return the error */
+               }
+               --rt->rt_refcnt;
+       }
+}
+
+static void
+route_output_change_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
+                         struct rtentry *rt, void *arg)
+{
+       struct rt_msghdr *rtm = arg;
+       struct ifaddr *ifa;
+
+       if (error)
+               goto done;
+
+       /*
+        * new gateway could require new ifaddr, ifp;
+        * flags may also be different; ifp may be specified
+        * by ll sockaddr when protocol address is ambiguous
+        */
+       if (((rt->rt_flags & RTF_GATEWAY) && rtinfo->rti_gateway != NULL) ||
+           rtinfo->rti_ifpaddr != NULL || (rtinfo->rti_ifaaddr != NULL &&
+           sa_equal(rtinfo->rti_ifaaddr, rt->rt_ifa->ifa_addr))
+       ) {
+               error = rt_getifa(rtinfo);
+               if (error != 0)
+                       goto done;
+       }
+       if (rtinfo->rti_gateway != NULL) {
+               error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway);
+               if (error != 0)
+                       goto done;
+       }
+       if ((ifa = rtinfo->rti_ifa) != NULL) {
+               struct ifaddr *oifa = rt->rt_ifa;
+
+               if (oifa != ifa) {
+                       if (oifa && oifa->ifa_rtrequest)
+                               oifa->ifa_rtrequest(RTM_DELETE, rt, rtinfo);
+                       IFAFREE(rt->rt_ifa);
+                       IFAREF(ifa);
+                       rt->rt_ifa = ifa;
+                       rt->rt_ifp = rtinfo->rti_ifp;
+               }
+       }
+       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;
+done:
+       /* XXX no way to return error */
+       ;
+}
+
+static void
+route_output_lock_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
+                          struct rtentry *rt, void *arg)
+{
+       struct rt_msghdr *rtm = arg;
+
+       rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
+       rt->rt_rmx.rmx_locks |=
+               (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+}
+
 static void
 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
 {
@@ -1162,6 +1211,7 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
        u_int   namelen = arg2;
        struct radix_node_head *rnh;
        int     i, error = EINVAL;
+       int     origcpu;
        u_char  af;
        struct  walkarg w;
 
@@ -1169,7 +1219,7 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
        namelen--;
        if (req->newptr)
                return (EPERM);
-       if (namelen != 3)
+       if (namelen != 3 && namelen != 4)
                return (EINVAL);
        af = name[0];
        bzero(&w, sizeof w);
@@ -1177,13 +1227,25 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
        w.w_arg = name[2];
        w.w_req = req;
 
+       /*
+        * Optional third argument specifies cpu, used primarily for
+        * debugging the route table.
+        */
+       if (namelen == 4) {
+               if (name[3] < 0 || name[3] >= ncpus)
+                       return (EINVAL);
+               origcpu = mycpuid;
+               lwkt_migratecpu(name[3]);
+       } else {
+               origcpu = -1;
+       }
        crit_enter();
        switch (w.w_op) {
-
        case NET_RT_DUMP:
        case NET_RT_FLAGS:
                for (i = 1; i <= AF_MAX; i++)
-                       if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
+                       if ((rnh = rt_tables[mycpuid][i]) &&
+                           (af == 0 || af == i) &&
                            (error = rnh->rnh_walktree(rnh,
                                                       sysctl_dumpentry, &w)))
                                break;
@@ -1195,6 +1257,8 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
        crit_exit();
        if (w.w_tmem != NULL)
                free(w.w_tmem, M_RTABLE);
+       if (origcpu >= 0)
+               lwkt_migratecpu(origcpu);
        return (error);
 }
 
index d7aca52..a62a21e 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)if_ether.c  8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/netinet/if_ether.c,v 1.64.2.23 2003/04/11 07:23:15 fjoe Exp $
- * $DragonFly: src/sys/netinet/if_ether.c,v 1.30 2005/12/21 16:40:25 corecode Exp $
+ * $DragonFly: src/sys/netinet/if_ether.c,v 1.31 2006/01/31 19:05:39 dillon Exp $
  */
 
 /*
@@ -153,7 +153,7 @@ struct llinfo_arp {
        u_short la_asked;       /* #times we QUERIED following expiration */
 };
 
-static LIST_HEAD(, llinfo_arp) llinfo_arp;
+static LIST_HEAD(, llinfo_arp) llinfo_arp_list[MAXCPU];
 
 static int     arp_maxtries = 5;
 static int     useloopback = 1; /* use loopback interface for local traffic */
@@ -178,7 +178,7 @@ static struct llinfo_arp
 static void    in_arpinput (struct mbuf *);
 #endif
 
-static struct callout  arptimer_ch;
+static struct callout  arptimer_ch[MAXCPU];
 
 /*
  * Timeout routine.  Age arp_tab entries periodically.
@@ -190,11 +190,11 @@ arptimer(void *ignored_arg)
        struct llinfo_arp *la, *nla;
 
        crit_enter();
-       LIST_FOREACH_MUTABLE(la, &llinfo_arp, la_le, nla) {
+       LIST_FOREACH_MUTABLE(la, &llinfo_arp_list[mycpuid], la_le, nla) {
                if (la->la_rt->rt_expire && la->la_rt->rt_expire <= time_second)
-                       arptfree(la);   /* might remove la from llinfo_arp! */
+                       arptfree(la);   
        }
-       callout_reset(&arptimer_ch, arpt_prune * hz, arptimer, NULL);
+       callout_reset(&arptimer_ch[mycpuid], arpt_prune * hz, arptimer, NULL);
        crit_exit();
 }
 
@@ -208,12 +208,12 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
        struct llinfo_arp *la = rt->rt_llinfo;
 
        struct sockaddr_dl null_sdl = { sizeof null_sdl, AF_LINK };
-       static boolean_t arpinit_done;
+       static boolean_t arpinit_done[MAXCPU];
 
-       if (!arpinit_done) {
-               arpinit_done = TRUE;
-               callout_init(&arptimer_ch);
-               callout_reset(&arptimer_ch, hz, arptimer, NULL);
+       if (!arpinit_done[mycpuid]) {
+               arpinit_done[mycpuid] = TRUE;
+               callout_init(&arptimer_ch[mycpuid]);
+               callout_reset(&arptimer_ch[mycpuid], hz, arptimer, NULL);
        }
        if (rt->rt_flags & RTF_GATEWAY)
                return;
@@ -270,7 +270,7 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
                bzero(la, sizeof *la);
                la->la_rt = rt;
                rt->rt_flags |= RTF_LLINFO;
-               LIST_INSERT_HEAD(&llinfo_arp, la, la_le);
+               LIST_INSERT_HEAD(&llinfo_arp_list[mycpuid], la, la_le);
 
 #ifdef INET
                /*
@@ -599,6 +599,156 @@ SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW,
        &log_arp_wrong_iface, 0,
        "log arp packets arriving on the wrong interface");
 
+#ifdef BRIDGE
+#define BRIDGE_TEST (do_bridge)
+#else
+#define BRIDGE_TEST (0) /* cc will optimise the test away */
+#endif
+
+static void
+arp_update_oncpu(struct mbuf *m, in_addr_t saddr, boolean_t create,
+                boolean_t dologging)
+{
+       struct arphdr *ah = mtod(m, struct arphdr *);
+       struct ifnet *ifp = m->m_pkthdr.rcvif;
+       struct llinfo_arp *la;
+       struct sockaddr_dl *sdl;
+       struct rtentry *rt;
+       int cpu = mycpuid;
+
+       la = arplookup(saddr, create, FALSE);
+       if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
+               struct in_addr isaddr = { saddr };
+
+               /* the following is not an error when doing bridging */
+               if (!BRIDGE_TEST && rt->rt_ifp != ifp) {
+                       if (dologging && log_arp_wrong_iface && cpu == 0) {
+                               log(LOG_ERR,
+                                   "arp: %s is on %s "
+                                   "but got reply from %*D on %s\n",
+                                   inet_ntoa(isaddr),
+                                   rt->rt_ifp->if_xname,
+                                   ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+                                   ifp->if_xname);
+                       }
+                       return;
+               }
+               if (sdl->sdl_alen &&
+                   bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
+                       if (rt->rt_expire != 0) {
+                               if (dologging && cpu == 0) {
+                                       log(LOG_INFO,
+                                       "arp: %s moved from %*D to %*D on %s\n",
+                                       inet_ntoa(isaddr),
+                                       ifp->if_addrlen, (u_char *)LLADDR(sdl),
+                                       ":", ifp->if_addrlen,
+                                       (u_char *)ar_sha(ah), ":",
+                                       ifp->if_xname);
+                               }
+                       } else {
+                               if (dologging && cpu == 0) {
+                                       log(LOG_ERR,
+                                       "arp: %*D attempts to modify permanent entry for %s on %s\n",
+                                       ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+                                       inet_ntoa(isaddr), ifp->if_xname);
+                               }
+                               return;
+                       }
+               }
+               /*
+                * sanity check for the address length.
+                * XXX this does not work for protocols with variable address
+                * length. -is
+                */
+               if (dologging && sdl->sdl_alen && sdl->sdl_alen != ah->ar_hln &&
+                   cpu == 0)
+               {
+                       log(LOG_WARNING,
+                           "arp from %*D: new addr len %d, was %d",
+                           ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
+                           ah->ar_hln, sdl->sdl_alen);
+               }
+               if (ifp->if_addrlen != ah->ar_hln) {
+                       if (dologging && cpu == 0) {
+                               log(LOG_WARNING,
+                               "arp from %*D: addr len: new %d, i/f %d (ignored)",
+                               ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
+                               ah->ar_hln, ifp->if_addrlen);
+                       }
+                       return;
+               }
+               memcpy(LLADDR(sdl), ar_sha(ah), sdl->sdl_alen = ah->ar_hln);
+               /*
+                * If we receive an arp from a token-ring station over
+                * a token-ring nic then try to save the source
+                * routing info.
+                */
+               if (ifp->if_type == IFT_ISO88025) {
+                       struct iso88025_header *th =
+                           (struct iso88025_header *)m->m_pkthdr.header;
+                       struct iso88025_sockaddr_dl_data *trld =
+                           SDL_ISO88025(sdl);
+                       int rif_len;
+
+                       rif_len = TR_RCF_RIFLEN(th->rcf);
+                       if ((th->iso88025_shost[0] & TR_RII) &&
+                           (rif_len > 2)) {
+                               trld->trld_rcf = th->rcf;
+                               trld->trld_rcf ^= htons(TR_RCF_DIR);
+                               memcpy(trld->trld_route, th->rd, rif_len - 2);
+                               trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK);
+                               /*
+                                * Set up source routing information for
+                                * reply packet (XXX)
+                                */
+                               m->m_data -= rif_len;
+                               m->m_len  += rif_len;
+                               m->m_pkthdr.len += rif_len;
+                       } else {
+                               th->iso88025_shost[0] &= ~TR_RII;
+                               trld->trld_rcf = 0;
+                       }
+                       m->m_data -= 8;
+                       m->m_len  += 8;
+                       m->m_pkthdr.len += 8;
+                       th->rcf = trld->trld_rcf;
+               }
+               if (rt->rt_expire != 0)
+                       rt->rt_expire = time_second + arpt_keep;
+               rt->rt_flags &= ~RTF_REJECT;
+               la->la_asked = 0;
+               la->la_preempt = arp_maxtries;
+
+               /*
+                * This particular cpu might have been holding an mbuf
+                * pending ARP resolution.  If so, transmit the mbuf now.
+                */
+               if (la->la_hold != NULL) {
+                       m_adj(la->la_hold, sizeof(struct ether_header));
+                       lwkt_serialize_enter(ifp->if_serializer);
+                       (*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt);
+                       lwkt_serialize_exit(ifp->if_serializer);
+                       la->la_hold = NULL;
+               }
+       }
+}
+
+#ifdef SMP
+
+struct netmsg_arp_update {
+       struct lwkt_msg lmsg;
+       struct mbuf     *m;
+       in_addr_t       saddr;
+       boolean_t       create;
+};
+
+static int arp_update_msghandler(struct lwkt_msg *lmsg);
+
+#endif
+
+/*
+ * Called from arpintr() - this routine is run from a single cpu.
+ */
 static void
 in_arpinput(struct mbuf *m)
 {
@@ -607,15 +757,15 @@ in_arpinput(struct mbuf *m)
        struct ether_header *eh;
        struct arc_header *arh;
        struct iso88025_header *th = (struct iso88025_header *)NULL;
-       struct iso88025_sockaddr_dl_data *trld;
-       struct llinfo_arp *la = NULL;
        struct rtentry *rt;
        struct ifaddr *ifa;
        struct in_ifaddr *ia;
-       struct sockaddr_dl *sdl;
        struct sockaddr sa;
        struct in_addr isaddr, itaddr, myaddr;
-       int op, rif_len;
+#ifdef SMP
+       struct netmsg_arp_update msg;
+#endif
+       int op;
        int req_len;
 
        req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
@@ -628,11 +778,6 @@ in_arpinput(struct mbuf *m)
        op = ntohs(ah->ar_op);
        memcpy(&isaddr, ar_spa(ah), sizeof isaddr);
        memcpy(&itaddr, ar_tpa(ah), sizeof itaddr);
-#ifdef BRIDGE
-#define BRIDGE_TEST (do_bridge)
-#else
-#define BRIDGE_TEST (0) /* cc will optimise the test away */
-#endif
        /*
         * For a bridge, we want to check the address irrespective
         * of the receive interface. (This will change slightly
@@ -715,100 +860,16 @@ match:
                itaddr = myaddr;
                goto reply;
        }
-       la = arplookup(isaddr.s_addr, (itaddr.s_addr == myaddr.s_addr), FALSE);
-       if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
-               /* the following is not an error when doing bridging */
-               if (!BRIDGE_TEST && rt->rt_ifp != ifp) {
-                   if (log_arp_wrong_iface)
-                       log(LOG_ERR,
-                           "arp: %s is on %s but got reply from %*D on %s\n",
-                           inet_ntoa(isaddr),
-                           rt->rt_ifp->if_xname,
-                           ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
-                           ifp->if_xname);
-                   goto reply;
-               }
-               if (sdl->sdl_alen &&
-                   bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
-                       if (rt->rt_expire)
-                           log(LOG_INFO,
-                               "arp: %s moved from %*D to %*D on %s\n",
-                               inet_ntoa(isaddr),
-                               ifp->if_addrlen, (u_char *)LLADDR(sdl), ":",
-                               ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
-                               ifp->if_xname);
-                       else {
-                           log(LOG_ERR,
-                               "arp: %*D attempts to modify permanent entry for %s on %s\n",
-                               ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
-                               inet_ntoa(isaddr), ifp->if_xname);
-                           goto reply;
-                       }
-               }
-               /*
-                * sanity check for the address length.
-                * XXX this does not work for protocols with variable address
-                * length. -is
-                */
-               if (sdl->sdl_alen &&
-                   sdl->sdl_alen != ah->ar_hln) {
-                       log(LOG_WARNING,
-                           "arp from %*D: new addr len %d, was %d",
-                           ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
-                           ah->ar_hln, sdl->sdl_alen);
-               }
-               if (ifp->if_addrlen != ah->ar_hln) {
-                       log(LOG_WARNING,
-                           "arp from %*D: addr len: new %d, i/f %d (ignored)",
-                           ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
-                           ah->ar_hln, ifp->if_addrlen);
-                       goto reply;
-               }
-               memcpy(LLADDR(sdl), ar_sha(ah), sdl->sdl_alen = ah->ar_hln);
-               /*
-                * If we receive an arp from a token-ring station over
-                * a token-ring nic then try to save the source
-                * routing info.
-                */
-               if (ifp->if_type == IFT_ISO88025) {
-                       th = (struct iso88025_header *)m->m_pkthdr.header;
-                       trld = SDL_ISO88025(sdl);
-                       rif_len = TR_RCF_RIFLEN(th->rcf);
-                       if ((th->iso88025_shost[0] & TR_RII) &&
-                           (rif_len > 2)) {
-                               trld->trld_rcf = th->rcf;
-                               trld->trld_rcf ^= htons(TR_RCF_DIR);
-                               memcpy(trld->trld_route, th->rd, rif_len - 2);
-                               trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK);
-                               /*
-                                * Set up source routing information for
-                                * reply packet (XXX)
-                                */
-                               m->m_data -= rif_len;
-                               m->m_len  += rif_len;
-                               m->m_pkthdr.len += rif_len;
-                       } else {
-                               th->iso88025_shost[0] &= ~TR_RII;
-                               trld->trld_rcf = 0;
-                       }
-                       m->m_data -= 8;
-                       m->m_len  += 8;
-                       m->m_pkthdr.len += 8;
-                       th->rcf = trld->trld_rcf;
-               }
-               if (rt->rt_expire)
-                       rt->rt_expire = time_second + arpt_keep;
-               rt->rt_flags &= ~RTF_REJECT;
-               la->la_asked = 0;
-               la->la_preempt = arp_maxtries;
-               if (la->la_hold != NULL) {
-                       m_adj(la->la_hold, sizeof(struct ether_header));
-                       lwkt_serialize_enter(ifp->if_serializer);
-                       (*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt);
-                       lwkt_serialize_exit(ifp->if_serializer);
-                       la->la_hold = NULL;
-               }
-       }
+#ifdef SMP
+       lwkt_initmsg(&msg.lmsg, &curthread->td_msgport, 0, 
+                    lwkt_cmd_func(arp_update_msghandler), lwkt_cmd_op_none);
+       msg.m = m;
+       msg.saddr = isaddr.s_addr;
+       msg.create = (itaddr.s_addr == myaddr.s_addr);
+       lwkt_domsg(rtable_portfn(0), &msg.lmsg);
+#endif
+       arp_update_oncpu(m, isaddr.s_addr, (itaddr.s_addr == myaddr.s_addr),
+                        TRUE);
 reply:
        if (op != ARPOP_REQUEST) {
                m_freem(m);
@@ -819,6 +880,8 @@ reply:
                memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
                memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln);
        } else {
+               struct llinfo_arp *la;
+
                la = arplookup(itaddr.s_addr, FALSE, SIN_PROXY);
                if (la == NULL) {
                        struct sockaddr_in sin;
@@ -854,6 +917,8 @@ reply:
                        printf("arp: proxying for %s\n", inet_ntoa(itaddr));
 #endif
                } else {
+                       struct sockaddr_dl *sdl;
+
                        rt = la->la_rt;
                        memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
                        sdl = SDL(rt->rt_gateway);
@@ -908,6 +973,29 @@ reply:
        lwkt_serialize_exit(ifp->if_serializer);
        return;
 }
+
+#ifdef SMP
+
+static
+int
+arp_update_msghandler(struct lwkt_msg *lmsg)
+{
+       struct netmsg_arp_update *msg = (struct netmsg_arp_update *)lmsg;
+       int nextcpu;
+
+       arp_update_oncpu(msg->m, msg->saddr, msg->create, FALSE);
+
+       nextcpu = mycpuid + 1;
+       if (nextcpu < ncpus) {
+               lwkt_forwardmsg(rtable_portfn(nextcpu), &msg->lmsg);
+       } else {
+               lwkt_replymsg(&msg->lmsg, 0);
+       }
+       return (0);
+}
+
+#endif
+
 #endif
 
 /*
@@ -993,7 +1081,10 @@ arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
 static void
 arp_init(void)
 {
-       LIST_INIT(&llinfo_arp);
+       int cpu;
+
+       for (cpu = 0; cpu < ncpus2; cpu++)
+               LIST_INIT(&llinfo_arp_list[cpu]);
        netisr_register(NETISR_ARP, cpu0_portfn, arpintr);
 }
 
index 97c5edf..8d17350 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
  * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.59.2.27 2004/01/02 04:06:42 ambrisko Exp $
- * $DragonFly: src/sys/netinet/in_pcb.c,v 1.37 2006/01/14 11:33:50 swildner Exp $
+ * $DragonFly: src/sys/netinet/in_pcb.c,v 1.38 2006/01/31 19:05:40 dillon Exp $
  */
 
 #include "opt_ipsec.h"
@@ -783,7 +783,7 @@ in_losing(struct inpcb *inp)
                rtinfo.rti_flags = rt->rt_flags;
                rt_missmsg(RTM_LOSING, &rtinfo, rt->rt_flags, 0);
                if (rt->rt_flags & RTF_DYNAMIC)
-                       rtrequest1(RTM_DELETE, &rtinfo, NULL);
+                       rtrequest1_global(RTM_DELETE, &rtinfo, NULL, NULL);
                inp->inp_route.ro_rt = NULL;
                rtfree(rt);
                /*
index 4908d1e..25c9718 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netinet/in_rmx.c,v 1.37.2.3 2002/08/09 14:49:23 ru Exp $
- * $DragonFly: src/sys/netinet/in_rmx.c,v 1.12 2005/06/02 23:52:42 dillon Exp $
+ * $DragonFly: src/sys/netinet/in_rmx.c,v 1.13 2006/01/31 19:05:40 dillon Exp $
  */
 
 /*
@@ -50,6 +50,7 @@
 #include <sys/socket.h>
 #include <sys/mbuf.h>
 #include <sys/syslog.h>
+#include <sys/globaldata.h>
 #include <sys/thread2.h>
 
 #include <net/if.h>
@@ -60,7 +61,7 @@
 
 #define RTPRF_EXPIRING RTF_PROTO3      /* set on routes we manage */
 
-static struct callout in_rtqtimo_ch;
+static struct callout in_rtqtimo_ch[MAXCPU];
 
 /*
  * Do what we need to do when inserting a route.
@@ -141,9 +142,10 @@ in_addroute(char *key, char *mask, struct radix_node_head *head,
         * and there is a cached route, free it.  Otherwise, we may end
         * up using the wrong route.
         */
-       if (ret != NULL && ipforwarding && ipforward_rt.ro_rt != NULL) {
-               RTFREE(ipforward_rt.ro_rt);
-               ipforward_rt.ro_rt = NULL;
+       if (ret != NULL && ipforwarding &&
+           ipforward_rt[mycpuid].ro_rt != NULL) {
+               RTFREE(ipforward_rt[mycpuid].ro_rt);
+               ipforward_rt[mycpuid].ro_rt = NULL;
        }
 
        return ret;
@@ -316,13 +318,14 @@ in_rtqtimo(void *rock)
 
        atv.tv_usec = 0;
        atv.tv_sec = arg.nextstop - time_second;
-       callout_reset(&in_rtqtimo_ch, tvtohz_high(&atv), in_rtqtimo, rock);
+       callout_reset(&in_rtqtimo_ch[mycpuid], tvtohz_high(&atv), in_rtqtimo,
+                     rock);
 }
 
 void
 in_rtqdrain(void)
 {
-       struct radix_node_head *rnh = rt_tables[AF_INET];
+       struct radix_node_head *rnh = rt_tables[mycpuid][AF_INET];
        struct rtqk_arg arg;
 
        arg.found = arg.killed = 0;
@@ -346,14 +349,14 @@ in_inithead(void **head, int off)
        if (!rn_inithead(head, off))
                return 0;
 
-       if (head != (void **)&rt_tables[AF_INET]) /* BOGUS! */
+       if (head != (void **)&rt_tables[mycpuid][AF_INET]) /* BOGUS! */
                return 1;       /* only do this for the real routing table */
 
        rnh = *head;
        rnh->rnh_addaddr = in_addroute;
        rnh->rnh_matchaddr = in_matchroute;
        rnh->rnh_close = in_closeroute;
-       callout_init(&in_rtqtimo_ch);
+       callout_init(&in_rtqtimo_ch[mycpuid]);
        in_rtqtimo(rnh);        /* kick off timeout first time */
        return 1;
 }
@@ -408,7 +411,7 @@ in_ifadown(struct ifaddr *ifa, int delete)
        if (ifa->ifa_addr->sa_family != AF_INET)
                return 1;
 
-       arg.rnh = rnh = rt_tables[AF_INET];
+       arg.rnh = rnh = rt_tables[mycpuid][AF_INET];
        arg.ifa = ifa;
        arg.del = delete;
        rnh->rnh_walktree(rnh, in_ifadownkill, &arg);
index a93b595..0ecaec4 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)ip_input.c  8.2 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/netinet/ip_input.c,v 1.130.2.52 2003/03/07 07:01:28 silby Exp $
- * $DragonFly: src/sys/netinet/ip_input.c,v 1.60 2005/10/28 15:56:47 liamfoy Exp $
+ * $DragonFly: src/sys/netinet/ip_input.c,v 1.61 2006/01/31 19:05:40 dillon Exp $
  */
 
 #define        _IP_VHL
@@ -396,7 +396,7 @@ ip_init(void)
  * the most recently used route ? it is cleared in in_addroute()
  * when a new route is successfully created.
  */
-struct route ipforward_rt;
+struct route ipforward_rt[MAXCPU];
 
 /* Do transport protocol processing. */
 static void
@@ -1577,7 +1577,8 @@ dropit:
                                                                        == NULL)
                                        ia = (INA)ifa_ifwithnet((SA)&ipaddr);
                        } else
-                               ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt);
+                               ia = ip_rtaddr(ipaddr.sin_addr,
+                                              &ipforward_rt[mycpuid]);
                        if (ia == NULL) {
                                type = ICMP_UNREACH;
                                code = ICMP_UNREACH_SRCFAIL;
@@ -1617,7 +1618,8 @@ dropit:
                         * use the incoming interface (should be same).
                         */
                        if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL &&
-                           (ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt))
+                           (ia = ip_rtaddr(ipaddr.sin_addr,
+                                           &ipforward_rt[mycpuid]))
                                                                     == NULL) {
                                type = ICMP_UNREACH;
                                code = ICMP_UNREACH_HOST;
@@ -1879,6 +1881,7 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
        n_long dest;
        struct in_addr pkt_dst;
        struct m_hdr tag;
+       struct route *cache_rt = &ipforward_rt[mycpuid];
 
        dest = INADDR_ANY;
        /*
@@ -1903,23 +1906,23 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                return;
        }
 
-       ipforward_rtaddr = (struct sockaddr_in *) &ipforward_rt.ro_dst;
-       if (ipforward_rt.ro_rt == NULL ||
+       ipforward_rtaddr = (struct sockaddr_in *) &cache_rt->ro_dst;
+       if (cache_rt->ro_rt == NULL ||
            ipforward_rtaddr->sin_addr.s_addr != pkt_dst.s_addr) {
-               if (ipforward_rt.ro_rt != NULL) {
-                       RTFREE(ipforward_rt.ro_rt);
-                       ipforward_rt.ro_rt = NULL;
+               if (cache_rt->ro_rt != NULL) {
+                       RTFREE(cache_rt->ro_rt);
+                       cache_rt->ro_rt = NULL;
                }
                ipforward_rtaddr->sin_family = AF_INET;
                ipforward_rtaddr->sin_len = sizeof(struct sockaddr_in);
                ipforward_rtaddr->sin_addr = pkt_dst;
-               rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
-               if (ipforward_rt.ro_rt == NULL) {
+               rtalloc_ign(cache_rt, RTF_PRCLONING);
+               if (cache_rt->ro_rt == NULL) {
                        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
                        return;
                }
        }
-       rt = ipforward_rt.ro_rt;
+       rt = cache_rt->ro_rt;
 
        /*
         * Save the IP header and at most 8 bytes of the payload,
@@ -2001,12 +2004,13 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                m = (struct mbuf *)&tag;
        }
 
-       error = ip_output(m, NULL, &ipforward_rt, IP_FORWARDING, NULL, NULL);
+       error = ip_output(m, NULL, cache_rt, IP_FORWARDING, NULL,
+                         NULL);
        if (error == 0) {
                ipstat.ips_forward++;
                if (type == 0) {
                        if (mcopy) {
-                               ipflow_create(&ipforward_rt, mcopy);
+                               ipflow_create(cache_rt, mcopy);
                                m_freem(mcopy);
                        }
                        return;         /* most common case */
@@ -2049,7 +2053,7 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                 *      tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
                 * XXX quickhack!!!
                 */
-               if (ipforward_rt.ro_rt != NULL) {
+               if (cache_rt->ro_rt != NULL) {
                        struct secpolicy *sp = NULL;
                        int ipsecerror;
                        int ipsechdr;
@@ -2061,7 +2065,7 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                                                    &ipsecerror);
 
                        if (sp == NULL)
-                               destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu;
+                               destmtu = cache_rt->ro_rt->rt_ifp->if_mtu;
                        else {
                                /* count IPsec header size */
                                ipsechdr = ipsec4_hdrsiz(mcopy,
@@ -2094,7 +2098,7 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                 *      tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
                 * XXX quickhack!!!
                 */
-               if (ipforward_rt.ro_rt != NULL) {
+               if (cache_rt->ro_rt != NULL) {
                        struct secpolicy *sp = NULL;
                        int ipsecerror;
                        int ipsechdr;
@@ -2106,7 +2110,7 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                                                   &ipsecerror);
 
                        if (sp == NULL)
-                               destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu;
+                               destmtu = cache_rt->ro_rt->rt_ifp->if_mtu;
                        else {
                                /* count IPsec header size */
                                ipsechdr = ipsec4_hdrsiz(mcopy,
@@ -2134,8 +2138,8 @@ ip_forward(struct mbuf *m, boolean_t using_srcrt, struct sockaddr_in *next_hop)
                        }
                }
 #else /* !IPSEC && !FAST_IPSEC */
-               if (ipforward_rt.ro_rt != NULL)
-                       destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu;
+               if (cache_rt->ro_rt != NULL)
+                       destmtu = cache_rt->ro_rt->rt_ifp->if_mtu;
 #endif /*IPSEC*/
                ipstat.ips_cantfrag++;
                break;
index 2a545b2..ebb9db4 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ip_var.h    8.2 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/netinet/ip_var.h,v 1.50.2.13 2003/08/24 08:24:38 hsu Exp $
- * $DragonFly: src/sys/netinet/ip_var.h,v 1.17 2005/08/15 16:46:21 dillon Exp $
+ * $DragonFly: src/sys/netinet/ip_var.h,v 1.18 2006/01/31 19:05:40 dillon Exp $
  */
 
 #ifndef _NETINET_IP_VAR_H_
@@ -161,10 +161,10 @@ struct lwkt_port;
 extern u_short ip_id;                          /* ip packet ctr, for ids */
 extern int     ip_defttl;                      /* default IP ttl */
 extern int     ipforwarding;                   /* ip forwarding */
-extern struct route ipforward_rt;              /* ip forwarding cached route */
+extern struct route ipforward_rt[];            /* ip forwarding cached route */
 extern u_char  ip_protox[];
-extern struct socket *ip_rsvpd;        /* reservation protocol daemon */
-extern struct socket *ip_mrouter; /* multicast routing daemon */
+extern struct socket *ip_rsvpd;                /* reservation protocol daemon */
+extern struct socket *ip_mrouter;      /* multicast routing daemon */
 extern int     (*legal_vif_num)(int);
 extern u_long  (*ip_mcast_src)(int);
 extern int rsvp_on;
index 2be108e..8f45628 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6.c,v 1.7.2.9 2002/04/28 05:40:26 suz Exp $        */
-/*     $DragonFly: src/sys/netinet6/in6.c,v 1.17 2006/01/14 11:44:25 swildner Exp $    */
+/*     $DragonFly: src/sys/netinet6/in6.c,v 1.18 2006/01/31 19:05:42 dillon Exp $      */
 /*     $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $  */
 
 /*
@@ -133,6 +133,7 @@ static int in6_lifaddr_ioctl (struct socket *, u_long, caddr_t,
 static int in6_ifinit (struct ifnet *, struct in6_ifaddr *,
                           struct sockaddr_in6 *, int);
 static void in6_unlink_ifa (struct in6_ifaddr *, struct ifnet *);
+static void in6_ifloop_request_callback(int, int, struct rt_addrinfo *, struct rtentry *, void *);
 
 struct in6_multihead in6_multihead;    /* XXX BSS initialization */
 
@@ -146,14 +147,14 @@ static void
 in6_ifloop_request(int cmd, struct ifaddr *ifa)
 {
        struct sockaddr_in6 all1_sa;
-       struct rtentry *nrt = NULL;
-       int e;
+        struct rt_addrinfo rtinfo;
+       int error;
        
        bzero(&all1_sa, sizeof(all1_sa));
        all1_sa.sin6_family = AF_INET6;
        all1_sa.sin6_len = sizeof(struct sockaddr_in6);
        all1_sa.sin6_addr = in6mask128;
-
        /*
         * We specify the address itself as the gateway, and set the
         * RTF_LLINFO flag, so that the corresponding host route would have
@@ -162,16 +163,31 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
         * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
         * which changes the outgoing interface to the loopback interface.
         */
-       e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
-                     (struct sockaddr *)&all1_sa,
-                     RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
-       if (e != 0) {
+       bzero(&rtinfo, sizeof(struct rt_addrinfo));
+       rtinfo.rti_info[RTAX_DST] = ifa->ifa_addr;
+       rtinfo.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
+       rtinfo.rti_info[RTAX_NETMASK] = (struct sockaddr *)&all1_sa;
+       rtinfo.rti_flags = RTF_UP|RTF_HOST|RTF_LLINFO;
+
+       error = rtrequest1_global(cmd, &rtinfo, 
+                                 in6_ifloop_request_callback, ifa);
+       if (error != 0) {
                log(LOG_ERR, "in6_ifloop_request: "
                    "%s operation failed for %s (errno=%d)\n",
                    cmd == RTM_ADD ? "ADD" : "DELETE",
                    ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
-                   e);
+                   error);
        }
+}
+
+static void
+in6_ifloop_request_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
+                           struct rtentry *rt, void *arg)
+{
+       struct ifaddr *ifa = arg;
+
+       if (error)
+               goto done;
 
        /*
         * Make sure rt_ifa be equal to IFA, the second argument of the
@@ -180,10 +196,12 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
         * ip6_input, we assume that the rt_ifa points to the address instead
         * of the loopback address.
         */
-       if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
-               IFAFREE(nrt->rt_ifa);
+       if (cmd == RTM_ADD && rt && ifa != rt->rt_ifa) {
+               ++rt->rt_refcnt;
+               IFAFREE(rt->rt_ifa);
                IFAREF(ifa);
-               nrt->rt_ifa = ifa;
+               rt->rt_ifa = ifa;
+               --rt->rt_refcnt;
        }
 
        /*
@@ -192,19 +210,19 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
         *      we end up reporting twice in such a case.  Should we rather
         *      omit the second report?
         */
-       if (nrt) {
-               rt_newaddrmsg(cmd, ifa, e, nrt);
+       if (rt) {
+               if (mycpuid == 0)
+                       rt_newaddrmsg(cmd, ifa, error, rt);
                if (cmd == RTM_DELETE) {
-                       if (nrt->rt_refcnt <= 0) {
-                               /* XXX: we should free the entry ourselves. */
-                               nrt->rt_refcnt++;
-                               rtfree(nrt);
+                       if (rt->rt_refcnt == 0) {
+                               ++rt->rt_refcnt;
+                               rtfree(rt);
                        }
-               } else {
-                       /* the cmd must be RTM_ADD here */
-                       nrt->rt_refcnt--;
                }
        }
+done:
+       /* no way to return any new error */
+       ;
 }
 
 /*
@@ -1030,12 +1048,11 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
 
                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
                if (in6m == NULL) {
-                       rtrequest(RTM_ADD,
+                       rtrequest_global(RTM_ADD,
                                  (struct sockaddr *)&mltaddr,
                                  (struct sockaddr *)&ia->ia_addr,
                                  (struct sockaddr *)&mltmask,
-                                 RTF_UP|RTF_CLONING,  /* xxx */
-                                 (struct rtentry **)0);
+                                 RTF_UP|RTF_CLONING);  /* xxx */
                        in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                        if (error != 0) {
                                log(LOG_WARNING,
@@ -1082,12 +1099,11 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
 
                        IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
                        if (in6m == NULL && ia_loop != NULL) {
-                               rtrequest(RTM_ADD,
+                               rtrequest_global(RTM_ADD,
                                          (struct sockaddr *)&mltaddr,
                                          (struct sockaddr *)&ia_loop->ia_addr,
                                          (struct sockaddr *)&mltmask,
-                                         RTF_UP,
-                                         (struct rtentry **)0);
+                                         RTF_UP);
                                in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
                                if (error != 0) {
                                        log(LOG_WARNING, "in6_update_ifa: "
index 5743d69..2cc3db0 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6_pcb.c,v 1.10.2.9 2003/01/24 05:11:35 sam Exp $   */
-/*     $DragonFly: src/sys/netinet6/in6_pcb.c,v 1.27 2005/06/03 19:56:08 eirikn Exp $  */
+/*     $DragonFly: src/sys/netinet6/in6_pcb.c,v 1.28 2006/01/31 19:05:42 dillon Exp $  */
 /*     $KAME: in6_pcb.c,v 1.31 2001/05/21 05:45:10 jinmei Exp $        */
   
 /*
@@ -947,7 +947,7 @@ in6_losing(struct inpcb *in6p)
                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
                if (rt->rt_flags & RTF_DYNAMIC)
-                       rtrequest1(RTM_DELETE, &info, NULL);
+                       rtrequest1_global(RTM_DELETE, &info, NULL, NULL);
                in6p->in6p_route.ro_rt = NULL;
                rtfree(rt);
                /*
index f246c3e..c9c43d0 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6_rmx.c,v 1.1.2.4 2004/10/06 02:35:17 suz Exp $    */
-/*     $DragonFly: src/sys/netinet6/in6_rmx.c,v 1.13 2005/06/03 19:56:08 eirikn Exp $  */
+/*     $DragonFly: src/sys/netinet6/in6_rmx.c,v 1.14 2006/01/31 19:05:42 dillon Exp $  */
 /*     $KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $        */
 
 /*
@@ -83,6 +83,7 @@
 #include <sys/socketvar.h>
 #include <sys/mbuf.h>
 #include <sys/syslog.h>
+#include <sys/globaldata.h>
 #include <sys/thread2.h>
 
 #include <net/if.h>
 #include <netinet/tcp_timer.h>
 #include <netinet/tcp_var.h>
 
-static struct callout  in6_rtqtimo_ch;
-static struct callout  in6_mtutimo_ch;
+static struct callout  in6_rtqtimo_ch[MAXCPU];
+static struct callout  in6_mtutimo_ch[MAXCPU];
 
 extern int     in6_inithead (void **head, int off);
 
@@ -380,7 +381,8 @@ in6_rtqtimo(void *rock)
 
        atv.tv_usec = 0;
        atv.tv_sec = arg.nextstop;
-       callout_reset(&in6_rtqtimo_ch, tvtohz_high(&atv), in6_rtqtimo, rock);
+       callout_reset(&in6_rtqtimo_ch[mycpuid], tvtohz_high(&atv), in6_rtqtimo,
+                     rock);
 }
 
 /*
@@ -434,14 +436,15 @@ in6_mtutimo(void *rock)
                printf("invalid mtu expiration time on routing table\n");
                arg.nextstop = time_second + 30;        /* last resort */
        }
-       callout_reset(&in6_mtutimo_ch, tvtohz_high(&atv), in6_mtutimo, rock);
+       callout_reset(&in6_mtutimo_ch[mycpuid], tvtohz_high(&atv), in6_mtutimo,
+                     rock);
 }
 
 #if 0
 void
 in6_rtqdrain(void)
 {
-       struct radix_node_head *rnh = rt_tables[AF_INET6];
+       struct radix_node_head *rnh = rt_tables[mycpuid][AF_INET6];
        struct rtqk_arg arg;
 
        arg.found = arg.killed = 0;
@@ -466,15 +469,15 @@ in6_inithead(void **head, int off)
        if (!rn_inithead(head, off))
                return 0;
 
-       if (head != (void **)&rt_tables[AF_INET6]) /* BOGUS! */
+       if (head != (void **)&rt_tables[mycpuid][AF_INET6]) /* BOGUS! */
                return 1;       /* only do this for the real routing table */
 
        rnh = *head;
        rnh->rnh_addaddr = in6_addroute;
        rnh->rnh_matchaddr = in6_matchroute;
        rnh->rnh_close = in6_clsroute;
-       callout_init(&in6_mtutimo_ch);
-       callout_init(&in6_rtqtimo_ch);
+       callout_init(&in6_mtutimo_ch[mycpuid]);
+       callout_init(&in6_rtqtimo_ch[mycpuid]);
        in6_rtqtimo(rnh);       /* kick off timeout first time */
        in6_mtutimo(rnh);       /* kick off timeout first time */
        return 1;
index e6f70de..fcb8d96 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/nd6_rtr.c,v 1.2.2.5 2003/04/05 10:28:53 ume Exp $    */
-/*     $DragonFly: src/sys/netinet6/nd6_rtr.c,v 1.11 2006/01/14 11:44:25 swildner Exp $        */
+/*     $DragonFly: src/sys/netinet6/nd6_rtr.c,v 1.12 2006/01/31 19:05:42 dillon Exp $  */
 /*     $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $       */
 
 /*
@@ -45,6 +45,7 @@
 #include <sys/errno.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
+#include <sys/globaldata.h>
 #include <sys/thread2.h>
 
 #include <net/if.h>
@@ -1879,7 +1880,7 @@ in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
 void
 rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
 {
-       struct radix_node_head *rnh = rt_tables[AF_INET6];
+       struct radix_node_head *rnh = rt_tables[mycpuid][AF_INET6];
 
        crit_enter();
 
index c7e5b3b..0410a86 100644 (file)
@@ -33,7 +33,7 @@
  * 
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.13 2005/06/16 21:12:46 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.14 2006/01/31 19:05:30 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
@@ -83,7 +83,12 @@ _get_mycpu(void)
 }
 
 #define mycpu          _get_mycpu()
-#define mycpuid        _get_mycpu()->gd_cpuid
+
+#ifdef SMP
+#define        mycpuid (_get_mycpu()->gd_cpuid)
+#else
+#define        mycpuid 0
+#endif
 
 /*
  * note: curthread is never NULL, but curproc can be.  Also note that
index accd0ca..45f82c8 100644 (file)
@@ -7,7 +7,7 @@
  * Types which must already be defined when this header is included by
  * userland:   struct md_thread
  * 
- * $DragonFly: src/sys/sys/thread.h,v 1.76 2005/12/02 22:02:20 dillon Exp $
+ * $DragonFly: src/sys/sys/thread.h,v 1.77 2006/01/31 19:05:44 dillon Exp $
  */
 
 #ifndef _SYS_THREAD_H_
@@ -408,6 +408,7 @@ extern void lwkt_setpri(thread_t td, int pri);
 extern void lwkt_setpri_self(int pri);
 extern int  lwkt_checkpri_self(void);
 extern void lwkt_setcpu_self(struct globaldata *rgd);
+extern void lwkt_migratecpu(int cpuid);
 
 #ifdef SMP
 
index 388cb62..d1aa537 100644 (file)
@@ -38,7 +38,7 @@
  * nfs/krpc_subr.c
  * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
  * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $
- * $DragonFly: src/sys/vfs/nfs/bootp_subr.c,v 1.12 2005/10/27 14:03:56 sephe Exp $
+ * $DragonFly: src/sys/vfs/nfs/bootp_subr.c,v 1.13 2006/01/31 19:05:45 dillon Exp $
  */
 
 #include "opt_bootp.h"
@@ -1137,11 +1137,10 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
        if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
                clear_sinaddr(&defdst);
                clear_sinaddr(&defmask);
-               error = rtrequest(RTM_ADD,
-                                 (struct sockaddr *) &defdst,
-                                 (struct sockaddr *) gw,
-                                 (struct sockaddr *) &defmask,
-                                 (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
+               error = rtrequest_global(RTM_ADD, (struct sockaddr *) &defdst,
+                                        (struct sockaddr *) gw,
+                                        (struct sockaddr *) &defmask,
+                                        (RTF_UP | RTF_GATEWAY | RTF_STATIC));
                if (error != 0) {
                        printf("bootpc_adjust_interface: "
                               "add net route, error=%d\n", error);
index 943a440..874c0dc 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/nfs/nfs_vfsops.c,v 1.91.2.7 2003/01/27 20:04:08 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.33 2005/09/17 07:43:12 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.34 2006/01/31 19:05:45 dillon Exp $
  */
 
 #include "opt_bootp.h"
@@ -518,10 +518,10 @@ nfs_mountroot(mp)
                sin.sin_len = sizeof(sin);
                printf("nfs_mountroot: gateway %s\n",
                        inet_ntoa(nd->mygateway.sin_addr));
-               error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
-                   (struct sockaddr *)&nd->mygateway,
-                   (struct sockaddr *)&mask,
-                   RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
+               error = rtrequest_global(RTM_ADD, (struct sockaddr *)&sin,
+                                       (struct sockaddr *)&nd->mygateway,
+                                       (struct sockaddr *)&mask,
+                                       RTF_UP | RTF_GATEWAY);
                if (error)
                        printf("nfs_mountroot: unable to set gateway, error %d, continuing anyway\n", error);
        }