Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2188587
  • 博文数量: 230
  • 博客积分: 9346
  • 博客等级: 中将
  • 技术积分: 3418
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-26 01:58
文章分类

全部博文(230)

文章存档

2015年(30)

2014年(7)

2013年(12)

2012年(2)

2011年(3)

2010年(42)

2009年(9)

2008年(15)

2007年(74)

2006年(36)

分类:

2007-06-02 11:25:47

 

Filters provide the method for checking and tagging packets. These tags can then be used by the classes to determine the membership in the class. Filters may be combined arbitrarily with queuing disciplines. Thinking again about the store analogy, the point where a single line splits into several parallel lines indicates the location of a filter application. The actual split mechanism could be a class decision based on an earlier filter tag. Consider the case where everybody who has less than five items and wants to pay cash will be put into the "less than five items & pays cash" line. There is a filter entity that checks each person and if they are a "less than 5 & cash," they are given a tag. Either then or later on another entity, think of class or RPDB, moves the person to another line based on the tag.

Now that you have an idea of how the basic set up works within the Linux DiffServ mechanism, you decide to play with using the ingress qdisc for routing tags.

In order to test this model you decide to use the 2.4 kernel with the classid-to-mark DiffServ extension. This extension will be part of the regular DiffServ code within the 2.4 series kernels. It provides an internal conversion map between a classid tag from a filter to a fwmark. In this way you can use the ultimate packet tagging power tool, the u32 classifier.

You go to router1 and make sure it is running a 2.4 kernel without any of the NetFilter architecture turned on. Then you set up the ingress qdisc on the Network B interface, eth1:

tc qdisc add dev eth1 handle ffff: ingress

Now you need to consider how the u32 filter works.

The most powerful filter available in Linux is the u32 filter. This filter allows you to actually make a choice based on any data within the packet itself. As with all of the DiffServ implementation for Linux you will use the tc utility from IPROUTE2. In this book the complete syntax and use of the tc utility will not be covered, Please refer to the IPROUTE2 documentation for details. Looking at the tc utility help for this filter gives a faint glimpse of this power:

tc filter add u32 help
Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]
     [ police POLICE_SPEC ] [ offset OFFSET_SPEC]
     [ ht HTID ] [ hashkey HASHKEY_SPEC ]
     [ sample SAMPLE ] or u32 divisor DIVISOR

Where: SELECTOR := SAMPLE SAMPLE ...
     SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS
     FILTERID := X:Y:Z

The actual heavy-duty selection mechanisms are in the SELECTOR. But all you are told is that the SELECTOR is a series of SAMPLE sections. And nowhere are you told what the SAMPLE_ARGS would have to be. But by reading through the source and looking around the Internet you amass some of the needed information for using u32 in the context of this book.

The u32 selectors are simply binary patterns with binary masks that are used to match any set of data within the packet. The most common usage is to perform matches within the packet header. There are two main types of selectors that are deeply interrelated. The human interface selectors are those that are specified using linguistic aliases for the actions specifying specific protocol and field matches, such as the IP destination address or protocol 4. Then there are the bitwizard selectors that are specified in terms of the bit pattern length. These selectors are the u32, u16, and u8 selectors themselves. Within the tc utility all of the human selectors are translated into bitwizard selectors.

For example, if you specify matching the human selector "match ip tos 0x10 0xff," the tc utility actually matches against the packet as "match u8 0x10 0xff at 1." Note from the human specification that you are trying to match TOS 10h. Now the TOS field within an IP header is one byte long, which is 8 bits and thus a u8 general length selector, and located at a one byte offset into the IP packet. Thus you can specify matching a one byte set of bits with a full mask located at one byte into the packet header, which is "match u8 0x10 0xff at 1." Or you can say "match ip tos 0x10 0xff."

Now you can see why this is bitwizard work. There is no man page or other help, you have to know your packet binary structure and hexadecimal conversions, and even the human interface is somewhat cryptic. But the power available using this filter is incredible. The ability to specify any binary data pattern means that you can pick out individual data streams for routing. Suppose that you are browsing several different Web sites from your machine. To the router, all the data streams look as though they originate from the same address to the same protocol. By using u32, you could look for data patterns that indicate SSL encryption on either the sent or returned packets and route them through a secure link. And that is without looking at the header at all.

Additionally, you can look for certain types of patterns by using the mask portion of the specification. In the TOS example from the previous paragraph you were looking for exactly TOS 16 decimal, which is 0x10 hex. But what if you wanted to consider all TOS decimal levels from 16 through 19 inclusive? You would just change the mask portion of the specification and would then have a command like match u8 0x10 0xf3 at 1. Thus between the specification of the length of pattern, the pattern itself, and the offset into the packet you can isolate any unique portion of the packet. You can also stack several selectors together to obtain any combination of selections you require.

As you work with the u32 filter you note some tricky behaviors on the part of the selectors. You consider the filter snippet match tcp src 0x1234. This human filter is coded by tc as match u16 0x1234 0xffff nexthdr+0, which means to match a 16-bit 0x1234 pattern within the internal protocol header at offset 0. But what is contained within the offset 0 of the internal protocol header is simply the IPv4 source port for the packet.

Thus, if you were expecting the match tcp part to only match TCP packets, you would be surprised. The filter snippet will actually match UDP packets as well because they also have the source port contained at offset 0 within the internal protocol header. If you want to specify only matching TCP packets with source port 0x1234, then you have to stack up selectors. You would then use match tcp src 0x1234 match ip protocol 0x6. The additional selector match ip protocol 0x6 states to also only look at packets of protocol 6 hex, which is TCP. Here is the list of u32 selectors as known at this time. Be sure to read through and for details about the IPv4 Header field definitions.

match src
match dst
match ip tos
match ip dsfield
match ip precedence
match ip ihl <8 bit ip header length in hex>
match ip protocol
match ip nofrag     = only match non fragmented ip packets
match ip firstfrag     = only match first ip fragment
match ip df     = IP Data Fragments (ie: !firstfrag ??)
match ip mf     = Matching Fragments (related to ??)
match sport
match dport
match ip icmp_type
match ip icmp_code
match icmp type
match icmp code

As you can see there are many ways in which you can look into the packet headers and determine your selection. When you combine these facilities with the ability to also specify any exact bit pattern at any offset into the packet that you want, you can see the power of the Linux DiffServ architecture.

Within the u32 filter there is another kind of selector available, the sample command. The sample command takes the same kinds of arguments as match. However, the sample command normally takes only a single argument for type. So where you would use match ip protocol 0x6 0xff, you can use sample tcp instead.

With your newly acquired knowledge of the u32 filter usage you first decide to try a simple test of the ingress filter. You know you have the ingress qdisc set up on router1 on the Network B interface. You decide to try tagging all incoming packets from 10.1.1.0/24 with classid 1. Then you will use a rule that sends those packets into table 1 and assign them additionally to realms 3/4 for tracking. You end up with the following sequence of commands:

tc filter add dev eth1 parent ffff: protocol ip prio 1 u32 \
     match ip src 10.1.1.0/24 classid :1

ip rule add fwmark 1 table 1 prio 15000 realms 3/4
ip route add default via 192.168.1.1 table 1 src 192.168.1.254
ip route flush cache

Then you run a ping from net1 to host1 and look at the output of the qdisc statistics and the realms:

[root@router1 /root]# tc -s qdisc ls dev eth1
qdisc ingress ffff: ----------------
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)

[root@router1 /root]# rtacct 3
Realm     BytesTo     PktsTo     BytesFrom     PktsFrom
3     0     0     504     6

[root@router1 /root]# rtacct 4
Realm     BytesTo     PktsTo     BytesFrom     PktsFrom
4     504     6     0     0

You note that the qdisc statistics do not show any traffic. That is expected because you are not using the classid anywhere on egress for DiffServ. You are only using the ingress qdisc to be able to tag packets with the u32 filter. You know that the filter is working because you have your ping packets showing up balanced on the realms. The only way the realms would list the packets is if they were acted upon by that rule. So your quick test was successful.







阅读(3308) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~