aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-14 23:36:32 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-14 23:36:32 -0400
commit72d9794f444734af56ef12833b496326643e2964 (patch)
treeaf0e5654cf7fc9a4801edd97fab3f2d6e5039b30
parent0c4c8cae44e9d71afd3031c1e8739bd398a831a8 (diff)
net-sched: cls_flow: add perturbation support
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/pkt_cls.h1
-rw-r--r--net/sched/cls_flow.c52
2 files changed, 44 insertions, 9 deletions
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 99efbed81fa2..7cf7824df778 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -374,6 +374,7 @@ enum
374 TCA_FLOW_ACT, 374 TCA_FLOW_ACT,
375 TCA_FLOW_POLICE, 375 TCA_FLOW_POLICE,
376 TCA_FLOW_EMATCHES, 376 TCA_FLOW_EMATCHES,
377 TCA_FLOW_PERTURB,
377 __TCA_FLOW_MAX 378 __TCA_FLOW_MAX
378}; 379};
379 380
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 971b867e0484..8f63a1a94014 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -36,6 +36,8 @@ struct flow_filter {
36 struct list_head list; 36 struct list_head list;
37 struct tcf_exts exts; 37 struct tcf_exts exts;
38 struct tcf_ematch_tree ematches; 38 struct tcf_ematch_tree ematches;
39 struct timer_list perturb_timer;
40 u32 perturb_period;
39 u32 handle; 41 u32 handle;
40 42
41 u32 nkeys; 43 u32 nkeys;
@@ -47,11 +49,9 @@ struct flow_filter {
47 u32 addend; 49 u32 addend;
48 u32 divisor; 50 u32 divisor;
49 u32 baseclass; 51 u32 baseclass;
52 u32 hashrnd;
50}; 53};
51 54
52static u32 flow_hashrnd __read_mostly;
53static int flow_hashrnd_initted __read_mostly;
54
55static const struct tcf_ext_map flow_ext_map = { 55static const struct tcf_ext_map flow_ext_map = {
56 .action = TCA_FLOW_ACT, 56 .action = TCA_FLOW_ACT,
57 .police = TCA_FLOW_POLICE, 57 .police = TCA_FLOW_POLICE,
@@ -348,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
348 } 348 }
349 349
350 if (f->mode == FLOW_MODE_HASH) 350 if (f->mode == FLOW_MODE_HASH)
351 classid = jhash2(keys, f->nkeys, flow_hashrnd); 351 classid = jhash2(keys, f->nkeys, f->hashrnd);
352 else { 352 else {
353 classid = keys[0]; 353 classid = keys[0];
354 classid = (classid & f->mask) ^ f->xor; 354 classid = (classid & f->mask) ^ f->xor;
@@ -369,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
369 return -1; 369 return -1;
370} 370}
371 371
372static void flow_perturbation(unsigned long arg)
373{
374 struct flow_filter *f = (struct flow_filter *)arg;
375
376 get_random_bytes(&f->hashrnd, 4);
377 if (f->perturb_period)
378 mod_timer(&f->perturb_timer, jiffies + f->perturb_period);
379}
380
372static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { 381static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
373 [TCA_FLOW_KEYS] = { .type = NLA_U32 }, 382 [TCA_FLOW_KEYS] = { .type = NLA_U32 },
374 [TCA_FLOW_MODE] = { .type = NLA_U32 }, 383 [TCA_FLOW_MODE] = { .type = NLA_U32 },
@@ -381,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
381 [TCA_FLOW_ACT] = { .type = NLA_NESTED }, 390 [TCA_FLOW_ACT] = { .type = NLA_NESTED },
382 [TCA_FLOW_POLICE] = { .type = NLA_NESTED }, 391 [TCA_FLOW_POLICE] = { .type = NLA_NESTED },
383 [TCA_FLOW_EMATCHES] = { .type = NLA_NESTED }, 392 [TCA_FLOW_EMATCHES] = { .type = NLA_NESTED },
393 [TCA_FLOW_PERTURB] = { .type = NLA_U32 },
384}; 394};
385 395
386static int flow_change(struct tcf_proto *tp, unsigned long base, 396static 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,
394 struct tcf_exts e; 404 struct tcf_exts e;
395 struct tcf_ematch_tree t; 405 struct tcf_ematch_tree t;
396 unsigned int nkeys = 0; 406 unsigned int nkeys = 0;
407 unsigned int perturb_period = 0;
397 u32 baseclass = 0; 408 u32 baseclass = 0;
398 u32 keymask = 0; 409 u32 keymask = 0;
399 u32 mode; 410 u32 mode;
@@ -442,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
442 mode = nla_get_u32(tb[TCA_FLOW_MODE]); 453 mode = nla_get_u32(tb[TCA_FLOW_MODE]);
443 if (mode != FLOW_MODE_HASH && nkeys > 1) 454 if (mode != FLOW_MODE_HASH && nkeys > 1)
444 goto err2; 455 goto err2;
456
457 if (mode == FLOW_MODE_HASH)
458 perturb_period = f->perturb_period;
459 if (tb[TCA_FLOW_PERTURB]) {
460 if (mode != FLOW_MODE_HASH)
461 goto err2;
462 perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
463 }
445 } else { 464 } else {
446 err = -EINVAL; 465 err = -EINVAL;
447 if (!handle) 466 if (!handle)
@@ -455,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
455 if (mode != FLOW_MODE_HASH && nkeys > 1) 474 if (mode != FLOW_MODE_HASH && nkeys > 1)
456 goto err2; 475 goto err2;
457 476
477 if (tb[TCA_FLOW_PERTURB]) {
478 if (mode != FLOW_MODE_HASH)
479 goto err2;
480 perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
481 }
482
458 if (TC_H_MAJ(baseclass) == 0) 483 if (TC_H_MAJ(baseclass) == 0)
459 baseclass = TC_H_MAKE(tp->q->handle, baseclass); 484 baseclass = TC_H_MAKE(tp->q->handle, baseclass);
460 if (TC_H_MIN(baseclass) == 0) 485 if (TC_H_MIN(baseclass) == 0)
@@ -467,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
467 492
468 f->handle = handle; 493 f->handle = handle;
469 f->mask = ~0U; 494 f->mask = ~0U;
495
496 get_random_bytes(&f->hashrnd, 4);
497 f->perturb_timer.function = flow_perturbation;
498 f->perturb_timer.data = (unsigned long)f;
499 init_timer_deferrable(&f->perturb_timer);
470 } 500 }
471 501
472 tcf_exts_change(tp, &f->exts, &e); 502 tcf_exts_change(tp, &f->exts, &e);
@@ -495,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
495 if (baseclass) 525 if (baseclass)
496 f->baseclass = baseclass; 526 f->baseclass = baseclass;
497 527
528 f->perturb_period = perturb_period;
529 del_timer(&f->perturb_timer);
530 if (perturb_period)
531 mod_timer(&f->perturb_timer, jiffies + perturb_period);
532
498 if (*arg == 0) 533 if (*arg == 0)
499 list_add_tail(&f->list, &head->filters); 534 list_add_tail(&f->list, &head->filters);
500 535
@@ -512,6 +547,7 @@ err1:
512 547
513static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f) 548static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f)
514{ 549{
550 del_timer_sync(&f->perturb_timer);
515 tcf_exts_destroy(tp, &f->exts); 551 tcf_exts_destroy(tp, &f->exts);
516 tcf_em_tree_destroy(tp, &f->ematches); 552 tcf_em_tree_destroy(tp, &f->ematches);
517 kfree(f); 553 kfree(f);
@@ -532,11 +568,6 @@ static int flow_init(struct tcf_proto *tp)
532{ 568{
533 struct flow_head *head; 569 struct flow_head *head;
534 570
535 if (!flow_hashrnd_initted) {
536 get_random_bytes(&flow_hashrnd, 4);
537 flow_hashrnd_initted = 1;
538 }
539
540 head = kzalloc(sizeof(*head), GFP_KERNEL); 571 head = kzalloc(sizeof(*head), GFP_KERNEL);
541 if (head == NULL) 572 if (head == NULL)
542 return -ENOBUFS; 573 return -ENOBUFS;
@@ -605,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh,
605 if (f->baseclass) 636 if (f->baseclass)
606 NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass); 637 NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
607 638
639 if (f->perturb_period)
640 NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ);
641
608 if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0) 642 if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
609 goto nla_put_failure; 643 goto nla_put_failure;
610#ifdef CONFIG_NET_EMATCH 644#ifdef CONFIG_NET_EMATCH