diff options
Diffstat (limited to 'net/sched/act_bpf.c')
-rw-r--r-- | net/sched/act_bpf.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index e9e923a8c747..aaae8e83bf18 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c | |||
@@ -27,9 +27,10 @@ | |||
27 | struct tcf_bpf_cfg { | 27 | struct tcf_bpf_cfg { |
28 | struct bpf_prog *filter; | 28 | struct bpf_prog *filter; |
29 | struct sock_filter *bpf_ops; | 29 | struct sock_filter *bpf_ops; |
30 | char *bpf_name; | 30 | const char *bpf_name; |
31 | u32 bpf_fd; | 31 | u32 bpf_fd; |
32 | u16 bpf_num_ops; | 32 | u16 bpf_num_ops; |
33 | bool is_ebpf; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act, | 36 | static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act, |
@@ -207,6 +208,7 @@ static int tcf_bpf_init_from_ops(struct nlattr **tb, struct tcf_bpf_cfg *cfg) | |||
207 | cfg->bpf_ops = bpf_ops; | 208 | cfg->bpf_ops = bpf_ops; |
208 | cfg->bpf_num_ops = bpf_num_ops; | 209 | cfg->bpf_num_ops = bpf_num_ops; |
209 | cfg->filter = fp; | 210 | cfg->filter = fp; |
211 | cfg->is_ebpf = false; | ||
210 | 212 | ||
211 | return 0; | 213 | return 0; |
212 | } | 214 | } |
@@ -241,18 +243,40 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg) | |||
241 | cfg->bpf_fd = bpf_fd; | 243 | cfg->bpf_fd = bpf_fd; |
242 | cfg->bpf_name = name; | 244 | cfg->bpf_name = name; |
243 | cfg->filter = fp; | 245 | cfg->filter = fp; |
246 | cfg->is_ebpf = true; | ||
244 | 247 | ||
245 | return 0; | 248 | return 0; |
246 | } | 249 | } |
247 | 250 | ||
251 | static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg) | ||
252 | { | ||
253 | if (cfg->is_ebpf) | ||
254 | bpf_prog_put(cfg->filter); | ||
255 | else | ||
256 | bpf_prog_destroy(cfg->filter); | ||
257 | |||
258 | kfree(cfg->bpf_ops); | ||
259 | kfree(cfg->bpf_name); | ||
260 | } | ||
261 | |||
262 | static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog, | ||
263 | struct tcf_bpf_cfg *cfg) | ||
264 | { | ||
265 | cfg->is_ebpf = tcf_bpf_is_ebpf(prog); | ||
266 | cfg->filter = prog->filter; | ||
267 | |||
268 | cfg->bpf_ops = prog->bpf_ops; | ||
269 | cfg->bpf_name = prog->bpf_name; | ||
270 | } | ||
271 | |||
248 | static int tcf_bpf_init(struct net *net, struct nlattr *nla, | 272 | static int tcf_bpf_init(struct net *net, struct nlattr *nla, |
249 | struct nlattr *est, struct tc_action *act, | 273 | struct nlattr *est, struct tc_action *act, |
250 | int replace, int bind) | 274 | int replace, int bind) |
251 | { | 275 | { |
252 | struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; | 276 | struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; |
277 | struct tcf_bpf_cfg cfg, old; | ||
253 | struct tc_act_bpf *parm; | 278 | struct tc_act_bpf *parm; |
254 | struct tcf_bpf *prog; | 279 | struct tcf_bpf *prog; |
255 | struct tcf_bpf_cfg cfg; | ||
256 | bool is_bpf, is_ebpf; | 280 | bool is_bpf, is_ebpf; |
257 | int ret; | 281 | int ret; |
258 | 282 | ||
@@ -301,6 +325,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, | |||
301 | prog = to_bpf(act); | 325 | prog = to_bpf(act); |
302 | spin_lock_bh(&prog->tcf_lock); | 326 | spin_lock_bh(&prog->tcf_lock); |
303 | 327 | ||
328 | if (ret != ACT_P_CREATED) | ||
329 | tcf_bpf_prog_fill_cfg(prog, &old); | ||
330 | |||
304 | prog->bpf_ops = cfg.bpf_ops; | 331 | prog->bpf_ops = cfg.bpf_ops; |
305 | prog->bpf_name = cfg.bpf_name; | 332 | prog->bpf_name = cfg.bpf_name; |
306 | 333 | ||
@@ -316,32 +343,22 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, | |||
316 | 343 | ||
317 | if (ret == ACT_P_CREATED) | 344 | if (ret == ACT_P_CREATED) |
318 | tcf_hash_insert(act); | 345 | tcf_hash_insert(act); |
346 | else | ||
347 | tcf_bpf_cfg_cleanup(&old); | ||
319 | 348 | ||
320 | return ret; | 349 | return ret; |
321 | 350 | ||
322 | destroy_fp: | 351 | destroy_fp: |
323 | if (is_ebpf) | 352 | tcf_bpf_cfg_cleanup(&cfg); |
324 | bpf_prog_put(cfg.filter); | ||
325 | else | ||
326 | bpf_prog_destroy(cfg.filter); | ||
327 | |||
328 | kfree(cfg.bpf_ops); | ||
329 | kfree(cfg.bpf_name); | ||
330 | |||
331 | return ret; | 353 | return ret; |
332 | } | 354 | } |
333 | 355 | ||
334 | static void tcf_bpf_cleanup(struct tc_action *act, int bind) | 356 | static void tcf_bpf_cleanup(struct tc_action *act, int bind) |
335 | { | 357 | { |
336 | const struct tcf_bpf *prog = act->priv; | 358 | struct tcf_bpf_cfg tmp; |
337 | |||
338 | if (tcf_bpf_is_ebpf(prog)) | ||
339 | bpf_prog_put(prog->filter); | ||
340 | else | ||
341 | bpf_prog_destroy(prog->filter); | ||
342 | 359 | ||
343 | kfree(prog->bpf_ops); | 360 | tcf_bpf_prog_fill_cfg(act->priv, &tmp); |
344 | kfree(prog->bpf_name); | 361 | tcf_bpf_cfg_cleanup(&tmp); |
345 | } | 362 | } |
346 | 363 | ||
347 | static struct tc_action_ops act_bpf_ops __read_mostly = { | 364 | static struct tc_action_ops act_bpf_ops __read_mostly = { |