tc u32 --- how to match L2 protocols in recent kernels?
I have a nice shaper, with hashed filtering, built at a linux bridge. In short, br0
connects external
and internal
physical interfaces, VLAN tagged packets are bridged "transparently" (I mean, no VLAN interfaces are there).
Now, different kernels do it differently. I can be wrong with exact kernel verions ranges, please forgive me. Thanks.
2.6.26
So, in debian, 2.6.26 and up (up to 2.6.32, I believe) --- this works:
tc filter add dev internal protocol 802.1q parent 1:0 prio 100 \
u32 ht 1:64 match ip dst 192.168.1.100 flowid 1:200
Here, "kernel" matches two bytes in "protocol" field with 0x8100, but counts the beginning of ip packet as a "zero position" (sorry for my English, if I'm a bit unclear).
2.6.32
Again, in debian (I've not built vanilla kernel), 2.6.32-5 --- this works:
tc filter add dev internal protocol 802.1q parent 1:0 prio 100 \
u32 ht 1:64 match ip dst 192.168.1.100 at 20 flowid 1:200
Here, "kernel" matches the same for protocol, but counts offset from the beginning of this protocol's header --- I have to add 4 bytes to offset (20, not 16 for dst address). It's ok, seems more logical, as for me.
3.2.11, the latest stable now
This works --- as if there is no 802.1q tag at all:
tc filter add dev internal protocol ip parent 1:0 prio 100 \
u32 ht 1:64 match ip dst 192.168.1.100 flowid 1:200
The problem is that I couldn't find a way to match 802.1q tag so far.
Matching 802.1q tag at past
I could do this before as follows:
tc filter add dev internal protocol 802.1q parent 1:0 prio 100 \
u32 match u16 0x0ed8 0x0fff at -4 flowid 1:300
Now I'm unable to match 802.1q tag with at 0
, at -2
, at -4
, at -6
or like that. The main issue that I have zero hits count --- this filter is not being checked at all, "wrong protocol", in other words.
Please, anyone, help me :-)
Thanks!
VLAN tag is stripped from skb in recent kernels. Try something like this to do a meta match in skb:
tc filter add dev internal protocol all parent 1:0 prio 100 basic match 'meta(vlan mask 0xfff eq 0x0ed8)' flowid 1:300
I had to do exactly this. I found that the answer suggested by @Thusitha was the correct way to do it for new kernels.
Tested with the Debian wheezy kernel 3.2.0-4 and iproute (from where the tc command comes from) version 20120521-3+b3
Here is the complete script, the tc filter
lines being almost exactly as specified by @Thusitha
function qos() {
if="$1"
vlan1="$2"
vlan2="$3"
# delete previous
tc qdisc del dev $if root >/dev/null 2>&1
tc qdisc del dev $if ingress >/dev/null 2>&1
# Root HTB for $if
tc qdisc add dev $if root handle 1: htb r2q 1 default 1
# Root class to borrow from
tc class add dev $if parent 1: classid 1:1 htb quantum 1000000 rate 500mbit ceil 500mbit burst 64k prio 2
tc qdisc add dev $if parent 1:1 handle 101 sfq perturb 10
# class for vlan1
tc class add dev $if parent 1:1 classid 1:106 htb quantum 1000000 rate 1.00mbit ceil 1.00mbit burst 6k
tc qdisc add dev $if parent 1:106 handle 107 sfq perturb 10
tc filter add dev $if protocol all parent 1: prio 100 basic match "meta(vlan mask 0xfff eq ${vlan1})" flowid 1:106
# class for vlan2
tc class add dev $if parent 1:1 classid 1:108 htb quantum 1000000 rate 1.00mbit ceil 10.00mbit burst 6k
tc qdisc add dev $if parent 1:108 handle 108 sfq perturb 10
tc filter add dev $if protocol all parent 1: prio 100 basic match "meta(vlan mask 0xfff eq ${vlan2})" flowid 1:108
}
qos eth1 1234 1235
qos eth2 2345 2346