tc filter … protocol 802.1q … u32 and filtering VLAN tagged packets

Posted on

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 protocol <proto>

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 0x0806.

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.

12 Replies to “tc filter … protocol 802.1q … u32 and filtering VLAN tagged packets”

  1. Hi,

    Thank you for the post! I tried this on my network. However I have problems. The data rate limits hold for each VLAN ID on each interface (which is great) but the inter VLAN data rates vary greatly. I expect to get equal or nearly equal data rate across each VLAN but it is not the case. I tried by changing the data rate limit, ranging from 1Mbit to 200Mbit. In all cases I have the same issue.

    I am running these commands in the exact same order and manner described by you here. I am using Ubuntu 11.10. Could you kindly let me know if my assumptions are correct? Would I receive equal or nearly equal data rates on all VLANs? Please do point out any mistakes I could have made.

    Thank you.

      1. Oh sorry. I meant data-rate across each VLAN (when there are many VLANs present in the network).

        More elaborately, I have set filters for different VLANs on each interface. So for example at an interface say eth1 if there are two vlan filters (say VLAN ID = 500 at 1 Mbps and VLAN ID = 501 at 1Mbps), shouldn’t data rate through both these VLANs be less than 1Mbps (which is the maximum bandwidth) and also same to one another (or nearly same)? In my case the both the VLANs have their data rates well within 1Mbps but they are not same.

        I have a file which I created by “echo”ing all the commands generated by my shell script. I can share that file. May be that will make my problem clearer. Please do let me know how I can share it with you?

        1. Data rates should not be equal. They will be more or less equal, if you’ve configured the same rate, ceil and prio for each class *and* both classes try to eat as much as possible.

          If, otherwise, each class is below it’s rate limit, HTB will not try to give them equal rates.

          You can share your script using any “paste it” online service and give link here. Sorry, now I am off and will be online tomorrow.

          1. Oh Okay. I have tried to do this. But I think I am doing something wrong.

            Here is my script:

            I am trying to achieve equal (or nearly equal) data rate of 100Mbps on each VLAN. Could you please point out my mistake here? Thank you so much for the support.

        2. Please, what whould you like to achieve?

          You are attaching qdisc for every VLAN interface, aren’t you? If so, these are *different* qdiscs, every one with it’s own filters tree and classes tree, so there is no any one who would equalize rates in different separate qdiscs.

          I am not sure that I understood your goals; anyway; if I would need to shape traffic in different vlans, I would not create vlan subinterfaces on shaper box, attach single qdisc to parent physical interface (eth0) and filter traffic in different vlans into different classes.

          If you need to shape traffic in different vlans *on router* (not bridge) box, try IMQ instead of HTB, or like that. Can not help you here, sorry.

          1. Thank you for the explanation. Things are a lot clearer to me. I think I had badly messed up filter and class tree creation. My goals are as follows:
            1) To limit the data rate within each VLAN
            2) To ensure that each of the data flows using each VLAN, gets the maximum bandwidth possible (which should be nearly same as the bandwidth got by other flows in that VLAN).

            I am still a little confused how to construct the filer and class trees. I have reworked on my scripts and created two versions. I am not sure which makes more sense?
            They are:

            Would be great if you could please look at them once and let me know which is closer to being correct and what problems it still has? Thank you once again.

        3. Both of new pasted scripts do attach separate qdiscs for every vlan interface, as far as I understood. In this case every qdisc can limit it’s traffic independently of other qdiscs. So, no one will “know” how loaded other qdiscs/classes are.

          So, every of both should work; however all filters in a tree should have the same parent actually.

  2. Using protocol 802.1q in the following filter command does not work in Ubuntu 14.04 LTS. Any idea?

    tc filter add dev eth1 parent 1:0 prio 100 \
            protocol 802.1q \
            u32 match u16 0x0016 0x0fff at -4 \
            flowid 1:22

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.