12

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!

brownian
  • 291
  • 3
  • 13

5 Answers5

4

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
Falcon Momot
  • 24,975
  • 13
  • 61
  • 92
Thusitha
  • 41
  • 2
  • An attempt to add a root filter for `protocol all` gives me `RTNETLINK answers: Invalid argument` (3.3.4 kernel here). I will test this with newer kernels. Thank you. – brownian Nov 18 '13 at 15:18
  • This worked for me with debian wheezy kernel 3.2.0. I've added another answer with full details. – Nick Craig-Wood Jan 13 '15 at 16:23
3

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
1

I would recommend using wireshark to capture what is going through the interface as visible in userspace, and using that to write the filter. I am wondering if perhaps the interface is stripping the VLAN tags for some reason (despite being configured to bridge transparently). Perhaps it is adding extra tags or something?

Falcon Momot
  • 24,975
  • 13
  • 61
  • 92
  • No, it's not stripping VLAN tag, definitely -- everything works (traffic gets switched via trunks on hardware switches), except filters in the shaper. I will look closer, however. I looked at VLAN tag offload capability, but those drivers are not capable to do vid offload. – brownian Apr 13 '12 at 06:47
  • `tcpdump` shows vlan IDs at all interfaces `bridge` and it ports. – brownian May 10 '12 at 12:47
  • Now my nice shaper works un linux kernel 3.3.4, everything works great except 8021q tag filtering (I can live without it). The problem remains unsolved. Thank you anyway. – brownian May 21 '12 at 14:59
1

You can mark vlan packtes with ebtables.

# mark packets according to the vlan id
ebtables -i br0 -A PREROUTING -p 802_1Q --vlan-id 1 -j mark --mark-set 1
ebtables -i br0 -A PREROUTING -p 802_1Q --vlan-id 5 -j mark --mark-set 2

Then apply shaping based on markings. ebtables and iptables share the same marking.

Haven't done this myself yet. So its rather a hunch.

rhasti
  • 477
  • 3
  • 9
  • I doubt it will work smoothly on 10Gb link... I'd like to avoid any *tables. Thanks for suggestion anyway. – brownian Apr 24 '13 at 17:18
  • @brownian you think doing exactly the same filtering in iproute2 will be higher performance? It's the same kernel, same code path, same algorithms. As long as you don't accidentally do something like turn on connection tracking, you shouldn't see a difference. *tables **can** impact performance because it **can** do a lot of complex stuff. But that doesn't means that it **will**. – tylerl Jun 27 '13 at 03:16
  • @tylerl Since I actually *have to filter* with iproute2 (hundreds of customers in the same vlan, a bunch of filters hashes) -- any other extra check for every packet *will* impact performance, I do believe. – brownian Jun 27 '13 at 07:05
0

Try to turn off reorder_hdr option on vlan interface. If reorder header option is enabled, then tags from frames are being removed. Check it by command ip -d link list dev vlan_iface.

brownian
  • 291
  • 3
  • 13
  • 1
    Please, can you clarify, _when_ it is removed, and _when_ it is inserted back? I mean, a tagged frame enters into linux bridge and then leaves it from another interface -- when/where these tag manipulations occur, and when/where `tc` filters are called? Do you have a link to a map or like that? Thanks! – brownian May 24 '12 at 17:55
  • Please, another thought: _which_ vlan interface do you mean? That bridge has no one vlan interface (I wrote "I mean, no VLAN interfaces are there" in the first paragraph). – brownian May 25 '12 at 11:09