u16                     pages;          /* Number of allocated pages */
        kmemcheck_bitfield_begin(meta);
        u16                     jited:1,        /* Is our filter JIT'ed? */
-                               gpl_compatible:1; /* Is filter GPL compatible? */
+                               gpl_compatible:1, /* Is filter GPL compatible? */
+                               dst_needed:1;   /* Do we need dst entry? */
        kmemcheck_bitfield_end(meta);
        u32                     len;            /* Number of filter blocks */
        enum bpf_prog_type      type;           /* Type of BPF program */
 
         * Return: TC_ACT_REDIRECT
         */
        BPF_FUNC_redirect,
+
+       /**
+        * bpf_get_route_realm(skb) - retrieve a dst's tclassid
+        * @skb: pointer to skb
+        * Return: realm if != 0
+        */
+       BPF_FUNC_get_route_realm,
        __BPF_FUNC_MAX_ID,
 };
 
 
                         */
                        BUG_ON(!prog->aux->ops->get_func_proto);
 
+                       if (insn->imm == BPF_FUNC_get_route_realm)
+                               prog->dst_needed = 1;
                        if (insn->imm == BPF_FUNC_tail_call) {
                                /* mark bpf_tail_call as different opcode
                                 * to avoid conditional branch in
 
 #include <net/sch_generic.h>
 #include <net/cls_cgroup.h>
 #include <net/dst_metadata.h>
+#include <net/dst.h>
 
 /**
  *     sk_filter - run a packet through a socket filter
        .arg1_type      = ARG_PTR_TO_CTX,
 };
 
+static u64 bpf_get_route_realm(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
+{
+#ifdef CONFIG_IP_ROUTE_CLASSID
+       const struct dst_entry *dst;
+
+       dst = skb_dst((struct sk_buff *) (unsigned long) r1);
+       if (dst)
+               return dst->tclassid;
+#endif
+       return 0;
+}
+
+static const struct bpf_func_proto bpf_get_route_realm_proto = {
+       .func           = bpf_get_route_realm,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+};
+
 static u64 bpf_skb_vlan_push(u64 r1, u64 r2, u64 vlan_tci, u64 r4, u64 r5)
 {
        struct sk_buff *skb = (struct sk_buff *) (long) r1;
                return bpf_get_skb_set_tunnel_key_proto();
        case BPF_FUNC_redirect:
                return &bpf_redirect_proto;
+       case BPF_FUNC_get_route_realm:
+               return &bpf_get_route_realm_proto;
        default:
                return sk_filter_func_proto(func_id);
        }
 
        return 0;
 }
 
-static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog)
+static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
+                                const struct tcf_proto *tp)
 {
        struct bpf_prog *fp;
        char *name = NULL;
        prog->bpf_name = name;
        prog->filter = fp;
 
+       if (fp->dst_needed)
+               netif_keep_dst(qdisc_dev(tp->q));
+
        return 0;
 }
 
        prog->exts_integrated = have_exts;
 
        ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
-                      cls_bpf_prog_from_efd(tb, prog);
+                      cls_bpf_prog_from_efd(tb, prog, tp);
        if (ret < 0) {
                tcf_exts_destroy(&exts);
                return ret;