Main index | Section 9 | Options |
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_var.h>
IFQ_ENQUEUE(), IFQ_HANDOFF() and IFQ_HANDOFF_ADJ() enqueue a packet m to the queue ifq. The underlying queuing discipline may discard the packet. The error argument is set to 0 on success, or ENOBUFS if the packet is discarded. The packet pointed to by m will be freed by the device driver on success, or by the queuing discipline on failure, so the caller should not touch m after enqueuing. IFQ_HANDOFF() and IFQ_HANDOFF_ADJ() combine the enqueue operation with statistic generation and call if_start() upon successful enqueue to initiate the actual send.
IFQ_DEQUEUE() dequeues a packet from the queue. The dequeued packet is returned in m, or m is set to NULL if no packet is dequeued. The caller must always check m since a non-empty queue could return NULL under rate-limiting.
IFQ_POLL_NOLOCK() returns the next packet without removing it from the queue. The caller must hold the queue mutex when calling IFQ_POLL_NOLOCK() in order to guarantee that a subsequent call to IFQ_DEQUEUE_NOLOCK() dequeues the same packet.
IFQ_*_NOLOCK() variants (if available) always assume that the caller holds the queue mutex. They can be grabbed with IFQ_LOCK() and released with IFQ_UNLOCK().
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.
IFQ_IS_EMPTY() can be used to check if the queue is empty. Note that IFQ_DEQUEUE() could still return NULL if the queuing discipline is non-work conserving.
IFQ_DRV_DEQUEUE() moves up to ifq->ifq_drv_maxlen packets from the queue to the "driver managed" queue and returns the first one via m. As for IFQ_DEQUEUE(), m can be NULL even for a non-empty queue. Subsequent calls to IFQ_DRV_DEQUEUE() pass the packets from the "driver managed" queue without obtaining the queue mutex. It is the responsibility of the caller to protect against concurrent access. Enabling ALTQ for a given queue sets ifq_drv_maxlen to 0 as the "bulk dequeue" performed by IFQ_DRV_DEQUEUE() for higher values of ifq_drv_maxlen is adverse to ALTQ internal timing. Note that a driver must not mix IFQ_DRV_*() macros with the default dequeue macros as the default macros do not look at the "driver managed" queue which might lead to an mbuf leak.
IFQ_DRV_PREPEND() prepends m to the "driver managed" queue from where it will be obtained with the next call to IFQ_DRV_DEQUEUE().
IFQ_DRV_PURGE() flushes all packets in the "driver managed" queue and calls to IFQ_PURGE() afterwards.
IFQ_DRV_IS_EMPTY() checks for packets in the "driver managed" part of the queue. If it is empty, it forwards to IFQ_IS_EMPTY().
IFQ_SET_MAXLEN() sets the queue length limit to the default FIFO queue. The ifq_drv_maxlen member of the ifaltq structure controls the length limit of the "driver managed" queue.
IFQ_INC_LEN() and IFQ_DEC_LEN() increment or decrement the current queue length in packets. This is mostly for internal purposes.
IFQ_INC_DROPS() increments the drop counter and is identical to IF_DROP(). It is defined for naming consistency only.
IFQ_SET_READY() sets a flag to indicate that a driver was converted to use the new macros. ALTQ can be enabled only on interfaces with this flag.
##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; }; | /* driver queue fields */ | ...... | /* altq related fields */ | ...... | }; |The new structure replaces struct ifqueue in struct ifnet.
##old-style## ##new-style## | struct ifnet { | struct ifnet { .... | .... | struct ifqueue if_snd; | struct ifaltq if_snd; | .... | .... }; | }; |The (simplified) new IFQ_*() macros look like:
#define IFQ_DEQUEUE(ifq, m) \ if (ALTQ_IS_ENABLED((ifq)) \ ALTQ_DEQUEUE((ifq), (m)); \ else \ IF_DEQUEUE((ifq), (m));
#define IFQ_ENQUEUE(ifq, m, error) \ do { \ if (IF_QFULL((ifq))) { \ m_freem((m)); \ (error) = ENOBUFS; \ IF_DROP(ifq); \ } else { \ IF_ENQUEUE((ifq), (m)); \ (error) = 0; \ } \ } while (0)
IFQ_ENQUEUE() does the following:
queue a packet, | |
drop (and free) a packet if the enqueue operation fails. | |
If the enqueue operation fails, error is set to ENOBUFS. The m mbuf is freed by the queuing discipline. The caller should not touch mbuf after calling IFQ_ENQUEUE() so that the caller may need to copy m_pkthdr.len or m_flags field beforehand for statistics. IFQ_HANDOFF() and IFQ_HANDOFF_ADJ() can be used if only default interface statistics and an immediate call to if_start() are desired. The caller should not use senderr() since mbuf was already freed.
The new style if_output() looks as follows:
##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); } | } |
Look for if_snd in the driver. Probably, you need to make changes to the lines that include if_snd.
##old-style## ##new-style## | if (ifp->if_snd.ifq_head != NULL) | if (!IFQ_IS_EMPTY(&ifp->if_snd)) |IFQ_IS_EMPTY() only checks if there is any packet stored in the queue. Note that even when IFQ_IS_EMPTY() is FALSE, IFQ_DEQUEUE() could still return NULL if the queue is under rate-limiting.
##old-style## ##new-style## | IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m); | if (m == NULL) | return; |A driver is supposed to call if_start() from transmission complete interrupts in order to trigger the next dequeue.
##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 */ } | } |It is guaranteed that IFQ_DEQUEUE_NOLOCK() under the same lock as a previous IFQ_POLL_NOLOCK() returns the same packet. Note that they need to be guarded by IFQ_LOCK().
##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 */ } | } |
##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); | } | |
##old-style## ##new-style## | if (ifp->if_snd.ifq_head != NULL) | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) |Make sure that calls to IFQ_DRV_DEQUEUE(), IFQ_DRV_PREPEND() and IFQ_DRV_PURGE() are protected with a mutex of some kind.
##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); |
##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); |
ALTQ (9) | March 20, 2018 |
Main index | Section 9 | Options |
Please direct any comments about this manual page service to Ben Bullock. Privacy policy.
“ | When people say "Drive safe!" I'm like no, a safe is for keeping money, I drive car. | ” |
— Artur Bagyants |