Skip to content

Commit

Permalink
net: sched: introduce tcf block infractructure
Browse files Browse the repository at this point in the history
Currently, the filter chains are direcly put into the private structures
of qdiscs. In order to be able to have multiple chains per qdisc and to
allow filter chains sharing among qdiscs, there is a need for common
object that would hold the chains. This introduces such object and calls
it "tcf_block".

Helpers to get and put the blocks are provided to be called from
individual qdisc code. Also, the original filter_list pointers are left
in qdisc privs to allow the entry into tcf_block processing without any
added overhead of possible multiple pointer dereference on fast path.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
jpirko authored and davem330 committed May 17, 2017
1 parent 87d8309 commit 6529eab
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 99 deletions.
13 changes: 11 additions & 2 deletions include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);

#ifdef CONFIG_NET_CLS
void tcf_destroy_chain(struct tcf_proto __rcu **fl);
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain);
void tcf_block_put(struct tcf_block *block);
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);

#else
static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
static inline
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain)
{
return 0;
}

static inline void tcf_block_put(struct tcf_block *block)
{
}

Expand Down
7 changes: 6 additions & 1 deletion include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ struct Qdisc_class_ops {
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);

/* Filter manipulation */
struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long);
struct tcf_block * (*tcf_block)(struct Qdisc *, unsigned long);
bool (*tcf_cl_offload)(u32 classid);
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long,
u32 classid);
Expand Down Expand Up @@ -236,6 +236,7 @@ struct tcf_proto {
struct Qdisc *q;
void *data;
const struct tcf_proto_ops *ops;
struct tcf_block *block;
struct rcu_head rcu;
};

Expand All @@ -247,6 +248,10 @@ struct qdisc_skb_cb {
unsigned char data[QDISC_CB_PRIV_LEN];
};

struct tcf_block {
struct tcf_proto __rcu **p_filter_chain;
};

static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
{
struct qdisc_skb_cb *qcb;
Expand Down
48 changes: 38 additions & 10 deletions net/sched/cls_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
}

static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
u32 prio, u32 parent, struct Qdisc *q)
u32 prio, u32 parent, struct Qdisc *q,
struct tcf_block *block)
{
struct tcf_proto *tp;
int err;
Expand Down Expand Up @@ -165,6 +166,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
tp->prio = prio;
tp->classid = parent;
tp->q = q;
tp->block = block;

err = tp->ops->init(tp);
if (err) {
Expand All @@ -185,7 +187,7 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
kfree_rcu(tp, rcu);
}

void tcf_destroy_chain(struct tcf_proto __rcu **fl)
static void tcf_destroy_chain(struct tcf_proto __rcu **fl)
{
struct tcf_proto *tp;

Expand All @@ -194,7 +196,28 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)
tcf_proto_destroy(tp);
}
}
EXPORT_SYMBOL(tcf_destroy_chain);

int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain)
{
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);

if (!block)
return -ENOMEM;
block->p_filter_chain = p_filter_chain;
*p_block = block;
return 0;
}
EXPORT_SYMBOL(tcf_block_get);

void tcf_block_put(struct tcf_block *block)
{
if (!block)
return;
tcf_destroy_chain(block->p_filter_chain);
kfree(block);
}
EXPORT_SYMBOL(tcf_block_put);

/* Main classifier routine: scans classifier chain attached
* to this qdisc, (optionally) tests for protocol and asks
Expand Down Expand Up @@ -260,6 +283,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct Qdisc *q;
struct tcf_proto __rcu **back;
struct tcf_proto __rcu **chain;
struct tcf_block *block;
struct tcf_proto *next;
struct tcf_proto *tp;
const struct Qdisc_class_ops *cops;
Expand Down Expand Up @@ -328,7 +352,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
if (!cops)
return -EINVAL;

if (cops->tcf_chain == NULL)
if (!cops->tcf_block)
return -EOPNOTSUPP;

/* Do we search for filter, attached to class? */
Expand All @@ -339,11 +363,13 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}

/* And the last stroke */
chain = cops->tcf_chain(q, cl);
if (chain == NULL) {
block = cops->tcf_block(q, cl);
if (!block) {
err = -EINVAL;
goto errout;
}
chain = block->p_filter_chain;

if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
tcf_destroy_chain(chain);
Expand Down Expand Up @@ -387,7 +413,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));

tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
protocol, nprio, parent, q);
protocol, nprio, parent, q, block);
if (IS_ERR(tp)) {
err = PTR_ERR(tp);
goto errout;
Expand Down Expand Up @@ -556,6 +582,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
int s_t;
struct net_device *dev;
struct Qdisc *q;
struct tcf_block *block;
struct tcf_proto *tp, __rcu **chain;
struct tcmsg *tcm = nlmsg_data(cb->nlh);
unsigned long cl = 0;
Expand All @@ -577,16 +604,17 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
cops = q->ops->cl_ops;
if (!cops)
goto errout;
if (cops->tcf_chain == NULL)
if (!cops->tcf_block)
goto errout;
if (TC_H_MIN(tcm->tcm_parent)) {
cl = cops->get(q, tcm->tcm_parent);
if (cl == 0)
goto errout;
}
chain = cops->tcf_chain(q, cl);
if (chain == NULL)
block = cops->tcf_block(q, cl);
if (!block)
goto errout;
chain = block->p_filter_chain;

s_t = cb->args[0];

Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ int register_qdisc(struct Qdisc_ops *qops)
if (!(cops->get && cops->put && cops->walk && cops->leaf))
goto out_einval;

if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
if (cops->tcf_block && !(cops->bind_tcf && cops->unbind_tcf))
goto out_einval;
}

Expand Down
27 changes: 19 additions & 8 deletions net/sched/sch_atm.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
struct atm_flow_data {
struct Qdisc *q; /* FIFO, TBF, etc. */
struct tcf_proto __rcu *filter_list;
struct tcf_block *block;
struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
void (*old_pop)(struct atm_vcc *vcc,
struct sk_buff *skb); /* chaining */
Expand Down Expand Up @@ -143,7 +144,7 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
list_del_init(&flow->list);
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
qdisc_destroy(flow->q);
tcf_destroy_chain(&flow->filter_list);
tcf_block_put(flow->block);
if (flow->sock) {
pr_debug("atm_tc_put: f_count %ld\n",
file_count(flow->sock->file));
Expand Down Expand Up @@ -274,7 +275,13 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
error = -ENOBUFS;
goto err_out;
}
RCU_INIT_POINTER(flow->filter_list, NULL);

error = tcf_block_get(&flow->block, &flow->filter_list);
if (error) {
kfree(flow);
goto err_out;
}

flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
if (!flow->q)
flow->q = &noop_qdisc;
Expand Down Expand Up @@ -346,14 +353,13 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
}
}

static struct tcf_proto __rcu **atm_tc_find_tcf(struct Qdisc *sch,
unsigned long cl)
static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
struct atm_flow_data *flow = (struct atm_flow_data *)cl;

pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
return flow ? &flow->filter_list : &p->link.filter_list;
return flow ? flow->block : p->link.block;
}

/* --------------------------- Qdisc operations ---------------------------- */
Expand Down Expand Up @@ -524,6 +530,7 @@ static struct sk_buff *atm_tc_peek(struct Qdisc *sch)
static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
int err;

pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
INIT_LIST_HEAD(&p->flows);
Expand All @@ -534,7 +541,11 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
if (!p->link.q)
p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
RCU_INIT_POINTER(p->link.filter_list, NULL);

err = tcf_block_get(&p->link.block, &p->link.filter_list);
if (err)
return err;

p->link.vcc = NULL;
p->link.sock = NULL;
p->link.classid = sch->handle;
Expand All @@ -561,7 +572,7 @@ static void atm_tc_destroy(struct Qdisc *sch)

pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
list_for_each_entry(flow, &p->flows, list)
tcf_destroy_chain(&flow->filter_list);
tcf_block_put(flow->block);

list_for_each_entry_safe(flow, tmp, &p->flows, list) {
if (flow->ref > 1)
Expand Down Expand Up @@ -646,7 +657,7 @@ static const struct Qdisc_class_ops atm_class_ops = {
.change = atm_tc_change,
.delete = atm_tc_delete,
.walk = atm_tc_walk,
.tcf_chain = atm_tc_find_tcf,
.tcf_block = atm_tc_tcf_block,
.bind_tcf = atm_tc_bind_filter,
.unbind_tcf = atm_tc_put,
.dump = atm_tc_dump_class,
Expand Down
19 changes: 13 additions & 6 deletions net/sched/sch_cbq.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct cbq_class {
struct tc_cbq_xstats xstats;

struct tcf_proto __rcu *filter_list;
struct tcf_block *block;

int refcnt;
int filters;
Expand Down Expand Up @@ -1405,7 +1406,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)

WARN_ON(cl->filters);

tcf_destroy_chain(&cl->filter_list);
tcf_block_put(cl->block);
qdisc_destroy(cl->q);
qdisc_put_rtab(cl->R_tab);
gen_kill_estimator(&cl->rate_est);
Expand All @@ -1430,7 +1431,7 @@ static void cbq_destroy(struct Qdisc *sch)
*/
for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode)
tcf_destroy_chain(&cl->filter_list);
tcf_block_put(cl->block);
}
for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
Expand Down Expand Up @@ -1585,12 +1586,19 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (cl == NULL)
goto failure;

err = tcf_block_get(&cl->block, &cl->filter_list);
if (err) {
kfree(cl);
return err;
}

if (tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
NULL,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
tcf_block_put(cl->block);
kfree(cl);
goto failure;
}
Expand Down Expand Up @@ -1688,16 +1696,15 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
return 0;
}

static struct tcf_proto __rcu **cbq_find_tcf(struct Qdisc *sch,
unsigned long arg)
static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class *)arg;

if (cl == NULL)
cl = &q->link;

return &cl->filter_list;
return cl->block;
}

static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
Expand Down Expand Up @@ -1756,7 +1763,7 @@ static const struct Qdisc_class_ops cbq_class_ops = {
.change = cbq_change_class,
.delete = cbq_delete,
.walk = cbq_walk,
.tcf_chain = cbq_find_tcf,
.tcf_block = cbq_tcf_block,
.bind_tcf = cbq_bind_filter,
.unbind_tcf = cbq_unbind_filter,
.dump = cbq_dump_class,
Expand Down

0 comments on commit 6529eab

Please sign in to comment.