Skip to content

Commit 2190d1d

Browse files
jpirkodavem330
authored andcommitted
net: sched: introduce helpers to work with filter chains
Introduce struct tcf_chain object and set of helpers around it. Wraps up insertion, deletion and search in the filter chain. Signed-off-by: Jiri Pirko <[email protected]> Acked-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7961973 commit 2190d1d

File tree

2 files changed

+113
-42
lines changed

2 files changed

+113
-42
lines changed

include/net/sch_generic.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,15 @@ struct qdisc_skb_cb {
248248
unsigned char data[QDISC_CB_PRIV_LEN];
249249
};
250250

251-
struct tcf_block {
251+
struct tcf_chain {
252+
struct tcf_proto __rcu *filter_chain;
252253
struct tcf_proto __rcu **p_filter_chain;
253254
};
254255

256+
struct tcf_block {
257+
struct tcf_chain *chain;
258+
};
259+
255260
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
256261
{
257262
struct qdisc_skb_cb *qcb;

net/sched/cls_api.c

Lines changed: 107 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,12 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
106106

107107
static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
108108
struct nlmsghdr *n,
109-
struct tcf_proto __rcu **chain, int event)
109+
struct tcf_chain *chain, int event)
110110
{
111-
struct tcf_proto __rcu **it_chain;
112111
struct tcf_proto *tp;
113112

114-
for (it_chain = chain; (tp = rtnl_dereference(*it_chain)) != NULL;
115-
it_chain = &tp->next)
113+
for (tp = rtnl_dereference(chain->filter_chain);
114+
tp; tp = rtnl_dereference(tp->next))
116115
tfilter_notify(net, oskb, n, tp, 0, event, false);
117116
}
118117

@@ -187,34 +186,57 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
187186
kfree_rcu(tp, rcu);
188187
}
189188

190-
static void tcf_chain_destroy(struct tcf_proto __rcu **fl)
189+
static struct tcf_chain *tcf_chain_create(void)
190+
{
191+
return kzalloc(sizeof(struct tcf_chain), GFP_KERNEL);
192+
}
193+
194+
static void tcf_chain_destroy(struct tcf_chain *chain)
191195
{
192196
struct tcf_proto *tp;
193197

194-
while ((tp = rtnl_dereference(*fl)) != NULL) {
195-
RCU_INIT_POINTER(*fl, tp->next);
198+
while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) {
199+
RCU_INIT_POINTER(chain->filter_chain, tp->next);
196200
tcf_proto_destroy(tp);
197201
}
202+
kfree(chain);
203+
}
204+
205+
static void
206+
tcf_chain_filter_chain_ptr_set(struct tcf_chain *chain,
207+
struct tcf_proto __rcu **p_filter_chain)
208+
{
209+
chain->p_filter_chain = p_filter_chain;
198210
}
199211

200212
int tcf_block_get(struct tcf_block **p_block,
201213
struct tcf_proto __rcu **p_filter_chain)
202214
{
203215
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
216+
int err;
204217

205218
if (!block)
206219
return -ENOMEM;
207-
block->p_filter_chain = p_filter_chain;
220+
block->chain = tcf_chain_create();
221+
if (!block->chain) {
222+
err = -ENOMEM;
223+
goto err_chain_create;
224+
}
225+
tcf_chain_filter_chain_ptr_set(block->chain, p_filter_chain);
208226
*p_block = block;
209227
return 0;
228+
229+
err_chain_create:
230+
kfree(block);
231+
return err;
210232
}
211233
EXPORT_SYMBOL(tcf_block_get);
212234

213235
void tcf_block_put(struct tcf_block *block)
214236
{
215237
if (!block)
216238
return;
217-
tcf_chain_destroy(block->p_filter_chain);
239+
tcf_chain_destroy(block->chain);
218240
kfree(block);
219241
}
220242
EXPORT_SYMBOL(tcf_block_put);
@@ -267,6 +289,65 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
267289
}
268290
EXPORT_SYMBOL(tcf_classify);
269291

292+
struct tcf_chain_info {
293+
struct tcf_proto __rcu **pprev;
294+
struct tcf_proto __rcu *next;
295+
};
296+
297+
static struct tcf_proto *tcf_chain_tp_prev(struct tcf_chain_info *chain_info)
298+
{
299+
return rtnl_dereference(*chain_info->pprev);
300+
}
301+
302+
static void tcf_chain_tp_insert(struct tcf_chain *chain,
303+
struct tcf_chain_info *chain_info,
304+
struct tcf_proto *tp)
305+
{
306+
if (chain->p_filter_chain &&
307+
*chain_info->pprev == chain->filter_chain)
308+
*chain->p_filter_chain = tp;
309+
RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info));
310+
rcu_assign_pointer(*chain_info->pprev, tp);
311+
}
312+
313+
static void tcf_chain_tp_remove(struct tcf_chain *chain,
314+
struct tcf_chain_info *chain_info,
315+
struct tcf_proto *tp)
316+
{
317+
struct tcf_proto *next = rtnl_dereference(chain_info->next);
318+
319+
if (chain->p_filter_chain && tp == chain->filter_chain)
320+
*chain->p_filter_chain = next;
321+
RCU_INIT_POINTER(*chain_info->pprev, next);
322+
}
323+
324+
static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
325+
struct tcf_chain_info *chain_info,
326+
u32 protocol, u32 prio,
327+
bool prio_allocate)
328+
{
329+
struct tcf_proto **pprev;
330+
struct tcf_proto *tp;
331+
332+
/* Check the chain for existence of proto-tcf with this priority */
333+
for (pprev = &chain->filter_chain;
334+
(tp = rtnl_dereference(*pprev)); pprev = &tp->next) {
335+
if (tp->prio >= prio) {
336+
if (tp->prio == prio) {
337+
if (prio_allocate ||
338+
(tp->protocol != protocol && protocol))
339+
return ERR_PTR(-EINVAL);
340+
} else {
341+
tp = NULL;
342+
}
343+
break;
344+
}
345+
}
346+
chain_info->pprev = pprev;
347+
chain_info->next = tp ? tp->next : NULL;
348+
return tp;
349+
}
350+
270351
/* Add/change/delete/get a filter node */
271352

272353
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
@@ -281,10 +362,9 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
281362
u32 parent;
282363
struct net_device *dev;
283364
struct Qdisc *q;
284-
struct tcf_proto __rcu **back;
285-
struct tcf_proto __rcu **chain;
365+
struct tcf_chain_info chain_info;
366+
struct tcf_chain *chain;
286367
struct tcf_block *block;
287-
struct tcf_proto *next;
288368
struct tcf_proto *tp;
289369
const struct Qdisc_class_ops *cops;
290370
unsigned long cl;
@@ -369,7 +449,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
369449
err = -EINVAL;
370450
goto errout;
371451
}
372-
chain = block->p_filter_chain;
452+
chain = block->chain;
373453

374454
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
375455
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
@@ -378,22 +458,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
378458
goto errout;
379459
}
380460

381-
/* Check the chain for existence of proto-tcf with this priority */
382-
for (back = chain;
383-
(tp = rtnl_dereference(*back)) != NULL;
384-
back = &tp->next) {
385-
if (tp->prio >= prio) {
386-
if (tp->prio == prio) {
387-
if (prio_allocate ||
388-
(tp->protocol != protocol && protocol)) {
389-
err = -EINVAL;
390-
goto errout;
391-
}
392-
} else {
393-
tp = NULL;
394-
}
395-
break;
396-
}
461+
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
462+
prio, prio_allocate);
463+
if (IS_ERR(tp)) {
464+
err = PTR_ERR(tp);
465+
goto errout;
397466
}
398467

399468
if (tp == NULL) {
@@ -411,7 +480,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
411480
}
412481

413482
if (prio_allocate)
414-
prio = tcf_auto_prio(rtnl_dereference(*back));
483+
prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
415484

416485
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
417486
protocol, prio, parent, q, block);
@@ -429,8 +498,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
429498

430499
if (fh == 0) {
431500
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
432-
next = rtnl_dereference(tp->next);
433-
RCU_INIT_POINTER(*back, next);
501+
tcf_chain_tp_remove(chain, &chain_info, tp);
434502
tfilter_notify(net, skb, n, tp, fh,
435503
RTM_DELTFILTER, false);
436504
tcf_proto_destroy(tp);
@@ -459,11 +527,10 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
459527
err = tp->ops->delete(tp, fh, &last);
460528
if (err)
461529
goto errout;
462-
next = rtnl_dereference(tp->next);
463530
tfilter_notify(net, skb, n, tp, t->tcm_handle,
464531
RTM_DELTFILTER, false);
465532
if (last) {
466-
RCU_INIT_POINTER(*back, next);
533+
tcf_chain_tp_remove(chain, &chain_info, tp);
467534
tcf_proto_destroy(tp);
468535
}
469536
goto errout;
@@ -480,10 +547,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
480547
err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
481548
n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
482549
if (err == 0) {
483-
if (tp_created) {
484-
RCU_INIT_POINTER(tp->next, rtnl_dereference(*back));
485-
rcu_assign_pointer(*back, tp);
486-
}
550+
if (tp_created)
551+
tcf_chain_tp_insert(chain, &chain_info, tp);
487552
tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
488553
} else {
489554
if (tp_created)
@@ -584,7 +649,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
584649
struct net_device *dev;
585650
struct Qdisc *q;
586651
struct tcf_block *block;
587-
struct tcf_proto *tp, __rcu **chain;
652+
struct tcf_proto *tp;
653+
struct tcf_chain *chain;
588654
struct tcmsg *tcm = nlmsg_data(cb->nlh);
589655
unsigned long cl = 0;
590656
const struct Qdisc_class_ops *cops;
@@ -615,11 +681,11 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
615681
block = cops->tcf_block(q, cl);
616682
if (!block)
617683
goto errout;
618-
chain = block->p_filter_chain;
684+
chain = block->chain;
619685

620686
s_t = cb->args[0];
621687

622-
for (tp = rtnl_dereference(*chain), t = 0;
688+
for (tp = rtnl_dereference(chain->filter_chain), t = 0;
623689
tp; tp = rtnl_dereference(tp->next), t++) {
624690
if (t < s_t)
625691
continue;

0 commit comments

Comments
 (0)