|
@@ -27,9 +27,10 @@
|
|
|
struct tcf_bpf_cfg {
|
|
|
struct bpf_prog *filter;
|
|
|
struct sock_filter *bpf_ops;
|
|
|
- char *bpf_name;
|
|
|
+ const char *bpf_name;
|
|
|
u32 bpf_fd;
|
|
|
u16 bpf_num_ops;
|
|
|
+ bool is_ebpf;
|
|
|
};
|
|
|
|
|
|
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)
|
|
|
cfg->bpf_ops = bpf_ops;
|
|
|
cfg->bpf_num_ops = bpf_num_ops;
|
|
|
cfg->filter = fp;
|
|
|
+ cfg->is_ebpf = false;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -241,18 +243,40 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
|
|
|
cfg->bpf_fd = bpf_fd;
|
|
|
cfg->bpf_name = name;
|
|
|
cfg->filter = fp;
|
|
|
+ cfg->is_ebpf = true;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
|
|
|
+{
|
|
|
+ if (cfg->is_ebpf)
|
|
|
+ bpf_prog_put(cfg->filter);
|
|
|
+ else
|
|
|
+ bpf_prog_destroy(cfg->filter);
|
|
|
+
|
|
|
+ kfree(cfg->bpf_ops);
|
|
|
+ kfree(cfg->bpf_name);
|
|
|
+}
|
|
|
+
|
|
|
+static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog,
|
|
|
+ struct tcf_bpf_cfg *cfg)
|
|
|
+{
|
|
|
+ cfg->is_ebpf = tcf_bpf_is_ebpf(prog);
|
|
|
+ cfg->filter = prog->filter;
|
|
|
+
|
|
|
+ cfg->bpf_ops = prog->bpf_ops;
|
|
|
+ cfg->bpf_name = prog->bpf_name;
|
|
|
+}
|
|
|
+
|
|
|
static int tcf_bpf_init(struct net *net, struct nlattr *nla,
|
|
|
struct nlattr *est, struct tc_action *act,
|
|
|
int replace, int bind)
|
|
|
{
|
|
|
struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
|
|
|
+ struct tcf_bpf_cfg cfg, old;
|
|
|
struct tc_act_bpf *parm;
|
|
|
struct tcf_bpf *prog;
|
|
|
- struct tcf_bpf_cfg cfg;
|
|
|
bool is_bpf, is_ebpf;
|
|
|
int ret;
|
|
|
|
|
@@ -301,6 +325,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
|
|
|
prog = to_bpf(act);
|
|
|
spin_lock_bh(&prog->tcf_lock);
|
|
|
|
|
|
+ if (ret != ACT_P_CREATED)
|
|
|
+ tcf_bpf_prog_fill_cfg(prog, &old);
|
|
|
+
|
|
|
prog->bpf_ops = cfg.bpf_ops;
|
|
|
prog->bpf_name = cfg.bpf_name;
|
|
|
|
|
@@ -316,32 +343,22 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
|
|
|
|
|
|
if (ret == ACT_P_CREATED)
|
|
|
tcf_hash_insert(act);
|
|
|
+ else
|
|
|
+ tcf_bpf_cfg_cleanup(&old);
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
destroy_fp:
|
|
|
- if (is_ebpf)
|
|
|
- bpf_prog_put(cfg.filter);
|
|
|
- else
|
|
|
- bpf_prog_destroy(cfg.filter);
|
|
|
-
|
|
|
- kfree(cfg.bpf_ops);
|
|
|
- kfree(cfg.bpf_name);
|
|
|
-
|
|
|
+ tcf_bpf_cfg_cleanup(&cfg);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
static void tcf_bpf_cleanup(struct tc_action *act, int bind)
|
|
|
{
|
|
|
- const struct tcf_bpf *prog = act->priv;
|
|
|
-
|
|
|
- if (tcf_bpf_is_ebpf(prog))
|
|
|
- bpf_prog_put(prog->filter);
|
|
|
- else
|
|
|
- bpf_prog_destroy(prog->filter);
|
|
|
+ struct tcf_bpf_cfg tmp;
|
|
|
|
|
|
- kfree(prog->bpf_ops);
|
|
|
- kfree(prog->bpf_name);
|
|
|
+ tcf_bpf_prog_fill_cfg(act->priv, &tmp);
|
|
|
+ tcf_bpf_cfg_cleanup(&tmp);
|
|
|
}
|
|
|
|
|
|
static struct tc_action_ops act_bpf_ops __read_mostly = {
|