You can use ematch - extended match - instead of u32 filter, which supports "less than" and "greater than" comparisons.
Have a look at the man page.
The following matches packets with source port in the range 70 - 90 (excluding)
tc filter add dev eth0 parent 1: protocol ip prio 1 basic match
"cmp(u16 at 0 layer transport gt 70) and cmp(u16 at 0 layer transport
lt 90)" flowid 1:3
u32 match ip sport 4096 0xf000 = sport 4096-8191
u32 match ip sport 8192 0xe000 = sport 8192-16383
0xf000/0xe000 is the mask. The word extracted from the packet is bit-wise with this mask before comparison.
value = 0001000000000000
mask = 1111000000000000
start = 0001000000000000
end = 0001111111111111
Also you can create many filter for one classid:
tc filter add dev eth0 parent 1:0 prio 3 protocol ip u32 match ip protocol 6 0xff match ip sport 10000 0xffff classid 1:13
tc filter add dev eth0 parent 1:0 prio 3 protocol ip u32 match ip protocol 6 0xff match ip sport 10001 0xffff classid 1:13
tc filter add dev eth0 parent 1:0 prio 3 protocol ip u32 match ip protocol 6 0xff match ip sport 10002 0xffff classid 1:13
For your example, your need create several 'tc filter':
first: sport 10000 0xfff0 (10000-10015)
second: sport 10016 0xffe0 (10016-10047)
.............
etc.
10000=10011100010000
0010011100010000
|
first not zero
1111111111111111
mask
1111111111110000=0xfff0
[Basically take the first number in the range (in this example 10,000) and
convert it to binary ( 0010011100010000 ); then scan this binary number from right to left until you encounter the 1st non 0 bit; then make the bits from the left of that bit all into 1's inclusive, and all the bits to the right of it to zeros. That is how you come out to 0xfff0 as the mask.]
import logging
logging.getLogger().setLevel(logging.DEBUG)
fp = 20001 # From port
tp = 25000 # to port
dev = 'ifb0' # dev to add filter rule to
flow = '1:10' # flow id to set
def find_lsm(p,o=1):
m = o
i = 1
while(True):
if(p & m > 0):
return m,i
m = m << 1
i += 1
l = 0xffff
ms = 2
me = None
cp = fp
i = 0
t = ''
while(True):
cm,s = find_lsm(cp)
if cm >= tp:
break
e = cp | cm - 1
m = l & (l << s -1)
logging.info('Range %i - %i, mask %08x', cp, e, m )
i += 1
t += "tc filter add dev {} parent 1: prio {} protocol ip u32 match ip protocol 17 0xff match ip dport {} 0x{:0>8x} flowid {}\n".format(dev,i,cp,m,flow)
cp += cm
print t
You can use ematch - extended match - instead of u32 filter, which supports "less than" and "greater than" comparisons. Have a look at the man page.
The following matches packets with source port in the range 70 - 90 (excluding)
You can use mask, but it difficult:
0xf000/0xe000 is the mask. The word extracted from the packet is bit-wise with this mask before comparison.
Also you can create many filter for one classid:
For your example, your need create several 'tc filter':
etc.
[Basically take the first number in the range (in this example 10,000) and convert it to binary ( 0010011100010000 ); then scan this binary number from right to left until you encounter the 1st non 0 bit; then make the bits from the left of that bit all into 1's inclusive, and all the bits to the right of it to zeros. That is how you come out to 0xfff0 as the mask.]
I made a script to do what @alvosu described for anyone interested.
http://blog.roeften.com/2017/01/mask-calculator.html
Currently it will include more ports on the right of the range.
The fiddle is at http://jsfiddle.net/hp6dfnvg/13/
A messy python implementation as well:
I've created this simple script on my blog to create the masks for any port range...
I got tired of googling it just to find the wrong ways to do it... Enjoy!
http://marcelustrojahn.blogspot.com/2011/06/u32-port-masks_14.htmlsite is down :(