| Commit | Line | Data |
|---|---|---|
| 66d6c637 JH |
1 | /* |
| 2 | * Copyright (c) 2003, 2004 Matthew Dillon. All rights reserved. | |
| 3 | * Copyright (c) 2003, 2004 Jeffrey M. Hsu. All rights reserved. | |
| 4 | * Copyright (c) 2003 Jonathan Lemon. All rights reserved. | |
| 5 | * Copyright (c) 2003, 2004 The DragonFly Project. All rights reserved. | |
| 6 | * | |
| 7 | * This code is derived from software contributed to The DragonFly Project | |
| 8 | * by Jonathan Lemon, Jeffrey M. Hsu, and Matthew Dillon. | |
| 9 | * | |
| d849e575 MD |
10 | * Jonathan Lemon gave Jeffrey Hsu permission to combine his copyright |
| 11 | * into this one around July 8 2004. | |
| 12 | * | |
| 66d6c637 JH |
13 | * Redistribution and use in source and binary forms, with or without |
| 14 | * modification, are permitted provided that the following conditions | |
| 15 | * are met: | |
| 16 | * 1. Redistributions of source code must retain the above copyright | |
| 17 | * notice, this list of conditions and the following disclaimer. | |
| 18 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 19 | * notice, this list of conditions and the following disclaimer in the | |
| 20 | * documentation and/or other materials provided with the distribution. | |
| 21 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 22 | * contributors may be used to endorse or promote products derived | |
| 23 | * from this software without specific, prior written permission. | |
| 24 | * | |
| 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 26 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 28 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 29 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 30 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 31 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 32 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 33 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 34 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 35 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 36 | * SUCH DAMAGE. | |
| 37 | * | |
| d06a01b6 | 38 | * $DragonFly: src/sys/net/netisr.c,v 1.49 2008/11/01 10:29:31 sephe Exp $ |
| ef0fdad1 MD |
39 | */ |
| 40 | ||
| 41 | #include <sys/param.h> | |
| 42 | #include <sys/systm.h> | |
| bf82f9b7 | 43 | #include <sys/kernel.h> |
| 9eeaa8a9 | 44 | #include <sys/malloc.h> |
| bf82f9b7 | 45 | #include <sys/msgport.h> |
| ef0fdad1 MD |
46 | #include <sys/proc.h> |
| 47 | #include <sys/interrupt.h> | |
| 8bde602d JH |
48 | #include <sys/socket.h> |
| 49 | #include <sys/sysctl.h> | |
| 50 | #include <net/if.h> | |
| 51 | #include <net/if_var.h> | |
| ef0fdad1 MD |
52 | #include <net/netisr.h> |
| 53 | #include <machine/cpufunc.h> | |
| ef0fdad1 | 54 | |
| 3227f1b8 MD |
55 | #include <sys/thread2.h> |
| 56 | #include <sys/msgport2.h> | |
| 4599cf19 | 57 | #include <net/netmsg2.h> |
| 3227f1b8 | 58 | |
| 92db3805 SZ |
59 | #define NETISR_GET_MPLOCK(ni) \ |
| 60 | do { \ | |
| 61 | if (((ni)->ni_flags & NETISR_FLAG_MPSAFE) == 0) \ | |
| 62 | get_mplock(); \ | |
| 63 | } while (0) | |
| 64 | ||
| 65 | #define NETISR_REL_MPLOCK(ni) \ | |
| 66 | do { \ | |
| 67 | if (((ni)->ni_flags & NETISR_FLAG_MPSAFE) == 0) \ | |
| 68 | rel_mplock(); \ | |
| 69 | } while (0) | |
| 70 | ||
| 4599cf19 | 71 | static void netmsg_sync_func(struct netmsg *msg); |
| 5c703385 MD |
72 | |
| 73 | struct netmsg_port_registration { | |
| 74 | TAILQ_ENTRY(netmsg_port_registration) npr_entry; | |
| 75 | lwkt_port_t npr_port; | |
| 76 | }; | |
| 77 | ||
| bf82f9b7 | 78 | static struct netisr netisrs[NETISR_MAX]; |
| 5c703385 | 79 | static TAILQ_HEAD(,netmsg_port_registration) netreglist; |
| bf82f9b7 MD |
80 | |
| 81 | /* Per-CPU thread to handle any protocol. */ | |
| 82 | struct thread netisr_cpu[MAXCPU]; | |
| 3227f1b8 | 83 | lwkt_port netisr_afree_rport; |
| a29576fc | 84 | lwkt_port netisr_adone_rport; |
| 6aad077d | 85 | lwkt_port netisr_apanic_rport; |
| 3efe7008 | 86 | lwkt_port netisr_sync_port; |
| 3227f1b8 | 87 | |
| fb0f29c4 MD |
88 | static int (*netmsg_fwd_port_fn)(lwkt_port_t, lwkt_msg_t); |
| 89 | ||
| 730902da | 90 | static int netisr_mpsafe_thread = NETMSG_SERVICE_ADAPTIVE; |
| 92db3805 SZ |
91 | TUNABLE_INT("net.netisr.mpsafe_thread", &netisr_mpsafe_thread); |
| 92 | ||
| 93 | SYSCTL_NODE(_net, OID_AUTO, netisr, CTLFLAG_RW, 0, "netisr"); | |
| 94 | SYSCTL_INT(_net_netisr, OID_AUTO, mpsafe_thread, CTLFLAG_RW, | |
| 95 | &netisr_mpsafe_thread, 0, | |
| 96 | "0:BGL, 1:Adaptive BGL, 2:No BGL(experimental)"); | |
| 37eacd1a | 97 | |
| ff4a1403 SZ |
98 | static __inline int |
| 99 | NETISR_TO_MSGF(const struct netisr *ni) | |
| 100 | { | |
| d06a01b6 SZ |
101 | int msg_flags = 0; |
| 102 | ||
| 103 | if (ni->ni_flags & NETISR_FLAG_MPSAFE) | |
| 104 | msg_flags |= MSGF_MPSAFE; | |
| 105 | return msg_flags; | |
| ff4a1403 SZ |
106 | } |
| 107 | ||
| 3227f1b8 MD |
108 | /* |
| 109 | * netisr_afree_rport replymsg function, only used to handle async | |
| 110 | * messages which the sender has abandoned to their fate. | |
| 111 | */ | |
| 112 | static void | |
| 113 | netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg) | |
| 114 | { | |
| efda3bd0 | 115 | kfree(msg, M_LWKTMSG); |
| 3227f1b8 | 116 | } |
| ef0fdad1 | 117 | |
| dc22b3aa | 118 | /* |
| fb0f29c4 MD |
119 | * We need a custom putport function to handle the case where the |
| 120 | * message target is the current thread's message port. This case | |
| 121 | * can occur when the TCP or UDP stack does a direct callback to NFS and NFS | |
| 122 | * then turns around and executes a network operation synchronously. | |
| 3efe7008 | 123 | * |
| fb0f29c4 MD |
124 | * To prevent deadlocking, we must execute these self-referential messages |
| 125 | * synchronously, effectively turning the message into a glorified direct | |
| 126 | * procedure call back into the protocol stack. The operation must be | |
| 127 | * complete on return or we will deadlock, so panic if it isn't. | |
| dc22b3aa | 128 | */ |
| 5c703385 | 129 | static int |
| dc22b3aa JH |
130 | netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg) |
| 131 | { | |
| 4599cf19 | 132 | netmsg_t netmsg = (void *)lmsg; |
| dc22b3aa | 133 | |
| fb0f29c4 | 134 | if ((lmsg->ms_flags & MSGF_SYNC) && port == &curthread->td_msgport) { |
| 4599cf19 MD |
135 | netmsg->nm_dispatch(netmsg); |
| 136 | if ((lmsg->ms_flags & MSGF_DONE) == 0) | |
| dc22b3aa | 137 | panic("netmsg_put_port: self-referential deadlock on netport"); |
| 4599cf19 | 138 | return(EASYNC); |
| dc22b3aa | 139 | } else { |
| fb0f29c4 | 140 | return(netmsg_fwd_port_fn(port, lmsg)); |
| dc22b3aa JH |
141 | } |
| 142 | } | |
| 143 | ||
| 3efe7008 MD |
144 | /* |
| 145 | * UNIX DOMAIN sockets still have to run their uipc functions synchronously, | |
| 146 | * because they depend on the user proc context for a number of things | |
| 147 | * (like creds) which we have not yet incorporated into the message structure. | |
| 148 | * | |
| 149 | * However, we maintain or message/port abstraction. Having a special | |
| 150 | * synchronous port which runs the commands synchronously gives us the | |
| 151 | * ability to serialize operations in one place later on when we start | |
| 152 | * removing the BGL. | |
| 3efe7008 MD |
153 | */ |
| 154 | static int | |
| 155 | netmsg_sync_putport(lwkt_port_t port, lwkt_msg_t lmsg) | |
| 156 | { | |
| 4599cf19 | 157 | netmsg_t netmsg = (void *)lmsg; |
| 3efe7008 | 158 | |
| e0383bf3 MD |
159 | KKASSERT((lmsg->ms_flags & MSGF_DONE) == 0); |
| 160 | ||
| 3efe7008 | 161 | lmsg->ms_target_port = port; /* required for abort */ |
| 4599cf19 | 162 | netmsg->nm_dispatch(netmsg); |
| e0383bf3 | 163 | return(EASYNC); |
| 3efe7008 MD |
164 | } |
| 165 | ||
| 166 | static void | |
| bf82f9b7 | 167 | netisr_init(void) |
| ef0fdad1 | 168 | { |
| bf82f9b7 MD |
169 | int i; |
| 170 | ||
| 5c703385 MD |
171 | TAILQ_INIT(&netreglist); |
| 172 | ||
| 3efe7008 MD |
173 | /* |
| 174 | * Create default per-cpu threads for generic protocol handling. | |
| 175 | */ | |
| 3227f1b8 | 176 | for (i = 0; i < ncpus; ++i) { |
| 92db3805 SZ |
177 | lwkt_create(netmsg_service_loop, &netisr_mpsafe_thread, NULL, |
| 178 | &netisr_cpu[i], TDF_NETWORK | TDF_MPSAFE, i, | |
| 179 | "netisr_cpu %d", i); | |
| 5c703385 | 180 | netmsg_service_port_init(&netisr_cpu[i].td_msgport); |
| 3227f1b8 | 181 | } |
| 3efe7008 MD |
182 | |
| 183 | /* | |
| 184 | * The netisr_afree_rport is a special reply port which automatically | |
| 6aad077d MD |
185 | * frees the replied message. The netisr_adone_rport simply marks |
| 186 | * the message as being done. The netisr_apanic_rport panics if | |
| 187 | * the message is replied to. | |
| 3efe7008 | 188 | */ |
| fb0f29c4 MD |
189 | lwkt_initport_replyonly(&netisr_afree_rport, netisr_autofree_reply); |
| 190 | lwkt_initport_replyonly_null(&netisr_adone_rport); | |
| 191 | lwkt_initport_panic(&netisr_apanic_rport); | |
| 3efe7008 MD |
192 | |
| 193 | /* | |
| 194 | * The netisr_syncport is a special port which executes the message | |
| 195 | * synchronously and waits for it if EASYNC is returned. | |
| 196 | */ | |
| fb0f29c4 | 197 | lwkt_initport_putonly(&netisr_sync_port, netmsg_sync_putport); |
| ef0fdad1 MD |
198 | } |
| 199 | ||
| b2632176 | 200 | SYSINIT(netisr, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, netisr_init, NULL); |
| bf82f9b7 | 201 | |
| 5c703385 MD |
202 | /* |
| 203 | * Finish initializing the message port for a netmsg service. This also | |
| 204 | * registers the port for synchronous cleanup operations such as when an | |
| 205 | * ifnet is being destroyed. There is no deregistration API yet. | |
| 206 | */ | |
| 207 | void | |
| 208 | netmsg_service_port_init(lwkt_port_t port) | |
| 209 | { | |
| 210 | struct netmsg_port_registration *reg; | |
| 211 | ||
| 212 | /* | |
| 213 | * Override the putport function. Our custom function checks for | |
| 214 | * self-references and executes such commands synchronously. | |
| 215 | */ | |
| fb0f29c4 MD |
216 | if (netmsg_fwd_port_fn == NULL) |
| 217 | netmsg_fwd_port_fn = port->mp_putport; | |
| 218 | KKASSERT(netmsg_fwd_port_fn == port->mp_putport); | |
| 5c703385 MD |
219 | port->mp_putport = netmsg_put_port; |
| 220 | ||
| 221 | /* | |
| 222 | * Keep track of ports using the netmsg API so we can synchronize | |
| 223 | * certain operations (such as freeing an ifnet structure) across all | |
| 224 | * consumers. | |
| 225 | */ | |
| efda3bd0 | 226 | reg = kmalloc(sizeof(*reg), M_TEMP, M_WAITOK|M_ZERO); |
| 5c703385 MD |
227 | reg->npr_port = port; |
| 228 | TAILQ_INSERT_TAIL(&netreglist, reg, npr_entry); | |
| 229 | } | |
| 230 | ||
| 231 | /* | |
| 232 | * This function synchronizes the caller with all netmsg services. For | |
| 233 | * example, if an interface is being removed we must make sure that all | |
| 234 | * packets related to that interface complete processing before the structure | |
| 235 | * can actually be freed. This sort of synchronization is an alternative to | |
| 236 | * ref-counting the netif, removing the ref counting overhead in favor of | |
| 237 | * placing additional overhead in the netif freeing sequence (where it is | |
| 238 | * inconsequential). | |
| 239 | */ | |
| 240 | void | |
| 241 | netmsg_service_sync(void) | |
| 242 | { | |
| 243 | struct netmsg_port_registration *reg; | |
| 244 | struct netmsg smsg; | |
| 245 | ||
| ff4a1403 | 246 | netmsg_init(&smsg, &curthread->td_msgport, MSGF_MPSAFE, netmsg_sync_func); |
| 5c703385 MD |
247 | |
| 248 | TAILQ_FOREACH(reg, &netreglist, npr_entry) { | |
| a22c590e | 249 | lwkt_domsg(reg->npr_port, &smsg.nm_lmsg, 0); |
| 5c703385 MD |
250 | } |
| 251 | } | |
| 252 | ||
| 253 | /* | |
| 254 | * The netmsg function simply replies the message. API semantics require | |
| 255 | * EASYNC to be returned if the netmsg function disposes of the message. | |
| 256 | */ | |
| 4599cf19 | 257 | static void |
| 5c703385 MD |
258 | netmsg_sync_func(struct netmsg *msg) |
| 259 | { | |
| 260 | lwkt_replymsg(&msg->nm_lmsg, 0); | |
| 5c703385 MD |
261 | } |
| 262 | ||
| 263 | /* | |
| 92db3805 | 264 | * Return current BGL lock state (1:locked, 0: unlocked) |
| 5c703385 | 265 | */ |
| 92db3805 SZ |
266 | int |
| 267 | netmsg_service(struct netmsg *msg, int mpsafe_mode, int mplocked) | |
| 8bde602d | 268 | { |
| 92db3805 SZ |
269 | /* |
| 270 | * Adjust the mplock dynamically. | |
| 271 | */ | |
| 272 | switch (mpsafe_mode) { | |
| 273 | case NETMSG_SERVICE_ADAPTIVE: /* Adaptive BGL */ | |
| 274 | if (msg->nm_lmsg.ms_flags & MSGF_MPSAFE) { | |
| 275 | if (mplocked) { | |
| 276 | rel_mplock(); | |
| 277 | mplocked = 0; | |
| 278 | } | |
| 279 | msg->nm_dispatch(msg); | |
| 280 | /* Leave mpunlocked */ | |
| 281 | } else { | |
| 282 | if (!mplocked) { | |
| 283 | get_mplock(); | |
| 284 | /* mplocked = 1; not needed */ | |
| 285 | } | |
| 286 | msg->nm_dispatch(msg); | |
| 287 | rel_mplock(); | |
| 288 | mplocked = 0; | |
| 289 | /* Leave mpunlocked, next msg might be mpsafe */ | |
| 290 | } | |
| 291 | break; | |
| 292 | ||
| 293 | case NETMSG_SERVICE_MPSAFE: /* No BGL */ | |
| 294 | if (mplocked) { | |
| 295 | rel_mplock(); | |
| 296 | mplocked = 0; | |
| 297 | } | |
| 298 | msg->nm_dispatch(msg); | |
| 299 | /* Leave mpunlocked */ | |
| 300 | break; | |
| 301 | ||
| 302 | default: /* BGL */ | |
| 303 | if (!mplocked) { | |
| 304 | get_mplock(); | |
| 305 | mplocked = 1; | |
| 306 | } | |
| 4599cf19 | 307 | msg->nm_dispatch(msg); |
| 92db3805 SZ |
308 | /* Leave mplocked */ |
| 309 | break; | |
| a29576fc | 310 | } |
| 92db3805 | 311 | return mplocked; |
| bf82f9b7 | 312 | } |
| 8bde602d | 313 | |
| bf82f9b7 | 314 | /* |
| 92db3805 SZ |
315 | * Generic netmsg service loop. Some protocols may roll their own but all |
| 316 | * must do the basic command dispatch function call done here. | |
| 95f8b5ce SZ |
317 | */ |
| 318 | void | |
| 92db3805 | 319 | netmsg_service_loop(void *arg) |
| 95f8b5ce | 320 | { |
| 92db3805 SZ |
321 | struct netmsg *msg; |
| 322 | int mplocked, *mpsafe_mode = arg; | |
| 323 | ||
| 324 | /* | |
| 325 | * Thread was started with TDF_MPSAFE | |
| 326 | */ | |
| 327 | mplocked = 0; | |
| 328 | ||
| 329 | /* | |
| 330 | * Loop on netmsgs | |
| 331 | */ | |
| 332 | while ((msg = lwkt_waitport(&curthread->td_msgport, 0))) { | |
| 333 | mplocked = netmsg_service(msg, *mpsafe_mode, mplocked); | |
| 334 | } | |
| 95f8b5ce SZ |
335 | } |
| 336 | ||
| 337 | /* | |
| bf82f9b7 MD |
338 | * Call the netisr directly. |
| 339 | * Queueing may be done in the msg port layer at its discretion. | |
| 340 | */ | |
| 341 | void | |
| 342 | netisr_dispatch(int num, struct mbuf *m) | |
| 343 | { | |
| 344 | /* just queue it for now XXX JH */ | |
| 345 | netisr_queue(num, m); | |
| 8bde602d JH |
346 | } |
| 347 | ||
| 348 | /* | |
| 349 | * Same as netisr_dispatch(), but always queue. | |
| 350 | * This is either used in places where we are not confident that | |
| 351 | * direct dispatch is possible, or where queueing is required. | |
| 352 | */ | |
| ef0fdad1 | 353 | int |
| 8bde602d | 354 | netisr_queue(int num, struct mbuf *m) |
| ef0fdad1 | 355 | { |
| 5944299a | 356 | struct netisr *ni; |
| 9eeaa8a9 | 357 | struct netmsg_packet *pmsg; |
| bf82f9b7 | 358 | lwkt_port_t port; |
| 8bde602d JH |
359 | |
| 360 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), | |
| ff86c8e0 | 361 | ("%s: bad isr %d", __func__, num)); |
| 8bde602d | 362 | |
| 5944299a MD |
363 | ni = &netisrs[num]; |
| 364 | if (ni->ni_handler == NULL) { | |
| ff86c8e0 | 365 | kprintf("%s: unregistered isr %d\n", __func__, num); |
| 68b67450 | 366 | m_freem(m); |
| 9eeaa8a9 | 367 | return (EIO); |
| 5944299a MD |
368 | } |
| 369 | ||
| b01ae44a | 370 | if ((port = ni->ni_mport(&m)) == NULL) |
| 9eeaa8a9 JH |
371 | return (EIO); |
| 372 | ||
| 6aad077d | 373 | pmsg = &m->m_hdr.mh_netmsg; |
| 8bde602d | 374 | |
| ff4a1403 SZ |
375 | netmsg_init(&pmsg->nm_netmsg, &netisr_apanic_rport, NETISR_TO_MSGF(ni), |
| 376 | ni->ni_handler); | |
| bf82f9b7 | 377 | pmsg->nm_packet = m; |
| 4599cf19 MD |
378 | pmsg->nm_netmsg.nm_lmsg.u.ms_result = num; |
| 379 | lwkt_sendmsg(port, &pmsg->nm_netmsg.nm_lmsg); | |
| 8bde602d JH |
380 | return (0); |
| 381 | } | |
| 382 | ||
| bf82f9b7 | 383 | void |
| f92bfd8c SZ |
384 | netisr_register(int num, pkt_portfn_t mportfn, |
| 385 | pktinfo_portfn_t mportfn_pktinfo, netisr_fn_t handler, | |
| 92db3805 | 386 | uint32_t flags) |
| 8bde602d | 387 | { |
| ff4a1403 SZ |
388 | struct netisr *ni; |
| 389 | ||
| 8bde602d | 390 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), |
| 1748bf82 | 391 | ("netisr_register: bad isr %d", num)); |
| ff4a1403 SZ |
392 | ni = &netisrs[num]; |
| 393 | ||
| 394 | ni->ni_mport = mportfn; | |
| f92bfd8c | 395 | ni->ni_mport_pktinfo = mportfn_pktinfo; |
| ff4a1403 SZ |
396 | ni->ni_handler = handler; |
| 397 | ni->ni_flags = flags; | |
| 398 | netmsg_init(&ni->ni_netmsg, &netisr_adone_rport, NETISR_TO_MSGF(ni), NULL); | |
| ef0fdad1 MD |
399 | } |
| 400 | ||
| 401 | int | |
| 8bde602d | 402 | netisr_unregister(int num) |
| ef0fdad1 | 403 | { |
| 8bde602d JH |
404 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), |
| 405 | ("unregister_netisr: bad isr number: %d\n", num)); | |
| 406 | ||
| bf82f9b7 | 407 | /* XXX JH */ |
| ef0fdad1 MD |
408 | return (0); |
| 409 | } | |
| bf82f9b7 MD |
410 | |
| 411 | /* | |
| 412 | * Return message port for default handler thread on CPU 0. | |
| 413 | */ | |
| 414 | lwkt_port_t | |
| b01ae44a | 415 | cpu0_portfn(struct mbuf **mptr) |
| bf82f9b7 | 416 | { |
| 97a43e72 SZ |
417 | struct mbuf *m = *mptr; |
| 418 | int cpu = 0; | |
| 419 | ||
| 420 | m->m_pkthdr.hash = cpu; | |
| 421 | m->m_flags |= M_HASH; | |
| 422 | return (&netisr_cpu[cpu].td_msgport); | |
| bf82f9b7 MD |
423 | } |
| 424 | ||
| ecdefdda MD |
425 | lwkt_port_t |
| 426 | cpu_portfn(int cpu) | |
| 427 | { | |
| 428 | return (&netisr_cpu[cpu].td_msgport); | |
| 429 | } | |
| 430 | ||
| c244d613 SZ |
431 | /* |
| 432 | * If the current thread is a network protocol thread (TDF_NETWORK), | |
| 433 | * then return the current thread's message port. | |
| 434 | * XXX Else, return the current CPU's netisr message port. | |
| 435 | */ | |
| 436 | lwkt_port_t | |
| 437 | cur_netport(void) | |
| 438 | { | |
| 439 | if (curthread->td_flags & TDF_NETWORK) | |
| 440 | return &curthread->td_msgport; | |
| 441 | else | |
| 442 | return cpu_portfn(mycpuid); | |
| 443 | } | |
| 444 | ||
| 9eeaa8a9 JH |
445 | /* ARGSUSED */ |
| 446 | lwkt_port_t | |
| 1c770505 | 447 | cpu0_soport(struct socket *so __unused, struct sockaddr *nam __unused, |
| 934c6849 | 448 | struct mbuf **dummy __unused, int req __unused) |
| 9eeaa8a9 JH |
449 | { |
| 450 | return (&netisr_cpu[0].td_msgport); | |
| 451 | } | |
| 452 | ||
| 3efe7008 | 453 | lwkt_port_t |
| e3873585 SZ |
454 | cpu0_ctlport(int cmd __unused, struct sockaddr *sa __unused, |
| 455 | void *extra __unused) | |
| 456 | { | |
| 457 | return (&netisr_cpu[0].td_msgport); | |
| 458 | } | |
| 459 | ||
| 460 | lwkt_port_t | |
| 3efe7008 | 461 | sync_soport(struct socket *so __unused, struct sockaddr *nam __unused, |
| 934c6849 | 462 | struct mbuf **dummy __unused, int req __unused) |
| 3efe7008 MD |
463 | { |
| 464 | return (&netisr_sync_port); | |
| 465 | } | |
| 466 | ||
| bf82f9b7 | 467 | /* |
| a29576fc | 468 | * schednetisr() is used to call the netisr handler from the appropriate |
| 9eeaa8a9 | 469 | * netisr thread for polling and other purposes. |
| a29576fc MD |
470 | * |
| 471 | * This function may be called from a hard interrupt or IPI and must be | |
| 472 | * MP SAFE and non-blocking. We use a fixed per-cpu message instead of | |
| 473 | * trying to allocate one. We must get ourselves onto the target cpu | |
| 474 | * to safely check the MSGF_DONE bit on the message but since the message | |
| 475 | * will be sent to that cpu anyway this does not add any extra work beyond | |
| 476 | * what lwkt_sendmsg() would have already had to do to schedule the target | |
| 477 | * thread. | |
| bf82f9b7 | 478 | */ |
| a29576fc MD |
479 | static void |
| 480 | schednetisr_remote(void *data) | |
| bf82f9b7 | 481 | { |
| 973c11b9 | 482 | int num = (int)(intptr_t)data; |
| bf82f9b7 | 483 | struct netisr *ni = &netisrs[num]; |
| bf82f9b7 | 484 | lwkt_port_t port = &netisr_cpu[0].td_msgport; |
| a29576fc | 485 | struct netmsg *pmsg; |
| bf82f9b7 | 486 | |
| a29576fc MD |
487 | pmsg = &netisrs[num].ni_netmsg; |
| 488 | crit_enter(); | |
| 489 | if (pmsg->nm_lmsg.ms_flags & MSGF_DONE) { | |
| ff4a1403 SZ |
490 | netmsg_init(pmsg, &netisr_adone_rport, NETISR_TO_MSGF(ni), |
| 491 | ni->ni_handler); | |
| a29576fc | 492 | pmsg->nm_lmsg.u.ms_result = num; |
| b76bed62 MD |
493 | lwkt_sendmsg(port, &pmsg->nm_lmsg); |
| 494 | } | |
| a29576fc MD |
495 | crit_exit(); |
| 496 | } | |
| 497 | ||
| 498 | void | |
| 499 | schednetisr(int num) | |
| 500 | { | |
| 501 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), | |
| 502 | ("schednetisr: bad isr %d", num)); | |
| 503 | #ifdef SMP | |
| 504 | if (mycpu->gd_cpuid != 0) | |
| 505 | lwkt_send_ipiq(globaldata_find(0), schednetisr_remote, (void *)num); | |
| 506 | else | |
| 973c11b9 | 507 | schednetisr_remote((void *)(intptr_t)num); |
| a29576fc | 508 | #else |
| 973c11b9 | 509 | schednetisr_remote((void *)(intptr_t)num); |
| a29576fc | 510 | #endif |
| bf82f9b7 | 511 | } |
| a29576fc | 512 | |
| 68b67450 | 513 | lwkt_port_t |
| 29bc1092 SZ |
514 | netisr_find_port(int num, struct mbuf **m0) |
| 515 | { | |
| 516 | struct netisr *ni; | |
| 517 | lwkt_port_t port; | |
| 518 | struct mbuf *m = *m0; | |
| 519 | ||
| 520 | *m0 = NULL; | |
| 521 | ||
| 522 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), | |
| 523 | ("%s: bad isr %d", __func__, num)); | |
| 524 | ||
| 525 | ni = &netisrs[num]; | |
| 526 | if (ni->ni_mport == NULL) { | |
| 527 | kprintf("%s: unregistered isr %d\n", __func__, num); | |
| 528 | m_freem(m); | |
| 529 | return NULL; | |
| 530 | } | |
| 531 | ||
| 532 | if ((port = ni->ni_mport(&m)) == NULL) | |
| 533 | return NULL; | |
| 534 | ||
| 535 | *m0 = m; | |
| 536 | return port; | |
| 537 | } | |
| 538 | ||
| 539 | void | |
| 540 | netisr_run(int num, struct mbuf *m) | |
| 541 | { | |
| 542 | struct netisr *ni; | |
| 543 | struct netmsg_packet *pmsg; | |
| 544 | ||
| 545 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), | |
| 546 | ("%s: bad isr %d", __func__, num)); | |
| 547 | ||
| 548 | ni = &netisrs[num]; | |
| 549 | if (ni->ni_handler == NULL) { | |
| 550 | kprintf("%s: unregistered isr %d\n", __func__, num); | |
| 551 | m_freem(m); | |
| 552 | return; | |
| 553 | } | |
| 554 | ||
| 555 | pmsg = &m->m_hdr.mh_netmsg; | |
| 556 | ||
| 557 | netmsg_init(&pmsg->nm_netmsg, &netisr_apanic_rport, 0, ni->ni_handler); | |
| 558 | pmsg->nm_packet = m; | |
| 559 | pmsg->nm_netmsg.nm_lmsg.u.ms_result = num; | |
| 560 | ||
| 92db3805 | 561 | NETISR_GET_MPLOCK(ni); |
| 29bc1092 | 562 | ni->ni_handler(&pmsg->nm_netmsg); |
| 92db3805 | 563 | NETISR_REL_MPLOCK(ni); |
| 29bc1092 | 564 | } |
| f92bfd8c SZ |
565 | |
| 566 | lwkt_port_t | |
| 2eb0d069 SZ |
567 | pktinfo_portfn_cpu0(const struct pktinfo *dummy __unused, |
| 568 | struct mbuf *m) | |
| f92bfd8c | 569 | { |
| 2eb0d069 | 570 | m->m_pkthdr.hash = 0; |
| f92bfd8c SZ |
571 | return &netisr_cpu[0].td_msgport; |
| 572 | } | |
| 573 | ||
| 574 | lwkt_port_t | |
| 2eb0d069 SZ |
575 | pktinfo_portfn_notsupp(const struct pktinfo *dummy __unused, |
| 576 | struct mbuf *m __unused) | |
| f92bfd8c SZ |
577 | { |
| 578 | return NULL; | |
| 579 | } | |
| 580 | ||
| 581 | lwkt_port_t | |
| 2eb0d069 | 582 | netisr_find_pktinfo_port(const struct pktinfo *pi, struct mbuf *m) |
| f92bfd8c SZ |
583 | { |
| 584 | struct netisr *ni; | |
| 2eb0d069 | 585 | int num = pi->pi_netisr; |
| f92bfd8c | 586 | |
| 2eb0d069 SZ |
587 | KASSERT(m->m_flags & M_HASH, ("packet does not contain hash\n")); |
| 588 | KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), | |
| 589 | ("%s: bad isr %d", __func__, num)); | |
| f92bfd8c | 590 | |
| 2eb0d069 | 591 | ni = &netisrs[num]; |
| f92bfd8c | 592 | if (ni->ni_mport_pktinfo == NULL) { |
| 2eb0d069 | 593 | kprintf("%s: unregistered isr %d\n", __func__, num); |
| f92bfd8c SZ |
594 | return NULL; |
| 595 | } | |
| 2eb0d069 | 596 | return ni->ni_mport_pktinfo(pi, m); |
| f92bfd8c | 597 | } |