LCOV - code coverage report
Current view: top level - net - ifq.h (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 16 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ifq.h,v 1.20 2018/01/04 11:02:57 tb Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2015 David Gwynne <dlg@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #ifndef _NET_IFQ_H_
      20             : #define _NET_IFQ_H_
      21             : 
      22             : struct ifnet;
      23             : 
      24             : struct ifq_ops;
      25             : 
      26             : struct ifqueue {
      27             :         struct ifnet            *ifq_if;
      28             :         union {
      29             :                 void                    *_ifq_softc;
      30             :                 /*
      31             :                  * a rings sndq is found by looking up an array of pointers.
      32             :                  * by default we only have one sndq and the default drivers
      33             :                  * dont use ifq_softc, so we can borrow it for the map until
      34             :                  * we need to allocate a proper map.
      35             :                  */
      36             :                 struct ifqueue          *_ifq_ifqs[1];
      37             :         } _ifq_ptr;
      38             : #define ifq_softc                _ifq_ptr._ifq_softc
      39             : #define ifq_ifqs                 _ifq_ptr._ifq_ifqs
      40             : 
      41             :         /* mbuf handling */
      42             :         struct mutex             ifq_mtx;
      43             :         const struct ifq_ops    *ifq_ops;
      44             :         void                    *ifq_q;
      45             :         struct mbuf_list         ifq_free;
      46             :         unsigned int             ifq_len;
      47             :         unsigned int             ifq_oactive;
      48             : 
      49             :         /* statistics */
      50             :         uint64_t                 ifq_packets;
      51             :         uint64_t                 ifq_bytes;
      52             :         uint64_t                 ifq_qdrops;
      53             :         uint64_t                 ifq_errors;
      54             :         uint64_t                 ifq_mcasts;
      55             : 
      56             :         /* work serialisation */
      57             :         struct mutex             ifq_task_mtx;
      58             :         struct task_list         ifq_task_list;
      59             :         void                    *ifq_serializer;
      60             : 
      61             :         /* work to be serialised */
      62             :         struct task              ifq_start;
      63             :         struct task              ifq_restart;
      64             : 
      65             :         /* properties */
      66             :         unsigned int             ifq_maxlen;
      67             :         unsigned int             ifq_idx;
      68             : };
      69             : 
      70             : struct ifiqueue {
      71             :         struct ifnet            *ifiq_if;
      72             :         struct taskq            *ifiq_softnet;
      73             :         union {
      74             :                 void                    *_ifiq_softc;
      75             :                 struct ifiqueue         *_ifiq_ifiqs[1];
      76             :         } _ifiq_ptr;
      77             : #define ifiq_softc               _ifiq_ptr._ifiq_softc
      78             : #define ifiq_ifiqs               _ifiq_ptr._ifiq_ifiqs
      79             : 
      80             :         struct mutex             ifiq_mtx;
      81             :         struct mbuf_list         ifiq_ml;
      82             :         struct task              ifiq_task;
      83             : 
      84             :         /* counters */
      85             :         uint64_t                 ifiq_packets;
      86             :         uint64_t                 ifiq_bytes;
      87             :         uint64_t                 ifiq_qdrops;
      88             :         uint64_t                 ifiq_errors;
      89             :         uint64_t                 ifiq_mcasts;
      90             :         uint64_t                 ifiq_noproto;
      91             : 
      92             :         /* properties */
      93             :         unsigned int             ifiq_idx;
      94             : };
      95             : 
      96             : #ifdef _KERNEL
      97             : 
      98             : #define IFQ_MAXLEN              256
      99             : 
     100             : /*
     101             :  *
     102             :  * Interface Send Queues
     103             :  *
     104             :  * struct ifqueue sits between the network stack and a drivers
     105             :  * transmission of packets. The high level view is that when the stack
     106             :  * has finished generating a packet it hands it to a driver for
     107             :  * transmission. It does this by queueing the packet on an ifqueue and
     108             :  * notifying the driver to start transmission of the queued packets.
     109             :  *
     110             :  * A network device may have multiple contexts for the transmission
     111             :  * of packets, ie, independent transmit rings. An network device
     112             :  * represented by a struct ifnet may have multiple ifqueue structures,
     113             :  * each of which represents an independent context.
     114             :  *
     115             :  * struct ifqueue also provides the point where conditioning of
     116             :  * traffic (ie, priq and hfsc) is implemented, and provides some
     117             :  * infrastructure to assist in the implementation of network drivers.
     118             :  *
     119             :  * = ifq API
     120             :  *
     121             :  * The ifq API provides functions for three distinct consumers:
     122             :  *
     123             :  * 1. The network stack
     124             :  * 2. Traffic QoS/conditioning implementations
     125             :  * 3. Network drivers
     126             :  *
     127             :  * == Network Stack API
     128             :  *
     129             :  * The network stack is responsible for initialising and destroying
     130             :  * the ifqueue structures, changing the traffic conditioner on an
     131             :  * interface, enqueuing packets for transmission, and notifying
     132             :  * the driver to start transmission of a particular ifqueue.
     133             :  *
     134             :  * === ifq_init()
     135             :  *
     136             :  * During if_attach(), the network stack calls ifq_init to initialise
     137             :  * the ifqueue structure. By default it configures the priq traffic
     138             :  * conditioner.
     139             :  *
     140             :  * === ifq_destroy()
     141             :  *
     142             :  * The network stack calls ifq_destroy() during if_detach to tear down
     143             :  * the ifqueue structure. It frees the traffic conditioner state, and
     144             :  * frees any mbufs that were left queued.
     145             :  *
     146             :  * === ifq_attach()
     147             :  *
     148             :  * ifq_attach() is used to replace the current traffic conditioner on
     149             :  * the ifqueue. All the pending mbufs are removed from the previous
     150             :  * conditioner and requeued on the new.
     151             :  *
     152             :  * === ifq_idx()
     153             :  *
     154             :  * ifq_idx() selects a specific ifqueue from the current ifnet
     155             :  * structure for use in the transmission of the mbuf.
     156             :  *
     157             :  * === ifq_enqueue()
     158             :  *
     159             :  * ifq_enqueue() attempts to fit an mbuf onto the ifqueue. The
     160             :  * current traffic conditioner may drop a packet to make space on the
     161             :  * queue.
     162             :  *
     163             :  * === ifq_start()
     164             :  *
     165             :  * Once a packet has been successfully queued with ifq_enqueue(),
     166             :  * the network card is notified with a call to ifq_start().
     167             :  * Calls to ifq_start() run in the ifqueue serialisation context,
     168             :  * guaranteeing that only one instance of ifp->if_qstart() will be
     169             :  * running on behalf of a specific ifqueue in the system at any point
     170             :  * in time.
     171             :  *
     172             :  * == Traffic conditioners API
     173             :  *
     174             :  * The majority of interaction between struct ifqueue and a traffic
     175             :  * conditioner occurs via the callbacks a traffic conditioner provides
     176             :  * in an instance of struct ifq_ops.
     177             :  *
     178             :  * XXX document ifqop_*
     179             :  *
     180             :  * The ifqueue API implements the locking on behalf of the conditioning
     181             :  * implementations so conditioners only have to reject or keep mbufs.
     182             :  * If something needs to inspect a conditioners internals, the queue lock
     183             :  * needs to be taken to allow for a consistent or safe view. The queue
     184             :  * lock may be taken and released with ifq_q_enter() and ifq_q_leave().
     185             :  *
     186             :  * === ifq_q_enter()
     187             :  *
     188             :  * Code wishing to access a conditioners internals may take the queue
     189             :  * lock with ifq_q_enter(). The caller must pass a reference to the
     190             :  * conditioners ifq_ops structure so the infrastructure can ensure the
     191             :  * caller is able to understand the internals. ifq_q_enter() returns
     192             :  * a pointer to the conditions internal structures, or NULL if the
     193             :  * ifq_ops did not match the current conditioner.
     194             :  *
     195             :  * === ifq_q_leave()
     196             :  *
     197             :  * The queue lock acquired with ifq_q_enter() is released with
     198             :  * ifq_q_leave().
     199             :  *
     200             :  * === ifq_mfreem() and ifq_mfreeml()
     201             :  *
     202             :  * A goal of the API is to avoid freeing an mbuf while mutexs are
     203             :  * held. Because the ifq API manages the lock on behalf of the backend
     204             :  * ifqops, the backend should not directly free mbufs. If a conditioner
     205             :  * backend needs to drop a packet during the handling of ifqop_deq_begin,
     206             :  * it may free it by calling ifq_mfreem(). This accounts for the drop,
     207             :  * and schedules the free of the mbuf outside the hold of ifq_mtx.
     208             :  * ifq_mfreeml() takes an mbuf list as an argument instead.
     209             :  *
     210             :  *
     211             :  * == Network Driver API
     212             :  *
     213             :  * The API used by network drivers is mostly documented in the
     214             :  * ifq_dequeue(9) manpage except for ifq_serialize(),
     215             :  * ifq_is_serialized(), and IFQ_ASSERT_SERIALIZED().
     216             :  *
     217             :  * === ifq_serialize()
     218             :  *
     219             :  * A driver may run arbitrary work in the ifqueue serialiser context
     220             :  * via ifq_serialize(). The work to be done is represented by a task
     221             :  * that has been prepared with task_set.
     222             :  *
     223             :  * The work will be run in series with any other work dispatched by
     224             :  * ifq_start(), ifq_restart(), or other ifq_serialize() calls.
     225             :  *
     226             :  * Because the work may be run on another CPU, the lifetime of the
     227             :  * task and the work it represents can extend beyond the end of the
     228             :  * call to ifq_serialize() that dispatched it.
     229             :  *
     230             :  * === ifq_is_serialized()
     231             :  *
     232             :  * This function returns whether the caller is currently within the
     233             :  * ifqueue serializer context.
     234             :  *
     235             :  * === IFQ_ASSERT_SERIALIZED()
     236             :  *
     237             :  * This macro will assert that the caller is currently within the
     238             :  * specified ifqueue serialiser context.
     239             :  *
     240             :  *
     241             :  * = ifqueue work serialisation
     242             :  *
     243             :  * ifqueues provide a mechanism to dispatch work to be run in a single
     244             :  * context. Work in this mechanism is represtented by task structures.
     245             :  *
     246             :  * The tasks are run in a context similar to a taskq serviced by a
     247             :  * single kernel thread, except the work is run immediately by the
     248             :  * first CPU that dispatches work. If a second CPU attempts to dispatch
     249             :  * additional tasks while the first is still running, it will be queued
     250             :  * to be run by the first CPU. The second CPU will return immediately.
     251             :  *
     252             :  * = MP Safe Network Drivers
     253             :  *
     254             :  * An MP safe network driver is one in which its start routine can be
     255             :  * called by the network stack without holding the big kernel lock.
     256             :  *
     257             :  * == Attach
     258             :  *
     259             :  * A driver advertises it's ability to run its start routine without
     260             :  * the kernel lock by setting the IFXF_MPSAFE flag in ifp->if_xflags
     261             :  * before calling if_attach(). Advertising an MPSAFE start routine
     262             :  * also implies that the driver understands that a network card can
     263             :  * have multiple rings or transmit queues, and therefore provides
     264             :  * if_qstart function (which takes an ifqueue pointer) instead of an
     265             :  * if_start function (which takes an ifnet pointer).
     266             :  *
     267             :  *      void    drv_start(struct ifqueue *);
     268             :  *
     269             :  *      void
     270             :  *      drv_attach()
     271             :  *      {
     272             :  *      ...
     273             :  *              ifp->if_xflags = IFXF_MPSAFE;
     274             :  *              ifp->if_qstart = drv_start;
     275             :  *              if_attach(ifp);
     276             :  *      }
     277             :  *
     278             :  * The network stack will then call ifp->if_qstart via ifq_start()
     279             :  * to guarantee there is only one instance of that function running
     280             :  * in the system and to serialise it with other work the driver may
     281             :  * provide.
     282             :  *
     283             :  * == Initialise
     284             :  *
     285             :  * When the stack requests an interface be brought up (ie, drv_ioctl()
     286             :  * is called to handle SIOCSIFFLAGS with IFF_UP set in ifp->if_flags)
     287             :  * drivers should set IFF_RUNNING in ifp->if_flags and call
     288             :  * ifq_clr_oactive().
     289             :  *
     290             :  * == if_start
     291             :  *
     292             :  * ifq_start() checks that IFF_RUNNING is set in ifp->if_flags, that
     293             :  * ifq_is_oactive() does not return true, and that there are pending
     294             :  * packets to transmit via a call to ifq_len(). Therefore, drivers are
     295             :  * no longer responsible for doing this themselves.
     296             :  *
     297             :  * If a driver should not transmit packets while its link is down, use
     298             :  * ifq_purge() to flush pending packets from the transmit queue.
     299             :  *
     300             :  * Drivers for hardware should use the following pattern to transmit
     301             :  * packets:
     302             :  *
     303             :  *      void
     304             :  *      drv_start(struct ifqueue *ifq)
     305             :  *      {
     306             :  *              struct ifnet *ifp = ifq->ifq_if;
     307             :  *              struct drv_softc *sc = ifp->if_softc;
     308             :  *              struct mbuf *m;
     309             :  *              int kick = 0;
     310             :  *
     311             :  *              if (NO_LINK) {
     312             :  *                      ifq_purge(ifq);
     313             :  *                      return;
     314             :  *              }
     315             :  *
     316             :  *              for (;;) {
     317             :  *                      if (NO_SPACE) {
     318             :  *                              ifq_set_oactive(ifq);
     319             :  *                              break;
     320             :  *                      }
     321             :  *
     322             :  *                      m = ifq_dequeue(ifq);
     323             :  *                      if (m == NULL)
     324             :  *                              break;
     325             :  *
     326             :  *                      if (drv_encap(sc, m) != 0) { // map and fill ring
     327             :  *                              m_freem(m);
     328             :  *                              continue;
     329             :  *                      }
     330             :  *
     331             :  *                      bpf_mtap();
     332             :  *              }
     333             :  *
     334             :  *              drv_kick(sc); // notify hw of new descriptors on the ring
     335             :  *       }
     336             :  *
     337             :  * == Transmission completion
     338             :  *
     339             :  * The following pattern should be used for transmit queue interrupt
     340             :  * processing:
     341             :  *
     342             :  *      void
     343             :  *      drv_txeof(struct ifqueue *ifq)
     344             :  *      {
     345             :  *              while (COMPLETED_PKTS) {
     346             :  *                      // unmap packets, m_freem() the mbufs.
     347             :  *              }
     348             :  *
     349             :  *              if (ifq_is_oactive(ifq))
     350             :  *                      ifq_restart(ifq);
     351             :  *      }
     352             :  *
     353             :  * == Stop
     354             :  *
     355             :  * Bringing an interface down (ie, IFF_UP was cleared in ifp->if_flags)
     356             :  * should clear IFF_RUNNING in ifp->if_flags, and guarantee the start
     357             :  * routine is not running before freeing any resources it uses:
     358             :  *
     359             :  *      void
     360             :  *      drv_down(struct drv_softc *sc)
     361             :  *      {
     362             :  *              struct ifnet *ifp = &sc->sc_if;
     363             :  *              struct ifqueue *ifq;
     364             :  *              int i;
     365             :  *
     366             :  *              CLR(ifp->if_flags, IFF_RUNNING);
     367             :  *              DISABLE_INTERRUPTS();
     368             :  *
     369             :  *              for (i = 0; i < sc->sc_num_queues; i++) {
     370             :  *                      ifq = ifp->if_ifqs[i];
     371             :  *                      ifq_barrier(ifq);
     372             :  *              }
     373             :  *
     374             :  *              intr_barrier(sc->sc_ih);
     375             :  *
     376             :  *              FREE_RESOURCES();
     377             :  *
     378             :  *              for (i = 0; i < sc->sc_num_queues; i++) {
     379             :  *                      ifq = ifp->if_ifqs[i];
     380             :  *                      ifq_clr_oactive(ifq);
     381             :  *              }
     382             :  *      }
     383             :  *
     384             :  */
     385             : 
     386             : struct ifq_ops {
     387             :         unsigned int             (*ifqop_idx)(unsigned int,
     388             :                                     const struct mbuf *);
     389             :         struct mbuf             *(*ifqop_enq)(struct ifqueue *, struct mbuf *);
     390             :         struct mbuf             *(*ifqop_deq_begin)(struct ifqueue *, void **);
     391             :         void                     (*ifqop_deq_commit)(struct ifqueue *,
     392             :                                     struct mbuf *, void *);
     393             :         void                     (*ifqop_purge)(struct ifqueue *,
     394             :                                     struct mbuf_list *);
     395             :         void                    *(*ifqop_alloc)(unsigned int, void *);
     396             :         void                     (*ifqop_free)(unsigned int, void *);
     397             : };
     398             : 
     399             : /*
     400             :  * Interface send queues.
     401             :  */
     402             : 
     403             : void             ifq_init(struct ifqueue *, struct ifnet *, unsigned int);
     404             : void             ifq_attach(struct ifqueue *, const struct ifq_ops *, void *);
     405             : void             ifq_destroy(struct ifqueue *);
     406             : void             ifq_add_data(struct ifqueue *, struct if_data *);
     407             : int              ifq_enqueue(struct ifqueue *, struct mbuf *);
     408             : struct mbuf     *ifq_deq_begin(struct ifqueue *);
     409             : void             ifq_deq_commit(struct ifqueue *, struct mbuf *);
     410             : void             ifq_deq_rollback(struct ifqueue *, struct mbuf *);
     411             : struct mbuf     *ifq_dequeue(struct ifqueue *);
     412             : void             ifq_mfreem(struct ifqueue *, struct mbuf *);
     413             : void             ifq_mfreeml(struct ifqueue *, struct mbuf_list *);
     414             : unsigned int     ifq_purge(struct ifqueue *);
     415             : void            *ifq_q_enter(struct ifqueue *, const struct ifq_ops *);
     416             : void             ifq_q_leave(struct ifqueue *, void *);
     417             : void             ifq_serialize(struct ifqueue *, struct task *);
     418             : int              ifq_is_serialized(struct ifqueue *);
     419             : void             ifq_barrier(struct ifqueue *);
     420             : 
     421             : #define ifq_len(_ifq)                   ((_ifq)->ifq_len)
     422             : #define ifq_empty(_ifq)                 (ifq_len(_ifq) == 0)
     423             : #define ifq_set_maxlen(_ifq, _l)        ((_ifq)->ifq_maxlen = (_l))
     424             : 
     425             : static inline void
     426           0 : ifq_set_oactive(struct ifqueue *ifq)
     427             : {
     428           0 :         ifq->ifq_oactive = 1;
     429           0 : }
     430             : 
     431             : static inline void
     432           0 : ifq_clr_oactive(struct ifqueue *ifq)
     433             : {
     434           0 :         ifq->ifq_oactive = 0;
     435           0 : }
     436             : 
     437             : static inline unsigned int
     438           0 : ifq_is_oactive(struct ifqueue *ifq)
     439             : {
     440           0 :         return (ifq->ifq_oactive);
     441             : }
     442             : 
     443             : static inline void
     444           0 : ifq_start(struct ifqueue *ifq)
     445             : {
     446           0 :         ifq_serialize(ifq, &ifq->ifq_start);
     447           0 : }
     448             : 
     449             : static inline void
     450           0 : ifq_restart(struct ifqueue *ifq)
     451             : {
     452           0 :         ifq_serialize(ifq, &ifq->ifq_restart);
     453           0 : }
     454             : 
     455             : static inline unsigned int
     456           0 : ifq_idx(struct ifqueue *ifq, unsigned int nifqs, const struct mbuf *m)
     457             : {
     458           0 :         return ((*ifq->ifq_ops->ifqop_idx)(nifqs, m));
     459             : }
     460             : 
     461             : #define IFQ_ASSERT_SERIALIZED(_ifq)     KASSERT(ifq_is_serialized(_ifq))
     462             : 
     463             : extern const struct ifq_ops * const ifq_priq_ops;
     464             : 
     465             : /* ifiq */
     466             : 
     467             : void             ifiq_init(struct ifiqueue *, struct ifnet *, unsigned int);
     468             : void             ifiq_destroy(struct ifiqueue *);
     469             : int              ifiq_input(struct ifiqueue *, struct mbuf_list *,
     470             :                      unsigned int);
     471             : int              ifiq_enqueue(struct ifiqueue *, struct mbuf *);
     472             : void             ifiq_add_data(struct ifiqueue *, struct if_data *);
     473             : void             ifiq_barrier(struct ifiqueue *);
     474             : 
     475             : #define ifiq_len(_ifiq)                 ml_len(&(_ifiq)->ifiq_ml)
     476             : #define ifiq_empty(_ifiq)               ml_empty(&(_ifiq)->ifiq_ml)
     477             : 
     478             : #endif /* _KERNEL */
     479             : 
     480             : #endif /* _NET_IFQ_H_ */

Generated by: LCOV version 1.13