Whole document tree 12. Advanced filters for (re-)classifying packetsAs explained in the section on classful queueing disciplines, filters are needed to classify packets into any of the sub-queues. These filters are called from within the classful qdisc. Here is an incomplete list of classifiers available:
Note that in general there are many ways in which you can classify packet and that it generally comes down to preference as to which system you wish to use. Classifiers in general accept a few arguments in common. They are listed here for convenience:
All the following sections will assume you are trying to shape the traffic
going to
12.1 The "u32" classifierThe U32 filter is the most advanced filter available in the current implementation. It entirely based on hashing tables, which make it robust when there are many filter rules. In its simplest form the U32 filter is a list of records, each consisting of two fields: a selector and an action. The selectors, described below, are compared with the currently processed IP packet until the first match occurs, and then the associated action is performed. The simplest type of action would be directing the packet into defined CBQ class. The commandline of
The The options decribed above apply to all filters, not only U32.
U32 selectorThe U32 selector contains definition of the pattern, that will be matched to the currently processed packet. Precisely, it defines which bits are to be matched in the packet header and nothing more, but this simple method is very powerful. Let's take a look at the following examples, taken directly from a pretty complex, real-world filter:
For now, leave the first line alone - all these parameters describe
the filter's hash tables. Focus on the selector line, containing
The
Having understood all the above, we will find the following selector
quite easy to read:
General selectorsGeneral selectors define the pattern, mask and offset the pattern will be matched to the packet contents. Using the general selectors you can match virtually any single bit in the IP (or upper layer) header. They are more difficult to write and read, though, than specific selectors that described below. The general selector syntax is:
One of the keywords
Some examples:
Packet will match to this rule, if its time to live (TTL) is 64. TTL is the field starting just after 8-th byte of the IP header.
FIXME: it has been pointed out that this syntax does not work currently. Stuart DJ Lynne uses this to match ACKs:
This rule will only match TCP packets with ACK bit set. Here we can see
an example of using two selectors, the final result will be logical AND
of their results. If we take a look at TCP header diagram, we can see
that the ACK bit is second older bit (0x10) in the 14-th byte of the TCP
header (
Specific selectorsThe following table contains a list of all specific selectors
the author of this section has found in the FIXME: table placeholder - the table is in separate file ,,selector.html'' FIXME: it's also still in Polish :-( FIXME: must be sgml'ized Some examples:
The above rule will match packets which have the TOS field set to 0x10.
The TOS field starts at second byte of the packet and is one byte big,
so we could write an equivalent general selector:
12.2 The "route" classifier
This classifier filters based on the results of the routing tables. When a packet that is traversing through the classes reaches one that is marked with the "route" filter, it splits the packets up based on information in the routing table.
Here we add a route classifier onto the parent node 1:0 with priority 100. When a packet reaches this node (which, since it is the root, will happen immediately) it will consult the routing table and if one matches will send it to the given class and give it a priority of 100. Then, to finally kick it into action, you add the appropriate routing entry: The trick here is to define 'realm' based on either destination or source. The way to do it is like this:
For instance, we can define our destination network 192.168.10.0 with a realm number 10:
When adding route filters, we can use realm numbers to represent the networks or hosts and specify how the routes match the filters.
The above rule says packets going to the network 192.168.10.0 match class id 1:10. Route filter can also be used to match source routes. For example, there is a subnetwork attached to the Linux router on eth2.
Here the filter specifies that packets from the subnetwork 192.168.2.0 (realm 2) will match class id 1:2.
12.3 Policing filtersTo make even more complicated setups possible, you can have filters that only match up to a certain bandwidth. You can declare a filter to entirely cease matching above a certain rate, or only to not match only the bandwidth exceeding a certain rate. So if you decided to police at 4mbit/s, but 5mbit/s of traffic is present, you can stop matching either the entire 5mbit/s, or only not match 1mbit/s, and do send 4mbit/s to the configured class. If bandwidth exceeds the configured rate, you can drop a packet, reclassify it, or see if another filter will match it.
Ways to policeThere are basically two ways to police. If you compiled the kernel with 'Estimators', the kernel can measure for each filter how much traffic it is passing, more or less. These estimators are very easy on the CPU, as they simply count 25 times per second how many data has been passed, and calculate the bitrate from that. The other way works again via a Token Bucket Filter, this time living within your filter. The TBF only matches traffic UP TO your configured bandwidth, if more is offered, only the excess is subject to the configured overlimit action.
With the kernel estimatorThis is very simple and has only one parameter: avrate. Either the flow remains below avrate, and the filter classifies the traffic to the classid configured, or your rate exceeds it in which case the specified action is taken, which is 'reclassify' by default. The kernel uses an Exponential Weighted Moving Average for your bandwidth which makes it less sensitive to short bursts.
With Token Bucket FilterUses the following parameters:
Which behave identical to those described in the Token Bucket Filter section.
Overlimit actionsIf your filter decides that it is overlimit, it can take 'actions'. Currently, three actions are available:
ExamplesThe only real example known is mentioned in the 'Protecting your host from SYN floods' section. FIXME: if you have used this, please share your experience with us
12.4 Hashing filters for very fast massive filteringIf you have a need for thousands of rules, for example if you have a lot of clients or computers, all with different QoS specifications, you may find that the kernel spends a lot of time matching all those rules. By default, all filters reside in one big chain which is matched in descending order of priority. If you have 1000 rules, 1000 checks may be needed to determine what to do with a packet. Matching would go much quicker if you would have 256 chains with each four rules - if you could divide packets over those 256 chains, so that the right rule will be there. Hashing makes this possible. Let's say you have 1024 cablemodem customers in your network, with IP addresses ranging from 1.2.0.0 to 1.2.3.255, and each has to go in another bin, for example 'lite', 'regular' and 'premium'. You would then have 1024 rules like this:
# tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.0.0 classid 1:1 # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.0.1 classid 1:1 ... # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.3.254 classid 1:3 # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.3.255 classid 1:2 To speed this up, we can use the last part of the IP address as a 'hash key'. We then get 256 tables, the first of which looks like this: # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.0.0 classid 1:1 # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.1.0 classid 1:1 # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.2.0 classid 1:3 # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.3.0 classid 1:2 The next one starts like this: # tc filter add dev eth1 parent 1:0 protocol ip prio 100 match ip src \ 1.2.0.1 classid 1:1 ... This way, only four checks are needed at most, two on average. Configuration is pretty complicated, but very worth it by the time you have this many rules. First we make a filter root, then we create a table with 256 entries: # tc filter add dev eth1 parent 1:0 prio 5 protocol ip u32 # tc filter add dev eth1 parent 1:0 prio 5 handle 2: u32 divisor 256 Now we add some rules to entries in the created table:
# tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: \ match ip src 1.2.0.123 flowid 1:1 # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: \ match ip src 1.2.1.123 flowid 1:2 # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: \ match ip src 1.2.3.123 flowid 1:3 # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: \ match ip src 1.2.4.123 flowid 1:2This is entry 123, which contains matches for 1.2.0.123, 1.2.1.123, 1.2.2.123, 1.2.3.123, and sends them to 1:1, 1:2, 1:3 and 1:2 respectively. Note that we need to specify our hash bucket in hex, 0x7b is 123. Next create a 'hashing filter' that directs traffic to the right entry in the hashing table: # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 800:: \ match ip src 1.2.0.0/16 \ hashkey mask 0x000000ff at 12 \ link 2:Ok, some numbers need explaining. The default hash table is called 800:: and all filtering starts there. Then we select the source address, which lives as position 12, 13, 14 and 15 in the IP header, and indicate that we are only interested in the last part. This we send to hash table 1:, which we created earlier. It is quite complicated, but it does work in practice and performance will be staggering. Note that this example could be improved to the ideal case where each chain contains 1 filter! Next Previous Contents |