Commit 72d9794f authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

net-sched: cls_flow: add perturbation support

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0c4c8cae
...@@ -374,6 +374,7 @@ enum ...@@ -374,6 +374,7 @@ enum
TCA_FLOW_ACT, TCA_FLOW_ACT,
TCA_FLOW_POLICE, TCA_FLOW_POLICE,
TCA_FLOW_EMATCHES, TCA_FLOW_EMATCHES,
TCA_FLOW_PERTURB,
__TCA_FLOW_MAX __TCA_FLOW_MAX
}; };
......
...@@ -36,6 +36,8 @@ struct flow_filter { ...@@ -36,6 +36,8 @@ struct flow_filter {
struct list_head list; struct list_head list;
struct tcf_exts exts; struct tcf_exts exts;
struct tcf_ematch_tree ematches; struct tcf_ematch_tree ematches;
struct timer_list perturb_timer;
u32 perturb_period;
u32 handle; u32 handle;
u32 nkeys; u32 nkeys;
...@@ -47,11 +49,9 @@ struct flow_filter { ...@@ -47,11 +49,9 @@ struct flow_filter {
u32 addend; u32 addend;
u32 divisor; u32 divisor;
u32 baseclass; 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 = { static const struct tcf_ext_map flow_ext_map = {
.action = TCA_FLOW_ACT, .action = TCA_FLOW_ACT,
.police = TCA_FLOW_POLICE, .police = TCA_FLOW_POLICE,
...@@ -348,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, ...@@ -348,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
} }
if (f->mode == FLOW_MODE_HASH) if (f->mode == FLOW_MODE_HASH)
classid = jhash2(keys, f->nkeys, flow_hashrnd); classid = jhash2(keys, f->nkeys, f->hashrnd);
else { else {
classid = keys[0]; classid = keys[0];
classid = (classid & f->mask) ^ f->xor; classid = (classid & f->mask) ^ f->xor;
...@@ -369,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, ...@@ -369,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
return -1; 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] = { static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[TCA_FLOW_KEYS] = { .type = NLA_U32 }, [TCA_FLOW_KEYS] = { .type = NLA_U32 },
[TCA_FLOW_MODE] = { .type = NLA_U32 }, [TCA_FLOW_MODE] = { .type = NLA_U32 },
...@@ -381,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { ...@@ -381,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[TCA_FLOW_ACT] = { .type = NLA_NESTED }, [TCA_FLOW_ACT] = { .type = NLA_NESTED },
[TCA_FLOW_POLICE] = { .type = NLA_NESTED }, [TCA_FLOW_POLICE] = { .type = NLA_NESTED },
[TCA_FLOW_EMATCHES] = { .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, 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, ...@@ -394,6 +404,7 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
struct tcf_exts e; struct tcf_exts e;
struct tcf_ematch_tree t; struct tcf_ematch_tree t;
unsigned int nkeys = 0; unsigned int nkeys = 0;
unsigned int perturb_period = 0;
u32 baseclass = 0; u32 baseclass = 0;
u32 keymask = 0; u32 keymask = 0;
u32 mode; u32 mode;
...@@ -442,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, ...@@ -442,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
mode = nla_get_u32(tb[TCA_FLOW_MODE]); mode = nla_get_u32(tb[TCA_FLOW_MODE]);
if (mode != FLOW_MODE_HASH && nkeys > 1) if (mode != FLOW_MODE_HASH && nkeys > 1)
goto err2; 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 { } else {
err = -EINVAL; err = -EINVAL;
if (!handle) if (!handle)
...@@ -455,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, ...@@ -455,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
if (mode != FLOW_MODE_HASH && nkeys > 1) if (mode != FLOW_MODE_HASH && nkeys > 1)
goto err2; 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) if (TC_H_MAJ(baseclass) == 0)
baseclass = TC_H_MAKE(tp->q->handle, baseclass); baseclass = TC_H_MAKE(tp->q->handle, baseclass);
if (TC_H_MIN(baseclass) == 0) if (TC_H_MIN(baseclass) == 0)
...@@ -467,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, ...@@ -467,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
f->handle = handle; f->handle = handle;
f->mask = ~0U; 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); tcf_exts_change(tp, &f->exts, &e);
...@@ -495,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, ...@@ -495,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
if (baseclass) if (baseclass)
f->baseclass = 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) if (*arg == 0)
list_add_tail(&f->list, &head->filters); list_add_tail(&f->list, &head->filters);
...@@ -512,6 +547,7 @@ err1: ...@@ -512,6 +547,7 @@ err1:
static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f) 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_exts_destroy(tp, &f->exts);
tcf_em_tree_destroy(tp, &f->ematches); tcf_em_tree_destroy(tp, &f->ematches);
kfree(f); kfree(f);
...@@ -532,11 +568,6 @@ static int flow_init(struct tcf_proto *tp) ...@@ -532,11 +568,6 @@ static int flow_init(struct tcf_proto *tp)
{ {
struct flow_head *head; struct flow_head *head;
if (!flow_hashrnd_initted) {
get_random_bytes(&flow_hashrnd, 4);
flow_hashrnd_initted = 1;
}
head = kzalloc(sizeof(*head), GFP_KERNEL); head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL) if (head == NULL)
return -ENOBUFS; return -ENOBUFS;
...@@ -605,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh, ...@@ -605,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh,
if (f->baseclass) if (f->baseclass)
NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, 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) if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_NET_EMATCH #ifdef CONFIG_NET_EMATCH
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment