Patch to allow for the ATM "cell tax"

Linux Advanced Routing and Traffic Control

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

 



I have been trying to optimise my ADSL connections for VOIP.
Funny things were happening - for example increasing the ping
packet size by 50% had no effect, but then adding one byte 
had a major effect.  It took me a while to figure out that I 
was seeing the effects of the fixed ATM cell size.

This is probably obvious to some of you.  For the rest: ADSL
uses ATM as its transport.  An ATM "packet" is called a cell.
A cell has a fixed length of 48 bytes of data, plus 5 bytes 
of header.  If there is not enough data to occupy the cell, 
padding is added.  Thus if you get unlucky there could be up 
to 47 bytes of padding.

This 47 bytes isn't really noticeable for large packets, such
as found in Web Traffic, as it is only 3% of the total packet
size.  It isn't even really noticeable for normal sources of
interactive traffic, because typical interactive traffic (eg 
telnet, ssh & irc) is so low volume, and hence doesn't take
up much of your link capacity.  Thus in both cases the total 
percentage of your link capacity devoted to carrying this 
"padding" (aka wasted bandwidth) is low.

In VOIP the situation changes.  Firstly, the packets are 
small, occupying only 2 to 3 cells.  Secondly, it saturates
the link.  Thus if you are doing VOIP, up to 1/3 of your
links capacity can be this padding.

It is not difficult using tc as it stands to generate a
rate table does a fairly good job of estimating the 
bandwidth used on your ADSL link by large packets, or by 
small packets of a consistent size.  You can't do both.  
You can play with the figures (overhead and base rate)
and get all sorts of trade offs.  If you are prepared to
overestimate the links carrying capacity at some packet 
sizes, (a serious error for VOIP), then you can get the 
worst case error down to around 20%.  If you don't want 
at overestimate link capacity under any circumstances, 
the worst case error rises to a 40% underestimate.

The following patch to tc allows it to perform an exact
ATM / ADSL rate calculation.  It adds one extra keyword
to the "tc class add htb ..." command line: "atm".  There
isn't a lot of spare bits hanging around to record this,
so the patch adds the feature at the expense of always 
forcing the "overhead" parameter to be even.

With the patch, these commands will generate a correct
rate table for:

  PPPoA + VC/Mux:  tc class add htb ... overhead 10 atm
  PPPoA + VC/LLC:  tc class add htb ... overhead 18 atm
  PPPoE + VC/Mux:  tc class add htb ... overhead 34 atm
  PPPoE + VC/LLC:  tc class add htb ... overhead 42 atm

When using this command lines, you always specify the ADSL
link capacity as quoted by the modem.  Eg, if you are
controlling incoming traffic on a 512k/128k link, you
specify the link speed as 512000bps.

For those of you running Debian sarge or unstable, you can
find a patched version of tc here:

  http://www.stuart.id.au/russell/files/debian/sarge/iproute


diff -Nur iproute-20051007.keep/tc/q_htb.c iproute-20051007/tc/q_htb.c
--- iproute-20051007.keep/tc/q_htb.c	2006-03-02 14:50:51.000000000 +1000
+++ iproute-20051007/tc/q_htb.c	2006-03-02 15:50:31.000000000 +1000
@@ -349,6 +349,7 @@
 		" burst    max bytes burst which can be accumulated during idle period {computed}\n"
 		" mpu      minimum packet size used in rate computations\n"
 		" overhead per-packet size overhead used in rate computations\n"
+		" atm      include atm cell tax in rate computations\n"
 
 		" ceil     definite upper class rate (no borrows) {rate}\n"
 		" cburst   burst but for ceil {computed}\n"
@@ -416,7 +417,7 @@
 	unsigned buffer=0,cbuffer=0;
 	int cell_log=-1,ccell_log = -1;
 	unsigned mtu, mpu;
-	unsigned char mpu8 = 0, overhead = 0;
+	unsigned char mpu8 = 0, overhead = 0, atm=0;
 	struct rtattr *tail;
 
 	memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
@@ -440,9 +441,11 @@
 			}
 		} else if (matches(*argv, "overhead") == 0) {
 			NEXT_ARG();
-			if (get_u8(&overhead, *argv, 10)) {
+			if (get_u8(&overhead, *argv, 10) || (overhead & 1)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "atm") == 0) {
+			atm = 1;
 		} else if (matches(*argv, "quantum") == 0) {
 			NEXT_ARG();
 			if (get_u32(&opt.quantum, *argv, 10)) {
@@ -515,7 +518,7 @@
 	if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu;
 
 /* encode overhead and mpu, 8 bits each, into lower 16 bits */
-	mpu = (unsigned)mpu8 | (unsigned)overhead << 8;
+	mpu = (unsigned)mpu8 | (unsigned)(overhead + atm) << 8;
 	opt.ceil.mpu = mpu; opt.rate.mpu = mpu;
 
 	if ((cell_log = tc_calc_rtable(opt.rate.rate, rtab, cell_log, mtu, mpu)) < 0) {
@@ -575,12 +578,16 @@
 			sprint_size(buffer, b1),
 			1<<hopt->rate.cell_log,
 			sprint_size(hopt->rate.mpu&0xFF, b2),
-			sprint_size((hopt->rate.mpu>>8)&0xFF, b3));
+			sprint_size((hopt->rate.mpu>>8)&0xFE, b3));
+		if (hopt->rate.mpu & 0x100)
+			fprintf(f, "atm ");
 		fprintf(f, "cburst %s/%u mpu %s overhead %s ",
 			sprint_size(cbuffer, b1),
 			1<<hopt->ceil.cell_log,
 			sprint_size(hopt->ceil.mpu&0xFF, b2),
-			sprint_size((hopt->ceil.mpu>>8)&0xFF, b3));
+			sprint_size((hopt->ceil.mpu>>8)&0xFE, b3));
+		if (hopt->ceil.mpu & 0x100)
+			fprintf(f, "atm ");
 		fprintf(f, "level %d ", (int)hopt->level);
 	    } else {
 		fprintf(f, "burst %s ", sprint_size(buffer, b1));
diff -Nur iproute-20051007.keep/tc/tc_core.c iproute-20051007/tc/tc_core.c
--- iproute-20051007.keep/tc/tc_core.c	2006-03-02 14:50:51.000000000 +1000
+++ iproute-20051007/tc/tc_core.c	2006-03-02 15:48:38.000000000 +1000
@@ -43,6 +43,32 @@
 }
 
 /*
+ * Calculate the link layer frame size using into information encoded
+ * in the mpu.
+ */
+static unsigned frame_size(unsigned size, unsigned mpu) {
+	unsigned min_packet_size   = mpu & 0xFF;
+	unsigned overhead          = (mpu >> 8) & 0xFE;
+	unsigned atm_cell_tax      = (mpu & 0x100) != 0;
+	const unsigned atm_header  = 5;
+	const unsigned atm_payload = 48;
+
+	size += overhead;
+	if (size < min_packet_size)
+		size = min_packet_size;
+	if (atm_cell_tax) {
+		int cells = size / atm_payload;
+		int tail = size % atm_payload;
+		if (tail != 0) {
+			size += atm_payload - tail;
+			cells += 1;
+		}
+		size += atm_header * cells;
+	}
+	return size;
+}
+
+/*
    rtab[pkt_len>>cell_log] = pkt_xmit_time
  */
 
@@ -50,23 +76,16 @@
 		   unsigned mpu)
 {
 	int i;
-	unsigned overhead = (mpu >> 8) & 0xFF;
-	mpu = mpu & 0xFF;
-
-	if (mtu == 0)
-		mtu = 2047;
 
 	if (cell_log < 0) {
+		if (mtu == 0)
+			mtu = 2047;
 		cell_log = 0;
 		while ((mtu>>cell_log) > 255)
 			cell_log++;
 	}
 	for (i=0; i<256; i++) {
-		unsigned sz = (i<<cell_log);
-		if (overhead)
-			sz += overhead;
-		if (sz < mpu)
-			sz = mpu;
+		unsigned sz = frame_size(i<<cell_log, mpu);
 		rtab[i] = tc_core_usec2tick(1000000*((double)sz/bps));
 	}
 	return cell_log;



--
Regards,
Russell Stuart


_______________________________________________
LARTC mailing list
LARTC@xxxxxxxxxxxxxxx
http://mailman.ds9a.nl/cgi-bin/mailman/listinfo/lartc

[Index of Archives]     [LARTC Home Page]     [Netfilter]     [Netfilter Development]     [Network Development]     [Bugtraq]     [GCC Help]     [Yosemite News]     [Linux Kernel]     [Fedora Users]
  Powered by Linux