Skip to content

Commit 6529eab

Browse files
jpirkodavem330
authored andcommitted
net: sched: introduce tcf block infractructure
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 <[email protected]> Acked-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 87d8309 commit 6529eab

17 files changed

+243
-99
lines changed

include/net/pkt_cls.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,21 @@ int register_tcf_proto_ops(struct tcf_proto_ops *ops);
1818
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
1919

2020
#ifdef CONFIG_NET_CLS
21-
void tcf_destroy_chain(struct tcf_proto __rcu **fl);
21+
int tcf_block_get(struct tcf_block **p_block,
22+
struct tcf_proto __rcu **p_filter_chain);
23+
void tcf_block_put(struct tcf_block *block);
2224
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
2325
struct tcf_result *res, bool compat_mode);
2426

2527
#else
26-
static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
28+
static inline
29+
int tcf_block_get(struct tcf_block **p_block,
30+
struct tcf_proto __rcu **p_filter_chain)
31+
{
32+
return 0;
33+
}
34+
35+
static inline void tcf_block_put(struct tcf_block *block)
2736
{
2837
}
2938

include/net/sch_generic.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ struct Qdisc_class_ops {
153153
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
154154

155155
/* Filter manipulation */
156-
struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long);
156+
struct tcf_block * (*tcf_block)(struct Qdisc *, unsigned long);
157157
bool (*tcf_cl_offload)(u32 classid);
158158
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long,
159159
u32 classid);
@@ -236,6 +236,7 @@ struct tcf_proto {
236236
struct Qdisc *q;
237237
void *data;
238238
const struct tcf_proto_ops *ops;
239+
struct tcf_block *block;
239240
struct rcu_head rcu;
240241
};
241242

@@ -247,6 +248,10 @@ struct qdisc_skb_cb {
247248
unsigned char data[QDISC_CB_PRIV_LEN];
248249
};
249250

251+
struct tcf_block {
252+
struct tcf_proto __rcu **p_filter_chain;
253+
};
254+
250255
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
251256
{
252257
struct qdisc_skb_cb *qcb;

net/sched/cls_api.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
129129
}
130130

131131
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
132-
u32 prio, u32 parent, struct Qdisc *q)
132+
u32 prio, u32 parent, struct Qdisc *q,
133+
struct tcf_block *block)
133134
{
134135
struct tcf_proto *tp;
135136
int err;
@@ -165,6 +166,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
165166
tp->prio = prio;
166167
tp->classid = parent;
167168
tp->q = q;
169+
tp->block = block;
168170

169171
err = tp->ops->init(tp);
170172
if (err) {
@@ -185,7 +187,7 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
185187
kfree_rcu(tp, rcu);
186188
}
187189

188-
void tcf_destroy_chain(struct tcf_proto __rcu **fl)
190+
static void tcf_destroy_chain(struct tcf_proto __rcu **fl)
189191
{
190192
struct tcf_proto *tp;
191193

@@ -194,7 +196,28 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)
194196
tcf_proto_destroy(tp);
195197
}
196198
}
197-
EXPORT_SYMBOL(tcf_destroy_chain);
199+
200+
int tcf_block_get(struct tcf_block **p_block,
201+
struct tcf_proto __rcu **p_filter_chain)
202+
{
203+
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
204+
205+
if (!block)
206+
return -ENOMEM;
207+
block->p_filter_chain = p_filter_chain;
208+
*p_block = block;
209+
return 0;
210+
}
211+
EXPORT_SYMBOL(tcf_block_get);
212+
213+
void tcf_block_put(struct tcf_block *block)
214+
{
215+
if (!block)
216+
return;
217+
tcf_destroy_chain(block->p_filter_chain);
218+
kfree(block);
219+
}
220+
EXPORT_SYMBOL(tcf_block_put);
198221

199222
/* Main classifier routine: scans classifier chain attached
200223
* to this qdisc, (optionally) tests for protocol and asks
@@ -260,6 +283,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
260283
struct Qdisc *q;
261284
struct tcf_proto __rcu **back;
262285
struct tcf_proto __rcu **chain;
286+
struct tcf_block *block;
263287
struct tcf_proto *next;
264288
struct tcf_proto *tp;
265289
const struct Qdisc_class_ops *cops;
@@ -328,7 +352,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
328352
if (!cops)
329353
return -EINVAL;
330354

331-
if (cops->tcf_chain == NULL)
355+
if (!cops->tcf_block)
332356
return -EOPNOTSUPP;
333357

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

341365
/* And the last stroke */
342-
chain = cops->tcf_chain(q, cl);
343-
if (chain == NULL) {
366+
block = cops->tcf_block(q, cl);
367+
if (!block) {
344368
err = -EINVAL;
345369
goto errout;
346370
}
371+
chain = block->p_filter_chain;
372+
347373
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
348374
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
349375
tcf_destroy_chain(chain);
@@ -387,7 +413,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
387413
nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
388414

389415
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
390-
protocol, nprio, parent, q);
416+
protocol, nprio, parent, q, block);
391417
if (IS_ERR(tp)) {
392418
err = PTR_ERR(tp);
393419
goto errout;
@@ -556,6 +582,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
556582
int s_t;
557583
struct net_device *dev;
558584
struct Qdisc *q;
585+
struct tcf_block *block;
559586
struct tcf_proto *tp, __rcu **chain;
560587
struct tcmsg *tcm = nlmsg_data(cb->nlh);
561588
unsigned long cl = 0;
@@ -577,16 +604,17 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
577604
cops = q->ops->cl_ops;
578605
if (!cops)
579606
goto errout;
580-
if (cops->tcf_chain == NULL)
607+
if (!cops->tcf_block)
581608
goto errout;
582609
if (TC_H_MIN(tcm->tcm_parent)) {
583610
cl = cops->get(q, tcm->tcm_parent);
584611
if (cl == 0)
585612
goto errout;
586613
}
587-
chain = cops->tcf_chain(q, cl);
588-
if (chain == NULL)
614+
block = cops->tcf_block(q, cl);
615+
if (!block)
589616
goto errout;
617+
chain = block->p_filter_chain;
590618

591619
s_t = cb->args[0];
592620

net/sched/sch_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ int register_qdisc(struct Qdisc_ops *qops)
163163
if (!(cops->get && cops->put && cops->walk && cops->leaf))
164164
goto out_einval;
165165

166-
if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
166+
if (cops->tcf_block && !(cops->bind_tcf && cops->unbind_tcf))
167167
goto out_einval;
168168
}
169169

net/sched/sch_atm.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
struct atm_flow_data {
4444
struct Qdisc *q; /* FIFO, TBF, etc. */
4545
struct tcf_proto __rcu *filter_list;
46+
struct tcf_block *block;
4647
struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
4748
void (*old_pop)(struct atm_vcc *vcc,
4849
struct sk_buff *skb); /* chaining */
@@ -143,7 +144,7 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
143144
list_del_init(&flow->list);
144145
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
145146
qdisc_destroy(flow->q);
146-
tcf_destroy_chain(&flow->filter_list);
147+
tcf_block_put(flow->block);
147148
if (flow->sock) {
148149
pr_debug("atm_tc_put: f_count %ld\n",
149150
file_count(flow->sock->file));
@@ -274,7 +275,13 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
274275
error = -ENOBUFS;
275276
goto err_out;
276277
}
277-
RCU_INIT_POINTER(flow->filter_list, NULL);
278+
279+
error = tcf_block_get(&flow->block, &flow->filter_list);
280+
if (error) {
281+
kfree(flow);
282+
goto err_out;
283+
}
284+
278285
flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
279286
if (!flow->q)
280287
flow->q = &noop_qdisc;
@@ -346,14 +353,13 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
346353
}
347354
}
348355

349-
static struct tcf_proto __rcu **atm_tc_find_tcf(struct Qdisc *sch,
350-
unsigned long cl)
356+
static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl)
351357
{
352358
struct atm_qdisc_data *p = qdisc_priv(sch);
353359
struct atm_flow_data *flow = (struct atm_flow_data *)cl;
354360

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

359365
/* --------------------------- Qdisc operations ---------------------------- */
@@ -524,6 +530,7 @@ static struct sk_buff *atm_tc_peek(struct Qdisc *sch)
524530
static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
525531
{
526532
struct atm_qdisc_data *p = qdisc_priv(sch);
533+
int err;
527534

528535
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
529536
INIT_LIST_HEAD(&p->flows);
@@ -534,7 +541,11 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
534541
if (!p->link.q)
535542
p->link.q = &noop_qdisc;
536543
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
537-
RCU_INIT_POINTER(p->link.filter_list, NULL);
544+
545+
err = tcf_block_get(&p->link.block, &p->link.filter_list);
546+
if (err)
547+
return err;
548+
538549
p->link.vcc = NULL;
539550
p->link.sock = NULL;
540551
p->link.classid = sch->handle;
@@ -561,7 +572,7 @@ static void atm_tc_destroy(struct Qdisc *sch)
561572

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

566577
list_for_each_entry_safe(flow, tmp, &p->flows, list) {
567578
if (flow->ref > 1)
@@ -646,7 +657,7 @@ static const struct Qdisc_class_ops atm_class_ops = {
646657
.change = atm_tc_change,
647658
.delete = atm_tc_delete,
648659
.walk = atm_tc_walk,
649-
.tcf_chain = atm_tc_find_tcf,
660+
.tcf_block = atm_tc_tcf_block,
650661
.bind_tcf = atm_tc_bind_filter,
651662
.unbind_tcf = atm_tc_put,
652663
.dump = atm_tc_dump_class,

net/sched/sch_cbq.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ struct cbq_class {
127127
struct tc_cbq_xstats xstats;
128128

129129
struct tcf_proto __rcu *filter_list;
130+
struct tcf_block *block;
130131

131132
int refcnt;
132133
int filters;
@@ -1405,7 +1406,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
14051406

14061407
WARN_ON(cl->filters);
14071408

1408-
tcf_destroy_chain(&cl->filter_list);
1409+
tcf_block_put(cl->block);
14091410
qdisc_destroy(cl->q);
14101411
qdisc_put_rtab(cl->R_tab);
14111412
gen_kill_estimator(&cl->rate_est);
@@ -1430,7 +1431,7 @@ static void cbq_destroy(struct Qdisc *sch)
14301431
*/
14311432
for (h = 0; h < q->clhash.hashsize; h++) {
14321433
hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode)
1433-
tcf_destroy_chain(&cl->filter_list);
1434+
tcf_block_put(cl->block);
14341435
}
14351436
for (h = 0; h < q->clhash.hashsize; h++) {
14361437
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
@@ -1585,12 +1586,19 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
15851586
if (cl == NULL)
15861587
goto failure;
15871588

1589+
err = tcf_block_get(&cl->block, &cl->filter_list);
1590+
if (err) {
1591+
kfree(cl);
1592+
return err;
1593+
}
1594+
15881595
if (tca[TCA_RATE]) {
15891596
err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
15901597
NULL,
15911598
qdisc_root_sleeping_running(sch),
15921599
tca[TCA_RATE]);
15931600
if (err) {
1601+
tcf_block_put(cl->block);
15941602
kfree(cl);
15951603
goto failure;
15961604
}
@@ -1688,16 +1696,15 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
16881696
return 0;
16891697
}
16901698

1691-
static struct tcf_proto __rcu **cbq_find_tcf(struct Qdisc *sch,
1692-
unsigned long arg)
1699+
static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
16931700
{
16941701
struct cbq_sched_data *q = qdisc_priv(sch);
16951702
struct cbq_class *cl = (struct cbq_class *)arg;
16961703

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

1700-
return &cl->filter_list;
1707+
return cl->block;
17011708
}
17021709

17031710
static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
@@ -1756,7 +1763,7 @@ static const struct Qdisc_class_ops cbq_class_ops = {
17561763
.change = cbq_change_class,
17571764
.delete = cbq_delete,
17581765
.walk = cbq_walk,
1759-
.tcf_chain = cbq_find_tcf,
1766+
.tcf_block = cbq_tcf_block,
17601767
.bind_tcf = cbq_bind_filter,
17611768
.unbind_tcf = cbq_unbind_filter,
17621769
.dump = cbq_dump_class,

0 commit comments

Comments
 (0)