Skip to content

Commit

Permalink
net: sched: cls_flower: implement chain templates
Browse files Browse the repository at this point in the history
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: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Jul 24, 2018
1 parent 33fb5cb commit b95ec7e
Showing 1 changed file with 105 additions and 1 deletion.
106 changes: 105 additions & 1 deletion net/sched/cls_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ struct fl_flow_mask {
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 rhashtable ht;
struct list_head masks;
Expand Down Expand Up @@ -147,6 +154,23 @@ static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
*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,
struct fl_flow_mask *mask)
{
Expand Down Expand Up @@ -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,
unsigned long base, struct nlattr **tb,
struct nlattr *est, bool ovr,
struct fl_flow_tmplt *tmplt,
struct netlink_ext_ack *extack)
{
int err;
Expand All @@ -959,6 +984,11 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
fl_mask_update_range(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;
}

Expand Down Expand Up @@ -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,
extack);
tp->chain->tmplt_priv, extack);
if (err)
goto errout_idr;

Expand Down Expand Up @@ -1164,6 +1194,52 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
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,
void *val, int val_type,
void *mask, int mask_type, int len)
Expand Down Expand Up @@ -1536,6 +1612,31 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
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)
{
struct cls_fl_filter *f = fh;
Expand All @@ -1556,6 +1657,9 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = {
.reoffload = fl_reoffload,
.dump = fl_dump,
.bind_class = fl_bind_class,
.tmplt_create = fl_tmplt_create,
.tmplt_destroy = fl_tmplt_destroy,
.tmplt_dump = fl_tmplt_dump,
.owner = THIS_MODULE,
};

Expand Down

0 comments on commit b95ec7e

Please sign in to comment.