net: sched: cls_u32: Undo tcf_bind_filter if u32_replace_hw_knode
authorVictor Nogueira <victor@mojatatu.com>
Thu, 13 Jul 2023 18:05:11 +0000 (15:05 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jul 2023 06:50:41 +0000 (08:50 +0200)
[ Upstream commit 9cb36faedeafb9720ac236aeae2ea57091d90a09 ]

When u32_replace_hw_knode fails, we need to undo the tcf_bind_filter
operation done at u32_set_parms.

Fixes: d34e3e181395 ("net: cls_u32: Add support for skip-sw flag to tc u32 classifier.")
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/sched/cls_u32.c

index a347753..7cfbcd5 100644 (file)
@@ -710,8 +710,23 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
        [TCA_U32_FLAGS]         = { .type = NLA_U32 },
 };
 
+static void u32_unbind_filter(struct tcf_proto *tp, struct tc_u_knode *n,
+                             struct nlattr **tb)
+{
+       if (tb[TCA_U32_CLASSID])
+               tcf_unbind_filter(tp, &n->res);
+}
+
+static void u32_bind_filter(struct tcf_proto *tp, struct tc_u_knode *n,
+                           unsigned long base, struct nlattr **tb)
+{
+       if (tb[TCA_U32_CLASSID]) {
+               n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
+               tcf_bind_filter(tp, &n->res, base);
+       }
+}
+
 static int u32_set_parms(struct net *net, struct tcf_proto *tp,
-                        unsigned long base,
                         struct tc_u_knode *n, struct nlattr **tb,
                         struct nlattr *est, u32 flags, u32 fl_flags,
                         struct netlink_ext_ack *extack)
@@ -758,10 +773,6 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp,
                if (ht_old)
                        ht_old->refcnt--;
        }
-       if (tb[TCA_U32_CLASSID]) {
-               n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
-               tcf_bind_filter(tp, &n->res, base);
-       }
 
        if (ifindex >= 0)
                n->ifindex = ifindex;
@@ -901,17 +912,20 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                if (!new)
                        return -ENOMEM;
 
-               err = u32_set_parms(net, tp, base, new, tb,
-                                   tca[TCA_RATE], flags, new->flags,
-                                   extack);
+               err = u32_set_parms(net, tp, new, tb, tca[TCA_RATE],
+                                   flags, new->flags, extack);
 
                if (err) {
                        __u32_destroy_key(new);
                        return err;
                }
 
+               u32_bind_filter(tp, new, base, tb);
+
                err = u32_replace_hw_knode(tp, new, flags, extack);
                if (err) {
+                       u32_unbind_filter(tp, new, tb);
+
                        __u32_destroy_key(new);
                        return err;
                }
@@ -1072,15 +1086,18 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        }
 #endif
 
-       err = u32_set_parms(net, tp, base, n, tb, tca[TCA_RATE],
+       err = u32_set_parms(net, tp, n, tb, tca[TCA_RATE],
                            flags, n->flags, extack);
+
+       u32_bind_filter(tp, n, base, tb);
+
        if (err == 0) {
                struct tc_u_knode __rcu **ins;
                struct tc_u_knode *pins;
 
                err = u32_replace_hw_knode(tp, n, flags, extack);
                if (err)
-                       goto errhw;
+                       goto errunbind;
 
                if (!tc_in_hw(n->flags))
                        n->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
@@ -1098,7 +1115,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                return 0;
        }
 
-errhw:
+errunbind:
+       u32_unbind_filter(tp, n, tb);
+
 #ifdef CONFIG_CLS_U32_MARK
        free_percpu(n->pcpu_success);
 #endif