net: sched: cls_bpf: Undo tcf_bind_filter in case of an error
If cls_bpf_offload errors out, we must also undo tcf_bind_filter that
was done before the error.
Fix that by calling tcf_unbind_filter in errout_parms.
Fixes: eadb41489f
("net: cls_bpf: add support for marking filters as hardware-only")
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Pedro Tammela <pctammela@mojatatu.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
e8d3d78c19
Коммит
26a2219492
|
@ -406,56 +406,6 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp,
|
||||
struct cls_bpf_prog *prog, unsigned long base,
|
||||
struct nlattr **tb, struct nlattr *est, u32 flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
bool is_bpf, is_ebpf, have_exts = false;
|
||||
u32 gen_flags = 0;
|
||||
int ret;
|
||||
|
||||
is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS];
|
||||
is_ebpf = tb[TCA_BPF_FD];
|
||||
if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = tcf_exts_validate(net, tp, tb, est, &prog->exts, flags,
|
||||
extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tb[TCA_BPF_FLAGS]) {
|
||||
u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
|
||||
|
||||
if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT)
|
||||
return -EINVAL;
|
||||
|
||||
have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
|
||||
}
|
||||
if (tb[TCA_BPF_FLAGS_GEN]) {
|
||||
gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]);
|
||||
if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS ||
|
||||
!tc_flags_valid(gen_flags))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
prog->exts_integrated = have_exts;
|
||||
prog->gen_flags = gen_flags;
|
||||
|
||||
ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
|
||||
cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tb[TCA_BPF_CLASSID]) {
|
||||
prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
|
||||
tcf_bind_filter(tp, &prog->res, base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
|
||||
struct tcf_proto *tp, unsigned long base,
|
||||
u32 handle, struct nlattr **tca,
|
||||
|
@ -463,9 +413,12 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_bpf_head *head = rtnl_dereference(tp->root);
|
||||
bool is_bpf, is_ebpf, have_exts = false;
|
||||
struct cls_bpf_prog *oldprog = *arg;
|
||||
struct nlattr *tb[TCA_BPF_MAX + 1];
|
||||
bool bound_to_filter = false;
|
||||
struct cls_bpf_prog *prog;
|
||||
u32 gen_flags = 0;
|
||||
int ret;
|
||||
|
||||
if (tca[TCA_OPTIONS] == NULL)
|
||||
|
@ -504,11 +457,51 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
|
|||
goto errout;
|
||||
prog->handle = handle;
|
||||
|
||||
ret = cls_bpf_set_parms(net, tp, prog, base, tb, tca[TCA_RATE], flags,
|
||||
extack);
|
||||
is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS];
|
||||
is_ebpf = tb[TCA_BPF_FD];
|
||||
if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf)) {
|
||||
ret = -EINVAL;
|
||||
goto errout_idr;
|
||||
}
|
||||
|
||||
ret = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &prog->exts,
|
||||
flags, extack);
|
||||
if (ret < 0)
|
||||
goto errout_idr;
|
||||
|
||||
if (tb[TCA_BPF_FLAGS]) {
|
||||
u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
|
||||
|
||||
if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) {
|
||||
ret = -EINVAL;
|
||||
goto errout_idr;
|
||||
}
|
||||
|
||||
have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
|
||||
}
|
||||
if (tb[TCA_BPF_FLAGS_GEN]) {
|
||||
gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]);
|
||||
if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS ||
|
||||
!tc_flags_valid(gen_flags)) {
|
||||
ret = -EINVAL;
|
||||
goto errout_idr;
|
||||
}
|
||||
}
|
||||
|
||||
prog->exts_integrated = have_exts;
|
||||
prog->gen_flags = gen_flags;
|
||||
|
||||
ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
|
||||
cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
|
||||
if (ret < 0)
|
||||
goto errout_idr;
|
||||
|
||||
if (tb[TCA_BPF_CLASSID]) {
|
||||
prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
|
||||
tcf_bind_filter(tp, &prog->res, base);
|
||||
bound_to_filter = true;
|
||||
}
|
||||
|
||||
ret = cls_bpf_offload(tp, prog, oldprog, extack);
|
||||
if (ret)
|
||||
goto errout_parms;
|
||||
|
@ -530,6 +523,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
|
|||
return 0;
|
||||
|
||||
errout_parms:
|
||||
if (bound_to_filter)
|
||||
tcf_unbind_filter(tp, &prog->res);
|
||||
cls_bpf_free_parms(prog);
|
||||
errout_idr:
|
||||
if (!oldprog)
|
||||
|
|
Загрузка…
Ссылка в новой задаче