Re: Tc Filter - Port Ranges Calculate Mask Value

Linux Advanced Routing and Traffic Control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



anshul makkar wrote:
Hi,

I need to support port ranges in tc filter rules.

I know how to formulate the rule but , I am not able to understand how
to calculate the mask value for a perticular range so as to segregate
the port values that lie within this range .

I got the following sample

"tc filter add dev eth1 parent 1:1 protocol ip prio 10 u32 match ip
sport 0x1ae0 0x1ff0 flowid 1:10 This rule will match all ports from
6880 to 6895. "

This rule correctly matches port range from 6880 to 6895. But I am
unable to figure out , how the mask value has been calculated.

First you need to have a good understanding of logical operations (and specifically AND). If you do not - do some reading until you at least can give the answer to something like 0b101 & 0b100.

Once you understand this is very easy if you convert all the numbers to binary (we use 16 bits, since the port numbers are 16bit). You have:
result 0x1AE0 == 0b0001101011100000
mask   0x1FF0 == 0b0001111111110000

So what happens is:
1) u32 extracts the sport
2) ANDs the extracted value with 0b0001111111110000
3) compares the result to 0b0001101011100000

This means that anything from
0b0001101011100000 to 0b0001101011101111 inclusive will result in a match (since the mask essentially strips the last 4 bits). If you convert this range back to decimal you get:
0b0001101011100000 == 6880
0b0001101011101111 == 6895

I am picking up port ranges from GUI. So the range can be any and I
need to calculte mask value so as to find out which ports lie within
the entered range.

Unfortunately this is impossible.

As you probably noticed the range you are matching causes variation of only the last 4 bits in the entire number. The first bits always stay the same (0b000110101110xxxx). If your range is _continuous_ (i.e. without "holes" in it), and this is exactly your case - such a range _must_ be aligned so that the start has N least significant 0's and the end has N least significant 1's. What does this mean in practice:

The size of the range R must be of the form 2^N (to guarantee trailing 0's). In your case 6895 - 6880 + 1 = 16[*] which is 2^4.

The start of the range S must be larger then R and also divisible by it. In your case 6880 / 16 = 430.

Based on the above you can easily calculate the end of the range E:
E = S + R - 1[*]. In your case: 6880 + 16 - 1 = 6895.

You might wonder why for a continuous range the last N bits of the mask must be 0. Think of it in decimal terms: Assume we want the range of all numbers between 130 and 139. We can say - we change the last digit to 0, and we check if the number equals 130. If we want a range between 100 and 199 - no problem again. Now what if we want the range between 130 and 149? We can say - we change the last digit to 0 and check if the number equals 130 or 140. Well there - a single mask does not work :)

HTH
Peter

[*] You might be wondering where the +1/-1 comes from. Well take the numbers from 3 to 6 inclusive, and count how many there actually are. 6 - 3?
_______________________________________________
LARTC mailing list
LARTC@xxxxxxxxxxxxxxx
http://mailman.ds9a.nl/cgi-bin/mailman/listinfo/lartc

[Index of Archives]     [LARTC Home Page]     [Netfilter]     [Netfilter Development]     [Network Development]     [Bugtraq]     [GCC Help]     [Yosemite News]     [Linux Kernel]     [Fedora Users]
  Powered by Linux