[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Priorizing empty ACKs

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. :)
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)
@@ -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;
 				atag->qid = r->qid;