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-2025 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |