From: Amir Vadai <ami...@mellanox.com>>

Signed-off-by: Amir Vadai <ami...@mellanox.com>>
---
 include/net/tc_act/tc_mirred.h        |  5 +++
 include/uapi/linux/tc_act/tc_mirred.h |  7 ++++
 net/sched/act_mirred.c                | 79 +++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)

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;
-- 
2.9.0

Reply via email to