Filters are used to classify packets based on certain properties of the packet, e.g., TOS byte in the IP header, IP addresses, port numbers etc. It is invoked when the enqueue function of a queuing discipline is invoked. Queuing disciplines use filters to assign the incoming packets to one of its classes.
Filters can be maintained per class or per queuing discipline based on the design of the queuing discipline. As already mentioned in the previous section, filters are maintained in filter lists. The filter list is specified as a struct tcf_proto, in include/net/pkt_cls.h.
struct tcf_proto
{
/* Fast access part */
struct tcf_proto *next;
void *root;
int (*classify)(struct sk_buff*, struct tcf_proto*,
struct tcf_result *);
u32 protocol;
/* All the rest */
u32 prio;
u32 classid;
struct Qdisc *q;
void *data;
struct tcf_proto_ops *ops;
};
This structure is used to represent filter lists and is maintained by the classes and queuing disciplines. As an example, the cbq_class structure in net/sched/sch_cbq.c maintains the filter list by using the tcf_proto structure. The tcf_chain function on classes, described in the previous section, is used to return the anchor to a filter list, which can be used to traverse the filter list. Filter lists are ordered by priority, in ascending order. Also, the entries are keyed by the protocol for which they apply, e.g., IP, UDP etc. Filters for the same protocol on the same filter list must have different priority values. The protocol numbers are used in skb->protocol and they are defined in include/linux/if_ether.h.
Filters may also have an internal structure: it may control internal elements, which are referenced by a handle. These handles are 32-bit long, but are not divided into major and minor numbers like class IDs. Handle 0 refers to the filter itself. Like classes, filters also have an internal ID, which can be obtained with the help of a get function. The basic structure of filters is shown in Figure 4.
When the enqueue function of a queuing discipline is invoked, the tc_classify function in include/net/pkt_cls.h is invoked to classify the packet.
extern __inline__ int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
struct tcf_result *res)
{
int err = 0;
u32 protocol = skb->protocol;
for ( ; tp; tp = tp->next) {
if ((tp->protocol == protocol ||
tp->protocol == __constant_htons(ETH_P_ALL))
&& (err = tp->classify(skb, tp, res)) >= >0)
return err;
}
return -1;
}
As seen above in this function, the protocol to which the packet belongs to
is determined from skb->protocol. Once this is obtained, the filters
corresponding to this protocol are all applied in the order of priority.
Within each filter all the internal elements are traversed in an attempt to
classify the packet. Once the packet is classified, as already mentioned, the
enqueue function of the queuing discipline owned by the class is invoked.
This process of obtaining a match for the packet is shown in Figure 5.
Let us now discuss the functions that can be performed on the filters. The functions are defined in the tc_proto_ops structure in include/net/pkt_cls.h.