From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Rabbitson Date: Tue, 23 Oct 2007 14:38:12 +0000 Subject: Re: [LARTC] Tc Filter - Port Ranges Calculate Mask Value Message-Id: <471E0754.3050408@rabbit.us> List-Id: References: In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: lartc@vger.kernel.org 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@mailman.ds9a.nl http://mailman.ds9a.nl/cgi-bin/mailman/listinfo/lartc