bridge: set fake_rtable's dst to NULL to avoid kernel Oops
when bridge is deleted before tap/vif device's delete, kernel may
encounter an oops because of NULL reference to fake_rtable's dst.
Set fake_rtable's dst to NULL before sending packets out can solve
this problem.
v4 reformat, change br_drop_fake_rtable(skb) to {}
v3 enrich commit header
v2 introducing new flag DST_FAKE_RTABLE to dst_entry struct.
[ Use "do { } while (0)" for nop br_drop_fake_rtable()
  implementation -DaveM ]
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Peter Huang <peter.huangpeng@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        } daddr;
 };
 
+static inline void br_drop_fake_rtable(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+
+       if (dst && (dst->flags & DST_FAKE_RTABLE))
+               skb_dst_drop(skb);
+}
+
 #else
 #define nf_bridge_maybe_copy_header(skb)       (0)
 #define nf_bridge_pad(skb)                     (0)
+#define br_drop_fake_rtable(skb)               do { } while (0)
 #endif /* CONFIG_BRIDGE_NETFILTER */
 
 #endif /* __KERNEL__ */
 
 #define DST_NOCACHE            0x0010
 #define DST_NOCOUNT            0x0020
 #define DST_NOPEER             0x0040
+#define DST_FAKE_RTABLE                0x0080
 
        short                   error;
        short                   obsolete;
 
                kfree_skb(skb);
        } else {
                skb_push(skb, ETH_HLEN);
+               br_drop_fake_rtable(skb);
                dev_queue_xmit(skb);
        }
 
 
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
        dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
-       rt->dst.flags   = DST_NOXFRM | DST_NOPEER;
+       rt->dst.flags   = DST_NOXFRM | DST_NOPEER | DST_FAKE_RTABLE;
        rt->dst.ops = &fake_dst_ops;
 }
 
                                   const struct net_device *out,
                                   int (*okfn)(struct sk_buff *))
 {
-       struct rtable *rt = skb_rtable(skb);
-
-       if (rt && rt == bridge_parent_rtable(in))
-               skb_dst_drop(skb);
-
+       br_drop_fake_rtable(skb);
        return NF_ACCEPT;
 }