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_ */
|