diff options
| -rw-r--r-- | include/net/pkt_cls.h | 14 | ||||
| -rw-r--r-- | include/net/sch_generic.h | 5 | ||||
| -rw-r--r-- | net/sched/cls_api.c | 54 | ||||
| -rw-r--r-- | net/sched/sch_ingress.c | 36 |
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 | ||
| 27 | struct tcf_block_ext_info { | 27 | struct 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 | ||
| 31 | struct tcf_block_cb; | 33 | struct tcf_block_cb; |
| @@ -37,12 +39,10 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | |||
| 37 | void tcf_chain_put(struct tcf_chain *chain); | 39 | void tcf_chain_put(struct tcf_chain *chain); |
| 38 | int tcf_block_get(struct tcf_block **p_block, | 40 | int 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); |
| 40 | int tcf_block_get_ext(struct tcf_block **p_block, | 42 | int 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); |
| 43 | void tcf_block_put(struct tcf_block *block); | 44 | void tcf_block_put(struct tcf_block *block); |
| 44 | void tcf_block_put_ext(struct tcf_block *block, | 45 | void 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 | ||
| 48 | static inline struct Qdisc *tcf_block_q(struct tcf_block *block) | 48 | static 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 | ||
| 84 | static inline | 84 | static inline |
| 85 | int tcf_block_get_ext(struct tcf_block **p_block, | 85 | int 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 | ||
| 96 | static inline | 95 | static inline |
| 97 | void tcf_block_put_ext(struct tcf_block *block, | 96 | void 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 | ||
| 263 | typedef void tcf_chain_head_change_t(struct tcf_proto *tp_head, void *priv); | ||
| 264 | |||
| 263 | struct tcf_chain { | 265 | struct 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 | ||
| 198 | static 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 | |||
| 198 | static void tcf_chain_flush(struct tcf_chain *chain) | 206 | static 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 | } |
| 243 | EXPORT_SYMBOL(tcf_chain_put); | 250 | EXPORT_SYMBOL(tcf_chain_put); |
| 244 | 251 | ||
| 245 | static void | ||
| 246 | tcf_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 | |||
| 252 | static void tcf_block_offload_cmd(struct tcf_block *block, struct Qdisc *q, | 252 | static 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 | ||
| 279 | int tcf_block_get_ext(struct tcf_block **p_block, | 279 | int 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 | } |
| 309 | EXPORT_SYMBOL(tcf_block_get_ext); | 310 | EXPORT_SYMBOL(tcf_block_get_ext); |
| 310 | 311 | ||
| 312 | static 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 | |||
| 311 | int tcf_block_get(struct tcf_block **p_block, | 319 | int 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 | } |
| 318 | EXPORT_SYMBOL(tcf_block_get); | 330 | EXPORT_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 | */ |
| 337 | void tcf_block_put_ext(struct tcf_block *block, | 349 | void 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 | ||
| 367 | EXPORT_SYMBOL(tcf_block_put); | 378 | EXPORT_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< | |||
