diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h
index 62770add15bd..43704c5550ab 100644
--- a/include/net/tc_act/tc_mirred.h
+++ b/include/net/tc_act/tc_mirred.h
@@ -11,6 +11,11 @@ struct tcf_mirred {
 	int			tcfm_ok_push;
 	struct net_device __rcu	*tcfm_dev;
 	struct list_head	tcfm_list;
+	struct metadata_dst     *tun_dst;
+	__be32			tcf_enc_saddr;
+	__be32			tcf_enc_daddr;
+	__be32			tcf_enc_key_id;
+	__be16			tcf_enc_port;
 };
 #define to_mirred(a) ((struct tcf_mirred *)a)
 
diff --git a/include/uapi/linux/tc_act/tc_mirred.h b/include/uapi/linux/tc_act/tc_mirred.h
index 3d7a2b352a62..89ae754d8f5e 100644
--- a/include/uapi/linux/tc_act/tc_mirred.h
+++ b/include/uapi/linux/tc_act/tc_mirred.h
@@ -21,6 +21,13 @@ enum {
 	TCA_MIRRED_TM,
 	TCA_MIRRED_PARMS,
 	TCA_MIRRED_PAD,
+
+	TCA_MIRRED_ENC_IPV4_SRC,	/* be32 */
+	TCA_MIRRED_ENC_IPV4_DST,	/* be32 */
+	TCA_MIRRED_ENC_IPV6_SRC,	/* struct in6_addr */
+	TCA_MIRRED_ENC_IPV6_DST,	/* struct in6_addr */
+	TCA_MIRRED_ENC_KEY_ID,		/* be32 */
+	TCA_MIRRED_ENC_DST_PORT,	/* be16 */
 	__TCA_MIRRED_MAX
 };
 #define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 6038c85d92f5..3aff8d8b2744 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -26,6 +26,9 @@
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_mirred.h>
 #include <net/tc_act/tc_mirred.h>
+#include <net/dst.h>
+#include <net/dst_metadata.h>
+#include <net/vxlan.h>
 
 #include <linux/if_arp.h>
 
@@ -38,6 +41,11 @@ static void tcf_mirred_release(struct tc_action *a, int bind)
 	struct tcf_mirred *m = to_mirred(a);
 	struct net_device *dev;
 
+        if (m->tun_dst) {
+                printk("%s:%d - releasing dst: %p\n", __func__, __LINE__, m->tun_dst);
+                dst_release((struct dst_entry *)m->tun_dst);
+        }
+
 	/* We could be called either in a RCU callback or with RTNL lock held. */
 	spin_lock_bh(&mirred_list_lock);
 	list_del(&m->tcfm_list);
@@ -49,11 +57,67 @@ static void tcf_mirred_release(struct tc_action *a, int bind)
 
 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
 	[TCA_MIRRED_PARMS]	= { .len = sizeof(struct tc_mirred) },
+	[TCA_MIRRED_ENC_IPV4_SRC]	= { .type = NLA_U32 },
+	[TCA_MIRRED_ENC_IPV4_DST]	= { .type = NLA_U32 },
+	[TCA_MIRRED_ENC_KEY_ID]		= { .type = NLA_U32 },
+	[TCA_MIRRED_ENC_DST_PORT]	= { .type = NLA_U16 },
 };
 
 static int mirred_net_id;
 static struct tc_action_ops act_mirred_ops;
 
+static int tunnel_alloc(struct tcf_mirred *m, struct nlattr **tb)
+{
+	struct ip_tunnel_info *tun_info;
+	struct metadata_dst *tun_dst;
+        struct vxlan_metadata md = { 0 };
+        u8 tos = 0;
+        u8 ttl = 0;
+        __be16 tun_flags = TUNNEL_VXLAN_OPT;
+        int err;
+
+	m->tcf_enc_saddr = nla_get_be32(tb[TCA_MIRRED_ENC_IPV4_SRC]);
+	m->tcf_enc_daddr = nla_get_be32(tb[TCA_MIRRED_ENC_IPV4_DST]);
+	m->tcf_enc_key_id = nla_get_be32(tb[TCA_MIRRED_ENC_KEY_ID]);
+	m->tcf_enc_port = nla_get_be32(tb[TCA_MIRRED_ENC_DST_PORT]);
+
+	if (!m->tcf_enc_saddr || !m->tcf_enc_daddr ||
+	    !m->tcf_enc_key_id || !m->tcf_enc_port)
+		return 0;
+
+	tun_dst = metadata_dst_alloc(sizeof(md), GFP_KERNEL);
+	if (!tun_dst)
+		return -ENOMEM;
+        printk("%s:%d allocated dst: %p\n", __func__, __LINE__, tun_dst);
+
+	printk("%s:%d mirred vxlan saddr: %pI4 daddr: %pI4 key_id: %d port: %d\n",
+	       __func__, __LINE__,
+	       &m->tcf_enc_saddr, &m->tcf_enc_daddr,
+	       be32_to_cpu(m->tcf_enc_key_id), be16_to_cpu(m->tcf_enc_port));
+
+	err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
+	if (err) {
+		dst_release((struct dst_entry *)tun_dst);
+		return err;
+	}
+
+	tun_info = &tun_dst->u.tun_info;
+	tun_info->mode = IP_TUNNEL_INFO_TX;
+
+        ip_tunnel_key_init(&tun_info->key,
+                           m->tcf_enc_saddr, m->tcf_enc_daddr,
+			   tos, ttl,
+                           0, 0,
+			   m->tcf_enc_port,
+			   vxlan_vni_to_tun_id(m->tcf_enc_key_id),
+			   tun_flags);
+        ip_tunnel_info_opts_set(tun_info, &md, sizeof(md));
+
+	m->tun_dst = tun_dst;
+
+        return 0;
+}
+
 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 			   struct nlattr *est, struct tc_action **a, int ovr,
 			   int bind)
@@ -139,6 +203,13 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 		m->tcfm_ok_push = ok_push;
 	}
 
+	/* Should not use ret here !!! */
+	if (tunnel_alloc(m, tb)) {
+		printk("%s:%d - error allocating tunnel info\n",
+		       __func__, __LINE__);
+	}
+
+
 	if (ret == ACT_P_CREATED) {
 		spin_lock_bh(&mirred_list_lock);
 		list_add(&m->tcfm_list, &mirred_list);
@@ -180,6 +251,9 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
 	if (!skb2)
 		goto out;
 
+	if (m->tun_dst)
+		skb_dst_set_noref(skb2, &m->tun_dst->dst);
+
 	if (!(at & AT_EGRESS)) {
 		if (m->tcfm_ok_push)
 			skb_push_rcsum(skb2, skb->mac_len);
@@ -221,6 +295,11 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i
 	if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
 		goto nla_put_failure;
 
+	nla_put_be32(skb, TCA_MIRRED_ENC_IPV4_SRC, m->tcf_enc_saddr);
+	nla_put_be32(skb, TCA_MIRRED_ENC_IPV4_DST, m->tcf_enc_daddr);
+	nla_put_be32(skb, TCA_MIRRED_ENC_KEY_ID, m->tcf_enc_key_id);
+	nla_put_be32(skb, TCA_MIRRED_ENC_DST_PORT, m->tcf_enc_port);
+
 	tcf_tm_dump(&t, &m->tcf_tm);
 	if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD))
 		goto nla_put_failure;
