| 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 | ||