Preface

The new version of the ZPH patch is based on the same idea - modify some information about the packets that belong to a SQUID HIT response. The older version simply used to put these packets in a predefined (at squid compilation time) class. It really works fine, but it is not possible to separate the SQUID cache engine from the QoS policing machine. It also does not allow you to re-classify those HIT packets in any way.

Implementation

In order to overcome those limitations I had to mark the HIT packets in a proper way. There are generally two options here: 1. Use some sort of netfilter voodoo (no offence here, really) to set the inner 32-bit mark field associated with every packet traversing the kernel; 2. Use the TOS field available in the IP header.
In case 1 - you have the same problem - no easy way to separate the SQUID engine from the QoS - these marks are internal to linux kernel and are not transmitted with the packets. In case 2 - the TOS field seems a better choice, but you normally can't set it to just anything you want (not absolutely true). Furthermore - TOS value is not garanteed to be preserved when packet is travelling through the network. Many devices may alter this field.

I choosed a third way: add an option to the IP header of HIT packets. IP options are part of the standart IP protocol implementation, and when reviewing the RFC791, I came accross a very convinient one. The option that my patch uses is called Stream Identifier (directly from RFC791, page 21):

+--------+--------+--------+--------+
|10001000|00000100|    Stream ID    |
+--------+--------+--------+--------+
Type=136 Length=4*

This option provides a way for the 16-bit SATNET stream
identifier to be carried through networks that do not support
the stream concept.

Must be copied on fragmentation.

I have no idea what SATNET is, after all the date of the RFC is September, 1981, but I do know this is a valid option. It will be copied on fragmentation (I tested it myself, using Cisco and linux routers). It will survive an arbitrary number of hops, without being disturbed - even NAT won't spoil it !
The only question that remains is what Stream ID to be used. Well, I have chosen the value of  0xABCD, but if you want you can change it in the patch itself.

How to use it

I won't get into details about the creating of qdiscs/classes this time. For a simple example about QoS, take a look at the old patch documentation, or the LARTC howto.

Somewhere in the network a patched SQUID caching proxy is working. A packet carrying HIT response from this proxy has arrived at the QoS machine. The packet is going to be forwarded to the client through interface eht1. How to classify it ? Here is the answer:
LANDEV=eth1
TC=/sbin/tc

$TC filter add dev $LANDEV parent 1:0 protocol ip prio 1 u32 \
match ip protocol 0x6 0xff \
match u32 0x8804ABCD 0xffffffff at 20 \
flowid 1:60

That's all folks !

You simply put every HIT packet in your fast class (1:60 in this example). This class should have a very low rate (1 kbit is a good number), but its ceil should be the maximum possible bandwidth of the interface.

Do not forget to put your own filters before/after this one !

INSTALL

1. Download SQUID 2.5 STABLE source (squid-2.5.STABLE7 is currently the latest supported).
2. Go to your favourite temporary directory and decompress the source:
tar -zxvf squid-2.5.STABLEX.tar.gz

or, for the bzip2 archive:

tar -jxvf squid-2.5.STABLEX.tar.bz2
3. Change to SQUID's source directory and apply the patch (this assumes you have downloaded the latest patch one directory above SQUID's source):
cd squid-2.5.STABLEX
patch -p1 < ../squid-2.5.STABLEX-option-marking-zph.diff
4. Follow SQUID's INSTALL guide to configure, compile and install the engine.
5. Create the appropriate QoS classes and qdiscs. Apply the proper filter configuration (tc filter) to classify the HIT packets according to your needs.
6. Start SQUID, and generate some traffic. After a while you should see packets being queued to the specified HIT class. Use this command to observe:
tc -s class show dev eth1
where you substitute eth1 with your internal (where the clients are connected) device name.

7. Drink a beer or two (i prefer vodka, though). Write me an e-mail if it worked.


   * Actually there is a mistake in this RFC. The Length is 4 bytes but on the bit layout a value of 2 is displayed (second octet). I let myself correct this on the ASCII representation shown here.