This info was tested with kernels 2.6.26 and 2.6.32. Caution, 2.6.31, looks like, has some nitpicks.
Well, I did not examine
cls_u32.c etc-etc — so I can be wrong .)
Some notes regarding «filtering logic»:
- When we write
tc filter ... protocol <proto> u32 match u<length> <value> <mask> at <offset>— we mention an offset «from ZERO», the kernel does it «from the beginning of IP packet».
- If an Ethernet frame does not contain IP packet inside — it’s possible to filter all packets for protocol specified (as, for example, one can filter all STP packets here), but not with an offset/mask. Such frames do not contain «zero» position, I guess.
- Filter tree should/may/can contain only filters for the same protocol. If we need to filter different protocols, we can do this, but this is another topic.
Here is a «demo» script (fully working however), which will filter packets in vlan 22 and 310 into different classes (as usually, I am talking of linux bridge with shaper on it; and this bridge passes throught vlan tagged traffic):
# delete prev: tc qdisc del dev eth1 root > /dev/null 2>&1 # create "roots": tc qdisc add dev eth1 root handle 1: htb default 1000 tc class add dev eth1 parent 1:0 classid 1:10 htb rate 10Mbit # default class: tc class add dev eth1 parent 1:10 classid 1:1000 htb rate 1Mbit # for vlan 22: tc class add dev eth1 parent 1:10 classid 1:22 htb rate 1Mbit # for vlan 310: tc class add dev eth1 parent 1:10 classid 1:310 htb rate 1Mbit # parent fitler: tc filter add dev eth1 parent 1:0 prio 100 protocol 802.1q u32 # vlan 22: tc filter add dev eth1 parent 1:0 prio 100 \ protocol 802.1q \ u32 match u16 0x0016 0x0fff at -4 \ flowid 1:22 # vlan 310: tc filter add dev eth1 parent 1:0 prio 100 \ protocol 802.1q \ u32 match u16 0x0136 0x0fff at -4 \ flowid 1:310
We use the offset –4 (`
at -4`) — because of in our case there is «standard» ethertype field after 802.1q header, and ethertype field is two bytes long. Yes, we need to know what’s in the frame in every particular case.
Probably, it would be better to write `
match u16 0x8100 0xffff at -6 match u16 0x0136 0x0fff at -4`, just to be sure. May be, we could even search IP protocol (hex 6) in ethertype etc-etc, but this would be «to be extremely sure», I’d say .)
A note regarding
Often one asks why
protocol ip does not filter packets with 802.1q tags etc.
The point is that in Ethernet frames protocol type is being placed in the same position always:
- in untagged packets (Ethernet_II) protocol type is placed after source MAC address;
- in tagged packets after source MAC there is always 802.1q tag, the first two bytes of which always contain 0x8100 — and this is, de facto, protocol type, too, for IEEE 802.1Q (yes, 802.1q tag is followed by ethertype, but «filterer» does not check internal encapsulated protocols).
So, actually, when we wrote, for example,
protocol arp — a filter checks a value in the first two bytes after source MAC address (which has fixed position in Ethernet frame always) to be equal
In other words, a filter always checks a value in those two bytes to be equal to numeric value for protocol type. It does not check other bytes to match protocol type.
But for «zero position» it uses the beginning of an IP packet. If any.