| ALTQ(9) | AerieBSD 1.0 Refernce Manual | ALTQ(9) |
##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;
}; | /* altq related fields */
| ......
| };
|
The new structure replaces structifqueue in structifnet.
##old-style## ##new-style##
|
struct ifnet { | struct ifnet {
.... | ....
|
struct ifqueue if_snd; | struct ifaltq if_snd;
|
.... | ....
}; | };
|
The (simplified) new IFQ_XXX(); macros looks like:
#ifdef ALTQ #define IFQ_DEQUEUE(ifq, m) \e if (ALTQ_IS_ENABLED((ifq)) \e ALTQ_DEQUEUE((ifq), (m)); \e else \e IF_DEQUEUE((ifq), (m)); #else #define IFQ_DEQUEUE(ifq, m) IF_DEQUEUE((ifq), (m)); #endif
#define IFQ_ENQUEUE(ifq, m, pattr, err) \e
do { \e
if (ALTQ_IS_ENABLED((ifq))) \e
ALTQ_ENQUEUE((ifq), (m), (pattr), (err)); \e
else { \e
if (IF_QFULL((ifq))) { \e
m_freem((m)); \e
(err) = ENOBUFS; \e
} else { \e
IF_ENQUEUE((ifq), (m)); \e
(err) = 0; \e
} \e
} \e
if ((err)) \e
(ifq)->ifq_drops++; \e
} while (0)
IFQ_ENQUEUE(); does the following:
##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,
| NULL, 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);
} | }
|
int
ether_output(ifp, m0, dst, rt0)
{
......
struct altq_pktattr pktattr;
......
/* classify the packet before prepending link-headers */
IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
/* prepend link-level headers */
......
IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
......
}
##old-style## ##new-style##
|
if (ifp->if_snd.ifq_head != NULL) | if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
|
Note that IFQ_POLL(); can be used for the same purpose, but IFQ_POLL(); could be costly for a complex scheduling algorithm since IFQ_POLL(); needs to run the scheduling algorithm to select the next packet. On the other hand, IFQ_IS_EMPTY(); checks only if there is any packet stored in the queue. Another difference is 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##
|
m = ifp->if_snd.ifq_head; | IFQ_POLL(&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)
return; | return;
|
IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m);
|
/* kick the hardware */ | /* kick the hardware */
} | }
|
It is guaranteed that IFQ_DEQUEUE(); immediately after IFQ_POLL(); returns the same packet. Note that they need to be guarded by splimp(); if called from outside of if_start();.
##old-style## ##new-style##
|
IF_DEQUEUE(&ifp->if_snd, m); | IFQ_POLL(&ifp->if_snd, m);
if (m != NULL) { | if (m != NULL) {
|
if (something_goes_wrong) { | if (something_goes_wrong) {
IF_PREPEND(&ifp->if_snd, m); |
return; | return;
} | }
|
| /* at this point, the driver
| * is committed to send this
| * packet.
| */
| IFQ_DEQUEUE(&ifp->if_snd, m);
|
/* 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##
|
ifp->if_snd.ifq_maxlen = qsize; | IFQ_SET_MAXLEN(&ifp->if_snd, 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);
|
Some drivers instruct the hardware to invoke transmission complete interrupts only when it thinks necessary. Rate-limiting breaks its assumption.
struct sl_softc {
struct ifnet sc_if; /* network-visible interface */
...
struct ifqueue sc_fastq; /* interactive output queue */
...
};
The driver doesn't compile in the new model since it has the following line ( if_snd is no longer a type of structifqueue ).
struct ifqueue *ifq = &ifp->if_snd;
A simple way is to use the original IF_XXX(); macros for sc_fastq and use the new IFQ_XXX(); macros for if_snd. The enqueue operation looks like:
##old-style## ##new-style##
|
struct ifqueue *ifq = &ifp->if_snd; | struct ifqueue *ifq = NULL;
|
if (ip->ip_tos & IPTOS_LOWDELAY) | if ((ip->ip_tos & IPTOS_LOWDELAY) &&
ifq = &sc->sc_fastq; | !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)) {
| ifq = &sc->sc_fastq;
if (IF_QFULL(ifq)) { | if (IF_QFULL(ifq)) {
IF_DROP(ifq); | IF_DROP(ifq);
m_freem(m); | m_freem(m);
splx(s); | error = ENOBUFS;
sc->sc_if.if_oerrors++; | } else {
return (ENOBUFS); | IF_ENQUEUE(ifq, m);
} | error = 0;
IF_ENQUEUE(ifq, m); | }
| } else
| IFQ_ENQUEUE(&sc->sc_if.if_snd,
| NULL, m, error);
|
| if (error) {
| splx(s);
| sc->sc_if.if_oerrors++;
| return (error);
| }
if ((sc->sc_oqlen = | if ((sc->sc_oqlen =
sc->sc_ttyp->t_outq.c_cc) == 0) | sc->sc_ttyp->t_outq.c_cc) == 0)
slstart(sc->sc_ttyp); | slstart(sc->sc_ttyp);
splx(s); | splx(s);
|
The dequeue operations looks like:
##old-style## ##new-style##
|
s = splimp(); | s = splimp();
IF_DEQUEUE(&sc->sc_fastq, m); | IF_DEQUEUE(&sc->sc_fastq, m);
if (m == NULL) | if (m == NULL)
IF_DEQUEUE(&sc->sc_if.if_snd, m); | IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
splx(s); | splx(s);
|
| AerieBSD 1.0 Reference Manual | August 26 2008 | ALTQ(9) |