aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2017-11-01 13:23:50 -0400
committerDavid S. Miller <davem@davemloft.net>2017-11-02 21:30:38 -0400
commitceffcc5e254b450e6159f173e4538215cebf1b59 (patch)
treee774e0c77b5f8a2979794ed08cc93b6365852114
parenta159d3c4b8291998c018f0dbddd4678315264a1e (diff)
net_sched: hold netns refcnt for each action
TC actions have been destroyed asynchronously for a long time, previously in a RCU callback and now in a workqueue. If we don't hold a refcnt for its netns, we could use the per netns data structure, struct tcf_idrinfo, after it has been freed by netns workqueue. Hold refcnt to ensure netns destroy happens after all actions are gone. Fixes: ddf97ccdd7cb ("net_sched: add network namespace support for tc actions") Reported-by: Lucas Bates <lucasb@mojatatu.com> Tested-by: Lucas Bates <lucasb@mojatatu.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/act_api.h4
-rw-r--r--net/sched/act_api.c2
-rw-r--r--net/sched/act_bpf.c2
-rw-r--r--net/sched/act_connmark.c2
-rw-r--r--net/sched/act_csum.c2
-rw-r--r--net/sched/act_gact.c2
-rw-r--r--net/sched/act_ife.c2
-rw-r--r--net/sched/act_ipt.c4
-rw-r--r--net/sched/act_mirred.c2
-rw-r--r--net/sched/act_nat.c2
-rw-r--r--net/sched/act_pedit.c2
-rw-r--r--net/sched/act_police.c2
-rw-r--r--net/sched/act_sample.c2
-rw-r--r--net/sched/act_simple.c2
-rw-r--r--net/sched/act_skbedit.c2
-rw-r--r--net/sched/act_skbmod.c2
-rw-r--r--net/sched/act_tunnel_key.c2
-rw-r--r--net/sched/act_vlan.c2
18 files changed, 22 insertions, 18 deletions
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 5072446d5f06..c68551255032 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -13,6 +13,7 @@
13struct tcf_idrinfo { 13struct tcf_idrinfo {
14 spinlock_t lock; 14 spinlock_t lock;
15 struct idr action_idr; 15 struct idr action_idr;
16 struct net *net;
16}; 17};
17 18
18struct tc_action_ops; 19struct tc_action_ops;
@@ -104,7 +105,7 @@ struct tc_action_net {
104 105
105static inline 106static inline
106int tc_action_net_init(struct tc_action_net *tn, 107int tc_action_net_init(struct tc_action_net *tn,
107 const struct tc_action_ops *ops) 108 const struct tc_action_ops *ops, struct net *net)
108{ 109{
109 int err = 0; 110 int err = 0;
110 111
@@ -112,6 +113,7 @@ int tc_action_net_init(struct tc_action_net *tn,
112 if (!tn->idrinfo) 113 if (!tn->idrinfo)
113 return -ENOMEM; 114 return -ENOMEM;
114 tn->ops = ops; 115 tn->ops = ops;
116 tn->idrinfo->net = net;
115 spin_lock_init(&tn->idrinfo->lock); 117 spin_lock_init(&tn->idrinfo->lock);
116 idr_init(&tn->idrinfo->action_idr); 118 idr_init(&tn->idrinfo->action_idr);
117 return err; 119 return err;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 8f2c63514956..ca2ff0b3123f 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -78,6 +78,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
78 spin_lock_bh(&idrinfo->lock); 78 spin_lock_bh(&idrinfo->lock);
79 idr_remove_ext(&idrinfo->action_idr, p->tcfa_index); 79 idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
80 spin_unlock_bh(&idrinfo->lock); 80 spin_unlock_bh(&idrinfo->lock);
81 put_net(idrinfo->net);
81 gen_kill_estimator(&p->tcfa_rate_est); 82 gen_kill_estimator(&p->tcfa_rate_est);
82 free_tcf(p); 83 free_tcf(p);
83} 84}
@@ -336,6 +337,7 @@ err3:
336 p->idrinfo = idrinfo; 337 p->idrinfo = idrinfo;
337 p->ops = ops; 338 p->ops = ops;
338 INIT_LIST_HEAD(&p->list); 339 INIT_LIST_HEAD(&p->list);
340 get_net(idrinfo->net);
339 *a = p; 341 *a = p;
340 return 0; 342 return 0;
341} 343}
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index c0c707eb2c96..9bce8cc84cbb 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -398,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
398{ 398{
399 struct tc_action_net *tn = net_generic(net, bpf_net_id); 399 struct tc_action_net *tn = net_generic(net, bpf_net_id);
400 400
401 return tc_action_net_init(tn, &act_bpf_ops); 401 return tc_action_net_init(tn, &act_bpf_ops, net);
402} 402}
403 403
404static void __net_exit bpf_exit_net(struct net *net) 404static void __net_exit bpf_exit_net(struct net *net)
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 10b7a8855a6c..34e52d01a5dd 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -206,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
206{ 206{
207 struct tc_action_net *tn = net_generic(net, connmark_net_id); 207 struct tc_action_net *tn = net_generic(net, connmark_net_id);
208 208
209 return tc_action_net_init(tn, &act_connmark_ops); 209 return tc_action_net_init(tn, &act_connmark_ops, net);
210} 210}
211 211
212static void __net_exit connmark_exit_net(struct net *net) 212static void __net_exit connmark_exit_net(struct net *net)
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 1c40caadcff9..35171df2ebef 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -626,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
626{ 626{
627 struct tc_action_net *tn = net_generic(net, csum_net_id); 627 struct tc_action_net *tn = net_generic(net, csum_net_id);
628 628
629 return tc_action_net_init(tn, &act_csum_ops); 629 return tc_action_net_init(tn, &act_csum_ops, net);
630} 630}
631 631
632static void __net_exit csum_exit_net(struct net *net) 632static void __net_exit csum_exit_net(struct net *net)
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index e29a48ef7fc3..ef7f7f39d26d 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -232,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
232{ 232{
233 struct tc_action_net *tn = net_generic(net, gact_net_id); 233 struct tc_action_net *tn = net_generic(net, gact_net_id);
234 234
235 return tc_action_net_init(tn, &act_gact_ops); 235 return tc_action_net_init(tn, &act_gact_ops, net);
236} 236}
237 237
238static void __net_exit gact_exit_net(struct net *net) 238static void __net_exit gact_exit_net(struct net *net)
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 8ccd35825b6b..f65e4b5058e0 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -818,7 +818,7 @@ static __net_init int ife_init_net(struct net *net)
818{ 818{
819 struct tc_action_net *tn = net_generic(net, ife_net_id); 819 struct tc_action_net *tn = net_generic(net, ife_net_id);
820 820
821 return tc_action_net_init(tn, &act_ife_ops); 821 return tc_action_net_init(tn, &act_ife_ops, net);
822} 822}
823 823
824static void __net_exit ife_exit_net(struct net *net) 824static void __net_exit ife_exit_net(struct net *net)
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index d9e399a7e3d5..dbdf3b2470d5 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -334,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net)
334{ 334{
335 struct tc_action_net *tn = net_generic(net, ipt_net_id); 335 struct tc_action_net *tn = net_generic(net, ipt_net_id);
336 336
337 return tc_action_net_init(tn, &act_ipt_ops); 337 return tc_action_net_init(tn, &act_ipt_ops, net);
338} 338}
339 339
340static void __net_exit ipt_exit_net(struct net *net) 340static void __net_exit ipt_exit_net(struct net *net)
@@ -384,7 +384,7 @@ static __net_init int xt_init_net(struct net *net)
384{ 384{
385 struct tc_action_net *tn = net_generic(net, xt_net_id); 385 struct tc_action_net *tn = net_generic(net, xt_net_id);
386 386
387 return tc_action_net_init(tn, &act_xt_ops); 387 return tc_action_net_init(tn, &act_xt_ops, net);
388} 388}
389 389
390static void __net_exit xt_exit_net(struct net *net) 390static void __net_exit xt_exit_net(struct net *net)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 416627c66f08..84759cfd5a33 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -343,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
343{ 343{
344 struct tc_action_net *tn = net_generic(net, mirred_net_id); 344 struct tc_action_net *tn = net_generic(net, mirred_net_id);
345 345
346 return tc_action_net_init(tn, &act_mirred_ops); 346 return tc_action_net_init(tn, &act_mirred_ops, net);
347} 347}
348 348
349static void __net_exit mirred_exit_net(struct net *net) 349static void __net_exit mirred_exit_net(struct net *net)
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index c365d01b99c8..7eeaaf9217b6 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -307,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
307{ 307{
308 struct tc_action_net *tn = net_generic(net, nat_net_id); 308 struct tc_action_net *tn = net_generic(net, nat_net_id);
309 309
310 return tc_action_net_init(tn, &act_nat_ops); 310 return tc_action_net_init(tn, &act_nat_ops, net);
311} 311}
312 312
313static void __net_exit nat_exit_net(struct net *net) 313static void __net_exit nat_exit_net(struct net *net)
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 491fe5deb09e..b3d82c334a5f 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -450,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
450{ 450{
451 struct tc_action_net *tn = net_generic(net, pedit_net_id); 451 struct tc_action_net *tn = net_generic(net, pedit_net_id);
452 452
453 return tc_action_net_init(tn, &act_pedit_ops); 453 return tc_action_net_init(tn, &act_pedit_ops, net);
454} 454}
455 455
456static void __net_exit pedit_exit_net(struct net *net) 456static void __net_exit pedit_exit_net(struct net *net)
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 3bb2ebf9e9ae..9ec42b26e4b9 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -331,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
331{ 331{
332 struct tc_action_net *tn = net_generic(net, police_net_id); 332 struct tc_action_net *tn = net_generic(net, police_net_id);
333 333
334 return tc_action_net_init(tn, &act_police_ops); 334 return tc_action_net_init(tn, &act_police_ops, net);
335} 335}
336 336
337static void __net_exit police_exit_net(struct net *net) 337static void __net_exit police_exit_net(struct net *net)
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 8b5abcd2f32f..e69a1e3a39bf 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -240,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
240{ 240{
241 struct tc_action_net *tn = net_generic(net, sample_net_id); 241 struct tc_action_net *tn = net_generic(net, sample_net_id);
242 242
243 return tc_action_net_init(tn, &act_sample_ops); 243 return tc_action_net_init(tn, &act_sample_ops, net);
244} 244}
245 245
246static void __net_exit sample_exit_net(struct net *net) 246static void __net_exit sample_exit_net(struct net *net)
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index e7b57e5071a3..a8d0ea95f894 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -201,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
201{ 201{
202 struct tc_action_net *tn = net_generic(net, simp_net_id); 202 struct tc_action_net *tn = net_generic(net, simp_net_id);
203 203
204 return tc_action_net_init(tn, &act_simp_ops); 204 return tc_action_net_init(tn, &act_simp_ops, net);
205} 205}
206 206
207static void __net_exit simp_exit_net(struct net *net) 207static void __net_exit simp_exit_net(struct net *net)
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 59949d61f20d..fbac62472e09 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -238,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
238{ 238{
239 struct tc_action_net *tn = net_generic(net, skbedit_net_id); 239 struct tc_action_net *tn = net_generic(net, skbedit_net_id);
240 240
241 return tc_action_net_init(tn, &act_skbedit_ops); 241 return tc_action_net_init(tn, &act_skbedit_ops, net);
242} 242}
243 243
244static void __net_exit skbedit_exit_net(struct net *net) 244static void __net_exit skbedit_exit_net(struct net *net)
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index b642ad3d39dd..8e12d8897d2f 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -263,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
263{ 263{
264 struct tc_action_net *tn = net_generic(net, skbmod_net_id); 264 struct tc_action_net *tn = net_generic(net, skbmod_net_id);
265 265
266 return tc_action_net_init(tn, &act_skbmod_ops); 266 return tc_action_net_init(tn, &act_skbmod_ops, net);
267} 267}
268 268
269static void __net_exit skbmod_exit_net(struct net *net) 269static void __net_exit skbmod_exit_net(struct net *net)
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 30c96274c638..c33faa373cf2 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -322,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
322{ 322{
323 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 323 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
324 324
325 return tc_action_net_init(tn, &act_tunnel_key_ops); 325 return tc_action_net_init(tn, &act_tunnel_key_ops, net);
326} 326}
327 327
328static void __net_exit tunnel_key_exit_net(struct net *net) 328static void __net_exit tunnel_key_exit_net(struct net *net)
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 16eb067a8d8f..115fc33cc6d8 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -269,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
269{ 269{
270 struct tc_action_net *tn = net_generic(net, vlan_net_id); 270 struct tc_action_net *tn = net_generic(net, vlan_net_id);
271 271
272 return tc_action_net_init(tn, &act_vlan_ops); 272 return tc_action_net_init(tn, &act_vlan_ops, net);
273} 273}
274 274
275static void __net_exit vlan_exit_net(struct net *net) 275static void __net_exit vlan_exit_net(struct net *net)