|
@@ -219,10 +219,10 @@ static const struct nla_policy tcindex_policy[TCA_TCINDEX_MAX + 1] = {
|
|
[TCA_TCINDEX_CLASSID] = { .type = NLA_U32 },
|
|
[TCA_TCINDEX_CLASSID] = { .type = NLA_U32 },
|
|
};
|
|
};
|
|
|
|
|
|
-static void tcindex_filter_result_init(struct tcindex_filter_result *r)
|
|
|
|
|
|
+static int tcindex_filter_result_init(struct tcindex_filter_result *r)
|
|
{
|
|
{
|
|
memset(r, 0, sizeof(*r));
|
|
memset(r, 0, sizeof(*r));
|
|
- tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
|
|
|
|
+ return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
}
|
|
}
|
|
|
|
|
|
static void __tcindex_partial_destroy(struct rcu_head *head)
|
|
static void __tcindex_partial_destroy(struct rcu_head *head)
|
|
@@ -233,23 +233,57 @@ static void __tcindex_partial_destroy(struct rcu_head *head)
|
|
kfree(p);
|
|
kfree(p);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void tcindex_free_perfect_hash(struct tcindex_data *cp)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < cp->hash; i++)
|
|
|
|
+ tcf_exts_destroy(&cp->perfect[i].exts);
|
|
|
|
+ kfree(cp->perfect);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int tcindex_alloc_perfect_hash(struct tcindex_data *cp)
|
|
|
|
+{
|
|
|
|
+ int i, err = 0;
|
|
|
|
+
|
|
|
|
+ cp->perfect = kcalloc(cp->hash, sizeof(struct tcindex_filter_result),
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ if (!cp->perfect)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < cp->hash; i++) {
|
|
|
|
+ err = tcf_exts_init(&cp->perfect[i].exts,
|
|
|
|
+ TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto errout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+errout:
|
|
|
|
+ tcindex_free_perfect_hash(cp);
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
u32 handle, struct tcindex_data *p,
|
|
u32 handle, struct tcindex_data *p,
|
|
struct tcindex_filter_result *r, struct nlattr **tb,
|
|
struct tcindex_filter_result *r, struct nlattr **tb,
|
|
struct nlattr *est, bool ovr)
|
|
struct nlattr *est, bool ovr)
|
|
{
|
|
{
|
|
- int err, balloc = 0;
|
|
|
|
struct tcindex_filter_result new_filter_result, *old_r = r;
|
|
struct tcindex_filter_result new_filter_result, *old_r = r;
|
|
struct tcindex_filter_result cr;
|
|
struct tcindex_filter_result cr;
|
|
- struct tcindex_data *cp, *oldp;
|
|
|
|
|
|
+ struct tcindex_data *cp = NULL, *oldp;
|
|
struct tcindex_filter *f = NULL; /* make gcc behave */
|
|
struct tcindex_filter *f = NULL; /* make gcc behave */
|
|
|
|
+ int err, balloc = 0;
|
|
struct tcf_exts e;
|
|
struct tcf_exts e;
|
|
|
|
|
|
- tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
|
|
- err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
|
|
|
|
|
|
+ err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
return err;
|
|
return err;
|
|
|
|
+ err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto errout;
|
|
|
|
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
/* tcindex_data attributes must look atomic to classifier/lookup so
|
|
/* tcindex_data attributes must look atomic to classifier/lookup so
|
|
@@ -270,19 +304,20 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
if (p->perfect) {
|
|
if (p->perfect) {
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- cp->perfect = kmemdup(p->perfect,
|
|
|
|
- sizeof(*r) * cp->hash, GFP_KERNEL);
|
|
|
|
- if (!cp->perfect)
|
|
|
|
|
|
+ if (tcindex_alloc_perfect_hash(cp) < 0)
|
|
goto errout;
|
|
goto errout;
|
|
for (i = 0; i < cp->hash; i++)
|
|
for (i = 0; i < cp->hash; i++)
|
|
- tcf_exts_init(&cp->perfect[i].exts,
|
|
|
|
- TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
|
|
|
|
|
|
+ cp->perfect[i].res = p->perfect[i].res;
|
|
balloc = 1;
|
|
balloc = 1;
|
|
}
|
|
}
|
|
cp->h = p->h;
|
|
cp->h = p->h;
|
|
|
|
|
|
- tcindex_filter_result_init(&new_filter_result);
|
|
|
|
- tcindex_filter_result_init(&cr);
|
|
|
|
|
|
+ err = tcindex_filter_result_init(&new_filter_result);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto errout1;
|
|
|
|
+ err = tcindex_filter_result_init(&cr);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto errout1;
|
|
if (old_r)
|
|
if (old_r)
|
|
cr.res = r->res;
|
|
cr.res = r->res;
|
|
|
|
|
|
@@ -338,15 +373,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
if (!cp->perfect && !cp->h) {
|
|
if (!cp->perfect && !cp->h) {
|
|
if (valid_perfect_hash(cp)) {
|
|
if (valid_perfect_hash(cp)) {
|
|
- int i;
|
|
|
|
-
|
|
|
|
- cp->perfect = kcalloc(cp->hash, sizeof(*r), GFP_KERNEL);
|
|
|
|
- if (!cp->perfect)
|
|
|
|
|
|
+ if (tcindex_alloc_perfect_hash(cp) < 0)
|
|
goto errout_alloc;
|
|
goto errout_alloc;
|
|
- for (i = 0; i < cp->hash; i++)
|
|
|
|
- tcf_exts_init(&cp->perfect[i].exts,
|
|
|
|
- TCA_TCINDEX_ACT,
|
|
|
|
- TCA_TCINDEX_POLICE);
|
|
|
|
balloc = 1;
|
|
balloc = 1;
|
|
} else {
|
|
} else {
|
|
struct tcindex_filter __rcu **hash;
|
|
struct tcindex_filter __rcu **hash;
|
|
@@ -373,8 +401,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
if (!f)
|
|
if (!f)
|
|
goto errout_alloc;
|
|
goto errout_alloc;
|
|
f->key = handle;
|
|
f->key = handle;
|
|
- tcindex_filter_result_init(&f->result);
|
|
|
|
f->next = NULL;
|
|
f->next = NULL;
|
|
|
|
+ err = tcindex_filter_result_init(&f->result);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ kfree(f);
|
|
|
|
+ goto errout_alloc;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (tb[TCA_TCINDEX_CLASSID]) {
|
|
if (tb[TCA_TCINDEX_CLASSID]) {
|
|
@@ -387,8 +419,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
else
|
|
else
|
|
tcf_exts_change(tp, &cr.exts, &e);
|
|
tcf_exts_change(tp, &cr.exts, &e);
|
|
|
|
|
|
- if (old_r && old_r != r)
|
|
|
|
- tcindex_filter_result_init(old_r);
|
|
|
|
|
|
+ if (old_r && old_r != r) {
|
|
|
|
+ err = tcindex_filter_result_init(old_r);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ kfree(f);
|
|
|
|
+ goto errout_alloc;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
oldp = p;
|
|
oldp = p;
|
|
r->res = cr.res;
|
|
r->res = cr.res;
|
|
@@ -415,9 +452,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
|
|
|
|
|
|
errout_alloc:
|
|
errout_alloc:
|
|
if (balloc == 1)
|
|
if (balloc == 1)
|
|
- kfree(cp->perfect);
|
|
|
|
|
|
+ tcindex_free_perfect_hash(cp);
|
|
else if (balloc == 2)
|
|
else if (balloc == 2)
|
|
kfree(cp->h);
|
|
kfree(cp->h);
|
|
|
|
+errout1:
|
|
|
|
+ tcf_exts_destroy(&cr.exts);
|
|
|
|
+ tcf_exts_destroy(&new_filter_result.exts);
|
|
errout:
|
|
errout:
|
|
kfree(cp);
|
|
kfree(cp);
|
|
tcf_exts_destroy(&e);
|
|
tcf_exts_destroy(&e);
|