summaryrefslogtreecommitdiff
path: root/share/man/man9/altq.9
diff options
context:
space:
mode:
Diffstat (limited to 'share/man/man9/altq.9')
-rw-r--r--share/man/man9/altq.9571
1 files changed, 571 insertions, 0 deletions
diff --git a/share/man/man9/altq.9 b/share/man/man9/altq.9
new file mode 100644
index 00000000000..44d1b92c656
--- /dev/null
+++ b/share/man/man9/altq.9
@@ -0,0 +1,571 @@
+.\" $OpenBSD: altq.9,v 1.1 2001/07/12 12:15:02 kjc Exp $
+.\"
+.\" Copyright (C) 2001
+.\" Sony Computer Science Laboratories Inc. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd July 10, 2001
+.Dt ALTQ 9
+.Os KAME
+.\"
+.Sh NAME
+.Nm ALTQ
+.Nd kernel interfaces for manipulating output queues on network interfaces
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <net/if.h>
+.Ft void \"macro
+.Fn IFQ_ENQUEUE "struct ifaltq *ifq" "struct mbuf *m" "int error"
+.Ft void \"macro
+.Fn IFQ_DEQUEUE "struct ifaltq *ifq" "struct mbuf *m"
+.Ft void \"macro
+.Fn IFQ_POLL "struct ifaltq *ifq" "struct mbuf *m"
+.Ft void \"macro
+.Fn IFQ_PURGE "struct ifaltq *ifq"
+.Ft void \"macro
+.Fn IFQ_CLASSIFY "struct ifaltq *ifq" "struct mbuf *m" "int af" "struct altq_pktattr *pktattr"
+.Ft void \"macro
+.Fn IFQ_IS_EMPTY "struct ifaltq *ifq"
+.Ft void \"macro
+.Fn IFQ_SET_MAXLEN "struct ifaltq *ifq" "int len"
+.Ft void \"macro
+.Fn IFQ_INC_LEN "struct ifaltq *ifq"
+.Ft void \"macro
+.Fn IFQ_DEC_LEN "struct ifaltq *ifq"
+.Ft void \"macro
+.Fn IFQ_INC_DROPS "struct ifaltq *ifq"
+.Ft void \"macro
+.Fn IFQ_SET_READY "struct ifaltq *ifq"
+.Sh DESCRIPTION
+The ALTQ system is a framework to manage queueing disciplines on network
+interfaces. ALTQ introduces new macros to manipulate output queues.
+The output queue macros are used to abstract queue operations and not to
+touch the internal fields of the output queue structure.
+The macros are independent from the ALTQ implementation, and compatible with the
+traditional
+.Dv ifqueue
+macros for ease of transition.
+.Pp
+.Fn IFQ_ENQUEUE
+enqueues a packet
+.Fa m ,
+to the queue
+.Fa ifq .
+The underlying queueing discipline may discard the packet.
+0 is set to
+.Fa error
+on success and
+.Dv ENOBUFS
+is set if the packet is discarded.
+.Fa m
+will be freed by the device driver on success or by the queueing discipline on
+failure so that the caller should not touch
+.Fa m
+after calling
+.Fn IFQ_ENQUEUE .
+.Pp
+.Fn IFQ_DEQUEUE
+dequeues a packet from the queue. The dequeued packet is set to
+.Fa m ,
+or
+.Dv NULL
+is set if no packet is dequeued.
+The caller must always check
+.Fa m
+since a non-empty queue could return
+.Dv NULL
+under rate-limiting.
+.Pp
+.Fn IFQ_POLL
+returns the next packet without removing it from the queue.
+It is guaranteed by the underlying queueing discipline that
+.Fn IFQ_DEQUEUE
+immediately after
+.Fn IFQ_POLL
+returns the same packet.
+.Pp
+.Fn IFQ_PURGE
+discards all the packets in the queue.
+The purge operation is needed since a non-work conserving queue cannot be
+emptied by a dequeue loop.
+.Pp
+.Fn IFQ_CLASSIFY
+classifies a packet to a scheduling class, and set the result to
+.Fa pktattr .
+.Pp
+.Fn IFQ_IS_EMPTY
+can be used to check if the queue is empty.
+Note that
+.Fn IFQ_DEQUEUE
+could still return
+.Dv NULL
+if the queueing discipline is non-work conserving.
+.Pp
+.Fn IFQ_SET_MAXLEN
+sets the queue length limit to the default FIFO queue.
+.Pp
+.Fn IFQ_INC_LEN
+and
+.Fn IFQ_DEC_LEN
+increment or decrement the current queue length in packets.
+.Pp
+.Fn IFQ_INC_DROPS
+increments the drop counter and is equal to
+.Fn IF_DROP .
+It is defined for naming consistency.
+.Pp
+.Fn IFQ_SET_READY
+sets a flag to indicate this driver is converted to use the new macros.
+ALTQ can be enabled only on interfaces with this flag.
+.Sh COMPATIBILITY
+.Ss ifaltq structure
+In order to keep compatibility with the existing code, the new
+output queue structure
+.Dv ifaltq
+has the same fields. The traditional
+.Fn IF_XXX
+macros and the code directly referencing to the fields within
+.Dv if_snd
+still work with
+.Dv ifaltq .
+(Once we finish conversions of all the drivers, we no longer need
+these fields.)
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ struct ifqueue { | struct ifaltq {
+ struct mbuf *ifq_head; | struct mbuf *ifq_head;
+ struct mbuf *ifq_tail; | struct mbuf *ifq_tail;
+ int ifq_len; | int ifq_len;
+ int ifq_maxlen; | int ifq_maxlen;
+ int ifq_drops; | int ifq_drops;
+ }; | /* altq related fields */
+ | ......
+ | };
+ |
+.Ed
+The new structure replaces
+.Dv struct ifqueue
+in
+.Dv struct ifnet .
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ struct ifnet { | struct ifnet {
+ .... | ....
+ |
+ struct ifqueue if_snd; | struct ifaltq if_snd;
+ |
+ .... | ....
+ }; | };
+ |
+.Ed
+The (simplified) new
+.Fn IFQ_XXX
+macros looks like:
+.Bd -literal
+ #ifdef ALTQ
+ #define IFQ_DEQUEUE(ifq, m) \e
+ if (ALTQ_IS_ENABLED((ifq)) \e
+ ALTQ_DEQUEUE((ifq), (m)); \e
+ else \e
+ IF_DEQUEUE((ifq), (m));
+ #else
+ #define IFQ_DEQUEUE(ifq, m) IF_DEQUEUE((ifq), (m));
+ #endif
+.Ed
+.Ss Enqueue operation
+The semantics of the enqueue operation is changed. In the new style,
+the enqueue and packet drop are combined since they cannot be easily
+separated in many queueing disciplines.
+The new enqueue operation corresponds to the following macro that is
+written with the old macros.
+.Bd -literal
+#define IFQ_ENQUEUE(ifq, m, error) \e
+do { \e
+ if (IF_QFULL((ifq))) { \e
+ m_freem((m)); \e
+ (error) = ENOBUFS; \e
+ IF_DROP(ifq); \e
+ } else { \e
+ IF_ENQUEUE((ifq), (m)); \e
+ (error) = 0; \e
+ } \e
+} while (0)
+.Ed
+.Pp
+.Fn IFQ_ENQUEUE
+does the followings:
+.Bl -hyphen -compact
+.It
+queue a packet
+.It
+drop (and free) a packet if the enqueue operation fails
+.El
+If the enqueue operation fails, an error
+.Dv ENOBUFS
+is set to
+.Dv error .
+.Dv mbuf
+is freed by the queueing discipline.
+The caller should not touch mbuf after calling
+.Fn IFQ_ENQUEUE
+so that the caller may need to copy
+.Fa m_pkthdr.len
+or
+.Fa m_flags
+field beforehand for statistics.
+The caller should not use
+.Fn senderr
+since mbuf was already freed.
+.Pp
+The new style
+.Fn if_output
+looks as follows:
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ int | int
+ ether_output(ifp, m0, dst, rt0) | ether_output(ifp, m0, dst, rt0)
+ { | {
+ ...... | ......
+ |
+ | mflags = m->m_flags;
+ | len = m->m_pkthdr.len;
+ s = splimp(); | s = splimp();
+ if (IF_QFULL(&ifp->if_snd)) { | IFQ_ENQUEUE(&ifp->if_snd, m,
+ | error);
+ IF_DROP(&ifp->if_snd); | if (error != 0) {
+ splx(s); | splx(s);
+ senderr(ENOBUFS); | retuen (error);
+ } | }
+ IF_ENQUEUE(&ifp->if_snd, m); |
+ ifp->if_obytes += | ifp->if_obytes += len;
+ m->m_pkthdr.len; |
+ if (m->m_flags & M_MCAST) | if (mflags & M_MCAST)
+ ifp->if_omcasts++; | ifp->if_omcasts++;
+ |
+ if ((ifp->if_flags & IFF_OACTIVE) | if ((ifp->if_flags & IFF_OACTIVE)
+ == 0) | == 0)
+ (*ifp->if_start)(ifp); | (*ifp->if_start)(ifp);
+ splx(s); | splx(s);
+ return (error); | return (error);
+ |
+ bad: | bad:
+ if (m) | if (m)
+ m_freem(m); | m_freem(m);
+ return (error); | return (error);
+ } | }
+ |
+.Ed
+.Ss Classifier
+The classifier mechanism is currently implemented in
+.Fn if_output .
+.Dv struct altq_pktattr
+is used to store the classifier result, and it is passed to the enqueue
+function.
+(We will change the method to tag the classifier result to mbuf in the future.)
+.Bd -literal
+int
+ether_output(ifp, m0, dst, rt0)
+{
+ ......
+ struct altq_pktattr pktattr;
+
+ ......
+
+ /* classify the packet before prepending link-headers */
+ IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
+
+ /* prepend link-level headers */
+ ......
+
+ IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
+
+ ......
+}
+.Ed
+.Sh HOW TO CONVERT THE EXISTING DRIVERS
+First, make sure the corresponding
+.Fn if_output
+is already converted to the new style.
+.Pp
+Look for
+.Fa if_snd
+in the driver. Probably, you need to make changes to the lines that include
+.Fa if_snd .
+.Ss Empty check operation
+If the code checks
+.Fa ifq_head
+to see whether the queue is empty or not, use
+.Fn IFQ_IS_EMPTY .
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ if (ifp->if_snd.ifq_head != NULL) | if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+ |
+.Ed
+Note that
+.Fn IFQ_POLL
+can be used for the same purpose, but
+.Fn IFQ_POLL
+could be costly for a complex scheduling algorithm since
+.Fn IFQ_POLL
+needs to run the scheduling algorithm to select the next packet.
+On the other hand,
+.Fn IFQ_EMPTY
+checks only if there is any packet stored in the queue.
+Another difference is that even when
+.Fn IFQ_EMPTY
+is
+.Dv FALSE ,
+.Fn IFQ_DEQUEUE
+could still return
+.Dv NULL
+if the queue is under rate-limiting.
+.Ss Dequeue operaion
+Replace
+.Fn IF_DEQUEUE
+by
+.Fn IFQ_DEQUEUE .
+Always check whether the dequeued mbuf is
+.Dv NULL
+or not.
+Note that even when
+.Fn IFQ_IS_EMPTY
+is
+.Dv FALSE ,
+.Fn IFQ_DEQUEUE
+could return
+.Dv NULL
+due to rate-limiting.
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m);
+ | if (m == NULL)
+ | return;
+ |
+.Ed
+A driver is supposed to call
+.Fn if_start
+from transmission complete interrupts in order to trigger the next dequeue.
+.Ss Poll-and-dequeue operation
+If the code polls the packet at the head of the queue and actually uses
+the packet before dequeueing it, use
+.Fn IFQ_POLL
+and
+IFQ_DEQUEUE .
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ m = ifp->if_snd.ifq_head; | IFQ_POLL(&ifp->if_snd, m);
+ if (m != NULL) { | if (m != NULL) {
+ |
+ /* use m to get resources */ | /* use m to get resources */
+ if (something goes wrong) | if (something goes wrong)
+ return; | return;
+ |
+ IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m);
+ |
+ /* kick the hardware */ | /* kick the hardware */
+ } | }
+ |
+.Ed
+It is guaranteed that
+.Fn IFQ_DEQUEUE
+immediately after
+.Fn IFQ_POLL
+returns the same packet.
+(They need to be guarded by
+.Fn splimp
+if called from outside of
+.Fn if_start .
+)
+.Ss Eliminating IF_PREPEND
+If the code uses
+.Fn IF_PREPEND ,
+you have to eliminate it since the prepend operation is not possible for many
+queueing disciplines. A common use of
+.Fn IF_PREPEND
+is to cancel the previous dequeue operation.
+You have to convert the logic into poll-and-dequeue.
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ IF_DEQUEUE(&ifp->if_snd, m); | IFQ_POLL(&ifp->if_snd, m);
+ if (m != NULL) { | if (m != NULL) {
+ |
+ if (something_goes_wrong) { | if (something_goes_wrong) {
+ IF_PREPEND(&ifp->if_snd, m); |
+ return; | return;
+ } | }
+ |
+ | /* at this point, the driver
+ | * is committed to send this
+ | * packet.
+ | */
+ | IFQ_DEQUEUE(&ifp->if_snd, m);
+ |
+ /* kick the hardware */ | /* kick the hardware */
+ } | }
+ |
+.Ed
+.Ss Purge operation
+Use
+.Fn IFQ_PURGE
+to empty the queue.
+Note that a non-work conserving queue cannot be emptied by a dequeue loop.
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ while (ifp->if_snd.ifq_head != NULL) {| IFQ_PURGE(&ifp->if_snd);
+ IF_DEQUEUE(&ifp->if_snd, m); |
+ m_freem(m); |
+ } |
+ |
+.Ed
+.Ss Attach routine
+Use
+.Fn IFQ_SET_MAXLEN
+to set a value to
+.Fa ifq_maxlen .
+Add
+.Fn IFQ_SET_READY
+to show this driver is converted to the new style.
+(this is used to distinguish new-style drivers.)
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ ifp->if_snd.ifq_maxlen = qsize; | IFQ_SET_MAXLEN(&ifp->if_snd, qsize);
+ | IFQ_SET_READY(&ifp->if_snd);
+ if_attach(ifp); | if_attach(ifp);
+ |
+.Ed
+.Ss Other issues
+The new macros for statistics:
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ IF_DROP(&ifp->if_snd); | IFQ_INC_DROPS(&ifp->if_snd);
+ |
+ ifp->if_snd.ifq_len++; | IFQ_INC_LEN(&ifp->if_snd);
+ |
+ ifp->if_snd.ifq_len--; | IFQ_INC_LEN(&ifp->if_snd);
+ |
+.Ed
+Some drivers instruct the hardware to invoke transmission complete
+interruts only when it thinks necessary. Rate-limiting breaks its assumption.
+.Ss How to convert drivers using multiple ifqueues
+Some (pseudo) devices (such as slip) have another
+.Dv ifqueue
+to prioritize packets. It is possible to eliminate the second queue
+since ALTQ provides more flexible mechanisms but the following shows
+how to keep the original behavior.
+.Bd -literal
+struct sl_softc {
+ struct ifnet sc_if; /* network-visible interface */
+ ...
+ struct ifqueue sc_fastq; /* interactive output queue */
+ ...
+};
+.Ed
+The driver doesn't compile in the new model since it has the following
+line (
+.Fa if_snd
+is no longer a type of
+.Dv struct ifqueue .
+)
+.Bd -literal
+ struct ifqueue *ifq = &ifp->if_snd;
+.Ed
+A simple way is to use the original
+.Fn IF_XXX
+macros for
+.Fa sc_fastq
+and use the new
+.Fn IFQ_XXX
+macros for
+.Fa if_snd .
+The enqueue operation looks like:
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ struct ifqueue *ifq = &ifp->if_snd; | struct ifqueue *ifq = NULL;
+ |
+ if (ip->ip_tos & IPTOS_LOWDELAY) | if ((ip->ip_tos & IPTOS_LOWDELAY) &&
+ ifq = &sc->sc_fastq; | !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)) {
+ | ifq = &sc->sc_fastq;
+ if (IF_QFULL(ifq)) { | if (IF_QFULL(ifq)) {
+ IF_DROP(ifq); | IF_DROP(ifq);
+ m_freem(m); | m_freem(m);
+ splx(s); | error = ENOBUFS;
+ sc->sc_if.if_oerrors++; | } else {
+ return (ENOBUFS); | IF_ENQUEUE(ifq, m);
+ } | error = 0;
+ IF_ENQUEUE(ifq, m); | }
+ | } else
+ | IFQ_ENQUEUE(&sc->sc_if.if_snd,
+ | m, error);
+ |
+ | if (error) {
+ | splx(s);
+ | sc->sc_if.if_oerrors++;
+ | return (error);
+ | }
+ if ((sc->sc_oqlen = | if ((sc->sc_oqlen =
+ sc->sc_ttyp->t_outq.c_cc) == 0) | sc->sc_ttyp->t_outq.c_cc) == 0)
+ slstart(sc->sc_ttyp); | slstart(sc->sc_ttyp);
+ splx(s); | splx(s);
+ |
+.Ed
+The dequeue operations looks like:
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ s = splimp(); | s = splimp();
+ IF_DEQUEUE(&sc->sc_fastq, m); | IF_DEQUEUE(&sc->sc_fastq, m);
+ if (m == NULL) | if (m == NULL)
+ IF_DEQUEUE(&sc->sc_if.if_snd, m); | IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
+ splx(s); | splx(s);
+ |
+.Ed
+.Sh QUEUEING DISCIPLINES
+Queueing disciplines need to maintain
+.Fa ifq_len .
+(used by
+.Fn IFQ_IS_EMPTY
+).
+Queueing disciplines also need to guarantee the same mbuf is returned if
+.Fn IFQ_DEQUEUE
+is called immediately after
+.Fn IFQ_POLL .
+.Sh SEE ALSO
+.Xr altq.conf 5 ,
+.Xr altqd 8 ,
+.Xr tbrconfig 8
+.Sh HISTORY
+The
+.Nm
+system first appeared in March 1997.