166d6c637SJeffrey Hsu /*
266d6c637SJeffrey Hsu * Copyright (c) 2003, 2004 Matthew Dillon. All rights reserved.
366d6c637SJeffrey Hsu * Copyright (c) 2003, 2004 Jeffrey M. Hsu. All rights reserved.
466d6c637SJeffrey Hsu * Copyright (c) 2003 Jonathan Lemon. All rights reserved.
566d6c637SJeffrey Hsu * Copyright (c) 2003, 2004 The DragonFly Project. All rights reserved.
6ef0fdad1SMatthew Dillon *
766d6c637SJeffrey Hsu * This code is derived from software contributed to The DragonFly Project
866d6c637SJeffrey Hsu * by Jonathan Lemon, Jeffrey M. Hsu, and Matthew Dillon.
966d6c637SJeffrey Hsu *
10d849e575SMatthew Dillon * Jonathan Lemon gave Jeffrey Hsu permission to combine his copyright
11d849e575SMatthew Dillon * into this one around July 8 2004.
12d849e575SMatthew Dillon *
1366d6c637SJeffrey Hsu * Redistribution and use in source and binary forms, with or without
1466d6c637SJeffrey Hsu * modification, are permitted provided that the following conditions
1566d6c637SJeffrey Hsu * are met:
1666d6c637SJeffrey Hsu * 1. Redistributions of source code must retain the above copyright
1766d6c637SJeffrey Hsu * notice, this list of conditions and the following disclaimer.
1866d6c637SJeffrey Hsu * 2. Redistributions in binary form must reproduce the above copyright
1966d6c637SJeffrey Hsu * notice, this list of conditions and the following disclaimer in the
2066d6c637SJeffrey Hsu * documentation and/or other materials provided with the distribution.
2166d6c637SJeffrey Hsu * 3. Neither the name of The DragonFly Project nor the names of its
2266d6c637SJeffrey Hsu * contributors may be used to endorse or promote products derived
2366d6c637SJeffrey Hsu * from this software without specific, prior written permission.
2466d6c637SJeffrey Hsu *
2566d6c637SJeffrey Hsu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2666d6c637SJeffrey Hsu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2766d6c637SJeffrey Hsu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2866d6c637SJeffrey Hsu * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2966d6c637SJeffrey Hsu * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
3066d6c637SJeffrey Hsu * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
3166d6c637SJeffrey Hsu * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3266d6c637SJeffrey Hsu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3366d6c637SJeffrey Hsu * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3466d6c637SJeffrey Hsu * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3566d6c637SJeffrey Hsu * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3666d6c637SJeffrey Hsu * SUCH DAMAGE.
37ef0fdad1SMatthew Dillon */
38ef0fdad1SMatthew Dillon
39ef0fdad1SMatthew Dillon #include <sys/param.h>
40ef0fdad1SMatthew Dillon #include <sys/systm.h>
41bf82f9b7SMatthew Dillon #include <sys/kernel.h>
429eeaa8a9SJeffrey Hsu #include <sys/malloc.h>
43bf82f9b7SMatthew Dillon #include <sys/msgport.h>
44ef0fdad1SMatthew Dillon #include <sys/proc.h>
45ef0fdad1SMatthew Dillon #include <sys/interrupt.h>
468bde602dSJeffrey Hsu #include <sys/socket.h>
478bde602dSJeffrey Hsu #include <sys/sysctl.h>
4848e7b118SMatthew Dillon #include <sys/socketvar.h>
498bde602dSJeffrey Hsu #include <net/if.h>
508bde602dSJeffrey Hsu #include <net/if_var.h>
515337421cSSepherosa Ziehau #include <net/netisr2.h>
52ef0fdad1SMatthew Dillon #include <machine/cpufunc.h>
53a91f9815SSepherosa Ziehau #include <machine/smp.h>
54ef0fdad1SMatthew Dillon
553227f1b8SMatthew Dillon #include <sys/thread2.h>
563227f1b8SMatthew Dillon #include <sys/msgport2.h>
574599cf19SMatthew Dillon #include <net/netmsg2.h>
583227f1b8SMatthew Dillon
591f4883b8SSepherosa Ziehau #include <vm/vm_extern.h>
601f4883b8SSepherosa Ziehau
61f63af080SSepherosa Ziehau static void netmsg_service_port_init(lwkt_port_t);
62c3c96e44SMatthew Dillon static void netmsg_service_loop(void *arg);
63ca86d83eSSepherosa Ziehau static void netisr_hashfn0(struct mbuf **mp, int hoff);
64e6f77b88SSepherosa Ziehau static void netisr_nohashck(struct mbuf *, const struct pktinfo *);
655c703385SMatthew Dillon
665c703385SMatthew Dillon struct netmsg_port_registration {
675c703385SMatthew Dillon TAILQ_ENTRY(netmsg_port_registration) npr_entry;
685c703385SMatthew Dillon lwkt_port_t npr_port;
695c703385SMatthew Dillon };
705c703385SMatthew Dillon
712879f880SSepherosa Ziehau struct netisr_rollup {
722879f880SSepherosa Ziehau TAILQ_ENTRY(netisr_rollup) ru_entry;
73c3c96e44SMatthew Dillon netisr_ru_t ru_func;
74239bdb58SSepherosa Ziehau int ru_prio;
752879f880SSepherosa Ziehau void *ru_key;
762879f880SSepherosa Ziehau };
772879f880SSepherosa Ziehau
782879f880SSepherosa Ziehau struct netmsg_rollup {
792879f880SSepherosa Ziehau struct netmsg_base base;
802879f880SSepherosa Ziehau netisr_ru_t func;
812879f880SSepherosa Ziehau int prio;
822879f880SSepherosa Ziehau void *key;
83c3c96e44SMatthew Dillon };
84c3c96e44SMatthew Dillon
85a91f9815SSepherosa Ziehau struct netmsg_barrier {
86a91f9815SSepherosa Ziehau struct netmsg_base base;
870503d1d0SSepherosa Ziehau volatile cpumask_t *br_cpumask;
88ca3321f8SSepherosa Ziehau volatile uint32_t br_done;
89a91f9815SSepherosa Ziehau };
90a91f9815SSepherosa Ziehau
91d0c7a72aSSepherosa Ziehau #define NETISR_BR_NOTDONE 0x1
92d0c7a72aSSepherosa Ziehau #define NETISR_BR_WAITDONE 0x80000000
93ca3321f8SSepherosa Ziehau
94a91f9815SSepherosa Ziehau struct netisr_barrier {
95a91f9815SSepherosa Ziehau struct netmsg_barrier *br_msgs[MAXCPU];
96a91f9815SSepherosa Ziehau int br_isset;
97a91f9815SSepherosa Ziehau };
98a91f9815SSepherosa Ziehau
991f4883b8SSepherosa Ziehau struct netisr_data {
1001f4883b8SSepherosa Ziehau struct thread thread;
1011f4883b8SSepherosa Ziehau #ifdef INVARIANTS
1021f4883b8SSepherosa Ziehau void *netlastfunc;
1031f4883b8SSepherosa Ziehau #endif
1042879f880SSepherosa Ziehau TAILQ_HEAD(, netisr_rollup) netrulist;
1051f4883b8SSepherosa Ziehau };
1061f4883b8SSepherosa Ziehau
1071f4883b8SSepherosa Ziehau static struct netisr_data *netisr_data[MAXCPU];
1081f4883b8SSepherosa Ziehau
1098bde602dSJeffrey Hsu static struct netisr netisrs[NETISR_MAX];
1105c703385SMatthew Dillon static TAILQ_HEAD(,netmsg_port_registration) netreglist;
1118bde602dSJeffrey Hsu
112bf82f9b7SMatthew Dillon /* Per-CPU thread to handle any protocol. */
1136617c2d1SSepherosa Ziehau struct thread *netisr_threads[MAXCPU];
11463fabf54SSepherosa Ziehau
1153227f1b8SMatthew Dillon lwkt_port netisr_afree_rport;
116c3d495a1SMatthew Dillon lwkt_port netisr_afree_free_so_rport;
117a29576fcSMatthew Dillon lwkt_port netisr_adone_rport;
1186aad077dSMatthew Dillon lwkt_port netisr_apanic_rport;
1193efe7008SMatthew Dillon lwkt_port netisr_sync_port;
1203227f1b8SMatthew Dillon
121fb0f29c4SMatthew Dillon static int (*netmsg_fwd_port_fn)(lwkt_port_t, lwkt_msg_t);
122fb0f29c4SMatthew Dillon
12392db3805SSepherosa Ziehau SYSCTL_NODE(_net, OID_AUTO, netisr, CTLFLAG_RW, 0, "netisr");
12463fabf54SSepherosa Ziehau
1252ff21866SMatthew Dillon __read_frequently static int netisr_rollup_limit = 32;
126b210f45eSMatthew Dillon SYSCTL_INT(_net_netisr, OID_AUTO, rollup_limit, CTLFLAG_RW,
127b210f45eSMatthew Dillon &netisr_rollup_limit, 0, "Message to process before rollup");
128b210f45eSMatthew Dillon
1292ff21866SMatthew Dillon __read_frequently int netisr_ncpus;
13005da34c3SSepherosa Ziehau TUNABLE_INT("net.netisr.ncpus", &netisr_ncpus);
1317310f736SSepherosa Ziehau SYSCTL_INT(_net_netisr, OID_AUTO, ncpus, CTLFLAG_RD,
13263fabf54SSepherosa Ziehau &netisr_ncpus, 0, "# of CPUs to handle network messages");
133ff4a1403SSepherosa Ziehau
1343227f1b8SMatthew Dillon /*
1353227f1b8SMatthew Dillon * netisr_afree_rport replymsg function, only used to handle async
1363227f1b8SMatthew Dillon * messages which the sender has abandoned to their fate.
1373227f1b8SMatthew Dillon */
1383227f1b8SMatthew Dillon static void
netisr_autofree_reply(lwkt_port_t port,lwkt_msg_t msg)1393227f1b8SMatthew Dillon netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
1403227f1b8SMatthew Dillon {
141efda3bd0SMatthew Dillon kfree(msg, M_LWKTMSG);
1423227f1b8SMatthew Dillon }
143ef0fdad1SMatthew Dillon
144c3d495a1SMatthew Dillon static void
netisr_autofree_free_so_reply(lwkt_port_t port,lwkt_msg_t msg)145c3d495a1SMatthew Dillon netisr_autofree_free_so_reply(lwkt_port_t port, lwkt_msg_t msg)
146c3d495a1SMatthew Dillon {
147c3d495a1SMatthew Dillon sofree(((netmsg_t)msg)->base.nm_so);
148c3d495a1SMatthew Dillon kfree(msg, M_LWKTMSG);
149c3d495a1SMatthew Dillon }
150c3d495a1SMatthew Dillon
151dc22b3aaSJeffrey Hsu /*
152fb0f29c4SMatthew Dillon * We need a custom putport function to handle the case where the
153fb0f29c4SMatthew Dillon * message target is the current thread's message port. This case
154fb0f29c4SMatthew Dillon * can occur when the TCP or UDP stack does a direct callback to NFS and NFS
155fb0f29c4SMatthew Dillon * then turns around and executes a network operation synchronously.
156dc22b3aaSJeffrey Hsu *
157fb0f29c4SMatthew Dillon * To prevent deadlocking, we must execute these self-referential messages
158fb0f29c4SMatthew Dillon * synchronously, effectively turning the message into a glorified direct
159fb0f29c4SMatthew Dillon * procedure call back into the protocol stack. The operation must be
160fb0f29c4SMatthew Dillon * complete on return or we will deadlock, so panic if it isn't.
161002c1265SMatthew Dillon *
162002c1265SMatthew Dillon * However, the target function is under no obligation to immediately
163002c1265SMatthew Dillon * reply the message. It may forward it elsewhere.
164dc22b3aaSJeffrey Hsu */
1655c703385SMatthew Dillon static int
netmsg_put_port(lwkt_port_t port,lwkt_msg_t lmsg)166dc22b3aaSJeffrey Hsu netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg)
167dc22b3aaSJeffrey Hsu {
168002c1265SMatthew Dillon netmsg_base_t nmsg = (void *)lmsg;
169dc22b3aaSJeffrey Hsu
170fb0f29c4SMatthew Dillon if ((lmsg->ms_flags & MSGF_SYNC) && port == &curthread->td_msgport) {
171002c1265SMatthew Dillon nmsg->nm_dispatch((netmsg_t)nmsg);
1724599cf19SMatthew Dillon return(EASYNC);
173dc22b3aaSJeffrey Hsu } else {
174fb0f29c4SMatthew Dillon return(netmsg_fwd_port_fn(port, lmsg));
175dc22b3aaSJeffrey Hsu }
176dc22b3aaSJeffrey Hsu }
177dc22b3aaSJeffrey Hsu
1783efe7008SMatthew Dillon /*
1793efe7008SMatthew Dillon * UNIX DOMAIN sockets still have to run their uipc functions synchronously,
1803efe7008SMatthew Dillon * because they depend on the user proc context for a number of things
1813efe7008SMatthew Dillon * (like creds) which we have not yet incorporated into the message structure.
1823efe7008SMatthew Dillon *
1833efe7008SMatthew Dillon * However, we maintain or message/port abstraction. Having a special
1843efe7008SMatthew Dillon * synchronous port which runs the commands synchronously gives us the
1853efe7008SMatthew Dillon * ability to serialize operations in one place later on when we start
1863efe7008SMatthew Dillon * removing the BGL.
1873efe7008SMatthew Dillon */
1883efe7008SMatthew Dillon static int
netmsg_sync_putport(lwkt_port_t port,lwkt_msg_t lmsg)1893efe7008SMatthew Dillon netmsg_sync_putport(lwkt_port_t port, lwkt_msg_t lmsg)
1903efe7008SMatthew Dillon {
191002c1265SMatthew Dillon netmsg_base_t nmsg = (void *)lmsg;
1923efe7008SMatthew Dillon
193e0383bf3SMatthew Dillon KKASSERT((lmsg->ms_flags & MSGF_DONE) == 0);
194e0383bf3SMatthew Dillon
1953efe7008SMatthew Dillon lmsg->ms_target_port = port; /* required for abort */
196002c1265SMatthew Dillon nmsg->nm_dispatch((netmsg_t)nmsg);
197e0383bf3SMatthew Dillon return(EASYNC);
1983efe7008SMatthew Dillon }
1993efe7008SMatthew Dillon
2003efe7008SMatthew Dillon static void
netisr_init(void)201bf82f9b7SMatthew Dillon netisr_init(void)
202ef0fdad1SMatthew Dillon {
203bf82f9b7SMatthew Dillon int i;
204ef0fdad1SMatthew Dillon
2052a048cf0SSepherosa Ziehau if (netisr_ncpus <= 0 || netisr_ncpus > ncpus) {
20605da34c3SSepherosa Ziehau /* Default. */
20705da34c3SSepherosa Ziehau netisr_ncpus = ncpus;
20805da34c3SSepherosa Ziehau }
20905da34c3SSepherosa Ziehau if (netisr_ncpus > NETISR_CPUMAX)
21005da34c3SSepherosa Ziehau netisr_ncpus = NETISR_CPUMAX;
21163fabf54SSepherosa Ziehau
2125c703385SMatthew Dillon TAILQ_INIT(&netreglist);
2135c703385SMatthew Dillon
2143efe7008SMatthew Dillon /*
2153efe7008SMatthew Dillon * Create default per-cpu threads for generic protocol handling.
2163efe7008SMatthew Dillon */
2173227f1b8SMatthew Dillon for (i = 0; i < ncpus; ++i) {
2181f4883b8SSepherosa Ziehau struct netisr_data *nd;
2191f4883b8SSepherosa Ziehau
220*1eeaf6b2SAaron LI nd = (void *)kmem_alloc3(kernel_map, sizeof(*nd),
2211f4883b8SSepherosa Ziehau VM_SUBSYS_GD, KM_CPU(i));
2221f4883b8SSepherosa Ziehau memset(nd, 0, sizeof(*nd));
2232879f880SSepherosa Ziehau TAILQ_INIT(&nd->netrulist);
2241f4883b8SSepherosa Ziehau netisr_data[i] = nd;
2251f4883b8SSepherosa Ziehau
2261f4883b8SSepherosa Ziehau lwkt_create(netmsg_service_loop, NULL, &netisr_threads[i],
2271f4883b8SSepherosa Ziehau &nd->thread, TDF_NOSTART|TDF_FORCE_SPINPORT|TDF_FIXEDCPU,
2286617c2d1SSepherosa Ziehau i, "netisr %d", i);
2296617c2d1SSepherosa Ziehau netmsg_service_port_init(&netisr_threads[i]->td_msgport);
2306617c2d1SSepherosa Ziehau lwkt_schedule(netisr_threads[i]);
2318bde602dSJeffrey Hsu }
2323efe7008SMatthew Dillon
2333efe7008SMatthew Dillon /*
2343efe7008SMatthew Dillon * The netisr_afree_rport is a special reply port which automatically
2356aad077dSMatthew Dillon * frees the replied message. The netisr_adone_rport simply marks
2366aad077dSMatthew Dillon * the message as being done. The netisr_apanic_rport panics if
2376aad077dSMatthew Dillon * the message is replied to.
2383efe7008SMatthew Dillon */
239fb0f29c4SMatthew Dillon lwkt_initport_replyonly(&netisr_afree_rport, netisr_autofree_reply);
240c3d495a1SMatthew Dillon lwkt_initport_replyonly(&netisr_afree_free_so_rport,
241c3d495a1SMatthew Dillon netisr_autofree_free_so_reply);
242fb0f29c4SMatthew Dillon lwkt_initport_replyonly_null(&netisr_adone_rport);
243fb0f29c4SMatthew Dillon lwkt_initport_panic(&netisr_apanic_rport);
2443efe7008SMatthew Dillon
2453efe7008SMatthew Dillon /*
2463efe7008SMatthew Dillon * The netisr_syncport is a special port which executes the message
2473efe7008SMatthew Dillon * synchronously and waits for it if EASYNC is returned.
2483efe7008SMatthew Dillon */
249fb0f29c4SMatthew Dillon lwkt_initport_putonly(&netisr_sync_port, netmsg_sync_putport);
2503227f1b8SMatthew Dillon }
251b2632176SSepherosa Ziehau SYSINIT(netisr, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, netisr_init, NULL);
252bf82f9b7SMatthew Dillon
2535c703385SMatthew Dillon /*
2545c703385SMatthew Dillon * Finish initializing the message port for a netmsg service. This also
2555c703385SMatthew Dillon * registers the port for synchronous cleanup operations such as when an
2565c703385SMatthew Dillon * ifnet is being destroyed. There is no deregistration API yet.
2575c703385SMatthew Dillon */
258f63af080SSepherosa Ziehau static void
netmsg_service_port_init(lwkt_port_t port)2595c703385SMatthew Dillon netmsg_service_port_init(lwkt_port_t port)
2605c703385SMatthew Dillon {
2615c703385SMatthew Dillon struct netmsg_port_registration *reg;
2625c703385SMatthew Dillon
2635c703385SMatthew Dillon /*
2645c703385SMatthew Dillon * Override the putport function. Our custom function checks for
2655c703385SMatthew Dillon * self-references and executes such commands synchronously.
2665c703385SMatthew Dillon */
267fb0f29c4SMatthew Dillon if (netmsg_fwd_port_fn == NULL)
268fb0f29c4SMatthew Dillon netmsg_fwd_port_fn = port->mp_putport;
269fb0f29c4SMatthew Dillon KKASSERT(netmsg_fwd_port_fn == port->mp_putport);
2705c703385SMatthew Dillon port->mp_putport = netmsg_put_port;
2715c703385SMatthew Dillon
2725c703385SMatthew Dillon /*
2735c703385SMatthew Dillon * Keep track of ports using the netmsg API so we can synchronize
2745c703385SMatthew Dillon * certain operations (such as freeing an ifnet structure) across all
2755c703385SMatthew Dillon * consumers.
2765c703385SMatthew Dillon */
277efda3bd0SMatthew Dillon reg = kmalloc(sizeof(*reg), M_TEMP, M_WAITOK|M_ZERO);
2785c703385SMatthew Dillon reg->npr_port = port;
2795c703385SMatthew Dillon TAILQ_INSERT_TAIL(&netreglist, reg, npr_entry);
2805c703385SMatthew Dillon }
2815c703385SMatthew Dillon
2825c703385SMatthew Dillon /*
2835c703385SMatthew Dillon * This function synchronizes the caller with all netmsg services. For
2845c703385SMatthew Dillon * example, if an interface is being removed we must make sure that all
2855c703385SMatthew Dillon * packets related to that interface complete processing before the structure
2865c703385SMatthew Dillon * can actually be freed. This sort of synchronization is an alternative to
2875c703385SMatthew Dillon * ref-counting the netif, removing the ref counting overhead in favor of
2885c703385SMatthew Dillon * placing additional overhead in the netif freeing sequence (where it is
2895c703385SMatthew Dillon * inconsequential).
2905c703385SMatthew Dillon */
2915c703385SMatthew Dillon void
netmsg_service_sync(void)2925c703385SMatthew Dillon netmsg_service_sync(void)
2935c703385SMatthew Dillon {
2945c703385SMatthew Dillon struct netmsg_port_registration *reg;
295002c1265SMatthew Dillon struct netmsg_base smsg;
2965c703385SMatthew Dillon
29779f504caSSepherosa Ziehau netmsg_init(&smsg, NULL, &curthread->td_msgport, 0, netmsg_sync_handler);
2985c703385SMatthew Dillon
2995c703385SMatthew Dillon TAILQ_FOREACH(reg, &netreglist, npr_entry) {
300002c1265SMatthew Dillon lwkt_domsg(reg->npr_port, &smsg.lmsg, 0);
3015c703385SMatthew Dillon }
3025c703385SMatthew Dillon }
3035c703385SMatthew Dillon
3045c703385SMatthew Dillon /*
3055c703385SMatthew Dillon * The netmsg function simply replies the message. API semantics require
3065c703385SMatthew Dillon * EASYNC to be returned if the netmsg function disposes of the message.
3075c703385SMatthew Dillon */
30879f504caSSepherosa Ziehau void
netmsg_sync_handler(netmsg_t msg)30979f504caSSepherosa Ziehau netmsg_sync_handler(netmsg_t msg)
3105c703385SMatthew Dillon {
311002c1265SMatthew Dillon lwkt_replymsg(&msg->lmsg, 0);
3125c703385SMatthew Dillon }
3135c703385SMatthew Dillon
3145c703385SMatthew Dillon /*
3155c703385SMatthew Dillon * Generic netmsg service loop. Some protocols may roll their own but all
3165c703385SMatthew Dillon * must do the basic command dispatch function call done here.
3175c703385SMatthew Dillon */
318c3c96e44SMatthew Dillon static void
netmsg_service_loop(void * arg)319bf82f9b7SMatthew Dillon netmsg_service_loop(void *arg)
320bf82f9b7SMatthew Dillon {
321002c1265SMatthew Dillon netmsg_base_t msg;
3223598cc14SSascha Wildner thread_t td = curthread;
323c3c96e44SMatthew Dillon int limit;
3241f4883b8SSepherosa Ziehau struct netisr_data *nd = netisr_data[mycpuid];
325c3c96e44SMatthew Dillon
326f256b6c0SSepherosa Ziehau td->td_type = TD_TYPE_NETISR;
327f256b6c0SSepherosa Ziehau
328c3c96e44SMatthew Dillon while ((msg = lwkt_waitport(&td->td_msgport, 0))) {
3292879f880SSepherosa Ziehau struct netisr_rollup *ru;
3302879f880SSepherosa Ziehau
331c3c96e44SMatthew Dillon /*
332c3c96e44SMatthew Dillon * Run up to 512 pending netmsgs.
333c3c96e44SMatthew Dillon */
334b210f45eSMatthew Dillon limit = netisr_rollup_limit;
335c3c96e44SMatthew Dillon do {
336c3c96e44SMatthew Dillon KASSERT(msg->nm_dispatch != NULL,
337ed20d0e3SSascha Wildner ("netmsg_service isr %d badmsg",
338002c1265SMatthew Dillon msg->lmsg.u.ms_result));
3391fe8db06SSepherosa Ziehau /*
3401fe8db06SSepherosa Ziehau * Don't match so_port, if the msg explicitly
3411fe8db06SSepherosa Ziehau * asks us to ignore its so_port.
3421fe8db06SSepherosa Ziehau */
3431fe8db06SSepherosa Ziehau if ((msg->lmsg.ms_flags & MSGF_IGNSOPORT) == 0 &&
3441fe8db06SSepherosa Ziehau msg->nm_so &&
3450ce0603eSMatthew Dillon msg->nm_so->so_port != &td->td_msgport) {
3460ce0603eSMatthew Dillon /*
3470ce0603eSMatthew Dillon * Sockets undergoing connect or disconnect
3480ce0603eSMatthew Dillon * ops can change ports on us. Chase the
3490ce0603eSMatthew Dillon * port.
3500ce0603eSMatthew Dillon */
351e368a6e9SSepherosa Ziehau #ifdef foo
352e368a6e9SSepherosa Ziehau /*
353e368a6e9SSepherosa Ziehau * This could be quite common for protocols
354e368a6e9SSepherosa Ziehau * which support asynchronous pru_connect,
355e368a6e9SSepherosa Ziehau * e.g. TCP, so kprintf socket port chasing
356e368a6e9SSepherosa Ziehau * could be too verbose for the console.
357e368a6e9SSepherosa Ziehau */
358c080b4cdSNuno Antunes kprintf("%s: Warning, port changed so=%p\n",
359c080b4cdSNuno Antunes __func__, msg->nm_so);
360e368a6e9SSepherosa Ziehau #endif
3610ce0603eSMatthew Dillon lwkt_forwardmsg(msg->nm_so->so_port,
362002c1265SMatthew Dillon &msg->lmsg);
3630ce0603eSMatthew Dillon } else {
3640ce0603eSMatthew Dillon /*
3650ce0603eSMatthew Dillon * We are on the correct port, dispatch it.
3660ce0603eSMatthew Dillon */
3671f4883b8SSepherosa Ziehau #ifdef INVARIANTS
3681f4883b8SSepherosa Ziehau nd->netlastfunc = msg->nm_dispatch;
3691f4883b8SSepherosa Ziehau #endif
370002c1265SMatthew Dillon msg->nm_dispatch((netmsg_t)msg);
3710ce0603eSMatthew Dillon }
372c3c96e44SMatthew Dillon if (--limit == 0)
373c3c96e44SMatthew Dillon break;
374c3c96e44SMatthew Dillon } while ((msg = lwkt_getport(&td->td_msgport)) != NULL);
375ef0fdad1SMatthew Dillon
3768bde602dSJeffrey Hsu /*
377c3c96e44SMatthew Dillon * Run all registered rollup functions for this cpu
378c3c96e44SMatthew Dillon * (e.g. tcp_willblock()).
37995f8b5ceSSepherosa Ziehau */
3802879f880SSepherosa Ziehau TAILQ_FOREACH(ru, &nd->netrulist, ru_entry)
381c3c96e44SMatthew Dillon ru->ru_func();
38292db3805SSepherosa Ziehau }
38395f8b5ceSSepherosa Ziehau }
38495f8b5ceSSepherosa Ziehau
38595f8b5ceSSepherosa Ziehau /*
386c3c96e44SMatthew Dillon * Forward a packet to a netisr service function.
387c3c96e44SMatthew Dillon *
388c3c96e44SMatthew Dillon * If the packet has not been assigned to a protocol thread we call
389c3c96e44SMatthew Dillon * the port characterization function to assign it. The caller must
390c3c96e44SMatthew Dillon * clear M_HASH (or not have set it in the first place) if the caller
391c3c96e44SMatthew Dillon * wishes the packet to be recharacterized.
3928bde602dSJeffrey Hsu */
3938bde602dSJeffrey Hsu int
netisr_queue(int num,struct mbuf * m)3948bde602dSJeffrey Hsu netisr_queue(int num, struct mbuf *m)
3958bde602dSJeffrey Hsu {
3965944299aSMatthew Dillon struct netisr *ni;
3979eeaa8a9SJeffrey Hsu struct netmsg_packet *pmsg;
398bf82f9b7SMatthew Dillon lwkt_port_t port;
3998bde602dSJeffrey Hsu
400c157ff7aSSascha Wildner KASSERT((num > 0 && num <= NELEM(netisrs)),
401c3c96e44SMatthew Dillon ("Bad isr %d", num));
4028bde602dSJeffrey Hsu
4035944299aSMatthew Dillon ni = &netisrs[num];
4045944299aSMatthew Dillon if (ni->ni_handler == NULL) {
405c080b4cdSNuno Antunes kprintf("%s: Unregistered isr %d\n", __func__, num);
40668b67450SSepherosa Ziehau m_freem(m);
4079eeaa8a9SJeffrey Hsu return (EIO);
4085944299aSMatthew Dillon }
4095944299aSMatthew Dillon
410c3c96e44SMatthew Dillon /*
411c3c96e44SMatthew Dillon * Figure out which protocol thread to send to. This does not
412c3c96e44SMatthew Dillon * have to be perfect but performance will be really good if it
413c3c96e44SMatthew Dillon * is correct. Major protocol inputs such as ip_input() will
414c3c96e44SMatthew Dillon * re-characterize the packet as necessary.
415c3c96e44SMatthew Dillon */
416c3c96e44SMatthew Dillon if ((m->m_flags & M_HASH) == 0) {
417ca86d83eSSepherosa Ziehau ni->ni_hashfn(&m, 0);
41818bb55fbSSepherosa Ziehau if (m == NULL)
4199eeaa8a9SJeffrey Hsu return (EIO);
420c3c96e44SMatthew Dillon if ((m->m_flags & M_HASH) == 0) {
421c080b4cdSNuno Antunes kprintf("%s(%d): packet hash failed\n",
422c080b4cdSNuno Antunes __func__, num);
423c3c96e44SMatthew Dillon m_freem(m);
424c3c96e44SMatthew Dillon return (EIO);
425c3c96e44SMatthew Dillon }
426c3c96e44SMatthew Dillon }
4279eeaa8a9SJeffrey Hsu
428c3c96e44SMatthew Dillon /*
429c3c96e44SMatthew Dillon * Get the protocol port based on the packet hash, initialize
430c3c96e44SMatthew Dillon * the netmsg, and send it off.
431c3c96e44SMatthew Dillon */
432b42f202aSSepherosa Ziehau port = netisr_hashport(m->m_pkthdr.hash);
4336aad077dSMatthew Dillon pmsg = &m->m_hdr.mh_netmsg;
434002c1265SMatthew Dillon netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
435c3c96e44SMatthew Dillon 0, ni->ni_handler);
436bf82f9b7SMatthew Dillon pmsg->nm_packet = m;
437002c1265SMatthew Dillon pmsg->base.lmsg.u.ms_result = num;
438002c1265SMatthew Dillon lwkt_sendmsg(port, &pmsg->base.lmsg);
439c3c96e44SMatthew Dillon
4408bde602dSJeffrey Hsu return (0);
4418bde602dSJeffrey Hsu }
4428bde602dSJeffrey Hsu
443c3c96e44SMatthew Dillon /*
444ebe4c2aeSSepherosa Ziehau * Run a netisr service function on the packet.
445ebe4c2aeSSepherosa Ziehau *
446ebe4c2aeSSepherosa Ziehau * The packet must have been correctly characterized!
447ebe4c2aeSSepherosa Ziehau */
448ebe4c2aeSSepherosa Ziehau int
netisr_handle(int num,struct mbuf * m)449ebe4c2aeSSepherosa Ziehau netisr_handle(int num, struct mbuf *m)
450ebe4c2aeSSepherosa Ziehau {
451ebe4c2aeSSepherosa Ziehau struct netisr *ni;
452ebe4c2aeSSepherosa Ziehau struct netmsg_packet *pmsg;
453ebe4c2aeSSepherosa Ziehau lwkt_port_t port;
454ebe4c2aeSSepherosa Ziehau
455ebe4c2aeSSepherosa Ziehau /*
456ebe4c2aeSSepherosa Ziehau * Get the protocol port based on the packet hash
457ebe4c2aeSSepherosa Ziehau */
458ed20d0e3SSascha Wildner KASSERT((m->m_flags & M_HASH), ("packet not characterized"));
459b42f202aSSepherosa Ziehau port = netisr_hashport(m->m_pkthdr.hash);
460ed20d0e3SSascha Wildner KASSERT(&curthread->td_msgport == port, ("wrong msgport"));
461ebe4c2aeSSepherosa Ziehau
462ebe4c2aeSSepherosa Ziehau KASSERT((num > 0 && num <= NELEM(netisrs)), ("bad isr %d", num));
463ebe4c2aeSSepherosa Ziehau ni = &netisrs[num];
464ebe4c2aeSSepherosa Ziehau if (ni->ni_handler == NULL) {
465c080b4cdSNuno Antunes kprintf("%s: unregistered isr %d\n", __func__, num);
466ebe4c2aeSSepherosa Ziehau m_freem(m);
467ebe4c2aeSSepherosa Ziehau return EIO;
468ebe4c2aeSSepherosa Ziehau }
469ebe4c2aeSSepherosa Ziehau
470ebe4c2aeSSepherosa Ziehau /*
471ebe4c2aeSSepherosa Ziehau * Initialize the netmsg, and run the handler directly.
472ebe4c2aeSSepherosa Ziehau */
473ebe4c2aeSSepherosa Ziehau pmsg = &m->m_hdr.mh_netmsg;
474ebe4c2aeSSepherosa Ziehau netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
475ebe4c2aeSSepherosa Ziehau 0, ni->ni_handler);
476ebe4c2aeSSepherosa Ziehau pmsg->nm_packet = m;
477ebe4c2aeSSepherosa Ziehau pmsg->base.lmsg.u.ms_result = num;
478ebe4c2aeSSepherosa Ziehau ni->ni_handler((netmsg_t)&pmsg->base);
479ebe4c2aeSSepherosa Ziehau
480ebe4c2aeSSepherosa Ziehau return 0;
481ebe4c2aeSSepherosa Ziehau }
482ebe4c2aeSSepherosa Ziehau
483ebe4c2aeSSepherosa Ziehau /*
484c3c96e44SMatthew Dillon * Pre-characterization of a deeper portion of the packet for the
485c3c96e44SMatthew Dillon * requested isr.
486c3c96e44SMatthew Dillon *
487c3c96e44SMatthew Dillon * The base of the ISR type (e.g. IP) that we want to characterize is
488c3c96e44SMatthew Dillon * at (hoff) relative to the beginning of the mbuf. This allows
489a45f4b4bSSepherosa Ziehau * e.g. ether_characterize() to not have to adjust the m_data/m_len.
490c3c96e44SMatthew Dillon */
491bf82f9b7SMatthew Dillon void
netisr_characterize(int num,struct mbuf ** mp,int hoff)492c3c96e44SMatthew Dillon netisr_characterize(int num, struct mbuf **mp, int hoff)
493c3c96e44SMatthew Dillon {
494c3c96e44SMatthew Dillon struct netisr *ni;
495c3c96e44SMatthew Dillon struct mbuf *m;
496c3c96e44SMatthew Dillon
497c3c96e44SMatthew Dillon /*
498c3c96e44SMatthew Dillon * Validation
499c3c96e44SMatthew Dillon */
500c3c96e44SMatthew Dillon m = *mp;
501c3c96e44SMatthew Dillon KKASSERT(m != NULL);
502c3c96e44SMatthew Dillon
503e6318d16SMatthew Dillon if (num < 0 || num >= NETISR_MAX) {
504e6318d16SMatthew Dillon if (num == NETISR_MAX) {
5057558541bSSepherosa Ziehau m_sethash(m, 0);
506e6318d16SMatthew Dillon return;
507e6318d16SMatthew Dillon }
508e6318d16SMatthew Dillon panic("Bad isr %d", num);
509e6318d16SMatthew Dillon }
510e6318d16SMatthew Dillon
511c3c96e44SMatthew Dillon /*
512c3c96e44SMatthew Dillon * Valid netisr?
513c3c96e44SMatthew Dillon */
514c3c96e44SMatthew Dillon ni = &netisrs[num];
515c3c96e44SMatthew Dillon if (ni->ni_handler == NULL) {
516c080b4cdSNuno Antunes kprintf("%s: Unregistered isr %d\n", __func__, num);
517c3c96e44SMatthew Dillon m_freem(m);
518c3c96e44SMatthew Dillon *mp = NULL;
519c3c96e44SMatthew Dillon }
520c3c96e44SMatthew Dillon
521c3c96e44SMatthew Dillon /*
522c3c96e44SMatthew Dillon * Characterize the packet
523c3c96e44SMatthew Dillon */
524c3c96e44SMatthew Dillon if ((m->m_flags & M_HASH) == 0) {
525ca86d83eSSepherosa Ziehau ni->ni_hashfn(mp, hoff);
526c3c96e44SMatthew Dillon m = *mp;
527c080b4cdSNuno Antunes if (m && (m->m_flags & M_HASH) == 0) {
528c080b4cdSNuno Antunes kprintf("%s(%d): packet hash failed\n",
529c080b4cdSNuno Antunes __func__, num);
530c080b4cdSNuno Antunes }
531c3c96e44SMatthew Dillon }
532c3c96e44SMatthew Dillon }
533c3c96e44SMatthew Dillon
534c3c96e44SMatthew Dillon void
netisr_register(int num,netisr_fn_t handler,netisr_hashfn_t hashfn)535ca86d83eSSepherosa Ziehau netisr_register(int num, netisr_fn_t handler, netisr_hashfn_t hashfn)
5368bde602dSJeffrey Hsu {
537ff4a1403SSepherosa Ziehau struct netisr *ni;
538ff4a1403SSepherosa Ziehau
539c157ff7aSSascha Wildner KASSERT((num > 0 && num <= NELEM(netisrs)),
5401748bf82SMatthew Dillon ("netisr_register: bad isr %d", num));
541c3c96e44SMatthew Dillon KKASSERT(handler != NULL);
542c3c96e44SMatthew Dillon
543ca86d83eSSepherosa Ziehau if (hashfn == NULL)
544ca86d83eSSepherosa Ziehau hashfn = netisr_hashfn0;
545c3c96e44SMatthew Dillon
546ff4a1403SSepherosa Ziehau ni = &netisrs[num];
547ff4a1403SSepherosa Ziehau
548ff4a1403SSepherosa Ziehau ni->ni_handler = handler;
549e6f77b88SSepherosa Ziehau ni->ni_hashck = netisr_nohashck;
550ca86d83eSSepherosa Ziehau ni->ni_hashfn = hashfn;
551c3c96e44SMatthew Dillon netmsg_init(&ni->ni_netmsg, NULL, &netisr_adone_rport, 0, NULL);
552ef0fdad1SMatthew Dillon }
553ef0fdad1SMatthew Dillon
554c3c96e44SMatthew Dillon void
netisr_register_hashcheck(int num,netisr_hashck_t hashck)555e6f77b88SSepherosa Ziehau netisr_register_hashcheck(int num, netisr_hashck_t hashck)
556e6f77b88SSepherosa Ziehau {
557e6f77b88SSepherosa Ziehau struct netisr *ni;
558e6f77b88SSepherosa Ziehau
559e6f77b88SSepherosa Ziehau KASSERT((num > 0 && num <= NELEM(netisrs)),
560e6f77b88SSepherosa Ziehau ("netisr_register: bad isr %d", num));
561e6f77b88SSepherosa Ziehau
562e6f77b88SSepherosa Ziehau ni = &netisrs[num];
563e6f77b88SSepherosa Ziehau ni->ni_hashck = hashck;
564e6f77b88SSepherosa Ziehau }
565e6f77b88SSepherosa Ziehau
5662879f880SSepherosa Ziehau static void
netisr_register_rollup_dispatch(netmsg_t nmsg)5672879f880SSepherosa Ziehau netisr_register_rollup_dispatch(netmsg_t nmsg)
568ef0fdad1SMatthew Dillon {
5692879f880SSepherosa Ziehau struct netmsg_rollup *nm = (struct netmsg_rollup *)nmsg;
5702879f880SSepherosa Ziehau int cpuid = mycpuid;
5712879f880SSepherosa Ziehau struct netisr_data *nd = netisr_data[cpuid];
5722879f880SSepherosa Ziehau struct netisr_rollup *new_ru, *ru;
5738bde602dSJeffrey Hsu
574239bdb58SSepherosa Ziehau new_ru = kmalloc(sizeof(*new_ru), M_TEMP, M_WAITOK|M_ZERO);
5752879f880SSepherosa Ziehau new_ru->ru_func = nm->func;
5762879f880SSepherosa Ziehau new_ru->ru_prio = nm->prio;
577239bdb58SSepherosa Ziehau
578239bdb58SSepherosa Ziehau /*
579239bdb58SSepherosa Ziehau * Higher priority "rollup" appears first
580239bdb58SSepherosa Ziehau */
5812879f880SSepherosa Ziehau TAILQ_FOREACH(ru, &nd->netrulist, ru_entry) {
582239bdb58SSepherosa Ziehau if (ru->ru_prio < new_ru->ru_prio) {
583239bdb58SSepherosa Ziehau TAILQ_INSERT_BEFORE(ru, new_ru, ru_entry);
5842879f880SSepherosa Ziehau goto done;
585239bdb58SSepherosa Ziehau }
586239bdb58SSepherosa Ziehau }
5872879f880SSepherosa Ziehau TAILQ_INSERT_TAIL(&nd->netrulist, new_ru, ru_entry);
5882879f880SSepherosa Ziehau done:
5892879f880SSepherosa Ziehau if (cpuid == 0)
5902879f880SSepherosa Ziehau nm->key = new_ru;
5912879f880SSepherosa Ziehau KKASSERT(nm->key != NULL);
5922879f880SSepherosa Ziehau new_ru->ru_key = nm->key;
5932879f880SSepherosa Ziehau
5942879f880SSepherosa Ziehau netisr_forwardmsg_all(&nm->base, cpuid + 1);
5952879f880SSepherosa Ziehau }
5962879f880SSepherosa Ziehau
5972879f880SSepherosa Ziehau struct netisr_rollup *
netisr_register_rollup(netisr_ru_t func,int prio)5982879f880SSepherosa Ziehau netisr_register_rollup(netisr_ru_t func, int prio)
5992879f880SSepherosa Ziehau {
6002879f880SSepherosa Ziehau struct netmsg_rollup nm;
6012879f880SSepherosa Ziehau
6022879f880SSepherosa Ziehau netmsg_init(&nm.base, NULL, &curthread->td_msgport, MSGF_PRIORITY,
6032879f880SSepherosa Ziehau netisr_register_rollup_dispatch);
6042879f880SSepherosa Ziehau nm.func = func;
6052879f880SSepherosa Ziehau nm.prio = prio;
6062879f880SSepherosa Ziehau nm.key = NULL;
6072879f880SSepherosa Ziehau netisr_domsg_global(&nm.base);
6082879f880SSepherosa Ziehau
6092879f880SSepherosa Ziehau KKASSERT(nm.key != NULL);
6102879f880SSepherosa Ziehau return (nm.key);
6112879f880SSepherosa Ziehau }
6122879f880SSepherosa Ziehau
6132879f880SSepherosa Ziehau static void
netisr_unregister_rollup_dispatch(netmsg_t nmsg)6142879f880SSepherosa Ziehau netisr_unregister_rollup_dispatch(netmsg_t nmsg)
6152879f880SSepherosa Ziehau {
6162879f880SSepherosa Ziehau struct netmsg_rollup *nm = (struct netmsg_rollup *)nmsg;
6172879f880SSepherosa Ziehau int cpuid = mycpuid;
6182879f880SSepherosa Ziehau struct netisr_data *nd = netisr_data[cpuid];
6192879f880SSepherosa Ziehau struct netisr_rollup *ru;
6202879f880SSepherosa Ziehau
6212879f880SSepherosa Ziehau TAILQ_FOREACH(ru, &nd->netrulist, ru_entry) {
6222879f880SSepherosa Ziehau if (ru->ru_key == nm->key)
6232879f880SSepherosa Ziehau break;
6242879f880SSepherosa Ziehau }
6252879f880SSepherosa Ziehau if (ru == NULL)
6262879f880SSepherosa Ziehau panic("netisr: no rullup for %p", nm->key);
6272879f880SSepherosa Ziehau
6282879f880SSepherosa Ziehau TAILQ_REMOVE(&nd->netrulist, ru, ru_entry);
6292879f880SSepherosa Ziehau kfree(ru, M_TEMP);
6302879f880SSepherosa Ziehau
6312879f880SSepherosa Ziehau netisr_forwardmsg_all(&nm->base, cpuid + 1);
6322879f880SSepherosa Ziehau }
6332879f880SSepherosa Ziehau
6342879f880SSepherosa Ziehau void
netisr_unregister_rollup(struct netisr_rollup * key)6352879f880SSepherosa Ziehau netisr_unregister_rollup(struct netisr_rollup *key)
6362879f880SSepherosa Ziehau {
6372879f880SSepherosa Ziehau struct netmsg_rollup nm;
6382879f880SSepherosa Ziehau
6392879f880SSepherosa Ziehau netmsg_init(&nm.base, NULL, &curthread->td_msgport, MSGF_PRIORITY,
6402879f880SSepherosa Ziehau netisr_unregister_rollup_dispatch);
6412879f880SSepherosa Ziehau nm.key = key;
6422879f880SSepherosa Ziehau netisr_domsg_global(&nm.base);
643ef0fdad1SMatthew Dillon }
644bf82f9b7SMatthew Dillon
645bf82f9b7SMatthew Dillon /*
646c3c96e44SMatthew Dillon * Return a default protocol control message processing thread port
647c3c96e44SMatthew Dillon */
6483efe7008SMatthew Dillon lwkt_port_t
cpu0_ctlport(int cmd __unused,struct sockaddr * sa __unused,void * extra __unused,int * cpuid)649e3873585SSepherosa Ziehau cpu0_ctlport(int cmd __unused, struct sockaddr *sa __unused,
650130b7902SSepherosa Ziehau void *extra __unused, int *cpuid)
651e3873585SSepherosa Ziehau {
652130b7902SSepherosa Ziehau *cpuid = 0;
653130b7902SSepherosa Ziehau return netisr_cpuport(*cpuid);
654e3873585SSepherosa Ziehau }
655e3873585SSepherosa Ziehau
656c3c96e44SMatthew Dillon /*
657c3c96e44SMatthew Dillon * This is a default netisr packet characterization function which
658ca86d83eSSepherosa Ziehau * sets M_HASH. If a netisr is registered with a NULL hashfn function
659c3c96e44SMatthew Dillon * this one is assigned.
660c3c96e44SMatthew Dillon *
661c3c96e44SMatthew Dillon * This function makes no attempt to validate the packet.
662c3c96e44SMatthew Dillon */
663c3c96e44SMatthew Dillon static void
netisr_hashfn0(struct mbuf ** mp,int hoff __unused)664ca86d83eSSepherosa Ziehau netisr_hashfn0(struct mbuf **mp, int hoff __unused)
665c3c96e44SMatthew Dillon {
666c3c96e44SMatthew Dillon
6677558541bSSepherosa Ziehau m_sethash(*mp, 0);
668c3c96e44SMatthew Dillon }
669c3c96e44SMatthew Dillon
670c3c96e44SMatthew Dillon /*
671a29576fcSMatthew Dillon * schednetisr() is used to call the netisr handler from the appropriate
6729eeaa8a9SJeffrey Hsu * netisr thread for polling and other purposes.
673a29576fcSMatthew Dillon *
674a29576fcSMatthew Dillon * This function may be called from a hard interrupt or IPI and must be
675a29576fcSMatthew Dillon * MP SAFE and non-blocking. We use a fixed per-cpu message instead of
676a29576fcSMatthew Dillon * trying to allocate one. We must get ourselves onto the target cpu
677a29576fcSMatthew Dillon * to safely check the MSGF_DONE bit on the message but since the message
678a29576fcSMatthew Dillon * will be sent to that cpu anyway this does not add any extra work beyond
679a29576fcSMatthew Dillon * what lwkt_sendmsg() would have already had to do to schedule the target
680a29576fcSMatthew Dillon * thread.
681bf82f9b7SMatthew Dillon */
682a29576fcSMatthew Dillon static void
schednetisr_remote(void * data)683a29576fcSMatthew Dillon schednetisr_remote(void *data)
684a29576fcSMatthew Dillon {
685973c11b9SMatthew Dillon int num = (int)(intptr_t)data;
686a29576fcSMatthew Dillon struct netisr *ni = &netisrs[num];
6876617c2d1SSepherosa Ziehau lwkt_port_t port = &netisr_threads[0]->td_msgport;
688002c1265SMatthew Dillon netmsg_base_t pmsg;
689a29576fcSMatthew Dillon
690a29576fcSMatthew Dillon pmsg = &netisrs[num].ni_netmsg;
691002c1265SMatthew Dillon if (pmsg->lmsg.ms_flags & MSGF_DONE) {
692c3c96e44SMatthew Dillon netmsg_init(pmsg, NULL, &netisr_adone_rport, 0, ni->ni_handler);
693002c1265SMatthew Dillon pmsg->lmsg.u.ms_result = num;
694002c1265SMatthew Dillon lwkt_sendmsg(port, &pmsg->lmsg);
695a29576fcSMatthew Dillon }
696a29576fcSMatthew Dillon }
697a29576fcSMatthew Dillon
698bf82f9b7SMatthew Dillon void
schednetisr(int num)699bf82f9b7SMatthew Dillon schednetisr(int num)
700bf82f9b7SMatthew Dillon {
701c157ff7aSSascha Wildner KASSERT((num > 0 && num <= NELEM(netisrs)),
7021748bf82SMatthew Dillon ("schednetisr: bad isr %d", num));
703c3c96e44SMatthew Dillon KKASSERT(netisrs[num].ni_handler != NULL);
704bfc09ba0SMatthew Dillon if (mycpu->gd_cpuid != 0) {
705bfc09ba0SMatthew Dillon lwkt_send_ipiq(globaldata_find(0),
706bfc09ba0SMatthew Dillon schednetisr_remote, (void *)(intptr_t)num);
707bfc09ba0SMatthew Dillon } else {
708c3c96e44SMatthew Dillon crit_enter();
709973c11b9SMatthew Dillon schednetisr_remote((void *)(intptr_t)num);
710c3c96e44SMatthew Dillon crit_exit();
711bfc09ba0SMatthew Dillon }
712a29576fcSMatthew Dillon }
713a91f9815SSepherosa Ziehau
714a91f9815SSepherosa Ziehau static void
netisr_barrier_dispatch(netmsg_t nmsg)715a91f9815SSepherosa Ziehau netisr_barrier_dispatch(netmsg_t nmsg)
716a91f9815SSepherosa Ziehau {
717a91f9815SSepherosa Ziehau struct netmsg_barrier *msg = (struct netmsg_barrier *)nmsg;
718a91f9815SSepherosa Ziehau
719c07315c4SMatthew Dillon ATOMIC_CPUMASK_NANDBIT(*msg->br_cpumask, mycpu->gd_cpuid);
720c07315c4SMatthew Dillon if (CPUMASK_TESTZERO(*msg->br_cpumask))
721a91f9815SSepherosa Ziehau wakeup(msg->br_cpumask);
722a91f9815SSepherosa Ziehau
723d0c7a72aSSepherosa Ziehau for (;;) {
724d0c7a72aSSepherosa Ziehau uint32_t done = msg->br_done;
725d0c7a72aSSepherosa Ziehau
726ca3321f8SSepherosa Ziehau cpu_ccfence();
727d0c7a72aSSepherosa Ziehau if ((done & NETISR_BR_NOTDONE) == 0)
728d0c7a72aSSepherosa Ziehau break;
729d0c7a72aSSepherosa Ziehau
730a91f9815SSepherosa Ziehau tsleep_interlock(&msg->br_done, 0);
731ca3321f8SSepherosa Ziehau if (atomic_cmpset_int(&msg->br_done,
732d0c7a72aSSepherosa Ziehau done, done | NETISR_BR_WAITDONE))
733a91f9815SSepherosa Ziehau tsleep(&msg->br_done, PINTERLOCKED, "nbrdsp", 0);
734ca3321f8SSepherosa Ziehau }
735a91f9815SSepherosa Ziehau
736a91f9815SSepherosa Ziehau lwkt_replymsg(&nmsg->lmsg, 0);
737a91f9815SSepherosa Ziehau }
738a91f9815SSepherosa Ziehau
739a91f9815SSepherosa Ziehau struct netisr_barrier *
netisr_barrier_create(void)740a91f9815SSepherosa Ziehau netisr_barrier_create(void)
741a91f9815SSepherosa Ziehau {
742a91f9815SSepherosa Ziehau struct netisr_barrier *br;
743a91f9815SSepherosa Ziehau
744a91f9815SSepherosa Ziehau br = kmalloc(sizeof(*br), M_LWKTMSG, M_WAITOK | M_ZERO);
745a91f9815SSepherosa Ziehau return br;
746a91f9815SSepherosa Ziehau }
747a91f9815SSepherosa Ziehau
748a91f9815SSepherosa Ziehau void
netisr_barrier_set(struct netisr_barrier * br)749a91f9815SSepherosa Ziehau netisr_barrier_set(struct netisr_barrier *br)
750a91f9815SSepherosa Ziehau {
7510503d1d0SSepherosa Ziehau volatile cpumask_t other_cpumask;
752a91f9815SSepherosa Ziehau int i, cur_cpuid;
753a91f9815SSepherosa Ziehau
7545204e13cSSepherosa Ziehau ASSERT_NETISR0;
755a91f9815SSepherosa Ziehau KKASSERT(!br->br_isset);
756a91f9815SSepherosa Ziehau
757c07315c4SMatthew Dillon other_cpumask = mycpu->gd_other_cpus;
758c07315c4SMatthew Dillon CPUMASK_ANDMASK(other_cpumask, smp_active_mask);
759a91f9815SSepherosa Ziehau cur_cpuid = mycpuid;
760a91f9815SSepherosa Ziehau
761a91f9815SSepherosa Ziehau for (i = 0; i < ncpus; ++i) {
762a91f9815SSepherosa Ziehau struct netmsg_barrier *msg;
763a91f9815SSepherosa Ziehau
764a91f9815SSepherosa Ziehau if (i == cur_cpuid)
765a91f9815SSepherosa Ziehau continue;
766a91f9815SSepherosa Ziehau
767a91f9815SSepherosa Ziehau msg = kmalloc(sizeof(struct netmsg_barrier),
768a91f9815SSepherosa Ziehau M_LWKTMSG, M_WAITOK);
7691fe8db06SSepherosa Ziehau
7701fe8db06SSepherosa Ziehau /*
7711fe8db06SSepherosa Ziehau * Don't use priority message here; mainly to keep
7721fe8db06SSepherosa Ziehau * it ordered w/ the previous data packets sent by
7731fe8db06SSepherosa Ziehau * the caller.
7741fe8db06SSepherosa Ziehau */
7751fe8db06SSepherosa Ziehau netmsg_init(&msg->base, NULL, &netisr_afree_rport, 0,
7761fe8db06SSepherosa Ziehau netisr_barrier_dispatch);
777a91f9815SSepherosa Ziehau msg->br_cpumask = &other_cpumask;
778ca3321f8SSepherosa Ziehau msg->br_done = NETISR_BR_NOTDONE;
779a91f9815SSepherosa Ziehau
780a91f9815SSepherosa Ziehau KKASSERT(br->br_msgs[i] == NULL);
781a91f9815SSepherosa Ziehau br->br_msgs[i] = msg;
782a91f9815SSepherosa Ziehau }
783a91f9815SSepherosa Ziehau
784a91f9815SSepherosa Ziehau for (i = 0; i < ncpus; ++i) {
785a91f9815SSepherosa Ziehau if (i == cur_cpuid)
786a91f9815SSepherosa Ziehau continue;
787ec7f7fc8SSepherosa Ziehau lwkt_sendmsg(netisr_cpuport(i), &br->br_msgs[i]->base.lmsg);
788a91f9815SSepherosa Ziehau }
789a91f9815SSepherosa Ziehau
790c07315c4SMatthew Dillon while (CPUMASK_TESTNZERO(other_cpumask)) {
791a91f9815SSepherosa Ziehau tsleep_interlock(&other_cpumask, 0);
792c07315c4SMatthew Dillon if (CPUMASK_TESTNZERO(other_cpumask))
793a91f9815SSepherosa Ziehau tsleep(&other_cpumask, PINTERLOCKED, "nbrset", 0);
794a91f9815SSepherosa Ziehau }
795a91f9815SSepherosa Ziehau br->br_isset = 1;
796a91f9815SSepherosa Ziehau }
797a91f9815SSepherosa Ziehau
798a91f9815SSepherosa Ziehau void
netisr_barrier_rem(struct netisr_barrier * br)799a91f9815SSepherosa Ziehau netisr_barrier_rem(struct netisr_barrier *br)
800a91f9815SSepherosa Ziehau {
801a91f9815SSepherosa Ziehau int i, cur_cpuid;
802a91f9815SSepherosa Ziehau
8035204e13cSSepherosa Ziehau ASSERT_NETISR0;
804a91f9815SSepherosa Ziehau KKASSERT(br->br_isset);
805a91f9815SSepherosa Ziehau
806a91f9815SSepherosa Ziehau cur_cpuid = mycpuid;
807a91f9815SSepherosa Ziehau for (i = 0; i < ncpus; ++i) {
808a91f9815SSepherosa Ziehau struct netmsg_barrier *msg = br->br_msgs[i];
809d0c7a72aSSepherosa Ziehau uint32_t done;
810a91f9815SSepherosa Ziehau
811a91f9815SSepherosa Ziehau msg = br->br_msgs[i];
812a91f9815SSepherosa Ziehau br->br_msgs[i] = NULL;
813a91f9815SSepherosa Ziehau
814a91f9815SSepherosa Ziehau if (i == cur_cpuid)
815a91f9815SSepherosa Ziehau continue;
816a91f9815SSepherosa Ziehau
817d0c7a72aSSepherosa Ziehau done = atomic_swap_int(&msg->br_done, 0);
818d0c7a72aSSepherosa Ziehau if (done & NETISR_BR_WAITDONE)
819a91f9815SSepherosa Ziehau wakeup(&msg->br_done);
820a91f9815SSepherosa Ziehau }
821a91f9815SSepherosa Ziehau br->br_isset = 0;
822a91f9815SSepherosa Ziehau }
823e6f77b88SSepherosa Ziehau
824e6f77b88SSepherosa Ziehau static void
netisr_nohashck(struct mbuf * m,const struct pktinfo * pi __unused)825e6f77b88SSepherosa Ziehau netisr_nohashck(struct mbuf *m, const struct pktinfo *pi __unused)
826e6f77b88SSepherosa Ziehau {
827e6f77b88SSepherosa Ziehau m->m_flags &= ~M_HASH;
828e6f77b88SSepherosa Ziehau }
829e6f77b88SSepherosa Ziehau
830e6f77b88SSepherosa Ziehau void
netisr_hashcheck(int num,struct mbuf * m,const struct pktinfo * pi)831e6f77b88SSepherosa Ziehau netisr_hashcheck(int num, struct mbuf *m, const struct pktinfo *pi)
832e6f77b88SSepherosa Ziehau {
833e6f77b88SSepherosa Ziehau struct netisr *ni;
834e6f77b88SSepherosa Ziehau
835e6f77b88SSepherosa Ziehau if (num < 0 || num >= NETISR_MAX)
836e6f77b88SSepherosa Ziehau panic("Bad isr %d", num);
837e6f77b88SSepherosa Ziehau
838e6f77b88SSepherosa Ziehau /*
839e6f77b88SSepherosa Ziehau * Valid netisr?
840e6f77b88SSepherosa Ziehau */
841e6f77b88SSepherosa Ziehau ni = &netisrs[num];
842e6f77b88SSepherosa Ziehau if (ni->ni_handler == NULL)
843ed20d0e3SSascha Wildner panic("Unregistered isr %d", num);
844e6f77b88SSepherosa Ziehau
845e6f77b88SSepherosa Ziehau ni->ni_hashck(m, pi);
846e6f77b88SSepherosa Ziehau }
847