ALTQ - kernel interfaces for manipulating output queues on network interfaces
IFQ_ENQUEUE (,);
IFQ_HANDOFF ();
and
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.
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
Fa m ,
or
Fa m
is set to
NULL
if no packet is dequeued.
The caller must always check
Fa 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
Fa ifq->ifq_drv_maxlen
packets from the queue to the
``driver managed''
queue and returns the first one via
Fa m .
As for
IFQ_DEQUEUE (,);
Fa 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
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 's
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
Fa 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
Vt 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.
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; int ifq_drops; | int ifq_drops; }; | /* driver queue fields */ | ...... | /* altq related fields */ | ...... | }; |The new structure replaces Vt struct ifqueue in Vt struct ifnet .
##old-style## ##new-style## | struct ifnet { | struct ifnet { .... | .... | struct ifqueue if_snd; | struct ifaltq if_snd; | .... | .... }; | }; |The (simplified) new IFQ_ (*);
#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:
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
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 ();
##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 ();
##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 ();
##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 (,);
##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); |
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |