net-sched: cls_flow: add perturbation support
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0c4c8cae44
								
							
						
					
					
						commit
						72d9794f44
					
				| @ -374,6 +374,7 @@ enum | ||||
| 	TCA_FLOW_ACT, | ||||
| 	TCA_FLOW_POLICE, | ||||
| 	TCA_FLOW_EMATCHES, | ||||
| 	TCA_FLOW_PERTURB, | ||||
| 	__TCA_FLOW_MAX | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -36,6 +36,8 @@ struct flow_filter { | ||||
| 	struct list_head	list; | ||||
| 	struct tcf_exts		exts; | ||||
| 	struct tcf_ematch_tree	ematches; | ||||
| 	struct timer_list	perturb_timer; | ||||
| 	u32			perturb_period; | ||||
| 	u32			handle; | ||||
| 
 | ||||
| 	u32			nkeys; | ||||
| @ -47,11 +49,9 @@ struct flow_filter { | ||||
| 	u32			addend; | ||||
| 	u32			divisor; | ||||
| 	u32			baseclass; | ||||
| 	u32			hashrnd; | ||||
| }; | ||||
| 
 | ||||
| static u32 flow_hashrnd __read_mostly; | ||||
| static int flow_hashrnd_initted __read_mostly; | ||||
| 
 | ||||
| static const struct tcf_ext_map flow_ext_map = { | ||||
| 	.action	= TCA_FLOW_ACT, | ||||
| 	.police	= TCA_FLOW_POLICE, | ||||
| @ -348,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, | ||||
| 		} | ||||
| 
 | ||||
| 		if (f->mode == FLOW_MODE_HASH) | ||||
| 			classid = jhash2(keys, f->nkeys, flow_hashrnd); | ||||
| 			classid = jhash2(keys, f->nkeys, f->hashrnd); | ||||
| 		else { | ||||
| 			classid = keys[0]; | ||||
| 			classid = (classid & f->mask) ^ f->xor; | ||||
| @ -369,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| static void flow_perturbation(unsigned long arg) | ||||
| { | ||||
| 	struct flow_filter *f = (struct flow_filter *)arg; | ||||
| 
 | ||||
| 	get_random_bytes(&f->hashrnd, 4); | ||||
| 	if (f->perturb_period) | ||||
| 		mod_timer(&f->perturb_timer, jiffies + f->perturb_period); | ||||
| } | ||||
| 
 | ||||
| static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { | ||||
| 	[TCA_FLOW_KEYS]		= { .type = NLA_U32 }, | ||||
| 	[TCA_FLOW_MODE]		= { .type = NLA_U32 }, | ||||
| @ -381,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { | ||||
| 	[TCA_FLOW_ACT]		= { .type = NLA_NESTED }, | ||||
| 	[TCA_FLOW_POLICE]	= { .type = NLA_NESTED }, | ||||
| 	[TCA_FLOW_EMATCHES]	= { .type = NLA_NESTED }, | ||||
| 	[TCA_FLOW_PERTURB]	= { .type = NLA_U32 }, | ||||
| }; | ||||
| 
 | ||||
| static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| @ -394,6 +404,7 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| 	struct tcf_exts e; | ||||
| 	struct tcf_ematch_tree t; | ||||
| 	unsigned int nkeys = 0; | ||||
| 	unsigned int perturb_period = 0; | ||||
| 	u32 baseclass = 0; | ||||
| 	u32 keymask = 0; | ||||
| 	u32 mode; | ||||
| @ -442,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| 			mode = nla_get_u32(tb[TCA_FLOW_MODE]); | ||||
| 		if (mode != FLOW_MODE_HASH && nkeys > 1) | ||||
| 			goto err2; | ||||
| 
 | ||||
| 		if (mode == FLOW_MODE_HASH) | ||||
| 			perturb_period = f->perturb_period; | ||||
| 		if (tb[TCA_FLOW_PERTURB]) { | ||||
| 			if (mode != FLOW_MODE_HASH) | ||||
| 				goto err2; | ||||
| 			perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ; | ||||
| 		} | ||||
| 	} else { | ||||
| 		err = -EINVAL; | ||||
| 		if (!handle) | ||||
| @ -455,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| 		if (mode != FLOW_MODE_HASH && nkeys > 1) | ||||
| 			goto err2; | ||||
| 
 | ||||
| 		if (tb[TCA_FLOW_PERTURB]) { | ||||
| 			if (mode != FLOW_MODE_HASH) | ||||
| 				goto err2; | ||||
| 			perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ; | ||||
| 		} | ||||
| 
 | ||||
| 		if (TC_H_MAJ(baseclass) == 0) | ||||
| 			baseclass = TC_H_MAKE(tp->q->handle, baseclass); | ||||
| 		if (TC_H_MIN(baseclass) == 0) | ||||
| @ -467,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| 
 | ||||
| 		f->handle = handle; | ||||
| 		f->mask	  = ~0U; | ||||
| 
 | ||||
| 		get_random_bytes(&f->hashrnd, 4); | ||||
| 		f->perturb_timer.function = flow_perturbation; | ||||
| 		f->perturb_timer.data = (unsigned long)f; | ||||
| 		init_timer_deferrable(&f->perturb_timer); | ||||
| 	} | ||||
| 
 | ||||
| 	tcf_exts_change(tp, &f->exts, &e); | ||||
| @ -495,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, | ||||
| 	if (baseclass) | ||||
| 		f->baseclass = baseclass; | ||||
| 
 | ||||
| 	f->perturb_period = perturb_period; | ||||
| 	del_timer(&f->perturb_timer); | ||||
| 	if (perturb_period) | ||||
| 		mod_timer(&f->perturb_timer, jiffies + perturb_period); | ||||
| 
 | ||||
| 	if (*arg == 0) | ||||
| 		list_add_tail(&f->list, &head->filters); | ||||
| 
 | ||||
| @ -512,6 +547,7 @@ err1: | ||||
| 
 | ||||
| static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f) | ||||
| { | ||||
| 	del_timer_sync(&f->perturb_timer); | ||||
| 	tcf_exts_destroy(tp, &f->exts); | ||||
| 	tcf_em_tree_destroy(tp, &f->ematches); | ||||
| 	kfree(f); | ||||
| @ -532,11 +568,6 @@ static int flow_init(struct tcf_proto *tp) | ||||
| { | ||||
| 	struct flow_head *head; | ||||
| 
 | ||||
| 	if (!flow_hashrnd_initted) { | ||||
| 		get_random_bytes(&flow_hashrnd, 4); | ||||
| 		flow_hashrnd_initted = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	head = kzalloc(sizeof(*head), GFP_KERNEL); | ||||
| 	if (head == NULL) | ||||
| 		return -ENOBUFS; | ||||
| @ -605,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh, | ||||
| 	if (f->baseclass) | ||||
| 		NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass); | ||||
| 
 | ||||
| 	if (f->perturb_period) | ||||
| 		NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ); | ||||
| 
 | ||||
| 	if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0) | ||||
| 		goto nla_put_failure; | ||||
| #ifdef CONFIG_NET_EMATCH | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user