xref: /netbsd/share/man/man9/altq.9 (revision bf9ec67e)
1.\"	$NetBSD: altq.9,v 1.8 2002/05/28 11:41:45 wiz Exp $
2.\"	$OpenBSD: altq.9,v 1.4 2001/07/12 12:41:42 itojun Exp $
3.\"
4.\" Copyright (C) 2001
5.\" Sony Computer Science Laboratories Inc.  All rights reserved.
6.\"
7.\" Redistribution and use in source and binary forms, with or without
8.\" modification, are permitted provided that the following conditions
9.\" are met:
10.\" 1. Redistributions of source code must retain the above copyright
11.\"    notice, this list of conditions and the following disclaimer.
12.\" 2. Redistributions in binary form must reproduce the above copyright
13.\"    notice, this list of conditions and the following disclaimer in the
14.\"    documentation and/or other materials provided with the distribution.
15.\"
16.\" THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19.\" ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26.\" SUCH DAMAGE.
27.\"
28.Dd July 10, 2001
29.Dt ALTQ 9
30.Os
31.\"
32.Sh NAME
33.Nm ALTQ
34.Nd kernel interfaces for manipulating output queues on network interfaces
35.Sh SYNOPSIS
36.Fd #include \*[Lt]sys/types.h\*[Gt]
37.Fd #include \*[Lt]sys/socket.h\*[Gt]
38.Fd #include \*[Lt]net/if.h\*[Gt]
39.Ft void \"macro
40.Fn IFQ_ENQUEUE "struct ifaltq *ifq" "struct mbuf *m" "int error"
41.Ft void \"macro
42.Fn IFQ_DEQUEUE "struct ifaltq *ifq" "struct mbuf *m"
43.Ft void \"macro
44.Fn IFQ_POLL "struct ifaltq *ifq" "struct mbuf *m"
45.Ft void \"macro
46.Fn IFQ_PURGE "struct ifaltq *ifq"
47.Ft void \"macro
48.Fn IFQ_CLASSIFY "struct ifaltq *ifq" "struct mbuf *m" "int af" "struct altq_pktattr *pktattr"
49.Ft void \"macro
50.Fn IFQ_IS_EMPTY "struct ifaltq *ifq"
51.Ft void \"macro
52.Fn IFQ_SET_MAXLEN "struct ifaltq *ifq" "int len"
53.Ft void \"macro
54.Fn IFQ_INC_LEN "struct ifaltq *ifq"
55.Ft void \"macro
56.Fn IFQ_DEC_LEN "struct ifaltq *ifq"
57.Ft void \"macro
58.Fn IFQ_INC_DROPS "struct ifaltq *ifq"
59.Ft void \"macro
60.Fn IFQ_SET_READY "struct ifaltq *ifq"
61.Sh DESCRIPTION
62The
63.Nm
64system is a framework to manage queueing disciplines on network
65interfaces.
66.Nm
67introduces new macros to manipulate output queues.
68The output queue macros are used to abstract queue operations and not to
69touch the internal fields of the output queue structure.
70The macros are independent from the
71.Nm
72implementation, and compatible with the traditional
73.Dv ifqueue
74macros for ease of transition.
75.Pp
76.Fn IFQ_ENQUEUE
77enqueues a packet
78.Fa m
79to the queue
80.Fa ifq .
81The underlying queueing discipline may discard the packet.
82.Fa error
83is set to 0 on success, or
84.Dv ENOBUFS
85if the packet is discarded.
86.Fa m
87will be freed by the device driver on success or by the queueing discipline on
88failure so that the caller should not touch
89.Fa m
90after calling
91.Fn IFQ_ENQUEUE .
92.Pp
93.Fn IFQ_DEQUEUE
94dequeues a packet from the queue.
95The dequeued packet is returned in
96.Fa m ,
97or
98.Fa m
99is set to
100.Dv NULL
101if no packet is dequeued.
102The caller must always check
103.Fa m
104since a non-empty queue could return
105.Dv NULL
106under rate-limiting.
107.Pp
108.Fn IFQ_POLL
109returns the next packet without removing it from the queue.
110It is guaranteed by the underlying queueing discipline that
111.Fn IFQ_DEQUEUE
112immediately after
113.Fn IFQ_POLL
114returns the same packet.
115.Pp
116.Fn IFQ_PURGE
117discards all the packets in the queue.
118The purge operation is needed since a non-work conserving queue cannot be
119emptied by a dequeue loop.
120.Pp
121.Fn IFQ_CLASSIFY
122classifies a packet to a scheduling class, and returns the result in
123.Fa pktattr .
124.Pp
125.Fn IFQ_IS_EMPTY
126can be used to check if the queue is empty.
127Note that
128.Fn IFQ_DEQUEUE
129could still return
130.Dv NULL
131if the queueing discipline is non-work conserving.
132.Pp
133.Fn IFQ_SET_MAXLEN
134sets the queue length limit to the default FIFO queue.
135.Pp
136.Fn IFQ_INC_LEN
137and
138.Fn IFQ_DEC_LEN
139increment or decrement the current queue length in packets.
140.Pp
141.Fn IFQ_INC_DROPS
142increments the drop counter and is equal to
143.Fn IF_DROP .
144It is defined for naming consistency.
145.Pp
146.Fn IFQ_SET_READY
147sets a flag to indicate this driver is converted to use the new macros.
148.Nm
149can be enabled only on interfaces with this flag.
150.Sh COMPATIBILITY
151.Ss ifaltq structure
152In order to keep compatibility with the existing code, the new
153output queue structure
154.Dv ifaltq
155has the same fields.
156The traditional
157.Fn IF_XXX
158macros and the code directly referencing the fields within
159.Dv if_snd
160still work with
161.Dv ifaltq .
162(Once we finish conversions of all the drivers, we no longer need
163these fields.)
164.Bd -literal
165            ##old-style##                           ##new-style##
166                                       |
167 struct ifqueue {                      | struct ifaltq {
168    struct mbuf *ifq_head;             |    struct mbuf *ifq_head;
169    struct mbuf *ifq_tail;             |    struct mbuf *ifq_tail;
170    int          ifq_len;              |    int          ifq_len;
171    int          ifq_maxlen;           |    int          ifq_maxlen;
172    int          ifq_drops;            |    int          ifq_drops;
173 };                                    |    /* altq related fields */
174                                       |    ......
175                                       | };
176                                       |
177.Ed
178The new structure replaces
179.Dv struct ifqueue
180in
181.Dv struct ifnet .
182.Bd -literal
183            ##old-style##                           ##new-style##
184                                       |
185 struct ifnet {                        | struct ifnet {
186     ....                              |     ....
187                                       |
188     struct ifqueue if_snd;            |     struct ifaltq if_snd;
189                                       |
190     ....                              |     ....
191 };                                    | };
192                                       |
193.Ed
194The (simplified) new
195.Fn IFQ_XXX
196macros looks like:
197.Bd -literal
198	#ifdef ALTQ
199	#define IFQ_DEQUEUE(ifq, m)			\e
200		if (ALTQ_IS_ENABLED((ifq))		\e
201			ALTQ_DEQUEUE((ifq), (m));	\e
202		else					\e
203			IF_DEQUEUE((ifq), (m));
204	#else
205	#define IFQ_DEQUEUE(ifq, m)	IF_DEQUEUE((ifq), (m));
206	#endif
207.Ed
208.Ss Enqueue operation
209The semantics of the enqueue operation is changed.
210In the new style,
211enqueue and packet drop are combined since they cannot be easily
212separated in many queueing disciplines.
213The new enqueue operation corresponds to the following macro that is
214written with the old macros.
215.Bd -literal
216#define	IFQ_ENQUEUE(ifq, m, error)                      \e
217do {                                                    \e
218        if (IF_QFULL((ifq))) {                          \e
219                m_freem((m));                           \e
220                (error) = ENOBUFS;                      \e
221                IF_DROP(ifq);                           \e
222         } else {                                       \e
223                IF_ENQUEUE((ifq), (m));                 \e
224                (error) = 0;                            \e
225         }                                              \e
226} while (0)
227.Ed
228.Pp
229.Fn IFQ_ENQUEUE
230does the followings:
231.Bl -hyphen -compact
232.It
233queue a packet
234.It
235drop (and free) a packet if the enqueue operation fails
236.El
237If the enqueue operation fails,
238.Fa error
239is set to
240.Dv ENOBUFS .
241.Fa mbuf
242is freed by the queueing discipline.
243The caller should not touch mbuf after calling
244.Fn IFQ_ENQUEUE
245so that the caller may need to copy
246.Fa m_pkthdr.len
247or
248.Fa m_flags
249field beforehand for statistics.
250The caller should not use
251.Fn senderr
252since mbuf was already freed.
253.Pp
254The new style
255.Fn if_output
256looks as follows:
257.Bd -literal
258            ##old-style##                           ##new-style##
259                                       |
260 int                                   | int
261 ether_output(ifp, m0, dst, rt0)       | ether_output(ifp, m0, dst, rt0)
262 {                                     | {
263     ......                            |     ......
264                                       |
265                                       |     mflags = m-\*[Gt]m_flags;
266                                       |     len = m-\*[Gt]m_pkthdr.len;
267     s = splimp();                     |     s = splimp();
268     if (IF_QFULL(\*[Am]ifp-\*[Gt]if_snd)) {     |     IFQ_ENQUEUE(\*[Am]ifp-\*[Gt]if_snd, m,
269                                       |                 error);
270         IF_DROP(\*[Am]ifp-\*[Gt]if_snd);        |     if (error != 0) {
271         splx(s);                      |         splx(s);
272         senderr(ENOBUFS);             |         return (error);
273     }                                 |     }
274     IF_ENQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);      |
275     ifp-\*[Gt]if_obytes +=                 |     ifp-\*[Gt]if_obytes += len;
276                    m-\*[Gt]m_pkthdr.len;   |
277     if (m-\*[Gt]m_flags \*[Am] M_MCAST)         |     if (mflags \*[Am] M_MCAST)
278         ifp-\*[Gt]if_omcasts++;            |         ifp-\*[Gt]if_omcasts++;
279                                       |
280     if ((ifp-\*[Gt]if_flags \*[Am] IFF_OACTIVE) |     if ((ifp-\*[Gt]if_flags \*[Am] IFF_OACTIVE)
281         == 0)                         |         == 0)
282         (*ifp-\*[Gt]if_start)(ifp);        |         (*ifp-\*[Gt]if_start)(ifp);
283     splx(s);                          |     splx(s);
284     return (error);                   |     return (error);
285                                       |
286 bad:                                  | bad:
287     if (m)                            |     if (m)
288         m_freem(m);                   |         m_freem(m);
289     return (error);                   |     return (error);
290 }                                     | }
291                                       |
292.Ed
293.Ss Classifier
294The classifier mechanism is currently implemented in
295.Fn if_output .
296.Dv struct altq_pktattr
297is used to store the classifier result, and it is passed to the enqueue
298function.
299(We will change the method to tag the classifier result to mbuf in the future.)
300.Bd -literal
301int
302ether_output(ifp, m0, dst, rt0)
303{
304	......
305	struct altq_pktattr pktattr;
306
307	......
308
309	/* classify the packet before prepending link-headers */
310	IFQ_CLASSIFY(\*[Am]ifp-\*[Gt]if_snd, m, dst-\*[Gt]sa_family, \*[Am]pktattr);
311
312	/* prepend link-level headers */
313	......
314
315	IFQ_ENQUEUE(\*[Am]ifp-\*[Gt]if_snd, m, \*[Am]pktattr, error);
316
317	......
318}
319.Ed
320.Sh HOW TO CONVERT THE EXISTING DRIVERS
321First, make sure the corresponding
322.Fn if_output
323is already converted to the new style.
324.Pp
325Look for
326.Fa if_snd
327in the driver.
328Probably, you need to make changes to the lines that include
329.Fa if_snd .
330.Ss Empty check operation
331If the code checks
332.Fa ifq_head
333to see whether the queue is empty or not, use
334.Fn IFQ_IS_EMPTY .
335.Bd -literal
336            ##old-style##                           ##new-style##
337                                       |
338 if (ifp-\*[Gt]if_snd.ifq_head != NULL)     | if (IFQ_IS_EMPTY(\*[Am]ifp-\*[Gt]if_snd) == 0)
339                                       |
340.Ed
341Note that
342.Fn IFQ_POLL
343can be used for the same purpose, but
344.Fn IFQ_POLL
345could be costly for a complex scheduling algorithm since
346.Fn IFQ_POLL
347needs to run the scheduling algorithm to select the next packet.
348On the other hand,
349.Fn IFQ_IS_EMPTY
350checks only if there is any packet stored in the queue.
351Another difference is that even when
352.Fn IFQ_IS_EMPTY
353is
354.Dv FALSE ,
355.Fn IFQ_DEQUEUE
356could still return
357.Dv NULL
358if the queue is under rate-limiting.
359.Ss Dequeue operation
360Replace
361.Fn IF_DEQUEUE
362by
363.Fn IFQ_DEQUEUE .
364Always check whether the dequeued mbuf is
365.Dv NULL
366or not.
367Note that even when
368.Fn IFQ_IS_EMPTY
369is
370.Dv FALSE ,
371.Fn IFQ_DEQUEUE
372could return
373.Dv NULL
374due to rate-limiting.
375.Bd -literal
376            ##old-style##                           ##new-style##
377                                       |
378 IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);          | IFQ_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);
379                                       | if (m == NULL)
380                                       |     return;
381                                       |
382.Ed
383A driver is supposed to call
384.Fn if_start
385from transmission complete interrupts in order to trigger the next dequeue.
386.Ss Poll-and-dequeue operation
387If the code polls the packet at the head of the queue and actually uses
388the packet before dequeueing it, use
389.Fn IFQ_POLL
390and
391.Fn IFQ_DEQUEUE .
392.Bd -literal
393            ##old-style##                           ##new-style##
394                                       |
395 m = ifp-\*[Gt]if_snd.ifq_head;             | IFQ_POLL(\*[Am]ifp-\*[Gt]if_snd, m);
396 if (m != NULL) {                      | if (m != NULL) {
397                                       |
398     /* use m to get resources */      |     /* use m to get resources */
399     if (something goes wrong)         |     if (something goes wrong)
400         return;                       |         return;
401                                       |
402     IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);      |     IFQ_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);
403                                       |
404     /* kick the hardware */           |     /* kick the hardware */
405 }                                     | }
406                                       |
407.Ed
408It is guaranteed that
409.Fn IFQ_DEQUEUE
410immediately after
411.Fn IFQ_POLL
412returns the same packet.
413Note that they need to be guarded by
414.Fn splimp
415if called from outside of
416.Fn if_start .
417.Ss Eliminating IF_PREPEND
418If the code uses
419.Fn IF_PREPEND ,
420you have to eliminate it since the prepend operation is not possible for many
421queueing disciplines.
422A common use of
423.Fn IF_PREPEND
424is to cancel the previous dequeue operation.
425You have to convert the logic into poll-and-dequeue.
426.Bd -literal
427            ##old-style##                           ##new-style##
428                                       |
429 IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);          | IFQ_POLL(\*[Am]ifp-\*[Gt]if_snd, m);
430 if (m != NULL) {                      | if (m != NULL) {
431                                       |
432     if (something_goes_wrong) {       |     if (something_goes_wrong) {
433         IF_PREPEND(\*[Am]ifp-\*[Gt]if_snd, m);  |
434         return;                       |         return;
435     }                                 |     }
436                                       |
437                                       |     /* at this point, the driver
438                                       |      * is committed to send this
439                                       |      * packet.
440                                       |      */
441                                       |     IFQ_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);
442                                       |
443     /* kick the hardware */           |     /* kick the hardware */
444 }                                     | }
445                                       |
446.Ed
447.Ss Purge operation
448Use
449.Fn IFQ_PURGE
450to empty the queue.
451Note that a non-work conserving queue cannot be emptied by a dequeue loop.
452.Bd -literal
453            ##old-style##                           ##new-style##
454                                       |
455 while (ifp-\*[Gt]if_snd.ifq_head != NULL) {|  IFQ_PURGE(\*[Am]ifp-\*[Gt]if_snd);
456     IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m);      |
457     m_freem(m);                       |
458 }                                     |
459                                       |
460.Ed
461.Ss Attach routine
462Use
463.Fn IFQ_SET_MAXLEN
464to set
465.Fa ifq_maxlen
466to
467.Fa len .
468Add
469.Fn IFQ_SET_READY
470to show this driver is converted to the new style.
471(This is used to distinguish new-style drivers.)
472.Bd -literal
473            ##old-style##                           ##new-style##
474                                       |
475 ifp-\*[Gt]if_snd.ifq_maxlen = qsize;       | IFQ_SET_MAXLEN(\*[Am]ifp-\*[Gt]if_snd, qsize);
476                                       | IFQ_SET_READY(\*[Am]ifp-\*[Gt]if_snd);
477 if_attach(ifp);                       | if_attach(ifp);
478                                       |
479.Ed
480.Ss Other issues
481The new macros for statistics:
482.Bd -literal
483            ##old-style##                           ##new-style##
484                                       |
485 IF_DROP(\*[Am]ifp-\*[Gt]if_snd);                | IFQ_INC_DROPS(\*[Am]ifp-\*[Gt]if_snd);
486                                       |
487 ifp-\*[Gt]if_snd.ifq_len++;                | IFQ_INC_LEN(\*[Am]ifp-\*[Gt]if_snd);
488                                       |
489 ifp-\*[Gt]if_snd.ifq_len--;                | IFQ_DEC_LEN(\*[Am]ifp-\*[Gt]if_snd);
490                                       |
491.Ed
492Some drivers instruct the hardware to invoke transmission complete
493interrupts only when it thinks necessary.
494Rate-limiting breaks its assumption.
495.Ss How to convert drivers using multiple ifqueues
496Some (pseudo) devices (such as slip) have another
497.Dv ifqueue
498to prioritize packets.
499It is possible to eliminate the second queue
500since
501.Nm
502provides more flexible mechanisms but the following shows
503how to keep the original behavior.
504.Bd -literal
505struct sl_softc {
506	struct	ifnet sc_if;		/* network-visible interface */
507	...
508	struct	ifqueue sc_fastq;	/* interactive output queue */
509	...
510};
511.Ed
512The driver doesn't compile in the new model since it has the following
513line
514.Po
515.Fa if_snd
516is no longer a type of
517.Dv struct ifqueue
518.Pc .
519.Bd -literal
520	struct ifqueue *ifq = \*[Am]ifp-\*[Gt]if_snd;
521.Ed
522A simple way is to use the original
523.Fn IF_XXX
524macros for
525.Fa sc_fastq
526and use the new
527.Fn IFQ_XXX
528macros for
529.Fa if_snd .
530The enqueue operation looks like:
531.Bd -literal
532            ##old-style##                           ##new-style##
533                                       |
534 struct ifqueue *ifq = \*[Am]ifp-\*[Gt]if_snd;   | struct ifqueue *ifq = NULL;
535                                       |
536 if (ip-\*[Gt]ip_tos \*[Am] IPTOS_LOWDELAY)      | if ((ip-\*[Gt]ip_tos \*[Am] IPTOS_LOWDELAY) \*[Am]\*[Am]
537     ifq = \*[Am]sc-\*[Gt]sc_fastq;              | !ALTQ_IS_ENABLED(\*[Am]sc-\*[Gt]sc_if.if_snd)) {
538                                       |     ifq = \*[Am]sc-\*[Gt]sc_fastq;
539 if (IF_QFULL(ifq)) {                  |     if (IF_QFULL(ifq)) {
540     IF_DROP(ifq);                     |         IF_DROP(ifq);
541     m_freem(m);                       |         m_freem(m);
542     splx(s);                          |         error = ENOBUFS;
543     sc-\*[Gt]sc_if.if_oerrors++;           |     } else {
544     return (ENOBUFS);                 |         IF_ENQUEUE(ifq, m);
545 }                                     |         error = 0;
546 IF_ENQUEUE(ifq, m);                   |     }
547                                       | } else
548                                       |     IFQ_ENQUEUE(\*[Am]sc-\*[Gt]sc_if.if_snd,
549                                       |                 m, error);
550                                       |
551                                       | if (error) {
552                                       |     splx(s);
553                                       |     sc-\*[Gt]sc_if.if_oerrors++;
554                                       |     return (error);
555                                       | }
556 if ((sc-\*[Gt]sc_oqlen =                   | if ((sc-\*[Gt]sc_oqlen =
557      sc-\*[Gt]sc_ttyp-\*[Gt]t_outq.c_cc) == 0)  |      sc-\*[Gt]sc_ttyp-\*[Gt]t_outq.c_cc) == 0)
558     slstart(sc-\*[Gt]sc_ttyp);             |     slstart(sc-\*[Gt]sc_ttyp);
559 splx(s);                              | splx(s);
560                                       |
561.Ed
562The dequeue operations looks like:
563.Bd -literal
564            ##old-style##                           ##new-style##
565                                       |
566 s = splimp();                         | s = splimp();
567 IF_DEQUEUE(\*[Am]sc-\*[Gt]sc_fastq, m);         | IF_DEQUEUE(\*[Am]sc-\*[Gt]sc_fastq, m);
568 if (m == NULL)                        | if (m == NULL)
569     IF_DEQUEUE(\*[Am]sc-\*[Gt]sc_if.if_snd, m); |     IFQ_DEQUEUE(\*[Am]sc-\*[Gt]sc_if.if_snd, m);
570 splx(s);                              | splx(s);
571                                       |
572.Ed
573.Sh QUEUEING DISCIPLINES
574Queueing disciplines need to maintain
575.Fa ifq_len
576.Po
577used by
578.Fn IFQ_IS_EMPTY
579.Pc .
580Queueing disciplines also need to guarantee the same mbuf is returned if
581.Fn IFQ_DEQUEUE
582is called immediately after
583.Fn IFQ_POLL .
584.Sh SEE ALSO
585.Xr altq.conf 5 ,
586.Xr altqd 8 ,
587.Xr tbrconfig 8
588.Sh HISTORY
589The
590.Nm
591system first appeared in March 1997.
592