Priority queueing is the default policy in OpenBSD and it distributes outgoing packets in 8 lists by priority (0-7) with an aggregate queue depth set by the interface: pseudo interfaces use IFQ_MAXLEN defined equal to 256, hardware device drivers normally size it by their TX ring minus 1 (therefore 127, 255, 511 are common values).
Unless a producer generating packets with altered priority is used (such as "set prio" pf directive, PPPoE management frames, ping -T lowdelay, VLAN priority, and so on) all outgoing traffic is sent with a priority of 3 hitting the same list. The drop policy used here is called tail drop because it drops the packet that we're trying to enqueue when there's no more space left on the queue. The obvious downside is that if our queue is full of packets representing low priority traffic, trying to enqueue a packet with a higher priority will still result in a drop. In my opinion, this defeats the purpose of priority queueing. The diff below changes the policy to a head drop from the queue with the lowest priority than the packet we're trying to enqueue. If there's no such queue (e.g. the default case where all traffic has priority of 3) only then the packet is dropped. This ensures that high priority traffic will almost always find the place on the queue and low priority bulk traffic gets a better chance at regulating its throughput. By performing a head drop instead a tail drop we also drop the oldest packet on the queue. This technique is akin to Active Queue Management algorithms. I'd like to stress again, that this doesn't change much for the default Ethernet-to-Ethernet case, but provides noticeable difference if different priorities are actually used, e.g. via pf. More tests are always welcome. This should go on top of the priq mbuf list diff, but here's a combined diff for convenience: http://gir.theapt.org/~mike/priq.diff --- sys/net/ifq.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git sys/net/ifq.c sys/net/ifq.c index 896b373c454..f678c2b01fd 100644 --- sys/net/ifq.c +++ sys/net/ifq.c @@ -407,18 +407,35 @@ priq_free(unsigned int idx, void *pq) int priq_enq(struct ifqueue *ifq, struct mbuf *m) { struct priq *pq; struct mbuf_list *pl; - - if (ifq_len(ifq) >= ifq->ifq_maxlen) - return (ENOBUFS); + unsigned int prio; pq = ifq->ifq_q; KASSERT(m->m_pkthdr.pf.prio <= IFQ_MAXPRIO); pl = &pq->pq_lists[m->m_pkthdr.pf.prio]; + /* Find a lower priority queue to drop from */ + if (ifq_len(ifq) >= ifq->ifq_maxlen) { + for (prio = 0; prio < m->m_pkthdr.pf.prio; prio++) { + pl = &pq->pq_lists[prio]; + if (ml_len(pl) > 0) { + m_freem(ml_dequeue(pl)); + ifq->ifq_len--; + ifq->ifq_qdrops++; + break; + } + } + /* + * There's no lower priority queue that we can + * drop from so don't enqueue this one. + */ + if (prio == m->m_pkthdr.pf.prio) + return (ENOBUFS); + } + ml_enqueue(pl, m); return (0); } -- 2.12.0
