Commit b95ec7eb authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

net: sched: cls_flower: implement chain templates

Use the previously introduced template extension and implement
callback to create, destroy and dump chain template. The existing
parsing and dumping functions are re-used. Also, check if newly added
filters fit the template if it is set.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 33fb5cba
...@@ -72,6 +72,13 @@ struct fl_flow_mask { ...@@ -72,6 +72,13 @@ struct fl_flow_mask {
struct list_head list; struct list_head list;
}; };
struct fl_flow_tmplt {
struct fl_flow_key dummy_key;
struct fl_flow_key mask;
struct flow_dissector dissector;
struct tcf_chain *chain;
};
struct cls_fl_head { struct cls_fl_head {
struct rhashtable ht; struct rhashtable ht;
struct list_head masks; struct list_head masks;
...@@ -147,6 +154,23 @@ static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, ...@@ -147,6 +154,23 @@ static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
*lmkey++ = *lkey++ & *lmask++; *lmkey++ = *lkey++ & *lmask++;
} }
static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
struct fl_flow_mask *mask)
{
const long *lmask = fl_key_get_start(&mask->key, mask);
const long *ltmplt;
int i;
if (!tmplt)
return true;
ltmplt = fl_key_get_start(&tmplt->mask, mask);
for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
if (~*ltmplt++ & *lmask++)
return false;
}
return true;
}
static void fl_clear_masked_range(struct fl_flow_key *key, static void fl_clear_masked_range(struct fl_flow_key *key,
struct fl_flow_mask *mask) struct fl_flow_mask *mask)
{ {
...@@ -939,6 +963,7 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp, ...@@ -939,6 +963,7 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
struct cls_fl_filter *f, struct fl_flow_mask *mask, struct cls_fl_filter *f, struct fl_flow_mask *mask,
unsigned long base, struct nlattr **tb, unsigned long base, struct nlattr **tb,
struct nlattr *est, bool ovr, struct nlattr *est, bool ovr,
struct fl_flow_tmplt *tmplt,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
int err; int err;
...@@ -959,6 +984,11 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp, ...@@ -959,6 +984,11 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
fl_mask_update_range(mask); fl_mask_update_range(mask);
fl_set_masked_key(&f->mkey, &f->key, mask); fl_set_masked_key(&f->mkey, &f->key, mask);
if (!fl_mask_fits_tmplt(tmplt, mask)) {
NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -1024,7 +1054,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -1024,7 +1054,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
} }
err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr,
extack); tp->chain->tmplt_priv, extack);
if (err) if (err)
goto errout_idr; goto errout_idr;
...@@ -1164,6 +1194,52 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, ...@@ -1164,6 +1194,52 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
return 0; return 0;
} }
static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
struct nlattr **tca,
struct netlink_ext_ack *extack)
{
struct fl_flow_tmplt *tmplt;
struct nlattr **tb;
int err;
if (!tca[TCA_OPTIONS])
return ERR_PTR(-EINVAL);
tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
if (!tb)
return ERR_PTR(-ENOBUFS);
err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
fl_policy, NULL);
if (err)
goto errout_tb;
tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
if (!tmplt)
goto errout_tb;
tmplt->chain = chain;
err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
if (err)
goto errout_tmplt;
kfree(tb);
fl_init_dissector(&tmplt->dissector, &tmplt->mask);
return tmplt;
errout_tmplt:
kfree(tmplt);
errout_tb:
kfree(tb);
return ERR_PTR(err);
}
static void fl_tmplt_destroy(void *tmplt_priv)
{
struct fl_flow_tmplt *tmplt = tmplt_priv;
kfree(tmplt);
}
static int fl_dump_key_val(struct sk_buff *skb, static int fl_dump_key_val(struct sk_buff *skb,
void *val, int val_type, void *val, int val_type,
void *mask, int mask_type, int len) void *mask, int mask_type, int len)
...@@ -1536,6 +1612,31 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, ...@@ -1536,6 +1612,31 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
return -1; return -1;
} }
static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
{
struct fl_flow_tmplt *tmplt = tmplt_priv;
struct fl_flow_key *key, *mask;
struct nlattr *nest;
nest = nla_nest_start(skb, TCA_OPTIONS);
if (!nest)
goto nla_put_failure;
key = &tmplt->dummy_key;
mask = &tmplt->mask;
if (fl_dump_key(skb, net, key, mask))
goto nla_put_failure;
nla_nest_end(skb, nest);
return skb->len;
nla_put_failure:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static void fl_bind_class(void *fh, u32 classid, unsigned long cl) static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
{ {
struct cls_fl_filter *f = fh; struct cls_fl_filter *f = fh;
...@@ -1556,6 +1657,9 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = { ...@@ -1556,6 +1657,9 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = {
.reoffload = fl_reoffload, .reoffload = fl_reoffload,
.dump = fl_dump, .dump = fl_dump,
.bind_class = fl_bind_class, .bind_class = fl_bind_class,
.tmplt_create = fl_tmplt_create,
.tmplt_destroy = fl_tmplt_destroy,
.tmplt_dump = fl_tmplt_dump,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
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