Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[firefly-linux-kernel-4.4.55.git] / net / sched / cls_bpf.c
index 91bd9c19471d58218cb340a2a871c8fe0ac8cd34..c79ecfd36e0f028388ea5f96a64dbb23451b01b1 100644 (file)
@@ -64,6 +64,11 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 {
        struct cls_bpf_head *head = rcu_dereference_bh(tp->root);
        struct cls_bpf_prog *prog;
+#ifdef CONFIG_NET_CLS_ACT
+       bool at_ingress = G_TC_AT(skb->tc_verd) & AT_INGRESS;
+#else
+       bool at_ingress = false;
+#endif
        int ret = -1;
 
        if (unlikely(!skb_mac_header_was_set(skb)))
@@ -72,7 +77,16 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
        /* Needed here for accessing maps. */
        rcu_read_lock();
        list_for_each_entry_rcu(prog, &head->plist, link) {
-               int filter_res = BPF_PROG_RUN(prog->filter, skb);
+               int filter_res;
+
+               if (at_ingress) {
+                       /* It is safe to push/pull even if skb_shared() */
+                       __skb_push(skb, skb->mac_len);
+                       filter_res = BPF_PROG_RUN(prog->filter, skb);
+                       __skb_pull(skb, skb->mac_len);
+               } else {
+                       filter_res = BPF_PROG_RUN(prog->filter, skb);
+               }
 
                if (filter_res == 0)
                        continue;