if: Multiple TX queue support step 1 of many; introduce ifaltq subqueue
[dragonfly.git] / sys / net / ifq_var.h
1 /*-
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  * 3. Neither the name of The DragonFly Project nor the names of its
15  *    contributors may be used to endorse or promote products derived
16  *    from this software without specific, prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef _NET_IFQ_VAR_H_
33 #define _NET_IFQ_VAR_H_
34
35 #ifndef _KERNEL
36
37 #error "This file should not be included by userland programs."
38
39 #else
40
41 #ifndef _SYS_SYSTM_H_
42 #include <sys/systm.h>
43 #endif
44 #ifndef _SYS_THREAD2_H_
45 #include <sys/thread2.h>
46 #endif
47 #ifndef _SYS_SERIALIZE_H_
48 #include <sys/serialize.h>
49 #endif
50 #ifndef _SYS_MBUF_H_
51 #include <sys/mbuf.h>
52 #endif
53 #ifndef _NET_IF_VAR_H_
54 #include <net/if_var.h>
55 #endif
56 #ifndef _NET_ALTQ_IF_ALTQ_H_
57 #include <net/altq/if_altq.h>
58 #endif
59
60 #define ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq) \
61         KASSERT(ifsq_get_ifp((ifsq)) == (ifp) && \
62             ifsq_get_index((ifsq)) == ALTQ_SUBQ_INDEX_DEFAULT, \
63             ("not ifp's default subqueue"));
64
65 struct ifaltq;
66
67 /*
68  * Support for "classic" ALTQ interfaces.
69  */
70 int             ifsq_classic_enqueue(struct ifaltq_subque *, struct mbuf *,
71                     struct altq_pktattr *);
72 struct mbuf     *ifsq_classic_dequeue(struct ifaltq_subque *, struct mbuf *,
73                     int);
74 int             ifsq_classic_request(struct ifaltq_subque *, int, void *);
75 void            ifq_set_classic(struct ifaltq *);
76
77 void            ifq_set_maxlen(struct ifaltq *, int);
78 void            ifq_set_methods(struct ifaltq *, ifsq_enqueue_t,
79                     ifsq_dequeue_t, ifsq_request_t);
80
81 void            ifsq_devstart(struct ifaltq_subque *ifsq);
82 void            ifsq_devstart_sched(struct ifaltq_subque *ifsq);
83
84 /*
85  * Dispatch a packet to an interface.
86  */
87 int             ifq_dispatch(struct ifnet *, struct mbuf *,
88                     struct altq_pktattr *);
89
90 #ifdef ALTQ
91
92 static __inline int
93 ifq_is_enabled(struct ifaltq *_ifq)
94 {
95         return(_ifq->altq_flags & ALTQF_ENABLED);
96 }
97
98 static __inline int
99 ifq_is_attached(struct ifaltq *_ifq)
100 {
101         return(_ifq->altq_disc != NULL);
102 }
103
104 #else   /* !ALTQ */
105
106 static __inline int
107 ifq_is_enabled(struct ifaltq *_ifq)
108 {
109         return(0);
110 }
111
112 static __inline int
113 ifq_is_attached(struct ifaltq *_ifq)
114 {
115         return(0);
116 }
117
118 #endif  /* ALTQ */
119
120 static __inline int
121 ifq_is_ready(struct ifaltq *_ifq)
122 {
123         return(_ifq->altq_flags & ALTQF_READY);
124 }
125
126 static __inline void
127 ifq_set_ready(struct ifaltq *_ifq)
128 {
129         _ifq->altq_flags |= ALTQF_READY;
130 }
131
132 /*
133  * ALTQ lock must be held
134  */
135 static __inline int
136 ifsq_enqueue_locked(struct ifaltq_subque *_ifsq, struct mbuf *_m,
137     struct altq_pktattr *_pa)
138 {
139 #ifdef ALTQ
140         if (!ifq_is_enabled(_ifsq->ifsq_altq))
141                 return ifsq_classic_enqueue(_ifsq, _m, _pa);
142         else
143 #endif
144         return _ifsq->ifsq_enqueue(_ifsq, _m, _pa);
145 }
146
147 static __inline int
148 ifsq_enqueue(struct ifaltq_subque *_ifsq, struct mbuf *_m,
149     struct altq_pktattr *_pa)
150 {
151         int _error;
152
153         ALTQ_SQ_LOCK(_ifsq);
154         _error = ifsq_enqueue_locked(_ifsq, _m, _pa);
155         ALTQ_SQ_UNLOCK(_ifsq);
156         return _error;
157 }
158
159 static __inline struct mbuf *
160 ifsq_dequeue(struct ifaltq_subque *_ifsq, struct mbuf *_mpolled)
161 {
162         struct mbuf *_m;
163
164         ALTQ_SQ_LOCK(_ifsq);
165         if (_ifsq->ifsq_prepended != NULL) {
166                 _m = _ifsq->ifsq_prepended;
167                 _ifsq->ifsq_prepended = NULL;
168                 KKASSERT(_ifsq->ifq_len > 0);
169                 _ifsq->ifq_len--;
170                 ALTQ_SQ_UNLOCK(_ifsq);
171                 return _m;
172         }
173
174 #ifdef ALTQ
175         if (_ifsq->ifsq_altq->altq_tbr != NULL)
176                 _m = tbr_dequeue(_ifsq, _mpolled, ALTDQ_REMOVE);
177         else if (!ifq_is_enabled(_ifsq->ifsq_altq))
178                 _m = ifsq_classic_dequeue(_ifsq, _mpolled, ALTDQ_REMOVE);
179         else
180 #endif
181         _m = _ifsq->ifsq_dequeue(_ifsq, _mpolled, ALTDQ_REMOVE);
182         ALTQ_SQ_UNLOCK(_ifsq);
183         return _m;
184 }
185
186 /*
187  * ALTQ lock must be held
188  */
189 static __inline struct mbuf *
190 ifsq_poll_locked(struct ifaltq_subque *_ifsq)
191 {
192         if (_ifsq->ifsq_prepended != NULL)
193                 return _ifsq->ifsq_prepended;
194
195 #ifdef ALTQ
196         if (_ifsq->ifsq_altq->altq_tbr != NULL)
197                 return tbr_dequeue(_ifsq, NULL, ALTDQ_POLL);
198         else if (!ifq_is_enabled(_ifsq->ifsq_altq))
199                 return ifsq_classic_dequeue(_ifsq, NULL, ALTDQ_POLL);
200         else
201 #endif
202         return _ifsq->ifsq_dequeue(_ifsq, NULL, ALTDQ_POLL);
203 }
204
205 static __inline struct mbuf *
206 ifsq_poll(struct ifaltq_subque *_ifsq)
207 {
208         struct mbuf *_m;
209
210         ALTQ_SQ_LOCK(_ifsq);
211         _m = ifsq_poll_locked(_ifsq);
212         ALTQ_SQ_UNLOCK(_ifsq);
213         return _m;
214 }
215
216 /*
217  * ALTQ lock must be held
218  */
219 static __inline void
220 ifsq_purge_locked(struct ifaltq_subque *_ifsq)
221 {
222         if (_ifsq->ifsq_prepended != NULL) {
223                 m_freem(_ifsq->ifsq_prepended);
224                 _ifsq->ifsq_prepended = NULL;
225                 KKASSERT(_ifsq->ifq_len > 0);
226                 _ifsq->ifq_len--;
227         }
228
229 #ifdef ALTQ
230         if (!ifq_is_enabled(_ifsq->ifsq_altq))
231                 ifsq_classic_request(_ifsq, ALTRQ_PURGE, NULL);
232         else
233 #endif
234         _ifsq->ifsq_request(_ifsq, ALTRQ_PURGE, NULL);
235 }
236
237 static __inline void
238 ifsq_purge(struct ifaltq_subque *_ifsq)
239 {
240         ALTQ_SQ_LOCK(_ifsq);
241         ifsq_purge_locked(_ifsq);
242         ALTQ_SQ_UNLOCK(_ifsq);
243 }
244
245 static __inline void
246 ifq_lock_all(struct ifaltq *_ifq)
247 {
248         int _q;
249
250         for (_q = 0; _q < _ifq->altq_subq_cnt; ++_q)
251                 ALTQ_SQ_LOCK(&_ifq->altq_subq[_q]);
252 }
253
254 static __inline void
255 ifq_unlock_all(struct ifaltq *_ifq)
256 {
257         int _q;
258
259         for (_q = _ifq->altq_subq_cnt - 1; _q >= 0; --_q)
260                 ALTQ_SQ_UNLOCK(&_ifq->altq_subq[_q]);
261 }
262
263 /*
264  * ALTQ lock must be held
265  */
266 static __inline void
267 ifq_purge_all_locked(struct ifaltq *_ifq)
268 {
269         int _q;
270
271         for (_q = 0; _q < _ifq->altq_subq_cnt; ++_q)
272                 ifsq_purge_locked(&_ifq->altq_subq[_q]);
273 }
274
275 static __inline void
276 ifq_purge_all(struct ifaltq *_ifq)
277 {
278         ifq_lock_all(_ifq);
279         ifq_purge_all_locked(_ifq);
280         ifq_unlock_all(_ifq);
281 }
282
283 static __inline void
284 ifq_classify(struct ifaltq *_ifq, struct mbuf *_m, uint8_t _af,
285     struct altq_pktattr *_pa)
286 {
287 #ifdef ALTQ
288         if (ifq_is_enabled(_ifq)) {
289                 _pa->pattr_af = _af;
290                 _pa->pattr_hdr = mtod(_m, caddr_t);
291                 if (ifq_is_enabled(_ifq) &&
292                     (_ifq->altq_flags & ALTQF_CLASSIFY)) {
293                         /* XXX default subqueue */
294                         struct ifaltq_subque *_ifsq =
295                             &_ifq->altq_subq[ALTQ_SUBQ_INDEX_DEFAULT];
296
297                         ALTQ_SQ_LOCK(_ifsq);
298                         if (ifq_is_enabled(_ifq) &&
299                             (_ifq->altq_flags & ALTQF_CLASSIFY))
300                                 _ifq->altq_classify(_ifq, _m, _pa);
301                         ALTQ_SQ_UNLOCK(_ifsq);
302                 }
303         }
304 #endif
305 }
306
307 static __inline void
308 ifsq_prepend(struct ifaltq_subque *_ifsq, struct mbuf *_m)
309 {
310         ALTQ_SQ_LOCK(_ifsq);
311         KASSERT(_ifsq->ifsq_prepended == NULL, ("pending prepended mbuf"));
312         _ifsq->ifsq_prepended = _m;
313         _ifsq->ifq_len++;
314         ALTQ_SQ_UNLOCK(_ifsq);
315 }
316
317 /*
318  * Interface TX serializer must be held
319  */
320 static __inline void
321 ifsq_set_oactive(struct ifaltq_subque *_ifsq)
322 {
323         _ifsq->ifsq_hw_oactive = 1;
324 }
325
326 /*
327  * Interface TX serializer must be held
328  */
329 static __inline void
330 ifsq_clr_oactive(struct ifaltq_subque *_ifsq)
331 {
332         _ifsq->ifsq_hw_oactive = 0;
333 }
334
335 /*
336  * Interface TX serializer must be held
337  */
338 static __inline int
339 ifsq_is_oactive(const struct ifaltq_subque *_ifsq)
340 {
341         return _ifsq->ifsq_hw_oactive;
342 }
343
344 /*
345  * Hand a packet to an interface.
346  *
347  * Interface TX serializer must be held.  If the interface TX
348  * serializer is not held yet, ifq_dispatch() should be used
349  * to get better performance.
350  */
351 static __inline int
352 ifq_handoff(struct ifnet *_ifp, struct mbuf *_m, struct altq_pktattr *_pa)
353 {
354         struct ifaltq_subque *_ifsq;
355         int _error;
356         int _qid = ALTQ_SUBQ_INDEX_DEFAULT; /* XXX default subqueue */
357
358         _ifsq = &_ifp->if_snd.altq_subq[_qid];
359
360         ASSERT_IFNET_SERIALIZED_TX(_ifp);
361         _error = ifsq_enqueue(_ifsq, _m, _pa);
362         if (_error == 0) {
363                 _ifp->if_obytes += _m->m_pkthdr.len;
364                 if (_m->m_flags & M_MCAST)
365                         _ifp->if_omcasts++;
366                 if (!ifsq_is_oactive(_ifsq))
367                         (*_ifp->if_start)(_ifp, _ifsq);
368         }
369         return(_error);
370 }
371
372 static __inline int
373 ifsq_is_empty(const struct ifaltq_subque *_ifsq)
374 {
375         return(_ifsq->ifq_len == 0);
376 }
377
378 /*
379  * ALTQ lock must be held
380  */
381 static __inline int
382 ifsq_data_ready(struct ifaltq_subque *_ifsq)
383 {
384 #ifdef ALTQ
385         if (_ifsq->ifsq_altq->altq_tbr != NULL)
386                 return (ifsq_poll_locked(_ifsq) != NULL);
387         else
388 #endif
389         return !ifsq_is_empty(_ifsq);
390 }
391
392 /*
393  * ALTQ lock must be held
394  */
395 static __inline int
396 ifsq_is_started(const struct ifaltq_subque *_ifsq)
397 {
398         return _ifsq->ifsq_started;
399 }
400
401 /*
402  * ALTQ lock must be held
403  */
404 static __inline void
405 ifsq_set_started(struct ifaltq_subque *_ifsq)
406 {
407         _ifsq->ifsq_started = 1;
408 }
409
410 /*
411  * ALTQ lock must be held
412  */
413 static __inline void
414 ifsq_clr_started(struct ifaltq_subque *_ifsq)
415 {
416         _ifsq->ifsq_started = 0;
417 }
418
419 static __inline struct ifsubq_stage *
420 ifsq_get_stage(struct ifaltq_subque *_ifsq, int _cpuid)
421 {
422         return &_ifsq->ifsq_stage[_cpuid];
423 }
424
425 static __inline int
426 ifsq_get_cpuid(const struct ifaltq_subque *_ifsq)
427 {
428         return _ifsq->ifsq_cpuid;
429 }
430
431 static __inline void
432 ifsq_set_cpuid(struct ifaltq_subque *_ifsq, int _cpuid)
433 {
434         KASSERT(_cpuid >= 0 && _cpuid < ncpus,
435             ("invalid ifsq_cpuid %d", _cpuid));
436         _ifsq->ifsq_cpuid = _cpuid;
437 }
438
439 static __inline struct lwkt_msg *
440 ifsq_get_ifstart_lmsg(struct ifaltq_subque *_ifsq, int _cpuid)
441 {
442         return &_ifsq->ifsq_ifstart_nmsg[_cpuid].lmsg;
443 }
444
445 static __inline int
446 ifsq_get_index(const struct ifaltq_subque *_ifsq)
447 {
448         return _ifsq->ifsq_index;
449 }
450
451 static __inline void
452 ifsq_set_priv(struct ifaltq_subque *_ifsq, void *_priv)
453 {
454         _ifsq->ifsq_hw_priv = _priv;
455 }
456
457 static __inline void *
458 ifsq_get_priv(const struct ifaltq_subque *_ifsq)
459 {
460         return _ifsq->ifsq_hw_priv;
461 }
462
463 static __inline struct ifnet *
464 ifsq_get_ifp(const struct ifaltq_subque *_ifsq)
465 {
466         return _ifsq->ifsq_ifp;
467 }
468
469 static __inline struct ifaltq_subque *
470 ifq_get_subq_default(const struct ifaltq *_ifq)
471 {
472         return &_ifq->altq_subq[ALTQ_SUBQ_INDEX_DEFAULT];
473 }
474
475 static __inline struct ifaltq_subque *
476 ifq_get_subq(const struct ifaltq *_ifq, int _idx)
477 {
478         KASSERT(_idx >= 0 && _idx < _ifq->altq_subq_cnt,
479             ("invalid qid %d", _idx));
480         return &_ifq->altq_subq[_idx];
481 }
482
483 /* COMPAT */
484 static __inline int
485 ifq_is_oactive(const struct ifaltq *_ifq)
486 {
487         return ifsq_is_oactive(ifq_get_subq_default(_ifq));
488 }
489
490 /* COMPAT */
491 static __inline void
492 ifq_set_oactive(struct ifaltq *_ifq)
493 {
494         ifsq_set_oactive(ifq_get_subq_default(_ifq));
495 }
496
497 /* COMPAT */
498 static __inline void
499 ifq_clr_oactive(struct ifaltq *_ifq)
500 {
501         ifsq_clr_oactive(ifq_get_subq_default(_ifq));
502 }
503
504 /* COMPAT */
505 static __inline int
506 ifq_is_empty(struct ifaltq *_ifq)
507 {
508         return ifsq_is_empty(ifq_get_subq_default(_ifq));
509 }
510
511 /* COMPAT */
512 static __inline void
513 ifq_purge(struct ifaltq *_ifq)
514 {
515         ifsq_purge(ifq_get_subq_default(_ifq));
516 }
517
518 /* COMPAT */
519 static __inline struct mbuf *
520 ifq_dequeue(struct ifaltq *_ifq, struct mbuf *_mpolled)
521 {
522         return ifsq_dequeue(ifq_get_subq_default(_ifq), _mpolled);
523 }
524
525 /* COMPAT */
526 static __inline void
527 ifq_prepend(struct ifaltq *_ifq, struct mbuf *_m)
528 {
529         ifsq_prepend(ifq_get_subq_default(_ifq), _m);
530 }
531
532 /* COMPAT */
533 static __inline void
534 ifq_set_cpuid(struct ifaltq *_ifq, int _cpuid)
535 {
536         KASSERT(_ifq->altq_subq_cnt == 1,
537             ("invalid subqueue count %d", _ifq->altq_subq_cnt));
538         ifsq_set_cpuid(ifq_get_subq_default(_ifq), _cpuid);
539 }
540
541 #endif  /* _KERNEL */
542 #endif  /* _NET_IFQ_VAR_H_ */