.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us> |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License as published by |
---|
6 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
7 | | - * (at your option) any later version. |
---|
8 | 4 | */ |
---|
9 | 5 | |
---|
10 | 6 | #include <linux/module.h> |
---|
.. | .. |
---|
16 | 12 | #include <linux/bpf.h> |
---|
17 | 13 | |
---|
18 | 14 | #include <net/netlink.h> |
---|
| 15 | +#include <net/sock.h> |
---|
19 | 16 | #include <net/pkt_sched.h> |
---|
| 17 | +#include <net/pkt_cls.h> |
---|
20 | 18 | |
---|
21 | 19 | #include <linux/tc_act/tc_bpf.h> |
---|
22 | 20 | #include <net/tc_act/tc_bpf.h> |
---|
.. | .. |
---|
56 | 54 | bpf_compute_data_pointers(skb); |
---|
57 | 55 | filter_res = BPF_PROG_RUN(filter, skb); |
---|
58 | 56 | } |
---|
| 57 | + if (skb_sk_is_prefetched(skb) && filter_res != TC_ACT_OK) |
---|
| 58 | + skb_orphan(skb); |
---|
59 | 59 | rcu_read_unlock(); |
---|
60 | 60 | |
---|
61 | 61 | /* A BPF program may overwrite the default action opcode. |
---|
.. | .. |
---|
278 | 278 | static int tcf_bpf_init(struct net *net, struct nlattr *nla, |
---|
279 | 279 | struct nlattr *est, struct tc_action **act, |
---|
280 | 280 | int replace, int bind, bool rtnl_held, |
---|
| 281 | + struct tcf_proto *tp, u32 flags, |
---|
281 | 282 | struct netlink_ext_ack *extack) |
---|
282 | 283 | { |
---|
283 | 284 | struct tc_action_net *tn = net_generic(net, bpf_net_id); |
---|
284 | 285 | struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; |
---|
| 286 | + struct tcf_chain *goto_ch = NULL; |
---|
285 | 287 | struct tcf_bpf_cfg cfg, old; |
---|
286 | 288 | struct tc_act_bpf *parm; |
---|
287 | 289 | struct tcf_bpf *prog; |
---|
.. | .. |
---|
292 | 294 | if (!nla) |
---|
293 | 295 | return -EINVAL; |
---|
294 | 296 | |
---|
295 | | - ret = nla_parse_nested(tb, TCA_ACT_BPF_MAX, nla, act_bpf_policy, NULL); |
---|
| 297 | + ret = nla_parse_nested_deprecated(tb, TCA_ACT_BPF_MAX, nla, |
---|
| 298 | + act_bpf_policy, NULL); |
---|
296 | 299 | if (ret < 0) |
---|
297 | 300 | return ret; |
---|
298 | 301 | |
---|
.. | .. |
---|
304 | 307 | ret = tcf_idr_check_alloc(tn, &index, act, bind); |
---|
305 | 308 | if (!ret) { |
---|
306 | 309 | ret = tcf_idr_create(tn, index, est, act, |
---|
307 | | - &act_bpf_ops, bind, true); |
---|
| 310 | + &act_bpf_ops, bind, true, flags); |
---|
308 | 311 | if (ret < 0) { |
---|
309 | 312 | tcf_idr_cleanup(tn, index); |
---|
310 | 313 | return ret; |
---|
.. | .. |
---|
324 | 327 | return ret; |
---|
325 | 328 | } |
---|
326 | 329 | |
---|
| 330 | + ret = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
---|
| 331 | + if (ret < 0) |
---|
| 332 | + goto release_idr; |
---|
| 333 | + |
---|
327 | 334 | is_bpf = tb[TCA_ACT_BPF_OPS_LEN] && tb[TCA_ACT_BPF_OPS]; |
---|
328 | 335 | is_ebpf = tb[TCA_ACT_BPF_FD]; |
---|
329 | 336 | |
---|
330 | 337 | if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf)) { |
---|
331 | 338 | ret = -EINVAL; |
---|
332 | | - goto out; |
---|
| 339 | + goto put_chain; |
---|
333 | 340 | } |
---|
334 | 341 | |
---|
335 | 342 | memset(&cfg, 0, sizeof(cfg)); |
---|
.. | .. |
---|
337 | 344 | ret = is_bpf ? tcf_bpf_init_from_ops(tb, &cfg) : |
---|
338 | 345 | tcf_bpf_init_from_efd(tb, &cfg); |
---|
339 | 346 | if (ret < 0) |
---|
340 | | - goto out; |
---|
| 347 | + goto put_chain; |
---|
341 | 348 | |
---|
342 | 349 | prog = to_bpf(*act); |
---|
343 | 350 | |
---|
.. | .. |
---|
351 | 358 | if (cfg.bpf_num_ops) |
---|
352 | 359 | prog->bpf_num_ops = cfg.bpf_num_ops; |
---|
353 | 360 | |
---|
354 | | - prog->tcf_action = parm->action; |
---|
| 361 | + goto_ch = tcf_action_set_ctrlact(*act, parm->action, goto_ch); |
---|
355 | 362 | rcu_assign_pointer(prog->filter, cfg.filter); |
---|
356 | 363 | spin_unlock_bh(&prog->tcf_lock); |
---|
357 | 364 | |
---|
358 | | - if (res == ACT_P_CREATED) { |
---|
359 | | - tcf_idr_insert(tn, *act); |
---|
360 | | - } else { |
---|
| 365 | + if (goto_ch) |
---|
| 366 | + tcf_chain_put_by_act(goto_ch); |
---|
| 367 | + |
---|
| 368 | + if (res != ACT_P_CREATED) { |
---|
361 | 369 | /* make sure the program being replaced is no longer executing */ |
---|
362 | 370 | synchronize_rcu(); |
---|
363 | 371 | tcf_bpf_cfg_cleanup(&old); |
---|
364 | 372 | } |
---|
365 | 373 | |
---|
366 | 374 | return res; |
---|
367 | | -out: |
---|
368 | | - tcf_idr_release(*act, bind); |
---|
369 | 375 | |
---|
| 376 | +put_chain: |
---|
| 377 | + if (goto_ch) |
---|
| 378 | + tcf_chain_put_by_act(goto_ch); |
---|
| 379 | + |
---|
| 380 | +release_idr: |
---|
| 381 | + tcf_idr_release(*act, bind); |
---|
370 | 382 | return ret; |
---|
371 | 383 | } |
---|
372 | 384 | |
---|
.. | .. |
---|
388 | 400 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
---|
389 | 401 | } |
---|
390 | 402 | |
---|
391 | | -static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index, |
---|
392 | | - struct netlink_ext_ack *extack) |
---|
| 403 | +static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index) |
---|
393 | 404 | { |
---|
394 | 405 | struct tc_action_net *tn = net_generic(net, bpf_net_id); |
---|
395 | 406 | |
---|
.. | .. |
---|
398 | 409 | |
---|
399 | 410 | static struct tc_action_ops act_bpf_ops __read_mostly = { |
---|
400 | 411 | .kind = "bpf", |
---|
401 | | - .type = TCA_ACT_BPF, |
---|
| 412 | + .id = TCA_ID_BPF, |
---|
402 | 413 | .owner = THIS_MODULE, |
---|
403 | 414 | .act = tcf_bpf_act, |
---|
404 | 415 | .dump = tcf_bpf_dump, |
---|