diff mbox series

[net-next,1/4] net: sched: add vxlan option support to act_tunnel_key

Message ID af3c3d95717d8ff70c2c21621cb2f49c310593e2.1574155869.git.lucien.xin@gmail.com
State Changes Requested
Delegated to: David Miller
Headers show
Series net: sched: support vxlan and erspan options | expand

Commit Message

Xin Long Nov. 19, 2019, 9:31 a.m. UTC
This patch is to allow setting vxlan options using the
act_tunnel_key action. Different from geneve options,
only one option can be set. And also, geneve options
and vxlan options can't be set at the same time.

gbp is the only param for vxlan options:

  # ip link add name vxlan0 type vxlan dstport 0 external
  # tc qdisc add dev eth0 ingress
  # tc filter add dev eth0 protocol ip parent ffff: \
           flower indev eth0 \
              ip_proto udp \
              action tunnel_key \
                  set src_ip 10.0.99.192 \
                  dst_ip 10.0.99.193 \
                  dst_port 6081 \
                  id 11 \
  		  vxlan_opts 01020304 \
          action mirred egress redirect dev vxlan0

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/uapi/linux/tc_act/tc_tunnel_key.h | 13 +++++
 net/sched/act_tunnel_key.c                | 83 ++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 1 deletion(-)

Comments

Jakub Kicinski Nov. 20, 2019, 12:12 a.m. UTC | #1
On Tue, 19 Nov 2019 17:31:46 +0800, Xin Long wrote:
> @@ -54,6 +55,7 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
>  static const struct nla_policy
>  enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {

[TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC] = 
	{ .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN, }

>  	[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]	= { .type = NLA_NESTED },
> +	[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]		= { .type = NLA_NESTED },
>  };
>  
>  static const struct nla_policy
> @@ -64,6 +66,11 @@ geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
>  						       .len = 128 },
>  };
>  
> +static const struct nla_policy
> +vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {

[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC] =
	{ .strict_type_start = TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC + 1,	}

> +	[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]	   = { .type = NLA_U32 },
> +};
> +
>  static int
>  tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
>  			   struct netlink_ext_ack *extack)
Xin Long Nov. 20, 2019, 5:08 a.m. UTC | #2
On Wed, Nov 20, 2019 at 8:12 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Tue, 19 Nov 2019 17:31:46 +0800, Xin Long wrote:
> > @@ -54,6 +55,7 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
> >  static const struct nla_policy
> >  enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
>
> [TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC] =
>         { .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN, }
>
> >       [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
> > +     [TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
> >  };
Agree, this one is necessary.

> >
> >  static const struct nla_policy
> > @@ -64,6 +66,11 @@ geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
> >                                                      .len = 128 },
> >  };
> >
> > +static const struct nla_policy
> > +vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
>
> [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC] =
>         { .strict_type_start = TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC + 1, }
>
> > +     [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
> > +};
> > +
But vxlan_opt_policy is a new policy, and it will be parsed by
nla_parse_nested()
where NL_VALIDATE_STRICT has been used.

.strict_type_start is used for setting NL_VALIDATE_STRICT for some new
option appending on an old policy.

So I think .strict_type_start is not needed here.

> >  static int
> >  tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
> >                          struct netlink_ext_ack *extack)
Jakub Kicinski Nov. 20, 2019, 5:17 p.m. UTC | #3
On Wed, 20 Nov 2019 13:08:39 +0800, Xin Long wrote:
> > >  static const struct nla_policy
> > > @@ -64,6 +66,11 @@ geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
> > >                                                      .len = 128 },
> > >  };
> > >
> > > +static const struct nla_policy
> > > +vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {  
> >
> > [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC] =
> >         { .strict_type_start = TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC + 1, }
> >  
> > > +     [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
> > > +};
> > > +  
> But vxlan_opt_policy is a new policy, and it will be parsed by
> nla_parse_nested()
> where NL_VALIDATE_STRICT has been used.
> 
> .strict_type_start is used for setting NL_VALIDATE_STRICT for some new
> option appending on an old policy.
> 
> So I think .strict_type_start is not needed here.

Hm, that's what I thought but then we were asked to add it in
act_mpls.c. I should've checked the code.

Anyway, we should probably clean up act_mpls.c and act_ct.c so people
don't copy it unnecessarily.
Xin Long Nov. 21, 2019, 5:45 a.m. UTC | #4
On Thu, Nov 21, 2019 at 1:17 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Wed, 20 Nov 2019 13:08:39 +0800, Xin Long wrote:
> > > >  static const struct nla_policy
> > > > @@ -64,6 +66,11 @@ geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
> > > >                                                      .len = 128 },
> > > >  };
> > > >
> > > > +static const struct nla_policy
> > > > +vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
> > >
> > > [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC] =
> > >         { .strict_type_start = TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC + 1, }
> > >
> > > > +     [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
> > > > +};
> > > > +
> > But vxlan_opt_policy is a new policy, and it will be parsed by
> > nla_parse_nested()
> > where NL_VALIDATE_STRICT has been used.
> >
> > .strict_type_start is used for setting NL_VALIDATE_STRICT for some new
> > option appending on an old policy.
> >
> > So I think .strict_type_start is not needed here.
>
> Hm, that's what I thought but then we were asked to add it in
> act_mpls.c. I should've checked the code.
>
> Anyway, we should probably clean up act_mpls.c and act_ct.c so people
> don't copy it unnecessarily.
will send a cleanup, also for the one in net/ipv4/nexthop.c.
Thanks.
David Ahern Nov. 21, 2019, 3:56 p.m. UTC | #5
On 11/20/19 10:45 PM, Xin Long wrote:
>> Hm, that's what I thought but then we were asked to add it in
>> act_mpls.c. I should've checked the code.
>>
>> Anyway, we should probably clean up act_mpls.c and act_ct.c so people
>> don't copy it unnecessarily.
> will send a cleanup, also for the one in net/ipv4/nexthop.c.

thanks. Clearly, I forgot .strict_type_start does not apply to users of
the new API.
diff mbox series

Patch

diff --git a/include/uapi/linux/tc_act/tc_tunnel_key.h b/include/uapi/linux/tc_act/tc_tunnel_key.h
index 41c8b46..f302c2a 100644
--- a/include/uapi/linux/tc_act/tc_tunnel_key.h
+++ b/include/uapi/linux/tc_act/tc_tunnel_key.h
@@ -50,6 +50,10 @@  enum {
 						 * TCA_TUNNEL_KEY_ENC_OPTS_
 						 * attributes
 						 */
+	TCA_TUNNEL_KEY_ENC_OPTS_VXLAN,		/* Nested
+						 * TCA_TUNNEL_KEY_ENC_OPTS_
+						 * attributes
+						 */
 	__TCA_TUNNEL_KEY_ENC_OPTS_MAX,
 };
 
@@ -67,4 +71,13 @@  enum {
 #define TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX \
 	(__TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX - 1)
 
+enum {
+	TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC,
+	TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP,		/* u32 */
+	__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX,
+};
+
+#define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \
+	(__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)
+
 #endif
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index cb34e5d..6519333 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -10,6 +10,7 @@ 
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 #include <net/geneve.h>
+#include <net/vxlan.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/dst.h>
@@ -54,6 +55,7 @@  static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
 static const struct nla_policy
 enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
 	[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]	= { .type = NLA_NESTED },
+	[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]		= { .type = NLA_NESTED },
 };
 
 static const struct nla_policy
@@ -64,6 +66,11 @@  geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
 						       .len = 128 },
 };
 
+static const struct nla_policy
+vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
+	[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]	   = { .type = NLA_U32 },
+};
+
 static int
 tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
 			   struct netlink_ext_ack *extack)
@@ -116,10 +123,36 @@  tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
 	return opt_len;
 }
 
+static int
+tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
+			  struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
+	int err;
+
+	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, nla,
+			       vxlan_opt_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]) {
+		NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp");
+		return -EINVAL;
+	}
+
+	if (dst) {
+		struct vxlan_metadata *md = dst;
+
+		md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
+	}
+
+	return sizeof(struct vxlan_metadata);
+}
+
 static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 				int dst_len, struct netlink_ext_ack *extack)
 {
-	int err, rem, opt_len, len = nla_len(nla), opts_len = 0;
+	int err, rem, opt_len, len = nla_len(nla), opts_len = 0, type = 0;
 	const struct nlattr *attr, *head = nla_data(nla);
 
 	err = nla_validate_deprecated(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX,
@@ -130,6 +163,10 @@  static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 	nla_for_each_attr(attr, head, len, rem) {
 		switch (nla_type(attr)) {
 		case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
+			if (type && type != TUNNEL_GENEVE_OPT) {
+				NL_SET_ERR_MSG(extack, "Wrong type for geneve options");
+				return -EINVAL;
+			}
 			opt_len = tunnel_key_copy_geneve_opt(attr, dst,
 							     dst_len, extack);
 			if (opt_len < 0)
@@ -139,6 +176,19 @@  static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 				dst_len -= opt_len;
 				dst += opt_len;
 			}
+			type = TUNNEL_GENEVE_OPT;
+			break;
+		case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN:
+			if (type) {
+				NL_SET_ERR_MSG(extack, "Wrong type for vxlan options");
+				return -EINVAL;
+			}
+			opt_len = tunnel_key_copy_vxlan_opt(attr, dst,
+							    dst_len, extack);
+			if (opt_len < 0)
+				return opt_len;
+			opts_len += opt_len;
+			type = TUNNEL_VXLAN_OPT;
 			break;
 		}
 	}
@@ -175,6 +225,14 @@  static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
 #else
 		return -EAFNOSUPPORT;
 #endif
+	case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN:
+#if IS_ENABLED(CONFIG_INET)
+		info->key.tun_flags |= TUNNEL_VXLAN_OPT;
+		return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
+					    opts_len, extack);
+#else
+		return -EAFNOSUPPORT;
+#endif
 	default:
 		NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type");
 		return -EINVAL;
@@ -451,6 +509,25 @@  static int tunnel_key_geneve_opts_dump(struct sk_buff *skb,
 	return 0;
 }
 
+static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb,
+				      const struct ip_tunnel_info *info)
+{
+	struct vxlan_metadata *md = (struct vxlan_metadata *)(info + 1);
+	struct nlattr *start;
+
+	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_VXLAN);
+	if (!start)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(skb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) {
+		nla_nest_cancel(skb, start);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, start);
+	return 0;
+}
+
 static int tunnel_key_opts_dump(struct sk_buff *skb,
 				const struct ip_tunnel_info *info)
 {
@@ -468,6 +545,10 @@  static int tunnel_key_opts_dump(struct sk_buff *skb,
 		err = tunnel_key_geneve_opts_dump(skb, info);
 		if (err)
 			goto err_out;
+	} else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) {
+		err = tunnel_key_vxlan_opts_dump(skb, info);
+		if (err)
+			goto err_out;
 	} else {
 err_out:
 		nla_nest_cancel(skb, start);