The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/netisr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  *
   10  * Jonathan Lemon gave Jeffrey Hsu permission to combine his copyright
   11  * into this one around July 8 2004.
   12  *
   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  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/msgport.h>
   44 #include <sys/proc.h>
   45 #include <sys/interrupt.h>
   46 #include <sys/socket.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/socketvar.h>
   49 #include <net/if.h>
   50 #include <net/if_var.h>
   51 #include <net/netisr2.h>
   52 #include <machine/cpufunc.h>
   53 #include <machine/smp.h>
   54 
   55 #include <sys/thread2.h>
   56 #include <sys/msgport2.h>
   57 #include <net/netmsg2.h>
   58 #include <sys/mplock2.h>
   59 
   60 static void netmsg_service_loop(void *arg);
   61 static void netisr_hashfn0(struct mbuf **mp, int hoff);
   62 static void netisr_nohashck(struct mbuf *, const struct pktinfo *);
   63 
   64 struct netmsg_port_registration {
   65         TAILQ_ENTRY(netmsg_port_registration) npr_entry;
   66         lwkt_port_t     npr_port;
   67 };
   68 
   69 struct netmsg_rollup {
   70         TAILQ_ENTRY(netmsg_rollup) ru_entry;
   71         netisr_ru_t     ru_func;
   72         int             ru_prio;
   73 };
   74 
   75 struct netmsg_barrier {
   76         struct netmsg_base      base;
   77         volatile cpumask_t      *br_cpumask;
   78         volatile uint32_t       br_done;
   79 };
   80 
   81 #define NETISR_BR_NOTDONE       0x1
   82 #define NETISR_BR_WAITDONE      0x80000000
   83 
   84 struct netisr_barrier {
   85         struct netmsg_barrier   *br_msgs[MAXCPU];
   86         int                     br_isset;
   87 };
   88 
   89 static struct netisr netisrs[NETISR_MAX];
   90 static TAILQ_HEAD(,netmsg_port_registration) netreglist;
   91 static TAILQ_HEAD(,netmsg_rollup) netrulist;
   92 
   93 /* Per-CPU thread to handle any protocol.  */
   94 struct thread netisr_cpu[MAXCPU];
   95 lwkt_port netisr_afree_rport;
   96 lwkt_port netisr_afree_free_so_rport;
   97 lwkt_port netisr_adone_rport;
   98 lwkt_port netisr_apanic_rport;
   99 lwkt_port netisr_sync_port;
  100 
  101 static int (*netmsg_fwd_port_fn)(lwkt_port_t, lwkt_msg_t);
  102 
  103 SYSCTL_NODE(_net, OID_AUTO, netisr, CTLFLAG_RW, 0, "netisr");
  104 
  105 /*
  106  * netisr_afree_rport replymsg function, only used to handle async
  107  * messages which the sender has abandoned to their fate.
  108  */
  109 static void
  110 netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
  111 {
  112         kfree(msg, M_LWKTMSG);
  113 }
  114 
  115 static void
  116 netisr_autofree_free_so_reply(lwkt_port_t port, lwkt_msg_t msg)
  117 {
  118         sofree(((netmsg_t)msg)->base.nm_so);
  119         kfree(msg, M_LWKTMSG);
  120 }
  121 
  122 /*
  123  * We need a custom putport function to handle the case where the
  124  * message target is the current thread's message port.  This case
  125  * can occur when the TCP or UDP stack does a direct callback to NFS and NFS
  126  * then turns around and executes a network operation synchronously.
  127  *
  128  * To prevent deadlocking, we must execute these self-referential messages
  129  * synchronously, effectively turning the message into a glorified direct
  130  * procedure call back into the protocol stack.  The operation must be
  131  * complete on return or we will deadlock, so panic if it isn't.
  132  *
  133  * However, the target function is under no obligation to immediately
  134  * reply the message.  It may forward it elsewhere.
  135  */
  136 static int
  137 netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg)
  138 {
  139         netmsg_base_t nmsg = (void *)lmsg;
  140 
  141         if ((lmsg->ms_flags & MSGF_SYNC) && port == &curthread->td_msgport) {
  142                 nmsg->nm_dispatch((netmsg_t)nmsg);
  143                 return(EASYNC);
  144         } else {
  145                 return(netmsg_fwd_port_fn(port, lmsg));
  146         }
  147 }
  148 
  149 /*
  150  * UNIX DOMAIN sockets still have to run their uipc functions synchronously,
  151  * because they depend on the user proc context for a number of things 
  152  * (like creds) which we have not yet incorporated into the message structure.
  153  *
  154  * However, we maintain or message/port abstraction.  Having a special 
  155  * synchronous port which runs the commands synchronously gives us the
  156  * ability to serialize operations in one place later on when we start
  157  * removing the BGL.
  158  */
  159 static int
  160 netmsg_sync_putport(lwkt_port_t port, lwkt_msg_t lmsg)
  161 {
  162         netmsg_base_t nmsg = (void *)lmsg;
  163 
  164         KKASSERT((lmsg->ms_flags & MSGF_DONE) == 0);
  165 
  166         lmsg->ms_target_port = port;    /* required for abort */
  167         nmsg->nm_dispatch((netmsg_t)nmsg);
  168         return(EASYNC);
  169 }
  170 
  171 static void
  172 netisr_init(void)
  173 {
  174         int i;
  175 
  176         TAILQ_INIT(&netreglist);
  177         TAILQ_INIT(&netrulist);
  178 
  179         /*
  180          * Create default per-cpu threads for generic protocol handling.
  181          */
  182         for (i = 0; i < ncpus; ++i) {
  183                 lwkt_create(netmsg_service_loop, NULL, NULL,
  184                             &netisr_cpu[i],
  185                             TDF_NOSTART|TDF_FORCE_SPINPORT|TDF_FIXEDCPU,
  186                             i, "netisr_cpu %d", i);
  187                 netmsg_service_port_init(&netisr_cpu[i].td_msgport);
  188                 lwkt_schedule(&netisr_cpu[i]);
  189         }
  190 
  191         /*
  192          * The netisr_afree_rport is a special reply port which automatically
  193          * frees the replied message.  The netisr_adone_rport simply marks
  194          * the message as being done.  The netisr_apanic_rport panics if
  195          * the message is replied to.
  196          */
  197         lwkt_initport_replyonly(&netisr_afree_rport, netisr_autofree_reply);
  198         lwkt_initport_replyonly(&netisr_afree_free_so_rport,
  199                                 netisr_autofree_free_so_reply);
  200         lwkt_initport_replyonly_null(&netisr_adone_rport);
  201         lwkt_initport_panic(&netisr_apanic_rport);
  202 
  203         /*
  204          * The netisr_syncport is a special port which executes the message
  205          * synchronously and waits for it if EASYNC is returned.
  206          */
  207         lwkt_initport_putonly(&netisr_sync_port, netmsg_sync_putport);
  208 }
  209 
  210 SYSINIT(netisr, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, netisr_init, NULL);
  211 
  212 /*
  213  * Finish initializing the message port for a netmsg service.  This also
  214  * registers the port for synchronous cleanup operations such as when an
  215  * ifnet is being destroyed.  There is no deregistration API yet.
  216  */
  217 void
  218 netmsg_service_port_init(lwkt_port_t port)
  219 {
  220         struct netmsg_port_registration *reg;
  221 
  222         /*
  223          * Override the putport function.  Our custom function checks for
  224          * self-references and executes such commands synchronously.
  225          */
  226         if (netmsg_fwd_port_fn == NULL)
  227                 netmsg_fwd_port_fn = port->mp_putport;
  228         KKASSERT(netmsg_fwd_port_fn == port->mp_putport);
  229         port->mp_putport = netmsg_put_port;
  230 
  231         /*
  232          * Keep track of ports using the netmsg API so we can synchronize
  233          * certain operations (such as freeing an ifnet structure) across all
  234          * consumers.
  235          */
  236         reg = kmalloc(sizeof(*reg), M_TEMP, M_WAITOK|M_ZERO);
  237         reg->npr_port = port;
  238         TAILQ_INSERT_TAIL(&netreglist, reg, npr_entry);
  239 }
  240 
  241 /*
  242  * This function synchronizes the caller with all netmsg services.  For
  243  * example, if an interface is being removed we must make sure that all
  244  * packets related to that interface complete processing before the structure
  245  * can actually be freed.  This sort of synchronization is an alternative to
  246  * ref-counting the netif, removing the ref counting overhead in favor of
  247  * placing additional overhead in the netif freeing sequence (where it is
  248  * inconsequential).
  249  */
  250 void
  251 netmsg_service_sync(void)
  252 {
  253         struct netmsg_port_registration *reg;
  254         struct netmsg_base smsg;
  255 
  256         netmsg_init(&smsg, NULL, &curthread->td_msgport, 0, netmsg_sync_handler);
  257 
  258         TAILQ_FOREACH(reg, &netreglist, npr_entry) {
  259                 lwkt_domsg(reg->npr_port, &smsg.lmsg, 0);
  260         }
  261 }
  262 
  263 /*
  264  * The netmsg function simply replies the message.  API semantics require
  265  * EASYNC to be returned if the netmsg function disposes of the message.
  266  */
  267 void
  268 netmsg_sync_handler(netmsg_t msg)
  269 {
  270         lwkt_replymsg(&msg->lmsg, 0);
  271 }
  272 
  273 /*
  274  * Generic netmsg service loop.  Some protocols may roll their own but all
  275  * must do the basic command dispatch function call done here.
  276  */
  277 static void
  278 netmsg_service_loop(void *arg)
  279 {
  280         struct netmsg_rollup *ru;
  281         netmsg_base_t msg;
  282         thread_t td = curthread;
  283         int limit;
  284 
  285         td->td_type = TD_TYPE_NETISR;
  286 
  287         while ((msg = lwkt_waitport(&td->td_msgport, 0))) {
  288                 /*
  289                  * Run up to 512 pending netmsgs.
  290                  */
  291                 limit = 512;
  292                 do {
  293                         KASSERT(msg->nm_dispatch != NULL,
  294                                 ("netmsg_service isr %d badmsg",
  295                                 msg->lmsg.u.ms_result));
  296                         if (msg->nm_so &&
  297                             msg->nm_so->so_port != &td->td_msgport) {
  298                                 /*
  299                                  * Sockets undergoing connect or disconnect
  300                                  * ops can change ports on us.  Chase the
  301                                  * port.
  302                                  */
  303 #ifdef foo
  304                                 /*
  305                                  * This could be quite common for protocols
  306                                  * which support asynchronous pru_connect,
  307                                  * e.g. TCP, so kprintf socket port chasing
  308                                  * could be too verbose for the console.
  309                                  */
  310                                 kprintf("netmsg_service_loop: Warning, "
  311                                         "port changed so=%p\n", msg->nm_so);
  312 #endif
  313                                 lwkt_forwardmsg(msg->nm_so->so_port,
  314                                                 &msg->lmsg);
  315                         } else {
  316                                 /*
  317                                  * We are on the correct port, dispatch it.
  318                                  */
  319                                 msg->nm_dispatch((netmsg_t)msg);
  320                         }
  321                         if (--limit == 0)
  322                                 break;
  323                 } while ((msg = lwkt_getport(&td->td_msgport)) != NULL);
  324 
  325                 /*
  326                  * Run all registered rollup functions for this cpu
  327                  * (e.g. tcp_willblock()).
  328                  */
  329                 TAILQ_FOREACH(ru, &netrulist, ru_entry)
  330                         ru->ru_func();
  331         }
  332 }
  333 
  334 /*
  335  * Forward a packet to a netisr service function.
  336  *
  337  * If the packet has not been assigned to a protocol thread we call
  338  * the port characterization function to assign it.  The caller must
  339  * clear M_HASH (or not have set it in the first place) if the caller
  340  * wishes the packet to be recharacterized.
  341  */
  342 int
  343 netisr_queue(int num, struct mbuf *m)
  344 {
  345         struct netisr *ni;
  346         struct netmsg_packet *pmsg;
  347         lwkt_port_t port;
  348 
  349         KASSERT((num > 0 && num <= NELEM(netisrs)),
  350                 ("Bad isr %d", num));
  351 
  352         ni = &netisrs[num];
  353         if (ni->ni_handler == NULL) {
  354                 kprintf("Unregistered isr %d\n", num);
  355                 m_freem(m);
  356                 return (EIO);
  357         }
  358 
  359         /*
  360          * Figure out which protocol thread to send to.  This does not
  361          * have to be perfect but performance will be really good if it
  362          * is correct.  Major protocol inputs such as ip_input() will
  363          * re-characterize the packet as necessary.
  364          */
  365         if ((m->m_flags & M_HASH) == 0) {
  366                 ni->ni_hashfn(&m, 0);
  367                 if (m == NULL) {
  368                         m_freem(m);
  369                         return (EIO);
  370                 }
  371                 if ((m->m_flags & M_HASH) == 0) {
  372                         kprintf("netisr_queue(%d): packet hash failed\n", num);
  373                         m_freem(m);
  374                         return (EIO);
  375                 }
  376         }
  377 
  378         /*
  379          * Get the protocol port based on the packet hash, initialize
  380          * the netmsg, and send it off.
  381          */
  382         port = netisr_hashport(m->m_pkthdr.hash);
  383         pmsg = &m->m_hdr.mh_netmsg;
  384         netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
  385                     0, ni->ni_handler);
  386         pmsg->nm_packet = m;
  387         pmsg->base.lmsg.u.ms_result = num;
  388         lwkt_sendmsg(port, &pmsg->base.lmsg);
  389 
  390         return (0);
  391 }
  392 
  393 /*
  394  * Run a netisr service function on the packet.
  395  *
  396  * The packet must have been correctly characterized!
  397  */
  398 int
  399 netisr_handle(int num, struct mbuf *m)
  400 {
  401         struct netisr *ni;
  402         struct netmsg_packet *pmsg;
  403         lwkt_port_t port;
  404 
  405         /*
  406          * Get the protocol port based on the packet hash
  407          */
  408         KASSERT((m->m_flags & M_HASH), ("packet not characterized"));
  409         port = netisr_hashport(m->m_pkthdr.hash);
  410         KASSERT(&curthread->td_msgport == port, ("wrong msgport"));
  411 
  412         KASSERT((num > 0 && num <= NELEM(netisrs)), ("bad isr %d", num));
  413         ni = &netisrs[num];
  414         if (ni->ni_handler == NULL) {
  415                 kprintf("unregistered isr %d\n", num);
  416                 m_freem(m);
  417                 return EIO;
  418         }
  419 
  420         /*
  421          * Initialize the netmsg, and run the handler directly.
  422          */
  423         pmsg = &m->m_hdr.mh_netmsg;
  424         netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
  425                     0, ni->ni_handler);
  426         pmsg->nm_packet = m;
  427         pmsg->base.lmsg.u.ms_result = num;
  428         ni->ni_handler((netmsg_t)&pmsg->base);
  429 
  430         return 0;
  431 }
  432 
  433 /*
  434  * Pre-characterization of a deeper portion of the packet for the
  435  * requested isr.
  436  *
  437  * The base of the ISR type (e.g. IP) that we want to characterize is
  438  * at (hoff) relative to the beginning of the mbuf.  This allows
  439  * e.g. ether_characterize() to not have to adjust the m_data/m_len.
  440  */
  441 void
  442 netisr_characterize(int num, struct mbuf **mp, int hoff)
  443 {
  444         struct netisr *ni;
  445         struct mbuf *m;
  446 
  447         /*
  448          * Validation
  449          */
  450         m = *mp;
  451         KKASSERT(m != NULL);
  452 
  453         if (num < 0 || num >= NETISR_MAX) {
  454                 if (num == NETISR_MAX) {
  455                         m->m_flags |= M_HASH;
  456                         m->m_pkthdr.hash = 0;
  457                         return;
  458                 }
  459                 panic("Bad isr %d", num);
  460         }
  461 
  462         /*
  463          * Valid netisr?
  464          */
  465         ni = &netisrs[num];
  466         if (ni->ni_handler == NULL) {
  467                 kprintf("Unregistered isr %d\n", num);
  468                 m_freem(m);
  469                 *mp = NULL;
  470         }
  471 
  472         /*
  473          * Characterize the packet
  474          */
  475         if ((m->m_flags & M_HASH) == 0) {
  476                 ni->ni_hashfn(mp, hoff);
  477                 m = *mp;
  478                 if (m && (m->m_flags & M_HASH) == 0)
  479                         kprintf("netisr_queue(%d): packet hash failed\n", num);
  480         }
  481 }
  482 
  483 void
  484 netisr_register(int num, netisr_fn_t handler, netisr_hashfn_t hashfn)
  485 {
  486         struct netisr *ni;
  487 
  488         KASSERT((num > 0 && num <= NELEM(netisrs)),
  489                 ("netisr_register: bad isr %d", num));
  490         KKASSERT(handler != NULL);
  491 
  492         if (hashfn == NULL)
  493                 hashfn = netisr_hashfn0;
  494 
  495         ni = &netisrs[num];
  496 
  497         ni->ni_handler = handler;
  498         ni->ni_hashck = netisr_nohashck;
  499         ni->ni_hashfn = hashfn;
  500         netmsg_init(&ni->ni_netmsg, NULL, &netisr_adone_rport, 0, NULL);
  501 }
  502 
  503 void
  504 netisr_register_hashcheck(int num, netisr_hashck_t hashck)
  505 {
  506         struct netisr *ni;
  507 
  508         KASSERT((num > 0 && num <= NELEM(netisrs)),
  509                 ("netisr_register: bad isr %d", num));
  510 
  511         ni = &netisrs[num];
  512         ni->ni_hashck = hashck;
  513 }
  514 
  515 void
  516 netisr_register_rollup(netisr_ru_t ru_func, int prio)
  517 {
  518         struct netmsg_rollup *new_ru, *ru;
  519 
  520         new_ru = kmalloc(sizeof(*new_ru), M_TEMP, M_WAITOK|M_ZERO);
  521         new_ru->ru_func = ru_func;
  522         new_ru->ru_prio = prio;
  523 
  524         /*
  525          * Higher priority "rollup" appears first
  526          */
  527         TAILQ_FOREACH(ru, &netrulist, ru_entry) {
  528                 if (ru->ru_prio < new_ru->ru_prio) {
  529                         TAILQ_INSERT_BEFORE(ru, new_ru, ru_entry);
  530                         return;
  531                 }
  532         }
  533         TAILQ_INSERT_TAIL(&netrulist, new_ru, ru_entry);
  534 }
  535 
  536 /*
  537  * Return a default protocol control message processing thread port
  538  */
  539 lwkt_port_t
  540 cpu0_ctlport(int cmd __unused, struct sockaddr *sa __unused,
  541              void *extra __unused)
  542 {
  543         return (&netisr_cpu[0].td_msgport);
  544 }
  545 
  546 /*
  547  * This is a default netisr packet characterization function which
  548  * sets M_HASH.  If a netisr is registered with a NULL hashfn function
  549  * this one is assigned.
  550  *
  551  * This function makes no attempt to validate the packet.
  552  */
  553 static void
  554 netisr_hashfn0(struct mbuf **mp, int hoff __unused)
  555 {
  556         struct mbuf *m = *mp;
  557 
  558         m->m_flags |= M_HASH;
  559         m->m_pkthdr.hash = 0;
  560 }
  561 
  562 /*
  563  * schednetisr() is used to call the netisr handler from the appropriate
  564  * netisr thread for polling and other purposes.
  565  *
  566  * This function may be called from a hard interrupt or IPI and must be
  567  * MP SAFE and non-blocking.  We use a fixed per-cpu message instead of
  568  * trying to allocate one.  We must get ourselves onto the target cpu
  569  * to safely check the MSGF_DONE bit on the message but since the message
  570  * will be sent to that cpu anyway this does not add any extra work beyond
  571  * what lwkt_sendmsg() would have already had to do to schedule the target
  572  * thread.
  573  */
  574 static void
  575 schednetisr_remote(void *data)
  576 {
  577         int num = (int)(intptr_t)data;
  578         struct netisr *ni = &netisrs[num];
  579         lwkt_port_t port = &netisr_cpu[0].td_msgport;
  580         netmsg_base_t pmsg;
  581 
  582         pmsg = &netisrs[num].ni_netmsg;
  583         if (pmsg->lmsg.ms_flags & MSGF_DONE) {
  584                 netmsg_init(pmsg, NULL, &netisr_adone_rport, 0, ni->ni_handler);
  585                 pmsg->lmsg.u.ms_result = num;
  586                 lwkt_sendmsg(port, &pmsg->lmsg);
  587         }
  588 }
  589 
  590 void
  591 schednetisr(int num)
  592 {
  593         KASSERT((num > 0 && num <= NELEM(netisrs)),
  594                 ("schednetisr: bad isr %d", num));
  595         KKASSERT(netisrs[num].ni_handler != NULL);
  596         if (mycpu->gd_cpuid != 0) {
  597                 lwkt_send_ipiq(globaldata_find(0),
  598                                schednetisr_remote, (void *)(intptr_t)num);
  599         } else {
  600                 crit_enter();
  601                 schednetisr_remote((void *)(intptr_t)num);
  602                 crit_exit();
  603         }
  604 }
  605 
  606 static void
  607 netisr_barrier_dispatch(netmsg_t nmsg)
  608 {
  609         struct netmsg_barrier *msg = (struct netmsg_barrier *)nmsg;
  610 
  611         atomic_clear_cpumask(msg->br_cpumask, mycpu->gd_cpumask);
  612         if (*msg->br_cpumask == 0)
  613                 wakeup(msg->br_cpumask);
  614 
  615         for (;;) {
  616                 uint32_t done = msg->br_done;
  617 
  618                 cpu_ccfence();
  619                 if ((done & NETISR_BR_NOTDONE) == 0)
  620                         break;
  621 
  622                 tsleep_interlock(&msg->br_done, 0);
  623                 if (atomic_cmpset_int(&msg->br_done,
  624                     done, done | NETISR_BR_WAITDONE))
  625                         tsleep(&msg->br_done, PINTERLOCKED, "nbrdsp", 0);
  626         }
  627 
  628         lwkt_replymsg(&nmsg->lmsg, 0);
  629 }
  630 
  631 struct netisr_barrier *
  632 netisr_barrier_create(void)
  633 {
  634         struct netisr_barrier *br;
  635 
  636         br = kmalloc(sizeof(*br), M_LWKTMSG, M_WAITOK | M_ZERO);
  637         return br;
  638 }
  639 
  640 void
  641 netisr_barrier_set(struct netisr_barrier *br)
  642 {
  643         volatile cpumask_t other_cpumask;
  644         int i, cur_cpuid;
  645 
  646         KKASSERT(&curthread->td_msgport == netisr_cpuport(0));
  647         KKASSERT(!br->br_isset);
  648 
  649         other_cpumask = mycpu->gd_other_cpus & smp_active_mask;
  650         cur_cpuid = mycpuid;
  651 
  652         for (i = 0; i < ncpus; ++i) {
  653                 struct netmsg_barrier *msg;
  654 
  655                 if (i == cur_cpuid)
  656                         continue;
  657 
  658                 msg = kmalloc(sizeof(struct netmsg_barrier),
  659                               M_LWKTMSG, M_WAITOK);
  660                 netmsg_init(&msg->base, NULL, &netisr_afree_rport,
  661                             MSGF_PRIORITY, netisr_barrier_dispatch);
  662                 msg->br_cpumask = &other_cpumask;
  663                 msg->br_done = NETISR_BR_NOTDONE;
  664 
  665                 KKASSERT(br->br_msgs[i] == NULL);
  666                 br->br_msgs[i] = msg;
  667         }
  668 
  669         for (i = 0; i < ncpus; ++i) {
  670                 if (i == cur_cpuid)
  671                         continue;
  672                 lwkt_sendmsg(netisr_cpuport(i), &br->br_msgs[i]->base.lmsg);
  673         }
  674 
  675         while (other_cpumask != 0) {
  676                 tsleep_interlock(&other_cpumask, 0);
  677                 if (other_cpumask != 0)
  678                         tsleep(&other_cpumask, PINTERLOCKED, "nbrset", 0);
  679         }
  680         br->br_isset = 1;
  681 }
  682 
  683 void
  684 netisr_barrier_rem(struct netisr_barrier *br)
  685 {
  686         int i, cur_cpuid;
  687 
  688         KKASSERT(&curthread->td_msgport == netisr_cpuport(0));
  689         KKASSERT(br->br_isset);
  690 
  691         cur_cpuid = mycpuid;
  692         for (i = 0; i < ncpus; ++i) {
  693                 struct netmsg_barrier *msg = br->br_msgs[i];
  694                 uint32_t done;
  695 
  696                 msg = br->br_msgs[i];
  697                 br->br_msgs[i] = NULL;
  698 
  699                 if (i == cur_cpuid)
  700                         continue;
  701 
  702                 done = atomic_swap_int(&msg->br_done, 0);
  703                 if (done & NETISR_BR_WAITDONE)
  704                         wakeup(&msg->br_done);
  705         }
  706         br->br_isset = 0;
  707 }
  708 
  709 static void
  710 netisr_nohashck(struct mbuf *m, const struct pktinfo *pi __unused)
  711 {
  712         m->m_flags &= ~M_HASH;
  713 }
  714 
  715 void
  716 netisr_hashcheck(int num, struct mbuf *m, const struct pktinfo *pi)
  717 {
  718         struct netisr *ni;
  719 
  720         if (num < 0 || num >= NETISR_MAX)
  721                 panic("Bad isr %d", num);
  722 
  723         /*
  724          * Valid netisr?
  725          */
  726         ni = &netisrs[num];
  727         if (ni->ni_handler == NULL)
  728                 panic("Unregistered isr %d", num);
  729 
  730         ni->ni_hashck(m, pi);
  731 }

Cache object: 97c4abe2a13f843a9cda967b13167c44


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.