aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/pkt_cls.h14
-rw-r--r--include/net/sch_generic.h5
-rw-r--r--net/sched/cls_api.c54
-rw-r--r--net/sched/sch_ingress.c36
4 files changed, 62 insertions, 47 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index d15c40c7bde7..505d4b71975f 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -26,6 +26,8 @@ enum tcf_block_binder_type {
26 26
27struct tcf_block_ext_info { 27struct tcf_block_ext_info {
28 enum tcf_block_binder_type binder_type; 28 enum tcf_block_binder_type binder_type;
29 tcf_chain_head_change_t *chain_head_change;
30 void *chain_head_change_priv;
29}; 31};
30 32
31struct tcf_block_cb; 33struct tcf_block_cb;
@@ -37,12 +39,10 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
37void tcf_chain_put(struct tcf_chain *chain); 39void tcf_chain_put(struct tcf_chain *chain);
38int tcf_block_get(struct tcf_block **p_block, 40int tcf_block_get(struct tcf_block **p_block,
39 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q); 41 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q);
40int tcf_block_get_ext(struct tcf_block **p_block, 42int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
41 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
42 struct tcf_block_ext_info *ei); 43 struct tcf_block_ext_info *ei);
43void tcf_block_put(struct tcf_block *block); 44void tcf_block_put(struct tcf_block *block);
44void tcf_block_put_ext(struct tcf_block *block, 45void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
45 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
46 struct tcf_block_ext_info *ei); 46 struct tcf_block_ext_info *ei);
47 47
48static inline struct Qdisc *tcf_block_q(struct tcf_block *block) 48static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
@@ -82,8 +82,7 @@ int tcf_block_get(struct tcf_block **p_block,
82} 82}
83 83
84static inline 84static inline
85int tcf_block_get_ext(struct tcf_block **p_block, 85int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
86 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
87 struct tcf_block_ext_info *ei) 86 struct tcf_block_ext_info *ei)
88{ 87{
89 return 0; 88 return 0;
@@ -94,8 +93,7 @@ static inline void tcf_block_put(struct tcf_block *block)
94} 93}
95 94
96static inline 95static inline
97void tcf_block_put_ext(struct tcf_block *block, 96void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
98 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
99 struct tcf_block_ext_info *ei) 97 struct tcf_block_ext_info *ei)
100{ 98{
101} 99}
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index c23e938f5b19..f230269e0bfb 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -260,9 +260,12 @@ struct qdisc_skb_cb {
260 unsigned char data[QDISC_CB_PRIV_LEN]; 260 unsigned char data[QDISC_CB_PRIV_LEN];
261}; 261};
262 262
263typedef void tcf_chain_head_change_t(struct tcf_proto *tp_head, void *priv);
264
263struct tcf_chain { 265struct tcf_chain {
264 struct tcf_proto __rcu *filter_chain; 266 struct tcf_proto __rcu *filter_chain;
265 struct tcf_proto __rcu **p_filter_chain; 267 tcf_chain_head_change_t *chain_head_change;
268 void *chain_head_change_priv;
266 struct list_head list; 269 struct list_head list;
267 struct tcf_block *block; 270 struct tcf_block *block;
268 u32 index; /* chain index */ 271 u32 index; /* chain index */
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 8d1885abee83..206e19f4fc01 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -195,12 +195,19 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
195 return chain; 195 return chain;
196} 196}
197 197
198static void tcf_chain_head_change(struct tcf_chain *chain,
199 struct tcf_proto *tp_head)
200{
201 if (chain->chain_head_change)
202 chain->chain_head_change(tp_head,
203 chain->chain_head_change_priv);
204}
205
198static void tcf_chain_flush(struct tcf_chain *chain) 206static void tcf_chain_flush(struct tcf_chain *chain)
199{ 207{
200 struct tcf_proto *tp; 208 struct tcf_proto *tp;
201 209
202 if (chain->p_filter_chain) 210 tcf_chain_head_change(chain, NULL);
203 RCU_INIT_POINTER(*chain->p_filter_chain, NULL);
204 while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) { 211 while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) {
205 RCU_INIT_POINTER(chain->filter_chain, tp->next); 212 RCU_INIT_POINTER(chain->filter_chain, tp->next);
206 tcf_chain_put(chain); 213 tcf_chain_put(chain);
@@ -242,13 +249,6 @@ void tcf_chain_put(struct tcf_chain *chain)
242} 249}
243EXPORT_SYMBOL(tcf_chain_put); 250EXPORT_SYMBOL(tcf_chain_put);
244 251
245static void
246tcf_chain_filter_chain_ptr_set(struct tcf_chain *chain,
247 struct tcf_proto __rcu **p_filter_chain)
248{
249 chain->p_filter_chain = p_filter_chain;
250}
251
252static void tcf_block_offload_cmd(struct tcf_block *block, struct Qdisc *q, 252static void tcf_block_offload_cmd(struct tcf_block *block, struct Qdisc *q,
253 struct tcf_block_ext_info *ei, 253 struct tcf_block_ext_info *ei,
254 enum tc_block_command command) 254 enum tc_block_command command)
@@ -276,8 +276,7 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
276 tcf_block_offload_cmd(block, q, ei, TC_BLOCK_UNBIND); 276 tcf_block_offload_cmd(block, q, ei, TC_BLOCK_UNBIND);
277} 277}
278 278
279int tcf_block_get_ext(struct tcf_block **p_block, 279int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
280 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
281 struct tcf_block_ext_info *ei) 280 struct tcf_block_ext_info *ei)
282{ 281{
283 struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL); 282 struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
@@ -295,7 +294,9 @@ int tcf_block_get_ext(struct tcf_block **p_block,
295 err = -ENOMEM; 294 err = -ENOMEM;
296 goto err_chain_create; 295 goto err_chain_create;
297 } 296 }
298 tcf_chain_filter_chain_ptr_set(chain, p_filter_chain); 297 WARN_ON(!ei->chain_head_change);
298 chain->chain_head_change = ei->chain_head_change;
299 chain->chain_head_change_priv = ei->chain_head_change_priv;
299 block->net = qdisc_net(q); 300 block->net = qdisc_net(q);
300 block->q = q; 301 block->q = q;
301 tcf_block_offload_bind(block, q, ei); 302 tcf_block_offload_bind(block, q, ei);
@@ -308,12 +309,23 @@ err_chain_create:
308} 309}
309EXPORT_SYMBOL(tcf_block_get_ext); 310EXPORT_SYMBOL(tcf_block_get_ext);
310 311
312static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
313{
314 struct tcf_proto __rcu **p_filter_chain = priv;
315
316 rcu_assign_pointer(*p_filter_chain, tp_head);
317}
318
311int tcf_block_get(struct tcf_block **p_block, 319int tcf_block_get(struct tcf_block **p_block,
312 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q) 320 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q)
313{ 321{
314 struct tcf_block_ext_info ei = {0, }; 322 struct tcf_block_ext_info ei = {
323 .chain_head_change = tcf_chain_head_change_dflt,
324 .chain_head_change_priv = p_filter_chain,
325 };
315 326
316 return tcf_block_get_ext(p_block, p_filter_chain, q, &ei); 327 WARN_ON(!p_filter_chain);
328 return tcf_block_get_ext(p_block, q, &ei);
317} 329}
318EXPORT_SYMBOL(tcf_block_get); 330EXPORT_SYMBOL(tcf_block_get);
319 331
@@ -334,8 +346,7 @@ static void tcf_block_put_final(struct work_struct *work)
334 * actions should be all removed after flushing. However, filters are now 346 * actions should be all removed after flushing. However, filters are now
335 * destroyed in tc filter workqueue with RTNL lock, they can not race here. 347 * destroyed in tc filter workqueue with RTNL lock, they can not race here.
336 */ 348 */
337void tcf_block_put_ext(struct tcf_block *block, 349void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
338 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
339 struct tcf_block_ext_info *ei) 350 struct tcf_block_ext_info *ei)
340{ 351{
341 struct tcf_chain *chain, *tmp; 352 struct tcf_chain *chain, *tmp;
@@ -361,7 +372,7 @@ void tcf_block_put(struct tcf_block *block)
361 372
362 if (!block) 373 if (!block)
363 return; 374 return;
364 tcf_block_put_ext(block, NULL, block->q, &ei); 375 tcf_block_put_ext(block, block->q, &ei);
365} 376}
366 377
367EXPORT_SYMBOL(tcf_block_put); 378EXPORT_SYMBOL(tcf_block_put);
@@ -537,9 +548,8 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
537 struct tcf_chain_info *chain_info, 548 struct tcf_chain_info *chain_info,
538 struct tcf_proto *tp) 549 struct tcf_proto *tp)
539{ 550{
540 if (chain->p_filter_chain && 551 if (*chain_info->pprev == chain->filter_chain)
541 *chain_info->pprev == chain->filter_chain) 552 tcf_chain_head_change(chain, tp);
542 rcu_assign_pointer(*chain->p_filter_chain, tp);
543 RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info)); 553 RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info));
544 rcu_assign_pointer(*chain_info->pprev, tp); 554 rcu_assign_pointer(*chain_info->pprev, tp);
545 tcf_chain_hold(chain); 555 tcf_chain_hold(chain);
@@ -551,8 +561,8 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
551<