xref: /openbsd-src/sys/net/ifq.h (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: ifq.h,v 1.5 2016/01/20 17:27:16 mikeb 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 
29 	/* mbuf handling */
30 	struct mutex		 ifq_mtx;
31 	uint64_t		 ifq_drops;
32 	const struct ifq_ops	*ifq_ops;
33 	void			*ifq_q;
34 	unsigned int		 ifq_len;
35 	unsigned int		 ifq_oactive;
36 
37 	/* work serialisation */
38 	struct mutex		 ifq_task_mtx;
39 	struct task_list	 ifq_task_list;
40 	void			*ifq_serializer;
41 
42 	/* work to be serialised */
43 	struct task		 ifq_start;
44 	struct task		 ifq_restart;
45 
46 	unsigned int		 ifq_maxlen;
47 };
48 
49 #ifdef _KERNEL
50 
51 #define IFQ_MAXLEN		256
52 
53 /*
54  *
55  * Interface Send Queues
56  *
57  * struct ifqueue sits between the network stack and a drivers
58  * transmission of packets. The high level view is that when the stack
59  * has finished generating a packet it hands it to a driver for
60  * transmission. It does this by queueing the packet on an ifqueue and
61  * notifying the driver to start transmission of the queued packets.
62  *
63  * struct ifqueue also provides the point where conditioning of
64  * traffic (ie, priq and hfsc) is implemented, and provides some
65  * infrastructure to assist in the implementation of network drivers.
66  *
67  * = ifq API
68  *
69  * The ifq API provides functions for three distinct consumers:
70  *
71  * 1. The network stack
72  * 2. Traffic QoS/conditioning implementations
73  * 3. Network drivers
74  *
75  * == Network Stack API
76  *
77  * The network stack is responsible for initialising and destroying
78  * the ifqueue structure, changing the traffic conditioner on an
79  * interface queue, enqueuing packets for transmission, and notifying
80  * the driver to start transmission.
81  *
82  * === ifq_init()
83  *
84  * During if_attach(), the network stack calls ifq_init to initialise
85  * the ifqueue structure. By default it configures the priq traffic
86  * conditioner.
87  *
88  * === ifq_destroy()
89  *
90  * The network stack calls ifq_destroy() during if_detach to tear down
91  * the ifqueue structure. It frees the traffic conditioner state, and
92  * frees any mbufs that were left queued.
93  *
94  * === ifq_attach()
95  *
96  * ifq_attach() is used to replace the current traffic conditioner on
97  * the ifqueue. All the pending mbufs are removed from the previous
98  * conditioner and requeued on the new.
99  *
100  * === ifq_enqueue() and ifq_enqueue_try()
101  *
102  * ifq_enqueue() and ifq_enqueue_try() attempt to fit an mbuf onto the
103  * ifqueue. If the current traffic conditioner rejects the packet it
104  * wont be queued and will be counted as a drop. ifq_enqueue() will
105  * free the mbuf on the callers behalf if the packet is rejected.
106  * ifq_enqueue_try() does not free the mbuf, allowing the caller to
107  * reuse it.
108  *
109  * === ifq_start()
110  *
111  * Once a packet has been successfully queued with ifq_enqueue() or
112  * ifq_enqueue_try(), the network card is notified with a call to
113  * if_start(). If an interface is marked with IFXF_MPSAFE in its
114  * if_xflags field, if_start() calls ifq_start() to dispatch the
115  * interfaces start routine. Calls to ifq_start() run in the ifqueue
116  * serialisation context, guaranteeing that only one instance of
117  * ifp->if_start() will be running in the system at any point in time.
118  *
119  *
120  * == Traffic conditioners API
121  *
122  * The majority of interaction between struct ifqueue and a traffic
123  * conditioner occurs via the callbacks a traffic conditioner provides
124  * in an instance of struct ifq_ops.
125  *
126  * XXX document ifqop_*
127  *
128  * The ifqueue API implements the locking on behalf of the conditioning
129  * implementations so conditioners only have to reject or keep mbufs.
130  * If something needs to inspect a conditioners internals, the queue lock
131  * needs to be taken to allow for a consistent or safe view. The queue
132  * lock may be taken and released with ifq_q_enter() and ifq_q_leave().
133  *
134  * === ifq_q_enter()
135  *
136  * Code wishing to access a conditioners internals may take the queue
137  * lock with ifq_q_enter(). The caller must pass a reference to the
138  * conditioners ifq_ops structure so the infrastructure can ensure the
139  * caller is able to understand the internals. ifq_q_enter() returns
140  * a pointer to the conditions internal structures, or NULL if the
141  * ifq_ops did not match the current conditioner.
142  *
143  * === ifq_q_leave()
144  *
145  * The queue lock acquired with ifq_q_enter() is released with
146  * ifq_q_leave().
147  *
148  *
149  * == Network Driver API
150  *
151  * The API used by network drivers is mostly documented in the
152  * ifq_dequeue(9) manpage except for ifq_serialize(),
153  * ifq_is_serialized(), and IFQ_ASSERT_SERIALIZED().
154  *
155  * === ifq_serialize()
156  *
157  * A driver may run arbitrary work in the ifqueue serialiser context
158  * via ifq_serialize(). The work to be done is represented by a task
159  * that has been prepared with task_set.
160  *
161  * The work will be run in series with any other work dispatched by
162  * ifq_start(), ifq_restart(), or other ifq_serialize() calls.
163  *
164  * Because the work may be run on another CPU, the lifetime of the
165  * task and the work it represents can extend beyond the end of the
166  * call to ifq_serialize() that dispatched it.
167  *
168  * === ifq_is_serialized()
169  *
170  * This function returns whether the caller is currently within the
171  * ifqueue serializer context.
172  *
173  * === IFQ_ASSERT_SERIALIZED()
174  *
175  * This macro will assert that the caller is currently within the
176  * specified ifqueue serialiser context.
177  *
178  *
179  * = ifqueue work serialisation
180  *
181  * ifqueues provide a mechanism to dispatch work to be run in a single
182  * context. Work in this mechanism is represtented by task structures.
183  *
184  * The tasks are run in a context similar to a taskq serviced by a
185  * single kernel thread, except the work is run immediately by the
186  * first CPU that dispatches work. If a second CPU attempts to dispatch
187  * additional tasks while the first is still running, it will be queued
188  * to be run by the first CPU. The second CPU will return immediately.
189  *
190  * = MP Safe Network Drivers
191  *
192  * An MP safe network driver is one in which its start routine can be
193  * called by the network stack without holding the big kernel lock.
194  *
195  * == Attach
196  *
197  * A driver advertises it's ability to run its start routine by setting
198  * the IFXF_MPSAFE flag in ifp->if_xflags before calling if_attach():
199  *
200  * 	ifp->if_xflags = IFXF_MPSAFE;
201  * 	ifp->if_start = drv_start;
202  * 	if_attach(ifp);
203  *
204  * The network stack will then wrap its calls to ifp->if_start with
205  * ifq_start() to guarantee there is only one instance of that function
206  * running in the system and to serialise it with other work the driver
207  * may provide.
208  *
209  * == Initialise
210  *
211  * When the stack requests an interface be brought up (ie, drv_ioctl()
212  * is called to handle SIOCSIFFLAGS with IFF_UP set in ifp->if_flags)
213  * drivers should set IFF_RUNNING in ifp->if_flags and call
214  * ifq_clr_oactive().
215  *
216  * == if_start
217  *
218  * ifq_start() checks that IFF_RUNNING is set in ifp->if_flags, that
219  * ifq_is_oactive() does not return true, and that there are pending
220  * packets to transmit via a call to ifq_len(). Therefore, drivers are
221  * no longer responsible for doing this themselves.
222  *
223  * If a driver should not transmit packets while its link is down, use
224  * ifq_purge() to flush pending packets from the transmit queue.
225  *
226  * Drivers for hardware should use the following pattern to transmit
227  * packets:
228  *
229  * 	void
230  * 	drv_start(struct ifnet *ifp)
231  * 	{
232  * 		struct drv_softc *sc = ifp->if_softc;
233  * 		struct mbuf *m;
234  * 		int kick = 0;
235  *
236  * 		if (NO_LINK) {
237  * 			ifq_purge(&ifp->if_snd);
238  * 			return;
239  * 		}
240  *
241  * 		for (;;) {
242  * 			if (NO_SPACE) {
243  * 				ifq_set_oactive(&ifp->if_snd);
244  * 				break;
245  * 			}
246  *
247  * 			m = ifq_dequeue(&ifp->if_snd);
248  * 			if (m == NULL)
249  * 				break;
250  *
251  * 			if (drv_encap(sc, m) != 0) { // map and fill ring
252  * 				m_freem(m);
253  * 				continue;
254  * 			}
255  *
256  * 			bpf_mtap();
257  * 		}
258  *
259  *  		drv_kick(sc); // notify hw of new descriptors on the ring
260  * 	 }
261  *
262  * == Transmission completion
263  *
264  * The following pattern should be used for transmit queue interrupt
265  * processing:
266  *
267  * 	void
268  * 	drv_txeof(struct drv_softc *sc)
269  * 	{
270  * 		struct ifnet *ifp = &sc->sc_if;
271  *
272  * 		while (COMPLETED_PKTS) {
273  * 			// unmap packets, m_freem() the mbufs.
274  * 		}
275  *
276  * 		if (ifq_is_oactive(&ifp->if_snd))
277  * 			ifq_restart(&ifp->if_snd);
278  * 	}
279  *
280  * == Stop
281  *
282  * Bringing an interface down (ie, IFF_UP was cleared in ifp->if_flags)
283  * should clear IFF_RUNNING in ifp->if_flags, and guarantee the start
284  * routine is not running before freeing any resources it uses:
285  *
286  * 	void
287  * 	drv_down(struct drv_softc *sc)
288  * 	{
289  * 		struct ifnet *ifp = &sc->sc_if;
290  *
291  * 		CLR(ifp->if_flags, IFF_RUNNING);
292  * 		DISABLE_INTERRUPTS();
293  *
294  * 		ifq_barrier(&ifp->if_snd);
295  * 		intr_barrier(sc->sc_ih);
296  *
297  * 		FREE_RESOURCES();
298  *
299  * 		ifq_clr_oactive();
300  * 	}
301  *
302  */
303 
304 struct ifq_ops {
305 	void			*(*ifqop_alloc)(void *);
306 	void			 (*ifqop_free)(void *);
307 	int			 (*ifqop_enq)(struct ifqueue *, struct mbuf *);
308 	struct mbuf 		*(*ifqop_deq_begin)(struct ifqueue *, void **);
309 	void			 (*ifqop_deq_commit)(struct ifqueue *,
310 				    struct mbuf *, void *);
311 	void	 		 (*ifqop_purge)(struct ifqueue *,
312 				    struct mbuf_list *);
313 };
314 
315 /*
316  * Interface send queues.
317  */
318 
319 void		 ifq_init(struct ifqueue *, struct ifnet *);
320 void		 ifq_attach(struct ifqueue *, const struct ifq_ops *, void *);
321 void		 ifq_destroy(struct ifqueue *);
322 int		 ifq_enqueue_try(struct ifqueue *, struct mbuf *);
323 int		 ifq_enqueue(struct ifqueue *, struct mbuf *);
324 struct mbuf	*ifq_deq_begin(struct ifqueue *);
325 void		 ifq_deq_commit(struct ifqueue *, struct mbuf *);
326 void		 ifq_deq_rollback(struct ifqueue *, struct mbuf *);
327 struct mbuf	*ifq_dequeue(struct ifqueue *);
328 unsigned int	 ifq_purge(struct ifqueue *);
329 void		*ifq_q_enter(struct ifqueue *, const struct ifq_ops *);
330 void		 ifq_q_leave(struct ifqueue *, void *);
331 void		 ifq_serialize(struct ifqueue *, struct task *);
332 int		 ifq_is_serialized(struct ifqueue *);
333 void		 ifq_barrier(struct ifqueue *);
334 
335 #define	ifq_len(_ifq)			((_ifq)->ifq_len)
336 #define	ifq_empty(_ifq)			(ifq_len(_ifq) == 0)
337 #define	ifq_set_maxlen(_ifq, _l)	((_ifq)->ifq_maxlen = (_l))
338 
339 static inline void
340 ifq_set_oactive(struct ifqueue *ifq)
341 {
342 	ifq->ifq_oactive = 1;
343 }
344 
345 static inline void
346 ifq_clr_oactive(struct ifqueue *ifq)
347 {
348 	ifq->ifq_oactive = 0;
349 }
350 
351 static inline unsigned int
352 ifq_is_oactive(struct ifqueue *ifq)
353 {
354 	return (ifq->ifq_oactive);
355 }
356 
357 static inline void
358 ifq_start(struct ifqueue *ifq)
359 {
360 	ifq_serialize(ifq, &ifq->ifq_start);
361 }
362 
363 static inline void
364 ifq_restart(struct ifqueue *ifq)
365 {
366 	ifq_serialize(ifq, &ifq->ifq_restart);
367 }
368 
369 #define IFQ_ASSERT_SERIALIZED(_ifq)	KASSERT(ifq_is_serialized(_ifq))
370 
371 extern const struct ifq_ops * const ifq_priq_ops;
372 
373 #endif /* _KERNEL */
374 
375 #endif /* _NET_IFQ_H_ */
376