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