summaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2004-08-07 12:35:56 +0000
committermlaier <mlaier@FreeBSD.org>2004-08-07 12:35:56 +0000
commitc794eed216d0b649225d9b92b6187289e7137f63 (patch)
tree2b9e753cfd6310eeeda4a056e8605887bc18ebd2 /share
parent7467edef223a9a72541ffd030f44481ef4fee6e3 (diff)
downloadFreeBSD-src-c794eed216d0b649225d9b92b6187289e7137f63.zip
FreeBSD-src-c794eed216d0b649225d9b92b6187289e7137f63.tar.gz
Add altq(9) explaining about the IFQ_* and IFQ_DRV_* macros in if_var.h and
how to convert drivers. Obtained from: NetBSD (with changes) Reviewed by: josef
Diffstat (limited to 'share')
-rw-r--r--share/man/man9/Makefile2
-rw-r--r--share/man/man9/altq.9597
2 files changed, 599 insertions, 0 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index f01e73a..fb4bb65 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -5,6 +5,7 @@ MAN= accept_filter.9 \
accf_http.9 \
acl.9 \
alq.9 \
+ altq.9 \
atomic.9 \
bios.9 \
boot.9 \
@@ -336,6 +337,7 @@ MLINKS= alq.9 ALQ.9 \
alq.9 alq_open.9 \
alq.9 alq_post.9 \
alq.9 alq_write.9
+MLINKS+=altq.9 ALTQ.9
MLINKS+=atomic.9 atomic_add.9 \
atomic.9 atomic_clear.9 \
atomic.9 atomic_cmpset.9 \
diff --git a/share/man/man9/altq.9 b/share/man/man9/altq.9
new file mode 100644
index 0000000..cb6e5ea
--- /dev/null
+++ b/share/man/man9/altq.9
@@ -0,0 +1,597 @@
+.\" $FreeBSD$
+.\" $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.
+.\"
+.Dd August 7, 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"
+.Fn IFQ_HANDOFF_ADJ "struct ifnet *ifp" "struct mbuf *m" "int adjust" "int error"
+.\"
+.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
+.Dv 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.
+.Fa error
+is set to 0 on success, or
+.Dv ENOBUFS
+if the packet is discarded.
+.Fa m
+will be freed by the device driver on success or by the queuing discipline on
+failure so that 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 to
+.Fn IFQ_POLL_NOLOCK
+in order to guarantee that a subsequent call to
+.Fn IFQ_DEQUEUE_NOLOCK
+dequeues the same packet.
+.Pp
+.Fn IFQ_XXX_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
+.Va ifq->ifq_drv_maxlen
+packets from the queue to the
+.Ql 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
+.Ql 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
+.Dv 0
+as the
+.Ql bulk dequeue
+performed by
+.Fn IFQ_DRV_DEQUEUE
+for higher values of
+.Va ifq_drv_maxlen
+is adverse to
+.Sy ALTQ's
+internal timing.
+Note that a driver must not mix
+.Fn IFQ_DRV_XXX
+macros with the default dequeue macros as the default macros do not look at the
+.Ql driver managed
+queue which might lead to an mbuf leak.
+.Pp
+.Fn IFQ_DRV_PREPEND
+prepends
+.Fa m
+to the
+.Ql 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
+.Ql driver managed
+queue and calls to
+.Fn IFQ_PURGE
+afterwards.
+.Pp
+.Fn IFQ_DRV_IS_EMPTY
+checks for packets in the
+.Ql driver managed
+part of the queue. If it is empty it forwards to
+.Fn IFQ_IS_EMPTY .
+.Pp
+.Pp
+.Fn IFQ_SET_MAXLEN
+sets the queue length limit to the default FIFO queue.
+.Va ifaltq.ifq_drv_maxlen
+controls the length limit of the
+.Ql 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 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.
+.Nm
+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 the fields within
+.Dv if_snd
+still work with
+.Dv 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
+.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
+ #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:
+.Bl -hyphen -compact
+.It
+queue a packet
+.It
+drop (and free) a packet if the enqueue operation fails
+.El
+If the enqueue operation fails,
+.Fa error
+is set to
+.Dv ENOBUFS .
+.Fa 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
+.Fa m_pkthdr.len
+or
+.Fa 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-\*[Gt]m_flags;
+ | len = m-\*[Gt]m_pkthdr.len;
+ s = splimp(); | s = splimp();
+ if (IF_QFULL(\*[Am]ifp-\*[Gt]if_snd)) { | IFQ_ENQUEUE(\*[Am]ifp-\*[Gt]if_snd, m,
+ | error);
+ IF_DROP(\*[Am]ifp-\*[Gt]if_snd); | if (error != 0) {
+ splx(s); | splx(s);
+ senderr(ENOBUFS); | return (error);
+ } | }
+ IF_ENQUEUE(\*[Am]ifp-\*[Gt]if_snd, m); |
+ ifp-\*[Gt]if_obytes += | ifp-\*[Gt]if_obytes += len;
+ m-\*[Gt]m_pkthdr.len; |
+ if (m-\*[Gt]m_flags \*[Am] M_MCAST) | if (mflags \*[Am] M_MCAST)
+ ifp-\*[Gt]if_omcasts++; | ifp-\*[Gt]if_omcasts++;
+ |
+ if ((ifp-\*[Gt]if_flags \*[Am] IFF_OACTIVE) | if ((ifp-\*[Gt]if_flags \*[Am] IFF_OACTIVE)
+ == 0) | == 0)
+ (*ifp-\*[Gt]if_start)(ifp); | (*ifp-\*[Gt]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
+.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-\*[Gt]if_snd.ifq_head != NULL) | if (!IFQ_IS_EMPTY(\*[Am]ifp-\*[Gt]if_snd))
+ |
+.Ed
+.Fn IFQ_IS_EMPTY
+checks only 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(\*[Am]ifp-\*[Gt]if_snd, m); | IFQ_DEQUEUE(\*[Am]ifp-\*[Gt]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(\*[Am]ifp-\*[Gt]if_snd);
+ m = ifp-\*[Gt]if_snd.ifq_head; | IFQ_POLL_NOLOCK(\*[Am]ifp-\*[Gt]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(\*[Am]ifp-\*[Gt]if_snd);
+ return; | return;
+ |
+ IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m); | IFQ_DEQUEUE_NOLOCK(\*[Am]ifp-\*[Gt]if_snd, m);
+ | IFQ_UNLOCK(\*[Am]ifp-\*[Gt]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 IF_PREPEND
+If the code uses
+.Fn IF_PREPEND ,
+you have to eliminate it unless you can use a
+.Ql driver managed
+queue which allows use of
+.Fn IFQ_DRV_PREPEND
+as a substitute.
+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##
+ |
+ | IFQ_LOCK(\*[Am]ifp-\*[Gt]if_snd);
+ IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m); | IFQ_POLL_NOLOCK(\*[Am]ifp-\*[Gt]if_snd, m);
+ if (m != NULL) { | if (m != NULL) {
+ |
+ if (something_goes_wrong) { | if (something_goes_wrong) {
+ IF_PREPEND(\*[Am]ifp-\*[Gt]if_snd, m); | IFQ_UNLOCK(\*[Am]ifp-\*[Gt]if_snd);
+ return; | return;
+ } | }
+ |
+ | /* at this point, the driver
+ | * is committed to send this
+ | * packet.
+ | */
+ | IFQ_DEQUEUE_NOLOCK(\*[Am]ifp-\*[Gt]if_snd, m);
+ | IFQ_UNLOCK(\*[Am]ifp-\*[Gt]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-\*[Gt]if_snd.ifq_head != NULL) {| IFQ_PURGE(\*[Am]ifp-\*[Gt]if_snd);
+ IF_DEQUEUE(\*[Am]ifp-\*[Gt]if_snd, m); |
+ m_freem(m); |
+ } |
+ |
+.Ed
+.Ss Conversion using a driver managed queue
+Convert
+.Fn IF_XXX
+macros to their equivalent
+.Fn IFQ_DRV_XXX
+and employ
+.Fn IFQ_DRV_IS_EMPTY
+where appropriate
+.Bd -literal
+ ##old-style## ##new-style##
+ |
+ if (ifp-\*[Gt]if_snd.ifq_head != NULL) | if (!IFQ_DRV_IS_EMPTY(\*[Am]ifp-\*[Gt]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.
+Setting
+.Dv IFF_NEEDSGIANT
+in
+.Va if_flags
+might also be appropriate.
+.Ss Attach routine
+Use
+.Fn IFQ_SET_MAXLEN
+to set
+.Fa ifq_maxlen
+to
+.Fa len .
+Initialize
+.Va ifq_drv_maxlen
+with a sensible value if you plan to use the
+.Fn IFQ_DRV_XXX
+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-\*[Gt]if_snd.ifq_maxlen = qsize; | IFQ_SET_MAXLEN(\*[Am]ifp-\*[Gt]if_snd, qsize);
+ | ifp-\*[Gt]if_snd.ifq_drv_maxlen = qsize;
+ | IFQ_SET_READY(\*[Am]ifp-\*[Gt]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(\*[Am]ifp-\*[Gt]if_snd); | IFQ_INC_DROPS(\*[Am]ifp-\*[Gt]if_snd);
+ |
+ ifp-\*[Gt]if_snd.ifq_len++; | IFQ_INC_LEN(\*[Am]ifp-\*[Gt]if_snd);
+ |
+ ifp-\*[Gt]if_snd.ifq_len--; | IFQ_DEC_LEN(\*[Am]ifp-\*[Gt]if_snd);
+ |
+.Ed
+.Sh QUEUING DISCIPLINES
+Queuing disciplines need to maintain
+.Fa ifq_len
+.Po
+used by
+.Fn IFQ_IS_EMPTY
+.Pc .
+Queuing 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 pf 4 ,
+.Xr pf.conf 5
+.Xr pfctl 8
+.Sh HISTORY
+The
+.Nm
+system first appeared in March 1997.
OpenPOWER on IntegriCloud