|
NAME
SYNOPSIS
Enqueue macros
Dequeue macros
Driver managed dequeue macros
General setup macros
DESCRIPTIONThe
COMPATIBILITYifaltq structureIn order to keep compatibility with the existing code, the new
output queue structure ifaltq has the same fields. The
traditional ##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 */
| ......
| };
|
##old-style## ##new-style##
|
struct ifnet { | struct ifnet {
.... | ....
|
struct ifqueue if_snd; | struct ifaltq if_snd;
|
.... | ....
}; | };
|
IFQ_*() macros look like:
#define IFQ_DEQUEUE(ifq, m) \ if (ALTQ_IS_ENABLED((ifq)) \ ALTQ_DEQUEUE((ifq), (m)); \ else \ IF_DEQUEUE((ifq), (m)); Enqueue operationThe 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. #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)
If the enqueue operation fails, error is set
to The new style ##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);
} | }
|
HOW TO CONVERT THE EXISTING DRIVERSFirst, make sure the corresponding
Look for if_snd in the driver. Probably, you need to make changes to the lines that include if_snd. Empty check operationIf the code checks ifq_head to see whether
the queue is empty or not, use
##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.
Dequeue operationReplace
##old-style## ##new-style##
|
IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m);
| if (m == NULL)
| return;
|
if_start() from
transmission complete interrupts in order to trigger the next dequeue.
Poll-and-dequeue operationIf the code polls the packet at the head of the queue and actually
uses the packet before dequeuing it, use
##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 */
} | }
|
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().
Eliminating
|
| March 20, 2018 | FreeBSD 14.3-RELEASE |
Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.