diff options
Diffstat (limited to 'net/sched/cls_fw.c')
| -rw-r--r-- | net/sched/cls_fw.c | 135 | 
1 files changed, 61 insertions, 74 deletions
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 93b0a7b6f9b..861b03ccfed 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -29,71 +29,45 @@  #include <net/act_api.h>  #include <net/pkt_cls.h> -#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *)) +#define HTSIZE 256 -struct fw_head -{ -	struct fw_filter *ht[HTSIZE]; -	u32 mask; +struct fw_head { +	u32			mask; +	struct fw_filter	*ht[HTSIZE];  }; -struct fw_filter -{ +struct fw_filter {  	struct fw_filter	*next;  	u32			id;  	struct tcf_result	res;  #ifdef CONFIG_NET_CLS_IND -	char			indev[IFNAMSIZ]; +	int			ifindex;  #endif /* CONFIG_NET_CLS_IND */  	struct tcf_exts		exts;  }; -static const struct tcf_ext_map fw_ext_map = { -	.action = TCA_FW_ACT, -	.police = TCA_FW_POLICE -}; - -static __inline__ int fw_hash(u32 handle) +static u32 fw_hash(u32 handle)  { -	if (HTSIZE == 4096) -		return ((handle >> 24) & 0xFFF) ^ -		       ((handle >> 12) & 0xFFF) ^ -		       (handle & 0xFFF); -	else if (HTSIZE == 2048) -		return ((handle >> 22) & 0x7FF) ^ -		       ((handle >> 11) & 0x7FF) ^ -		       (handle & 0x7FF); -	else if (HTSIZE == 1024) -		return ((handle >> 20) & 0x3FF) ^ -		       ((handle >> 10) & 0x3FF) ^ -		       (handle & 0x3FF); -	else if (HTSIZE == 512) -		return (handle >> 27) ^ -		       ((handle >> 18) & 0x1FF) ^ -		       ((handle >> 9) & 0x1FF) ^ -		       (handle & 0x1FF); -	else if (HTSIZE == 256) { -		u8 *t = (u8 *) &handle; -		return t[0] ^ t[1] ^ t[2] ^ t[3]; -	} else -		return handle & (HTSIZE - 1); +	handle ^= (handle >> 16); +	handle ^= (handle >> 8); +	return handle % HTSIZE;  } -static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, +static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,  			  struct tcf_result *res)  { -	struct fw_head *head = (struct fw_head*)tp->root; +	struct fw_head *head = tp->root;  	struct fw_filter *f;  	int r;  	u32 id = skb->mark;  	if (head != NULL) {  		id &= head->mask; -		for (f=head->ht[fw_hash(id)]; f; f=f->next) { +		for (f = head->ht[fw_hash(id)]; f; f = f->next) {  			if (f->id == id) {  				*res = f->res;  #ifdef CONFIG_NET_CLS_IND -				if (!tcf_match_indev(skb, f->indev)) +				if (!tcf_match_indev(skb, f->ifindex))  					continue;  #endif /* CONFIG_NET_CLS_IND */  				r = tcf_exts_exec(skb, &f->exts, res); @@ -105,7 +79,8 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,  		}  	} else {  		/* old method */ -		if (id && (TC_H_MAJ(id) == 0 || !(TC_H_MAJ(id^tp->q->handle)))) { +		if (id && (TC_H_MAJ(id) == 0 || +			   !(TC_H_MAJ(id ^ tp->q->handle)))) {  			res->classid = id;  			res->class = 0;  			return 0; @@ -117,13 +92,13 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,  static unsigned long fw_get(struct tcf_proto *tp, u32 handle)  { -	struct fw_head *head = (struct fw_head*)tp->root; +	struct fw_head *head = tp->root;  	struct fw_filter *f;  	if (head == NULL)  		return 0; -	for (f=head->ht[fw_hash(handle)]; f; f=f->next) { +	for (f = head->ht[fw_hash(handle)]; f; f = f->next) {  		if (f->id == handle)  			return (unsigned long)f;  	} @@ -139,8 +114,7 @@ static int fw_init(struct tcf_proto *tp)  	return 0;  } -static inline void -fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) +static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f)  {  	tcf_unbind_filter(tp, &f->res);  	tcf_exts_destroy(tp, &f->exts); @@ -156,8 +130,8 @@ static void fw_destroy(struct tcf_proto *tp)  	if (head == NULL)  		return; -	for (h=0; h<HTSIZE; h++) { -		while ((f=head->ht[h]) != NULL) { +	for (h = 0; h < HTSIZE; h++) { +		while ((f = head->ht[h]) != NULL) {  			head->ht[h] = f->next;  			fw_delete_filter(tp, f);  		} @@ -167,14 +141,14 @@ static void fw_destroy(struct tcf_proto *tp)  static int fw_delete(struct tcf_proto *tp, unsigned long arg)  { -	struct fw_head *head = (struct fw_head*)tp->root; -	struct fw_filter *f = (struct fw_filter*)arg; +	struct fw_head *head = tp->root; +	struct fw_filter *f = (struct fw_filter *)arg;  	struct fw_filter **fp;  	if (head == NULL || f == NULL)  		goto out; -	for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) { +	for (fp = &head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {  		if (*fp == f) {  			tcf_tree_lock(tp);  			*fp = f->next; @@ -194,19 +168,19 @@ static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = {  };  static int -fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, -	struct nlattr **tb, struct nlattr **tca, unsigned long base) +fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, +	struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr)  { -	struct fw_head *head = (struct fw_head *)tp->root; +	struct fw_head *head = tp->root;  	struct tcf_exts e;  	u32 mask;  	int err; -	err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &fw_ext_map); +	tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE); +	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);  	if (err < 0)  		return err; -	err = -EINVAL;  	if (tb[TCA_FW_CLASSID]) {  		f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);  		tcf_bind_filter(tp, &f->res, base); @@ -214,12 +188,17 @@ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,  #ifdef CONFIG_NET_CLS_IND  	if (tb[TCA_FW_INDEV]) { -		err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV]); -		if (err < 0) +		int ret; +		ret = tcf_change_indev(net, tb[TCA_FW_INDEV]); +		if (ret < 0) { +			err = ret;  			goto errout; +		} +		f->ifindex = ret;  	}  #endif /* CONFIG_NET_CLS_IND */ +	err = -EINVAL;  	if (tb[TCA_FW_MASK]) {  		mask = nla_get_u32(tb[TCA_FW_MASK]);  		if (mask != head->mask) @@ -235,12 +214,13 @@ errout:  	return err;  } -static int fw_change(struct tcf_proto *tp, unsigned long base, +static int fw_change(struct net *net, struct sk_buff *in_skb, +		     struct tcf_proto *tp, unsigned long base,  		     u32 handle,  		     struct nlattr **tca, -		     unsigned long *arg) +		     unsigned long *arg, bool ovr)  { -	struct fw_head *head = (struct fw_head*)tp->root; +	struct fw_head *head = tp->root;  	struct fw_filter *f = (struct fw_filter *) *arg;  	struct nlattr *opt = tca[TCA_OPTIONS];  	struct nlattr *tb[TCA_FW_MAX + 1]; @@ -256,7 +236,7 @@ static int fw_change(struct tcf_proto *tp, unsigned long base,  	if (f != NULL) {  		if (f->id != handle && handle)  			return -EINVAL; -		return fw_change_attrs(tp, f, tb, tca, base); +		return fw_change_attrs(net, tp, f, tb, tca, base, ovr);  	}  	if (!handle) @@ -281,9 +261,10 @@ static int fw_change(struct tcf_proto *tp, unsigned long base,  	if (f == NULL)  		return -ENOBUFS; +	tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);  	f->id = handle; -	err = fw_change_attrs(tp, f, tb, tca, base); +	err = fw_change_attrs(net, tp, f, tb, tca, base, ovr);  	if (err < 0)  		goto errout; @@ -302,7 +283,7 @@ errout:  static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)  { -	struct fw_head *head = (struct fw_head*)tp->root; +	struct fw_head *head = tp->root;  	int h;  	if (head == NULL) @@ -328,11 +309,11 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)  	}  } -static int fw_dump(struct tcf_proto *tp, unsigned long fh, +static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,  		   struct sk_buff *skb, struct tcmsg *t)  { -	struct fw_head *head = (struct fw_head *)tp->root; -	struct fw_filter *f = (struct fw_filter*)fh; +	struct fw_head *head = tp->root; +	struct fw_filter *f = (struct fw_filter *)fh;  	unsigned char *b = skb_tail_pointer(skb);  	struct nlattr *nest; @@ -348,21 +329,27 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh,  	if (nest == NULL)  		goto nla_put_failure; -	if (f->res.classid) -		NLA_PUT_U32(skb, TCA_FW_CLASSID, f->res.classid); +	if (f->res.classid && +	    nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid)) +		goto nla_put_failure;  #ifdef CONFIG_NET_CLS_IND -	if (strlen(f->indev)) -		NLA_PUT_STRING(skb, TCA_FW_INDEV, f->indev); +	if (f->ifindex) { +		struct net_device *dev; +		dev = __dev_get_by_index(net, f->ifindex); +		if (dev && nla_put_string(skb, TCA_FW_INDEV, dev->name)) +			goto nla_put_failure; +	}  #endif /* CONFIG_NET_CLS_IND */ -	if (head->mask != 0xFFFFFFFF) -		NLA_PUT_U32(skb, TCA_FW_MASK, head->mask); +	if (head->mask != 0xFFFFFFFF && +	    nla_put_u32(skb, TCA_FW_MASK, head->mask)) +		goto nla_put_failure; -	if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) +	if (tcf_exts_dump(skb, &f->exts) < 0)  		goto nla_put_failure;  	nla_nest_end(skb, nest); -	if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0) +	if (tcf_exts_dump_stats(skb, &f->exts) < 0)  		goto nla_put_failure;  	return skb->len;  | 
