All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] net: sched: support vxlan and erspan options
@ 2019-11-19  9:31 Xin Long
  2019-11-19  9:31 ` [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key Xin Long
  2019-11-19 14:18 ` [PATCH net-next 0/4] net: sched: support vxlan and erspan options Roman Mashak
  0 siblings, 2 replies; 16+ messages in thread
From: Xin Long @ 2019-11-19  9:31 UTC (permalink / raw)
  To: network dev; +Cc: davem, simon.horman

This patchset is to add vxlan and erspan options support in
cls_flower and act_tunnel_key. The form is pretty much like
geneve_opts in:

  https://patchwork.ozlabs.org/patch/935272/
  https://patchwork.ozlabs.org/patch/954564/

but only one option is allowed for vxlan and erspan.

Xin Long (4):
  net: sched: add vxlan option support to act_tunnel_key
  net: sched: add erspan option support to act_tunnel_key
  net: sched: allow flower to match vxlan options
  net: sched: allow flower to match erspan options

 include/uapi/linux/pkt_cls.h              |  29 ++++
 include/uapi/linux/tc_act/tc_tunnel_key.h |  29 ++++
 net/sched/act_tunnel_key.c                | 191 +++++++++++++++++++++-
 net/sched/cls_flower.c                    | 252 ++++++++++++++++++++++++++++++
 4 files changed, 500 insertions(+), 1 deletion(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-19  9:31 [PATCH net-next 0/4] net: sched: support vxlan and erspan options Xin Long
@ 2019-11-19  9:31 ` Xin Long
  2019-11-19  9:31   ` [PATCH net-next 2/4] net: sched: add erspan " Xin Long
  2019-11-20  0:12   ` [PATCH net-next 1/4] net: sched: add vxlan " Jakub Kicinski
  2019-11-19 14:18 ` [PATCH net-next 0/4] net: sched: support vxlan and erspan options Roman Mashak
  1 sibling, 2 replies; 16+ messages in thread
From: Xin Long @ 2019-11-19  9:31 UTC (permalink / raw)
  To: network dev; +Cc: davem, simon.horman

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(-)

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);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key
  2019-11-19  9:31 ` [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key Xin Long
@ 2019-11-19  9:31   ` Xin Long
  2019-11-19  9:31     ` [PATCH net-next 3/4] net: sched: allow flower to match vxlan options Xin Long
  2019-11-20  0:27     ` [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key Jakub Kicinski
  2019-11-20  0:12   ` [PATCH net-next 1/4] net: sched: add vxlan " Jakub Kicinski
  1 sibling, 2 replies; 16+ messages in thread
From: Xin Long @ 2019-11-19  9:31 UTC (permalink / raw)
  To: network dev; +Cc: davem, simon.horman

This patch is to allow setting erspan options using the
act_tunnel_key action. Different from geneve options,
only one option can be set. And also, geneve options,
vxlan options or erspan options can't be set at the
same time.

Options are expressed as ver:index:dir:hwid, when ver
is set to 1, index will be applied while dir and hwid
will be ignored, and when ver is set to 2, dir and
hwid will be used while index will be ignored.

  # ip link add name erspan1 type erspan 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 \
  		erspan_opts 1:2:0:0 \
          action mirred egress redirect dev erspan1

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

diff --git a/include/uapi/linux/tc_act/tc_tunnel_key.h b/include/uapi/linux/tc_act/tc_tunnel_key.h
index f302c2a..3f10dc4 100644
--- a/include/uapi/linux/tc_act/tc_tunnel_key.h
+++ b/include/uapi/linux/tc_act/tc_tunnel_key.h
@@ -54,6 +54,10 @@ enum {
 						 * TCA_TUNNEL_KEY_ENC_OPTS_
 						 * attributes
 						 */
+	TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN,		/* Nested
+						 * TCA_TUNNEL_KEY_ENC_OPTS_
+						 * attributes
+						 */
 	__TCA_TUNNEL_KEY_ENC_OPTS_MAX,
 };
 
@@ -80,4 +84,16 @@ enum {
 #define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \
 	(__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)
 
+enum {
+	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_UNSPEC,
+	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER,		/* u8 */
+	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX,		/* be32 */
+	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR,		/* u8 */
+	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID,		/* u8 */
+	__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX,
+};
+
+#define TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX \
+	(__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX - 1)
+
 #endif
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 6519333..0272e9b 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -11,6 +11,7 @@
 #include <linux/rtnetlink.h>
 #include <net/geneve.h>
 #include <net/vxlan.h>
+#include <net/erspan.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/dst.h>
@@ -56,6 +57,7 @@ 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 },
+	[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]	= { .type = NLA_NESTED },
 };
 
 static const struct nla_policy
@@ -71,6 +73,14 @@ vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
 	[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]	   = { .type = NLA_U32 },
 };
 
+static const struct nla_policy
+erspan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1] = {
+	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]	   = { .type = NLA_U8 },
+	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]	   = { .type = NLA_U32 },
+	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]	   = { .type = NLA_U8 },
+	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]	   = { .type = NLA_U8 },
+};
+
 static int
 tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
 			   struct netlink_ext_ack *extack)
@@ -149,6 +159,49 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
 	return sizeof(struct vxlan_metadata);
 }
 
+static int
+tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len,
+			   struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
+	int err;
+
+	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla,
+			       erspan_opt_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) {
+		NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver");
+		return -EINVAL;
+	}
+
+	if (dst) {
+		struct erspan_metadata *md = dst;
+
+		nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER];
+		md->version = nla_get_u8(nla);
+
+		if (md->version == 1 &&
+		    tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) {
+			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX];
+			md->u.index = nla_get_be32(nla);
+		} else if (md->version == 2 &&
+			   tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] &&
+			   tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) {
+			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR];
+			md->u.md2.dir = nla_get_u8(nla);
+			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID];
+			set_hwid(&md->u.md2, nla_get_u8(nla));
+		} else {
+			NL_SET_ERR_MSG(extack, "erspan ver is incorrect or some option is missed");
+			return -EINVAL;
+		}
+	}
+
+	return sizeof(struct erspan_metadata);
+}
+
 static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 				int dst_len, struct netlink_ext_ack *extack)
 {
@@ -190,6 +243,18 @@ static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 			opts_len += opt_len;
 			type = TUNNEL_VXLAN_OPT;
 			break;
+		case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN:
+			if (type) {
+				NL_SET_ERR_MSG(extack, "Wrong type for erspan options");
+				return -EINVAL;
+			}
+			opt_len = tunnel_key_copy_erspan_opt(attr, dst,
+							     dst_len, extack);
+			if (opt_len < 0)
+				return opt_len;
+			opts_len += opt_len;
+			type = TUNNEL_ERSPAN_OPT;
+			break;
 		}
 	}
 
@@ -233,6 +298,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_ERSPAN:
+#if IS_ENABLED(CONFIG_INET)
+		info->key.tun_flags |= TUNNEL_ERSPAN_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;
@@ -528,6 +601,37 @@ static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb,
 	return 0;
 }
 
+static int tunnel_key_erspan_opts_dump(struct sk_buff *skb,
+				       const struct ip_tunnel_info *info)
+{
+	struct erspan_metadata *md = (struct erspan_metadata *)(info + 1);
+	struct nlattr *start;
+
+	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN);
+	if (!start)
+		return -EMSGSIZE;
+
+	if (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER, md->version))
+		goto err;
+
+	if (md->version == 1 &&
+	    nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index))
+		goto err;
+
+	if (md->version == 2 &&
+	    (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR,
+			md->u.md2.dir) ||
+	     nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID,
+			get_hwid(&md->u.md2))))
+		goto err;
+
+	nla_nest_end(skb, start);
+	return 0;
+err:
+	nla_nest_cancel(skb, start);
+	return -EMSGSIZE;
+}
+
 static int tunnel_key_opts_dump(struct sk_buff *skb,
 				const struct ip_tunnel_info *info)
 {
@@ -549,6 +653,10 @@ static int tunnel_key_opts_dump(struct sk_buff *skb,
 		err = tunnel_key_vxlan_opts_dump(skb, info);
 		if (err)
 			goto err_out;
+	} else if (info->key.tun_flags & TUNNEL_ERSPAN_OPT) {
+		err = tunnel_key_erspan_opts_dump(skb, info);
+		if (err)
+			goto err_out;
 	} else {
 err_out:
 		nla_nest_cancel(skb, start);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 3/4] net: sched: allow flower to match vxlan options
  2019-11-19  9:31   ` [PATCH net-next 2/4] net: sched: add erspan " Xin Long
@ 2019-11-19  9:31     ` Xin Long
  2019-11-19  9:31       ` [PATCH net-next 4/4] net: sched: allow flower to match erspan options Xin Long
  2019-11-20  0:27     ` [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key Jakub Kicinski
  1 sibling, 1 reply; 16+ messages in thread
From: Xin Long @ 2019-11-19  9:31 UTC (permalink / raw)
  To: network dev; +Cc: davem, simon.horman

This patch is to allow matching gbp option in vxlan.

The options can be described in the form GBP/GBP_MASK,
where GBP is represented as a 32bit hexadecimal value.
Different from geneve, only one option can be set. And
also, geneve options and vxlan options can't be set at
the same time.

  # ip link add name vxlan0 type vxlan dstport 0 external
  # tc qdisc add dev vxlan0 ingress
  # tc filter add dev vxlan0 protocol ip parent ffff: \
      flower \
        enc_src_ip 10.0.99.192 \
        enc_dst_ip 10.0.99.193 \
        enc_key_id 11 \
        vxlan_opts 01020304/ffffffff \
        ip_proto udp \
        action mirred egress redirect dev eth0

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/uapi/linux/pkt_cls.h |  13 ++++++
 net/sched/cls_flower.c       | 107 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+)

diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index c6ad22f..929825d 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -571,6 +571,10 @@ enum {
 					 * TCA_FLOWER_KEY_ENC_OPT_GENEVE_
 					 * attributes
 					 */
+	TCA_FLOWER_KEY_ENC_OPTS_VXLAN,	/* Nested
+					 * TCA_FLOWER_KEY_ENC_OPT_VXLAN_
+					 * attributes
+					 */
 	__TCA_FLOWER_KEY_ENC_OPTS_MAX,
 };
 
@@ -589,6 +593,15 @@ enum {
 		(__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
 
 enum {
+	TCA_FLOWER_KEY_ENC_OPT_VXLAN_UNSPEC,
+	TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP,		/* u32 */
+	__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX \
+		(__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1)
+
+enum {
 	TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
 	TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
 };
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 74221e3..80b0c8f0 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -22,6 +22,7 @@
 #include <net/ip.h>
 #include <net/flow_dissector.h>
 #include <net/geneve.h>
+#include <net/vxlan.h>
 
 #include <net/dst.h>
 #include <net/dst_metadata.h>
@@ -689,6 +690,7 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
 static const struct nla_policy
 enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
+	[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
 };
 
 static const struct nla_policy
@@ -699,6 +701,11 @@ geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
 						       .len = 128 },
 };
 
+static const struct nla_policy
+vxlan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1] = {
+	[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
+};
+
 static void fl_set_key_val(struct nlattr **tb,
 			   void *val, int val_type,
 			   void *mask, int mask_type, int len)
@@ -928,6 +935,41 @@ static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
 	return sizeof(struct geneve_opt) + data_len;
 }
 
+static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key,
+			    int depth, int option_len,
+			    struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1];
+	struct vxlan_metadata *md;
+	int err;
+
+	md = (struct vxlan_metadata *)&key->enc_opts.data[key->enc_opts.len];
+	memset(md, 0xff, sizeof(*md));
+
+	if (!depth)
+		return sizeof(*md);
+
+	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_VXLAN) {
+		NL_SET_ERR_MSG(extack, "Non-vxlan option type for mask");
+		return -EINVAL;
+	}
+
+	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, nla,
+			       vxlan_opt_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) {
+		NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option");
+		return -EINVAL;
+	}
+
+	if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP])
+		md->gbp = nla_get_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]);
+
+	return sizeof(*md);
+}
+
 static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 			  struct fl_flow_key *mask,
 			  struct netlink_ext_ack *extack)
@@ -958,6 +1000,11 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
 		switch (nla_type(nla_opt_key)) {
 		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
+			if (key->enc_opts.dst_opt_type &&
+			    key->enc_opts.dst_opt_type != TUNNEL_GENEVE_OPT) {
+				NL_SET_ERR_MSG(extack, "Wrong type for geneve options");
+				return -EINVAL;
+			}
 			option_len = 0;
 			key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
 			option_len = fl_set_geneve_opt(nla_opt_key, key,
@@ -986,6 +1033,39 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 			if (msk_depth)
 				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
 			break;
+		case TCA_FLOWER_KEY_ENC_OPTS_VXLAN:
+			if (key->enc_opts.dst_opt_type) {
+				NL_SET_ERR_MSG(extack, "Wrong type for vxlan options");
+				return -EINVAL;
+			}
+			option_len = 0;
+			key->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT;
+			option_len = fl_set_vxlan_opt(nla_opt_key, key,
+						      key_depth, option_len,
+						      extack);
+			if (option_len < 0)
+				return option_len;
+
+			key->enc_opts.len += option_len;
+			/* At the same time we need to parse through the mask
+			 * in order to verify exact and mask attribute lengths.
+			 */
+			mask->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT;
+			option_len = fl_set_vxlan_opt(nla_opt_msk, mask,
+						      msk_depth, option_len,
+						      extack);
+			if (option_len < 0)
+				return option_len;
+
+			mask->enc_opts.len += option_len;
+			if (key->enc_opts.len != mask->enc_opts.len) {
+				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
+				return -EINVAL;
+			}
+
+			if (msk_depth)
+				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
+			break;
 		default:
 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
 			return -EINVAL;
@@ -2135,6 +2215,28 @@ static int fl_dump_key_geneve_opt(struct sk_buff *skb,
 	return -EMSGSIZE;
 }
 
+static int fl_dump_key_vxlan_opt(struct sk_buff *skb,
+				 struct flow_dissector_key_enc_opts *enc_opts)
+{
+	struct vxlan_metadata *md;
+	struct nlattr *nest;
+
+	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_VXLAN);
+	if (!nest)
+		goto nla_put_failure;
+
+	md = (struct vxlan_metadata *)&enc_opts->data[0];
+	if (nla_put_u32(skb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, md->gbp))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest);
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	return -EMSGSIZE;
+}
+
 static int fl_dump_key_ct(struct sk_buff *skb,
 			  struct flow_dissector_key_ct *key,
 			  struct flow_dissector_key_ct *mask)
@@ -2188,6 +2290,11 @@ static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
 		if (err)
 			goto nla_put_failure;
 		break;
+	case TUNNEL_VXLAN_OPT:
+		err = fl_dump_key_vxlan_opt(skb, enc_opts);
+		if (err)
+			goto nla_put_failure;
+		break;
 	default:
 		goto nla_put_failure;
 	}
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 4/4] net: sched: allow flower to match erspan options
  2019-11-19  9:31     ` [PATCH net-next 3/4] net: sched: allow flower to match vxlan options Xin Long
@ 2019-11-19  9:31       ` Xin Long
  0 siblings, 0 replies; 16+ messages in thread
From: Xin Long @ 2019-11-19  9:31 UTC (permalink / raw)
  To: network dev; +Cc: davem, simon.horman

This patch is to allow matching options in erspan.

The options can be described in the form:
VER:INDEX:DIR:HWID/VER:INDEX_MASK:DIR_MASK:HWID_MASK.
When ver is set to 1, index will be applied while dir
and hwid will be ignored, and when ver is set to 2,
dir and hwid will be used while index will be ignored.

Different from geneve, only one option can be set. And
also, geneve options, vxlan options or erspan options
can't be set at the same time.

  # ip link add name erspan1 type erspan external
  # tc qdisc add dev erspan1 ingress
  # tc filter add dev erspan1 protocol ip parent ffff: \
      flower \
        enc_src_ip 10.0.99.192 \
        enc_dst_ip 10.0.99.193 \
        enc_key_id 11 \
        erspan_opts 1:12:0:0/1:ffff:0:0 \
        ip_proto udp \
        action mirred egress redirect dev eth0

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/uapi/linux/pkt_cls.h |  16 +++++
 net/sched/cls_flower.c       | 145 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 161 insertions(+)

diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 929825d..449a639 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -575,6 +575,10 @@ enum {
 					 * TCA_FLOWER_KEY_ENC_OPT_VXLAN_
 					 * attributes
 					 */
+	TCA_FLOWER_KEY_ENC_OPTS_ERSPAN,	/* Nested
+					 * TCA_FLOWER_KEY_ENC_OPT_ERSPAN_
+					 * attributes
+					 */
 	__TCA_FLOWER_KEY_ENC_OPTS_MAX,
 };
 
@@ -602,6 +606,18 @@ enum {
 		(__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1)
 
 enum {
+	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_UNSPEC,
+	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER,              /* u8 */
+	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX,            /* be32 */
+	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR,              /* u8 */
+	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID,             /* u8 */
+	__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \
+		(__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1)
+
+enum {
 	TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
 	TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
 };
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 80b0c8f0..23e5ef1 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -23,6 +23,7 @@
 #include <net/flow_dissector.h>
 #include <net/geneve.h>
 #include <net/vxlan.h>
+#include <net/erspan.h>
 
 #include <net/dst.h>
 #include <net/dst_metadata.h>
@@ -691,6 +692,7 @@ static const struct nla_policy
 enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
 	[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
+	[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]        = { .type = NLA_NESTED },
 };
 
 static const struct nla_policy
@@ -706,6 +708,14 @@ vxlan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1] = {
 	[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
 };
 
+static const struct nla_policy
+erspan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1] = {
+	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]        = { .type = NLA_U8 },
+	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]      = { .type = NLA_U32 },
+	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]        = { .type = NLA_U8 },
+	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]       = { .type = NLA_U8 },
+};
+
 static void fl_set_key_val(struct nlattr **tb,
 			   void *val, int val_type,
 			   void *mask, int mask_type, int len)
@@ -970,6 +980,70 @@ static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key,
 	return sizeof(*md);
 }
 
+static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
+			     int depth, int option_len,
+			     struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1];
+	struct erspan_metadata *md;
+	int err;
+
+	md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len];
+	memset(md, 0xff, sizeof(*md));
+	md->version = 1;
+
+	if (!depth)
+		return sizeof(*md);
+
+	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_ERSPAN) {
+		NL_SET_ERR_MSG(extack, "Non-erspan option type for mask");
+		return -EINVAL;
+	}
+
+	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, nla,
+			       erspan_opt_policy, extack);
+	if (err < 0)
+		return err;
+
+	if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) {
+		NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option");
+		return -EINVAL;
+	}
+
+	if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER])
+		md->version = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]);
+
+	if (md->version == 1) {
+		if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
+			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option");
+			return -EINVAL;
+		}
+		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
+			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX];
+			md->u.index = nla_get_be32(nla);
+		}
+	} else if (md->version == 2) {
+		if (!option_len && (!tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] ||
+				    !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID])) {
+			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option");
+			return -EINVAL;
+		}
+		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) {
+			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR];
+			md->u.md2.dir = nla_get_u8(nla);
+		}
+		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) {
+			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID];
+			set_hwid(&md->u.md2, nla_get_u8(nla));
+		}
+	} else {
+		NL_SET_ERR_MSG(extack, "erspan ver is not correct");
+		return -EINVAL;
+	}
+
+	return sizeof(*md);
+}
+
 static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 			  struct fl_flow_key *mask,
 			  struct netlink_ext_ack *extack)
@@ -1066,6 +1140,39 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 			if (msk_depth)
 				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
 			break;
+		case TCA_FLOWER_KEY_ENC_OPTS_ERSPAN:
+			if (key->enc_opts.dst_opt_type) {
+				NL_SET_ERR_MSG(extack, "Wrong type for erspan options");
+				return -EINVAL;
+			}
+			option_len = 0;
+			key->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT;
+			option_len = fl_set_erspan_opt(nla_opt_key, key,
+						       key_depth, option_len,
+						       extack);
+			if (option_len < 0)
+				return option_len;
+
+			key->enc_opts.len += option_len;
+			/* At the same time we need to parse through the mask
+			 * in order to verify exact and mask attribute lengths.
+			 */
+			mask->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT;
+			option_len = fl_set_erspan_opt(nla_opt_msk, mask,
+						       msk_depth, option_len,
+						       extack);
+			if (option_len < 0)
+				return option_len;
+
+			mask->enc_opts.len += option_len;
+			if (key->enc_opts.len != mask->enc_opts.len) {
+				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
+				return -EINVAL;
+			}
+
+			if (msk_depth)
+				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
+			break;
 		default:
 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
 			return -EINVAL;
@@ -2237,6 +2344,39 @@ static int fl_dump_key_vxlan_opt(struct sk_buff *skb,
 	return -EMSGSIZE;
 }
 
+static int fl_dump_key_erspan_opt(struct sk_buff *skb,
+				  struct flow_dissector_key_enc_opts *enc_opts)
+{
+	struct erspan_metadata *md;
+	struct nlattr *nest;
+
+	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_ERSPAN);
+	if (!nest)
+		goto nla_put_failure;
+
+	md = (struct erspan_metadata *)&enc_opts->data[0];
+	if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, md->version))
+		goto nla_put_failure;
+
+	if (md->version == 1 &&
+	    nla_put_be32(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index))
+		goto nla_put_failure;
+
+	if (md->version == 2 &&
+	    (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR,
+			md->u.md2.dir) ||
+	     nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID,
+			get_hwid(&md->u.md2))))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest);
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	return -EMSGSIZE;
+}
+
 static int fl_dump_key_ct(struct sk_buff *skb,
 			  struct flow_dissector_key_ct *key,
 			  struct flow_dissector_key_ct *mask)
@@ -2295,6 +2435,11 @@ static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
 		if (err)
 			goto nla_put_failure;
 		break;
+	case TUNNEL_ERSPAN_OPT:
+		err = fl_dump_key_erspan_opt(skb, enc_opts);
+		if (err)
+			goto nla_put_failure;
+		break;
 	default:
 		goto nla_put_failure;
 	}
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 0/4] net: sched: support vxlan and erspan options
  2019-11-19  9:31 [PATCH net-next 0/4] net: sched: support vxlan and erspan options Xin Long
  2019-11-19  9:31 ` [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key Xin Long
@ 2019-11-19 14:18 ` Roman Mashak
  2019-11-19 15:55   ` Xin Long
  1 sibling, 1 reply; 16+ messages in thread
From: Roman Mashak @ 2019-11-19 14:18 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, David Miller, Simon Horman

On Tue, Nov 19, 2019 at 4:32 AM Xin Long <lucien.xin@gmail.com> wrote:
>
> This patchset is to add vxlan and erspan options support in
> cls_flower and act_tunnel_key. The form is pretty much like
> geneve_opts in:
>
>   https://patchwork.ozlabs.org/patch/935272/
>   https://patchwork.ozlabs.org/patch/954564/
>
> but only one option is allowed for vxlan and erspan.

[...]

Are you considering to add tdc tests for the new features in separate patch?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 0/4] net: sched: support vxlan and erspan options
  2019-11-19 14:18 ` [PATCH net-next 0/4] net: sched: support vxlan and erspan options Roman Mashak
@ 2019-11-19 15:55   ` Xin Long
  2019-11-19 16:06     ` Roman Mashak
  0 siblings, 1 reply; 16+ messages in thread
From: Xin Long @ 2019-11-19 15:55 UTC (permalink / raw)
  To: Roman Mashak; +Cc: network dev, David Miller, Simon Horman

On Tue, Nov 19, 2019 at 10:18 PM Roman Mashak <mrv@mojatatu.com> wrote:
>
> On Tue, Nov 19, 2019 at 4:32 AM Xin Long <lucien.xin@gmail.com> wrote:
> >
> > This patchset is to add vxlan and erspan options support in
> > cls_flower and act_tunnel_key. The form is pretty much like
> > geneve_opts in:
> >
> >   https://patchwork.ozlabs.org/patch/935272/
> >   https://patchwork.ozlabs.org/patch/954564/
> >
> > but only one option is allowed for vxlan and erspan.
>
> [...]
>
> Are you considering to add tdc tests for the new features in separate patch?
You mean in selftests?
I will post iproute2 side patch to support these first, then
considering to add selftests.
(this patch series is the kernel side only)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 0/4] net: sched: support vxlan and erspan options
  2019-11-19 15:55   ` Xin Long
@ 2019-11-19 16:06     ` Roman Mashak
  2019-11-19 16:23       ` Xin Long
  0 siblings, 1 reply; 16+ messages in thread
From: Roman Mashak @ 2019-11-19 16:06 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, David Miller, Simon Horman

Xin Long <lucien.xin@gmail.com> writes:

> On Tue, Nov 19, 2019 at 10:18 PM Roman Mashak <mrv@mojatatu.com> wrote:
>>
>> On Tue, Nov 19, 2019 at 4:32 AM Xin Long <lucien.xin@gmail.com> wrote:
>> >
>> > This patchset is to add vxlan and erspan options support in
>> > cls_flower and act_tunnel_key. The form is pretty much like
>> > geneve_opts in:
>> >
>> >   https://patchwork.ozlabs.org/patch/935272/
>> >   https://patchwork.ozlabs.org/patch/954564/
>> >
>> > but only one option is allowed for vxlan and erspan.
>>
>> [...]
>>
>> Are you considering to add tdc tests for the new features in separate patch?
> You mean in selftests?
> I will post iproute2 side patch to support these first, then
> considering to add selftests.
> (this patch series is the kernel side only)

Yes, I mean tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 0/4] net: sched: support vxlan and erspan options
  2019-11-19 16:06     ` Roman Mashak
@ 2019-11-19 16:23       ` Xin Long
  0 siblings, 0 replies; 16+ messages in thread
From: Xin Long @ 2019-11-19 16:23 UTC (permalink / raw)
  To: Roman Mashak; +Cc: network dev, David Miller, Simon Horman

On Wed, Nov 20, 2019 at 12:06 AM Roman Mashak <mrv@mojatatu.com> wrote:
>
> Xin Long <lucien.xin@gmail.com> writes:
>
> > On Tue, Nov 19, 2019 at 10:18 PM Roman Mashak <mrv@mojatatu.com> wrote:
> >>
> >> On Tue, Nov 19, 2019 at 4:32 AM Xin Long <lucien.xin@gmail.com> wrote:
> >> >
> >> > This patchset is to add vxlan and erspan options support in
> >> > cls_flower and act_tunnel_key. The form is pretty much like
> >> > geneve_opts in:
> >> >
> >> >   https://patchwork.ozlabs.org/patch/935272/
> >> >   https://patchwork.ozlabs.org/patch/954564/
> >> >
> >> > but only one option is allowed for vxlan and erspan.
> >>
> >> [...]
> >>
> >> Are you considering to add tdc tests for the new features in separate patch?
> > You mean in selftests?
> > I will post iproute2 side patch to support these first, then
> > considering to add selftests.
> > (this patch series is the kernel side only)
>
> Yes, I mean tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json
>
Sure, and it can only be done after tc userspace supports it.
Thanks for pointing this .json file out.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-19  9:31 ` [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key Xin Long
  2019-11-19  9:31   ` [PATCH net-next 2/4] net: sched: add erspan " Xin Long
@ 2019-11-20  0:12   ` Jakub Kicinski
  2019-11-20  5:08     ` Xin Long
  1 sibling, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2019-11-20  0:12 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, davem, simon.horman

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)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key
  2019-11-19  9:31   ` [PATCH net-next 2/4] net: sched: add erspan " Xin Long
  2019-11-19  9:31     ` [PATCH net-next 3/4] net: sched: allow flower to match vxlan options Xin Long
@ 2019-11-20  0:27     ` Jakub Kicinski
  2019-11-20  5:15       ` Xin Long
  1 sibling, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2019-11-20  0:27 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, davem, simon.horman

On Tue, 19 Nov 2019 17:31:47 +0800, Xin Long wrote:
> @@ -149,6 +159,49 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
>  	return sizeof(struct vxlan_metadata);
>  }
>  
> +static int
> +tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len,
> +			   struct netlink_ext_ack *extack)
> +{
> +	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
> +	int err;
> +
> +	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla,
> +			       erspan_opt_policy, extack);
> +	if (err < 0)
> +		return err;
> +
> +	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) {
> +		NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver");
> +		return -EINVAL;
> +	}
> +
> +	if (dst) {
> +		struct erspan_metadata *md = dst;
> +
> +		nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER];
> +		md->version = nla_get_u8(nla);
> +
> +		if (md->version == 1 &&
> +		    tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) {
> +			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX];
> +			md->u.index = nla_get_be32(nla);
> +		} else if (md->version == 2 &&
> +			   tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] &&
> +			   tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) {
> +			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR];
> +			md->u.md2.dir = nla_get_u8(nla);
> +			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID];
> +			set_hwid(&md->u.md2, nla_get_u8(nla));
> +		} else {
> +			NL_SET_ERR_MSG(extack, "erspan ver is incorrect or some option is missed");

I think s/missed/missing/

But I think it'd be better if the validation was done also when dst is
not yet allocated. I don't think it matters today, just think it'd be
cleaner.

> +			return -EINVAL;
> +		}
> +	}
> +
> +	return sizeof(struct erspan_metadata);
> +}
> +
>  static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
>  				int dst_len, struct netlink_ext_ack *extack)
>  {
> @@ -190,6 +243,18 @@ static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
>  			opts_len += opt_len;
>  			type = TUNNEL_VXLAN_OPT;
>  			break;
> +		case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN:
> +			if (type) {
> +				NL_SET_ERR_MSG(extack, "Wrong type for erspan options");

Wrong or duplicate, right? If I'm reading this right unlike for Geneve
opts there can be only one instance of opts for other types.

> +				return -EINVAL;
> +			}
> +			opt_len = tunnel_key_copy_erspan_opt(attr, dst,
> +							     dst_len, extack);
> +			if (opt_len < 0)
> +				return opt_len;
> +			opts_len += opt_len;
> +			type = TUNNEL_ERSPAN_OPT;
> +			break;
>  		}
>  	}
>  

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-20  0:12   ` [PATCH net-next 1/4] net: sched: add vxlan " Jakub Kicinski
@ 2019-11-20  5:08     ` Xin Long
  2019-11-20 17:17       ` Jakub Kicinski
  0 siblings, 1 reply; 16+ messages in thread
From: Xin Long @ 2019-11-20  5:08 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: network dev, davem, Simon Horman

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)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key
  2019-11-20  0:27     ` [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key Jakub Kicinski
@ 2019-11-20  5:15       ` Xin Long
  0 siblings, 0 replies; 16+ messages in thread
From: Xin Long @ 2019-11-20  5:15 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: network dev, davem, Simon Horman

On Wed, Nov 20, 2019 at 8:27 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Tue, 19 Nov 2019 17:31:47 +0800, Xin Long wrote:
> > @@ -149,6 +159,49 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
> >       return sizeof(struct vxlan_metadata);
> >  }
> >
> > +static int
> > +tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len,
> > +                        struct netlink_ext_ack *extack)
> > +{
> > +     struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
> > +     int err;
> > +
> > +     err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla,
> > +                            erspan_opt_policy, extack);
> > +     if (err < 0)
> > +             return err;
> > +
> > +     if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) {
> > +             NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver");
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (dst) {
> > +             struct erspan_metadata *md = dst;
> > +
> > +             nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER];
> > +             md->version = nla_get_u8(nla);
> > +
> > +             if (md->version == 1 &&
> > +                 tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) {
> > +                     nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX];
> > +                     md->u.index = nla_get_be32(nla);
> > +             } else if (md->version == 2 &&
> > +                        tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] &&
> > +                        tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) {
> > +                     nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR];
> > +                     md->u.md2.dir = nla_get_u8(nla);
> > +                     nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID];
> > +                     set_hwid(&md->u.md2, nla_get_u8(nla));
> > +             } else {
> > +                     NL_SET_ERR_MSG(extack, "erspan ver is incorrect or some option is missed");
>
> I think s/missed/missing/
ah right.

>
> But I think it'd be better if the validation was done also when dst is
> not yet allocated. I don't think it matters today, just think it'd be
> cleaner.
sure, I can improve in that way.

>
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     return sizeof(struct erspan_metadata);
> > +}
> > +
> >  static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
> >                               int dst_len, struct netlink_ext_ack *extack)
> >  {
> > @@ -190,6 +243,18 @@ static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
> >                       opts_len += opt_len;
> >                       type = TUNNEL_VXLAN_OPT;
> >                       break;
> > +             case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN:
> > +                     if (type) {
> > +                             NL_SET_ERR_MSG(extack, "Wrong type for erspan options");
>
> Wrong or duplicate, right? If I'm reading this right unlike for Geneve
> opts there can be only one instance of opts for other types.
yes, 'Duplicate' is better,
will change to "Duplicate type for erspan options", as well as for vxlan.

Thanks.

>
> > +                             return -EINVAL;
> > +                     }
> > +                     opt_len = tunnel_key_copy_erspan_opt(attr, dst,
> > +                                                          dst_len, extack);
> > +                     if (opt_len < 0)
> > +                             return opt_len;
> > +                     opts_len += opt_len;
> > +                     type = TUNNEL_ERSPAN_OPT;
> > +                     break;
> >               }
> >       }
> >

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-20  5:08     ` Xin Long
@ 2019-11-20 17:17       ` Jakub Kicinski
  2019-11-21  5:45         ` Xin Long
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2019-11-20 17:17 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, davem, Simon Horman, dsahern

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.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-20 17:17       ` Jakub Kicinski
@ 2019-11-21  5:45         ` Xin Long
  2019-11-21 15:56           ` David Ahern
  0 siblings, 1 reply; 16+ messages in thread
From: Xin Long @ 2019-11-21  5:45 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: network dev, davem, Simon Horman, dsahern

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.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key
  2019-11-21  5:45         ` Xin Long
@ 2019-11-21 15:56           ` David Ahern
  0 siblings, 0 replies; 16+ messages in thread
From: David Ahern @ 2019-11-21 15:56 UTC (permalink / raw)
  To: Xin Long, Jakub Kicinski; +Cc: network dev, davem, Simon Horman

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.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2019-11-21 15:56 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-19  9:31 [PATCH net-next 0/4] net: sched: support vxlan and erspan options Xin Long
2019-11-19  9:31 ` [PATCH net-next 1/4] net: sched: add vxlan option support to act_tunnel_key Xin Long
2019-11-19  9:31   ` [PATCH net-next 2/4] net: sched: add erspan " Xin Long
2019-11-19  9:31     ` [PATCH net-next 3/4] net: sched: allow flower to match vxlan options Xin Long
2019-11-19  9:31       ` [PATCH net-next 4/4] net: sched: allow flower to match erspan options Xin Long
2019-11-20  0:27     ` [PATCH net-next 2/4] net: sched: add erspan option support to act_tunnel_key Jakub Kicinski
2019-11-20  5:15       ` Xin Long
2019-11-20  0:12   ` [PATCH net-next 1/4] net: sched: add vxlan " Jakub Kicinski
2019-11-20  5:08     ` Xin Long
2019-11-20 17:17       ` Jakub Kicinski
2019-11-21  5:45         ` Xin Long
2019-11-21 15:56           ` David Ahern
2019-11-19 14:18 ` [PATCH net-next 0/4] net: sched: support vxlan and erspan options Roman Mashak
2019-11-19 15:55   ` Xin Long
2019-11-19 16:06     ` Roman Mashak
2019-11-19 16:23       ` Xin Long

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.