Merge tag 'armsoc-arm64' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[deliverable/linux.git] / net / sched / cls_flower.c
index b3b7978f418214104d5d360aa4ea6154b36fc038..5060801a2f6db6f24d3d31f7b182cb72b072aa4a 100644 (file)
@@ -66,6 +66,7 @@ struct cls_fl_filter {
        struct fl_flow_key key;
        struct list_head list;
        u32 handle;
+       u32 flags;
        struct rcu_head rcu;
 };
 
@@ -123,6 +124,9 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
        struct fl_flow_key skb_key;
        struct fl_flow_key skb_mkey;
 
+       if (!atomic_read(&head->ht.nelems))
+               return -1;
+
        fl_clear_masked_range(&skb_key, &head->mask);
        skb_key.indev_ifindex = skb->skb_iif;
        /* skb_flow_dissect() does not set n_proto in case an unknown protocol,
@@ -136,7 +140,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
        f = rhashtable_lookup_fast(&head->ht,
                                   fl_key_get_start(&skb_mkey, &head->mask),
                                   head->ht_params);
-       if (f) {
+       if (f && !tc_skip_sw(f->flags)) {
                *res = f->res;
                return tcf_exts_exec(skb, &f->exts, res);
        }
@@ -183,19 +187,20 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, unsigned long cookie)
        dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
 }
 
-static void fl_hw_replace_filter(struct tcf_proto *tp,
-                                struct flow_dissector *dissector,
-                                struct fl_flow_key *mask,
-                                struct fl_flow_key *key,
-                                struct tcf_exts *actions,
-                                unsigned long cookie, u32 flags)
+static int fl_hw_replace_filter(struct tcf_proto *tp,
+                               struct flow_dissector *dissector,
+                               struct fl_flow_key *mask,
+                               struct fl_flow_key *key,
+                               struct tcf_exts *actions,
+                               unsigned long cookie, u32 flags)
 {
        struct net_device *dev = tp->q->dev_queue->dev;
        struct tc_cls_flower_offload offload = {0};
        struct tc_to_netdev tc;
+       int err;
 
        if (!tc_should_offload(dev, tp, flags))
-               return;
+               return tc_skip_sw(flags) ? -EINVAL : 0;
 
        offload.command = TC_CLSFLOWER_REPLACE;
        offload.cookie = cookie;
@@ -207,7 +212,12 @@ static void fl_hw_replace_filter(struct tcf_proto *tp,
        tc.type = TC_SETUP_CLSFLOWER;
        tc.cls_flower = &offload;
 
-       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+       err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+
+       if (tc_skip_sw(flags))
+               return err;
+
+       return 0;
 }
 
 static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
@@ -524,7 +534,6 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        struct cls_fl_filter *fnew;
        struct nlattr *tb[TCA_FLOWER_MAX + 1];
        struct fl_flow_mask mask = {};
-       u32 flags = 0;
        int err;
 
        if (!tca[TCA_OPTIONS])
@@ -552,8 +561,14 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        }
        fnew->handle = handle;
 
-       if (tb[TCA_FLOWER_FLAGS])
-               flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
+       if (tb[TCA_FLOWER_FLAGS]) {
+               fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
+
+               if (!tc_flags_valid(fnew->flags)) {
+                       err = -EINVAL;
+                       goto errout;
+               }
+       }
 
        err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
        if (err)
@@ -563,19 +578,23 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        if (err)
                goto errout;
 
-       err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
-                                    head->ht_params);
+       if (!tc_skip_sw(fnew->flags)) {
+               err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
+                                            head->ht_params);
+               if (err)
+                       goto errout;
+       }
+
+       err = fl_hw_replace_filter(tp,
+                                  &head->dissector,
+                                  &mask.key,
+                                  &fnew->key,
+                                  &fnew->exts,
+                                  (unsigned long)fnew,
+                                  fnew->flags);
        if (err)
                goto errout;
 
-       fl_hw_replace_filter(tp,
-                            &head->dissector,
-                            &mask.key,
-                            &fnew->key,
-                            &fnew->exts,
-                            (unsigned long)fnew,
-                            flags);
-
        if (fold) {
                rhashtable_remove_fast(&head->ht, &fold->ht_node,
                                       head->ht_params);
@@ -734,6 +753,8 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                                  sizeof(key->tp.dst))))
                goto nla_put_failure;
 
+       nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags);
+
        if (tcf_exts_dump(skb, &f->exts))
                goto nla_put_failure;
 
This page took 0.029121 seconds and 5 git commands to generate.