/share/man/man9/altq.9
https://bitbucket.org/freebsd/freebsd-head/ · Unknown · 599 lines · 599 code · 0 blank · 0 comment · 0 complexity · 172cf03171e64565dca640fbc0822e40 MD5 · raw file
- .\" $NetBSD: altq.9,v 1.8 2002/05/28 11:41:45 wiz Exp $
- .\" $OpenBSD: altq.9,v 1.4 2001/07/12 12:41:42 itojun Exp $
- .\"
- .\" Copyright (C) 2004 Max Laier. All rights reserved.
- .\" 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.
- .\"
- .\" $FreeBSD$
- .\"
- .Dd August 25, 2004
- .Dt ALTQ 9
- .Os
- .\"
- .Sh NAME
- .Nm ALTQ
- .Nd kernel interfaces for manipulating output queues on network interfaces
- .Sh SYNOPSIS
- .In sys/types.h
- .In sys/socket.h
- .In net/if.h
- .In net/if_var.h
- .\"
- .Ss Enqueue macros
- .Fn IFQ_ENQUEUE "struct ifaltq *ifq" "struct mbuf *m" "int error"
- .Fn IFQ_HANDOFF "struct ifnet *ifp" "struct mbuf *m" "int error"
- .Fo IFQ_HANDOFF_ADJ
- .Fa "struct ifnet *ifp" "struct mbuf *m" "int adjust" "int error"
- .Fc
- .\"
- .Ss Dequeue macros
- .Fn IFQ_DEQUEUE "struct ifaltq *ifq" "struct mbuf *m"
- .Fn IFQ_POLL_NOLOCK "struct ifaltq *ifq" "struct mbuf *m"
- .Fn IFQ_PURGE "struct ifaltq *ifq"
- .Fn IFQ_IS_EMPTY "struct ifaltq *ifq"
- .\"
- .Ss Driver managed dequeue macros
- .Fn IFQ_DRV_DEQUEUE "struct ifaltq *ifq" "struct mbuf *m"
- .Fn IFQ_DRV_PREPEND "struct ifaltq *ifq" "struct mbuf *m"
- .Fn IFQ_DRV_PURGE "struct ifaltq *ifq"
- .Fn IFQ_DRV_IS_EMPTY "struct ifaltq *ifq"
- .\"
- .Ss General setup macros
- .Fn IFQ_SET_MAXLEN "struct ifaltq *ifq" "int len"
- .Fn IFQ_INC_LEN "struct ifaltq *ifq"
- .Fn IFQ_DEC_LEN "struct ifaltq *ifq"
- .Fn IFQ_INC_DROPS "struct ifaltq *ifq"
- .Fn IFQ_SET_READY "struct ifaltq *ifq"
- .Sh DESCRIPTION
- The
- .Nm
- system is a framework to manage queuing disciplines on network
- interfaces.
- .Nm
- 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
- .Nm
- implementation, and compatible with the traditional
- .Vt ifqueue
- macros for ease of transition.
- .Pp
- .Fn IFQ_ENQUEUE ,
- .Fn IFQ_HANDOFF
- and
- .Fn IFQ_HANDOFF_ADJ
- enqueue a packet
- .Fa m
- to the queue
- .Fa ifq .
- The underlying queuing discipline may discard the packet.
- The
- .Fa error
- argument is set to 0 on success, or
- .Er ENOBUFS
- if the packet is discarded.
- The packet pointed to by
- .Fa m
- will be freed by the device driver on success, or by the queuing discipline on
- failure, so the caller should not touch
- .Fa m
- after enqueuing.
- .Fn IFQ_HANDOFF
- and
- .Fn IFQ_HANDOFF_ADJ
- combine the enqueue operation with statistic generation and call
- .Fn if_start
- upon successful enqueue to initiate the actual send.
- .Pp
- .Fn IFQ_DEQUEUE
- dequeues a packet from the queue.
- The dequeued packet is returned in
- .Fa m ,
- or
- .Fa m
- is set to
- .Dv NULL
- 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_NOLOCK
- returns the next packet without removing it from the queue.
- The caller must hold the queue mutex when calling
- .Fn IFQ_POLL_NOLOCK
- in order to guarantee that a subsequent call to
- .Fn IFQ_DEQUEUE_NOLOCK
- dequeues the same packet.
- .Pp
- .Fn IFQ_*_NOLOCK
- variants (if available) always assume that the caller holds the queue mutex.
- They can be grabbed with
- .Fn IFQ_LOCK
- and released with
- .Fn IFQ_UNLOCK .
- .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_IS_EMPTY
- can be used to check if the queue is empty.
- Note that
- .Fn IFQ_DEQUEUE
- could still return
- .Dv NULL
- if the queuing discipline is non-work conserving.
- .Pp
- .Fn IFQ_DRV_DEQUEUE
- moves up to
- .Fa ifq->ifq_drv_maxlen
- packets from the queue to the
- .Dq "driver managed"
- queue and returns the first one via
- .Fa m .
- As for
- .Fn IFQ_DEQUEUE ,
- .Fa m
- can be
- .Dv NULL
- even for a non-empty queue.
- Subsequent calls to
- .Fn IFQ_DRV_DEQUEUE
- pass the packets from the
- .Dq "driver managed"
- queue without obtaining the queue mutex.
- It is the responsibility of the caller to protect against concurrent access.
- Enabling
- .Nm
- for a given queue sets
- .Va ifq_drv_maxlen
- to 0 as the
- .Dq "bulk dequeue"
- performed by
- .Fn IFQ_DRV_DEQUEUE
- for higher values of
- .Va ifq_drv_maxlen
- is adverse to
- .Nm ALTQ Ns 's
- internal timing.
- Note that a driver must not mix
- .Fn IFQ_DRV_*
- macros with the default dequeue macros as the default macros do not look at the
- .Dq "driver managed"
- queue which might lead to an mbuf leak.
- .Pp
- .Fn IFQ_DRV_PREPEND
- prepends
- .Fa m
- to the
- .Dq "driver managed"
- queue from where it will be obtained with the next call to
- .Fn IFQ_DRV_DEQUEUE .
- .Pp
- .Fn IFQ_DRV_PURGE
- flushes all packets in the
- .Dq "driver managed"
- queue and calls to
- .Fn IFQ_PURGE
- afterwards.
- .Pp
- .Fn IFQ_DRV_IS_EMPTY
- checks for packets in the
- .Dq "driver managed"
- part of the queue.
- If it is empty, it forwards to
- .Fn IFQ_IS_EMPTY .
- .Pp
- .Fn IFQ_SET_MAXLEN
- sets the queue length limit to the default FIFO queue.
- The
- .Va ifq_drv_maxlen
- member of the
- .Vt ifaltq
- structure controls the length limit of the
- .Dq "driver managed"
- queue.
- .Pp
- .Fn IFQ_INC_LEN
- and
- .Fn IFQ_DEC_LEN
- increment or decrement the current queue length in packets.
- This is mostly for internal purposes.
- .Pp
- .Fn IFQ_INC_DROPS
- increments the drop counter and is identical to
- .Fn IF_DROP .
- It is defined for naming consistency only.
- .Pp
- .Fn IFQ_SET_READY
- sets a flag to indicate that a driver was converted to use the new macros.
- .Nm
- can be enabled only on interfaces with this flag.
- .Sh COMPATIBILITY
- .Ss Vt ifaltq Ss structure
- In order to keep compatibility with the existing code, the new
- output queue structure
- .Vt ifaltq
- has the same fields.
- The traditional
- .Fn IF_*
- macros and the code directly referencing the fields within
- .Va if_snd
- still work with
- .Vt ifaltq .
- .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;
- }; | /* driver queue fields */
- | ......
- | /* altq related fields */
- | ......
- | };
- |
- .Ed
- The new structure replaces
- .Vt "struct ifqueue"
- in
- .Vt "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_*
- macros look like:
- .Bd -literal
- #define IFQ_DEQUEUE(ifq, m) \e
- if (ALTQ_IS_ENABLED((ifq)) \e
- ALTQ_DEQUEUE((ifq), (m)); \e
- else \e
- IF_DEQUEUE((ifq), (m));
- .Ed
- .Ss Enqueue operation
- The semantics of the enqueue operation is changed.
- In the new style,
- enqueue and packet drop are combined since they cannot be easily
- separated in many queuing 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 following:
- .Pp
- .Bl -hyphen -compact
- .It
- queue a packet,
- .It
- drop (and free) a packet if the enqueue operation fails.
- .El
- .Pp
- If the enqueue operation fails,
- .Fa error
- is set to
- .Er ENOBUFS .
- The
- .Fa m
- mbuf is freed by the queuing discipline.
- The caller should not touch mbuf after calling
- .Fn IFQ_ENQUEUE
- so that the caller may need to copy
- .Va m_pkthdr.len
- or
- .Va m_flags
- field beforehand for statistics.
- .Fn IFQ_HANDOFF
- and
- .Fn IFQ_HANDOFF_ADJ
- can be used if only default interface statistics and an immediate call to
- .Fn if_start
- are desired.
- 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); | return (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
- .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
- .Va if_snd
- in the driver.
- Probably, you need to make changes to the lines that include
- .Va if_snd .
- .Ss Empty check operation
- If the code checks
- .Va 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))
- |
- .Ed
- .Fn IFQ_IS_EMPTY
- only checks if there is any packet stored in the queue.
- Note that even when
- .Fn IFQ_IS_EMPTY
- is
- .Dv FALSE ,
- .Fn IFQ_DEQUEUE
- could still return
- .Dv NULL
- if the queue is under rate-limiting.
- .Ss Dequeue operation
- 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 dequeuing it, use
- .Fn IFQ_POLL_NOLOCK
- and
- .Fn IFQ_DEQUEUE_NOLOCK .
- .Bd -literal
- ##old-style## ##new-style##
- |
- | IFQ_LOCK(&ifp->if_snd);
- m = ifp->if_snd.ifq_head; | IFQ_POLL_NOLOCK(&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)
- | IFQ_UNLOCK(&ifp->if_snd);
- return; | return;
- |
- IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE_NOLOCK(&ifp->if_snd, m);
- | IFQ_UNLOCK(&ifp->if_snd);
- |
- /* kick the hardware */ | /* kick the hardware */
- } | }
- |
- .Ed
- It is guaranteed that
- .Fn IFQ_DEQUEUE_NOLOCK
- under the same lock as a previous
- .Fn IFQ_POLL_NOLOCK
- returns the same packet.
- Note that they need to be guarded by
- .Fn IFQ_LOCK .
- .Ss Eliminating Fn IF_PREPEND
- If the code uses
- .Fn IF_PREPEND ,
- you have to eliminate it unless you can use a
- .Dq "driver managed"
- queue which allows the use of
- .Fn IFQ_DRV_PREPEND
- as a substitute.
- A common usage 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##
- |
- | IFQ_LOCK(&ifp->if_snd);
- IF_DEQUEUE(&ifp->if_snd, m); | IFQ_POLL_NOLOCK(&ifp->if_snd, m);
- if (m != NULL) { | if (m != NULL) {
- |
- if (something_goes_wrong) { | if (something_goes_wrong) {
- IF_PREPEND(&ifp->if_snd, m); | IFQ_UNLOCK(&ifp->if_snd);
- return; | return;
- } | }
- |
- | /* at this point, the driver
- | * is committed to send this
- | * packet.
- | */
- | IFQ_DEQUEUE_NOLOCK(&ifp->if_snd, m);
- | IFQ_UNLOCK(&ifp->if_snd);
- |
- /* 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 Conversion using a driver managed queue
- Convert
- .Fn IF_*
- macros to their equivalent
- .Fn IFQ_DRV_*
- and employ
- .Fn IFQ_DRV_IS_EMPTY
- where appropriate.
- .Bd -literal
- ##old-style## ##new-style##
- |
- if (ifp->if_snd.ifq_head != NULL) | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- |
- .Ed
- Make sure that calls to
- .Fn IFQ_DRV_DEQUEUE ,
- .Fn IFQ_DRV_PREPEND
- and
- .Fn IFQ_DRV_PURGE
- are protected with a mutex of some kind.
- .Ss Attach routine
- Use
- .Fn IFQ_SET_MAXLEN
- to set
- .Va ifq_maxlen
- to
- .Fa len .
- Initialize
- .Va ifq_drv_maxlen
- with a sensible value if you plan to use the
- .Fn IFQ_DRV_*
- macros.
- 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);
- | ifp->if_snd.ifq_drv_maxlen = 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_DEC_LEN(&ifp->if_snd);
- |
- .Ed
- .Sh QUEUING DISCIPLINES
- Queuing disciplines need to maintain
- .Fa ifq_len
- (used by
- .Fn IFQ_IS_EMPTY ) .
- Queuing disciplines also need to guarantee that the same mbuf is returned if
- .Fn IFQ_DEQUEUE
- is called immediately after
- .Fn IFQ_POLL .
- .Sh SEE ALSO
- .Xr pf 4 ,
- .Xr pf.conf 5 ,
- .Xr pfctl 8
- .Sh HISTORY
- The
- .Nm
- system first appeared in March 1997.