Викладене нижче перевірялося для 2.6.26 та 2.6.32. Обережно, у 2.6.31, ніби, є нюанси.
Зауважу, що я не дивився у cls_u32.c
тощо — і можу капітально помилятися .)
Отже, спершу трохи про «логіку фільтрування»:
- Коли ми пишемо
tc filter ... protocol <proto> u32 match u<length> <value> <mask> at <offset>
— ми маємо на увазі зміщення «від позиції НУЛЬ», ядро має на увазі «від початку IP пакета». - Якщо у Ethernet пакеті немає IP — можна фільтрувати лише всі пакети для вибраного протоколу (як, наприклад, тут фільтрують всі STP пакети), а не по масці/зміщенню. «Нуля» в такому пакеті, схоже, немає.
- У «дереві» фільтрів мають бути лише фільтри для одного і того самого протоколу. Якщо хочеться для різних, то можна щось придумати, але про це іншим разом.
Тепер — «демонстративний» (але цілком робочий) скрипт, яким можна фільтрувати влани 22 і 310 у різні класи (мова, як завжди, про linux bridge із сконфігурованим шейпером; при цьому крізь цей комутатор бігають 802.1q tagged пакети):
# 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 |
Там вказано `at -4
` — це тому, що у даній ситуації після мітки 802.1q іде «стандартна» мітка ethertype, двобайтна. Так, у кожній конкретній ситуації, на жаль, треба знати «хто в рукавичці живе».
Можливо, тут було б краще написати `match u16 0x8100 0xffff at -6 match u16 0x0136 0x0fff at -4
`, для переконливості. Можна навіть шукати у ethertype саме IP (hex 6) тощо, але якщо саме для переконливості .)
Ще одна примітка стосовно protocol <proto>
Часто виникають питання «чому protocol ip
не фільтрує пакети з 8021q мітками?» тощо.
Справа в тому, що, наприклад, у пакеті Ethernet тип протоколу завжди у певному місці:
- для немічених пакетів (Ethernet_II) після адреси відправника завжди іде тип протоколу;
- для мічених пакетів після MAC адреси відправника завжди іде мітка 802.1q, перші два байти якої містять 0x8100 — і є також, де факто, типом протоколу, IEEE 802.1Q (так, за цією міткою іде ethertype, але на внутрішні заголовки «фільтрувач» вже не дивиться).
Отже, фактично, коли ми пишемо, наприклад, protocol arp
— фільтр перевіряє значення у перших двох байтах після адреси відправника (а це завжди фіксоване зміщення від початку Ethernet кадра) на рівність 0x0806
.
Іншими словами — фільтр завжди перевіряє значення тих двох байтів на рівність чисельному значенню вказаного протоколу. На інші байти, перевіряючи тип протоколу, не дивиться.
А «нуль» бере від початку пакета IP. Якщо такий є.
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.
Sorry, I am not sure that I understand what you’d like to achieve. And what is inter VLAN data?
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?
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.
Oh Okay. I have tried to do this. But I think I am doing something wrong.
Here is my script: http://justpaste.it/1nvj
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.
Here is another smaller script for a smaller network: http://justpaste.it/1nwo
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.
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:
http://justpaste.it/1o0v
http://justpaste.it/1o0u
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.
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.
Alright, thank you so much once again :)
Using protocol 802.1q in the following filter command does not work in Ubuntu 14.04 LTS. Any idea?
I guess this discussion may help you.