summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Buslov <vladbu@mellanox.com>2019-08-26 09:45:03 -0400
committerDavid S. Miller <davem@davemloft.net>2019-08-26 17:17:43 -0400
commit9838b20a7fb28c69fa66ac8e68d967ffe1d0ecad (patch)
tree9ed88766141671e1bd7f930d7b53746a18d11c37
parent11bd634da25735a3f2f12112d02661d462a76792 (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.h2
-rw-r--r--net/sched/cls_api.c17
-rw-r--r--net/sched/cls_flower.c6
-rw-r--r--net/sched/cls_matchall.c4
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
506int tc_setup_flow_action(struct flow_action *flow_action, 506int tc_setup_flow_action(struct flow_action *flow_action,
507 const struct tcf_exts *exts); 507 const struct tcf_exts *exts, bool rtnl_held);
508int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, 508int 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);
510int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp, 510int 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,
3266EXPORT_SYMBOL(tc_setup_cb_reoffload); 3266EXPORT_SYMBOL(tc_setup_cb_reoffload);
3267 3267
3268int tc_setup_flow_action(struct flow_action *flow_action, 3268int 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
3403err_out: 3409err_out:
3404 return -EOPNOTSUPP; 3410 if (!rtnl_held)
3411 rtnl_unlock();
3412
3413 return err;
3405} 3414}
3406EXPORT_SYMBOL(tc_setup_flow_action); 3415EXPORT_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)) {