Now that Henning fixed the altq problem, something I wanted to try for a
very long time actually works.

I have an ADSL (asymmetric) link with 512 kbps downstream and 128 kbps
upstream capacity. One very annoying problem is that downloads suffer
when the upstream is saturated.

The reason is that when I download through TCP, I still need to send
ACKs regularly to keep the peer sending. Those ACKs are empty (they have
no data payload). When the uplink gets saturated, the empty ACKs get
delayed, and the effect is that the download speed decreases
dramatically (from 50 to 7 KB/s).

Now, the idea is to priorize the empty ACKs with pf/altq. The code is
already there. You can specify two queues in a rule, one for normal
packets and one for priorized packets. Currently, only packets with tos
(type of service) 'lowdelay' get priorized. The small patch below makes
pf use the priority queue for empty ACKs as well.

I use the following rules in pf.conf:

  altq on kue0 cbq bandwidth 100Kb queue { q_std }
  queue q_std bandwidth 100% cbq(default) { q_pri, q_def }
  queue   q_pri priority 7
  queue   q_def priority 1 cbq(red ecn)

  pass out on $ext_if inet proto tcp from $ext_if to any \
        flags S/SA keep state queue(q_def, q_pri)

  pass in  on $ext_if inet proto tcp from any to $ext_if port $services_tcp \
        flags S/SA keep state queue (q_def, q_pri)

When I now start a download, it starts with the full 50 KB/s. When I
start a concurrent upload, the cool thing is that the download speed
stays that high, even if the upstream gets saturated. The outgoing empty
ACKs related to the download are just priorized over the outgoing
packets with payload related to the upload.

Let me know if this works as well for you. :)

Daniel


Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.322
diff -u -r1.322 pf.c
--- pf.c        25 Feb 2003 17:54:06 -0000      1.322
+++ pf.c        26 Feb 2003 22:37:17 -0000
@@ -4229,6 +4229,7 @@
        struct pf_state *s = NULL;
        struct pf_pdesc  pd;
        int              off;
+       int              pqid = 0;
 
        if (!pf_status.running ||
            (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
@@ -4293,6 +4294,8 @@
                        goto done;
                }
                pd.p_len = pd.tot_len - off - (th.th_off << 2);
+               if (th.th_flags & TH_ACK && !pd.p_len)
+                       pqid = 1;
                action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd);
                if (action == PF_DROP)
                        break;
@@ -4402,7 +4405,7 @@
                mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
                if (mtag != NULL) {
                        atag = (struct altq_tag *)(mtag + 1);
-                       if (pd.tos == IPTOS_LOWDELAY)
+                       if (pqid || pd.tos == IPTOS_LOWDELAY)
                                atag->qid = r->pqid;
                        else
                                atag->qid = r->qid;

Reply via email to