diff options
author | Vlad Buslov <vladbu@mellanox.com> | 2019-08-26 09:45:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-08-26 17:17:43 -0400 |
commit | 9838b20a7fb28c69fa66ac8e68d967ffe1d0ecad (patch) | |
tree | 9ed88766141671e1bd7f930d7b53746a18d11c37 | |
parent | 11bd634da25735a3f2f12112d02661d462a76792 (diff) |
net: sched: take rtnl lock in tc_setup_flow_action()
In order to allow using new flow_action infrastructure from unlocked
classifiers, modify tc_setup_flow_action() to accept new 'rtnl_held'
argument. Take rtnl lock before accessing tc_action data. This is necessary
to protect from concurrent action replace.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/pkt_cls.h | 2 | ||||
-rw-r--r-- | net/sched/cls_api.c | 17 | ||||
-rw-r--r-- | net/sched/cls_flower.c | 6 | ||||
-rw-r--r-- | net/sched/cls_matchall.c | 4 |
4 files changed, 20 insertions, 9 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 612232492f67..a48824bc1489 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h | |||
@@ -504,7 +504,7 @@ tcf_match_indev(struct sk_buff *skb, int ifindex) | |||
504 | } | 504 | } |
505 | 505 | ||
506 | int tc_setup_flow_action(struct flow_action *flow_action, | 506 | int tc_setup_flow_action(struct flow_action *flow_action, |
507 | const struct tcf_exts *exts); | 507 | const struct tcf_exts *exts, bool rtnl_held); |
508 | int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, | 508 | int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, |
509 | void *type_data, bool err_stop, bool rtnl_held); | 509 | void *type_data, bool err_stop, bool rtnl_held); |
510 | int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp, | 510 | int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp, |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 3c103cf9fd0d..8751bb8a682f 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -3266,14 +3266,17 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp, | |||
3266 | EXPORT_SYMBOL(tc_setup_cb_reoffload); | 3266 | EXPORT_SYMBOL(tc_setup_cb_reoffload); |
3267 | 3267 | ||
3268 | int tc_setup_flow_action(struct flow_action *flow_action, | 3268 | int tc_setup_flow_action(struct flow_action *flow_action, |
3269 | const struct tcf_exts *exts) | 3269 | const struct tcf_exts *exts, bool rtnl_held) |
3270 | { | 3270 | { |
3271 | const struct tc_action *act; | 3271 | const struct tc_action *act; |
3272 | int i, j, k; | 3272 | int i, j, k, err = 0; |
3273 | 3273 | ||
3274 | if (!exts) | 3274 | if (!exts) |
3275 | return 0; | 3275 | return 0; |
3276 | 3276 | ||
3277 | if (!rtnl_held) | ||
3278 | rtnl_lock(); | ||
3279 | |||
3277 | j = 0; | 3280 | j = 0; |
3278 | tcf_exts_for_each_action(i, act, exts) { | 3281 | tcf_exts_for_each_action(i, act, exts) { |
3279 | struct flow_action_entry *entry; | 3282 | struct flow_action_entry *entry; |
@@ -3318,6 +3321,7 @@ int tc_setup_flow_action(struct flow_action *flow_action, | |||
3318 | entry->vlan.prio = tcf_vlan_push_prio(act); | 3321 | entry->vlan.prio = tcf_vlan_push_prio(act); |
3319 | break; | 3322 | break; |
3320 | default: | 3323 | default: |
3324 | err = -EOPNOTSUPP; | ||
3321 | goto err_out; | 3325 | goto err_out; |
3322 | } | 3326 | } |
3323 | } else if (is_tcf_tunnel_set(act)) { | 3327 | } else if (is_tcf_tunnel_set(act)) { |
@@ -3335,6 +3339,7 @@ int tc_setup_flow_action(struct flow_action *flow_action, | |||
3335 | entry->id = FLOW_ACTION_ADD; | 3339 | entry->id = FLOW_ACTION_ADD; |
3336 | break; | 3340 | break; |
3337 | default: | 3341 | default: |
3342 | err = -EOPNOTSUPP; | ||
3338 | goto err_out; | 3343 | goto err_out; |
3339 | } | 3344 | } |
3340 | entry->mangle.htype = tcf_pedit_htype(act, k); | 3345 | entry->mangle.htype = tcf_pedit_htype(act, k); |
@@ -3393,15 +3398,19 @@ int tc_setup_flow_action(struct flow_action *flow_action, | |||
3393 | entry->id = FLOW_ACTION_PTYPE; | 3398 | entry->id = FLOW_ACTION_PTYPE; |
3394 | entry->ptype = tcf_skbedit_ptype(act); | 3399 | entry->ptype = tcf_skbedit_ptype(act); |
3395 | } else { | 3400 | } else { |
3401 | err = -EOPNOTSUPP; | ||
3396 | goto err_out; | 3402 | goto err_out; |
3397 | } | 3403 | } |
3398 | 3404 | ||
3399 | if (!is_tcf_pedit(act)) | 3405 | if (!is_tcf_pedit(act)) |
3400 | j++; | 3406 | j++; |
3401 | } | 3407 | } |
3402 | return 0; | 3408 | |
3403 | err_out: | 3409 | err_out: |
3404 | return -EOPNOTSUPP; | 3410 | if (!rtnl_held) |
3411 | rtnl_unlock(); | ||
3412 | |||
3413 | return err; | ||
3405 | } | 3414 | } |
3406 | EXPORT_SYMBOL(tc_setup_flow_action); | 3415 | EXPORT_SYMBOL(tc_setup_flow_action); |
3407 | 3416 | ||
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 5cb694469b51..fb305bd45d93 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -452,7 +452,8 @@ static int fl_hw_replace_filter(struct tcf_proto *tp, | |||
452 | cls_flower.rule->match.key = &f->mkey; | 452 | cls_flower.rule->match.key = &f->mkey; |
453 | cls_flower.classid = f->res.classid; | 453 | cls_flower.classid = f->res.classid; |
454 | 454 | ||
455 | err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); | 455 | err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts, |
456 | true); | ||
456 | if (err) { | 457 | if (err) { |
457 | kfree(cls_flower.rule); | 458 | kfree(cls_flower.rule); |
458 | if (skip_sw) | 459 | if (skip_sw) |
@@ -1819,7 +1820,8 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, | |||
1819 | cls_flower.rule->match.mask = &f->mask->key; | 1820 | cls_flower.rule->match.mask = &f->mask->key; |
1820 | cls_flower.rule->match.key = &f->mkey; | 1821 | cls_flower.rule->match.key = &f->mkey; |
1821 | 1822 | ||
1822 | err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); | 1823 | err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts, |
1824 | true); | ||
1823 | if (err) { | 1825 | if (err) { |
1824 | kfree(cls_flower.rule); | 1826 | kfree(cls_flower.rule); |
1825 | if (tc_skip_sw(f->flags)) { | 1827 | if (tc_skip_sw(f->flags)) { |
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index 911d1ea28bb2..3266f25011cc 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c | |||
@@ -97,7 +97,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp, | |||
97 | cls_mall.command = TC_CLSMATCHALL_REPLACE; | 97 | cls_mall.command = TC_CLSMATCHALL_REPLACE; |
98 | cls_mall.cookie = cookie; | 98 | cls_mall.cookie = cookie; |
99 | 99 | ||
100 | err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts); | 100 | err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts, true); |
101 | if (err) { | 101 | if (err) { |
102 | kfree(cls_mall.rule); | 102 | kfree(cls_mall.rule); |
103 | mall_destroy_hw_filter(tp, head, cookie, NULL); | 103 | mall_destroy_hw_filter(tp, head, cookie, NULL); |
@@ -300,7 +300,7 @@ static int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, | |||
300 | TC_CLSMATCHALL_REPLACE : TC_CLSMATCHALL_DESTROY; | 300 | TC_CLSMATCHALL_REPLACE : TC_CLSMATCHALL_DESTROY; |
301 | cls_mall.cookie = (unsigned long)head; | 301 | cls_mall.cookie = (unsigned long)head; |
302 | 302 | ||
303 | err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts); | 303 | err = tc_setup_flow_action(&cls_mall.rule->action, &head->exts, true); |
304 | if (err) { | 304 | if (err) { |
305 | kfree(cls_mall.rule); | 305 | kfree(cls_mall.rule); |
306 | if (add && tc_skip_sw(head->flags)) { | 306 | if (add && tc_skip_sw(head->flags)) { |