All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support
@ 2019-10-22 15:47 Pablo Neira Ayuso
  2019-10-22 15:47 ` [PATCH nf-next,RFC 1/2] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-10-22 15:47 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, wenxu

Hi,

This is a RFC patchset, untested, to introduce new infrastructure to
specify protocol decapsulation and encapsulation actions. This patchset
comes with initial support for VLAN, eg.

1) VLAN decapsulation:

	... meta iif . vlan id { eth0 . 10, eth1 . 11} decap vlan

The decapsulation is a single statement with no extra options.

2) VLAN encapsulation:

	add vlan "network0" { type push; id 100; proto 0x8100; }
        add vlan "network1" { type update; id 101; }
	... encap vlan set ip daddr map { 192.168.0.0/24 : "network0",
					  192.168.1.0/24 : "network1" }

The idea is that the user specifies the vlan policy through object
definition, eg. "network0" and "network1", then it applies this policy
via the "encap vlan set" statement.

This infrastructure should allow for more encapsulation protocols
with little work, eg. MPLS.

I have places the encap object and the decap expression in the same
nft_encap module.

I'm still considering to extend the object infrastructure to specify
the operation type through the rule, ie.

	add vlan "network0" { id 100; proto 0x8100; }
        add vlan "network1" { id 101; }
	... encap vlan push ip daddr map { 192.168.0.0/24 : "network0",
					   192.168.1.0/24 : "network1" }

So the VLAN object does not come with the operation type, instead this
is specified through the encap statement, that would require a bit more
work on the object infrastructure which is probably a good idea.

This is work-in-progress, syntax is tentative, comments welcome.

Thanks.

Pablo Neira Ayuso (2):
  netfilter: nf_tables: add decapsulation support
  netfilter: nf_tables: add encapsulation support

 include/uapi/linux/netfilter/nf_tables.h |  56 ++++-
 net/netfilter/Kconfig                    |   6 +
 net/netfilter/Makefile                   |   1 +
 net/netfilter/nft_encap.c                | 341 +++++++++++++++++++++++++++++++
 4 files changed, 403 insertions(+), 1 deletion(-)
 create mode 100644 net/netfilter/nft_encap.c

--
2.11.0


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

* [PATCH nf-next,RFC 1/2] netfilter: nf_tables: add decapsulation support
  2019-10-22 15:47 [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
@ 2019-10-22 15:47 ` Pablo Neira Ayuso
  2019-10-22 15:47 ` [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
  2019-10-23  3:49 ` [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support wenxu
  2 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-10-22 15:47 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, wenxu

This patch adds support for the decapsulation infrastructure, including
VLAN support for this.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |  16 +++++
 net/netfilter/Kconfig                    |   6 ++
 net/netfilter/Makefile                   |   1 +
 net/netfilter/nft_encap.c                | 119 +++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+)
 create mode 100644 net/netfilter/nft_encap.c

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 81fed16fe2b2..25e26340a0ba 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1625,6 +1625,22 @@ enum nft_xfrm_keys {
 };
 #define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1)
 
+enum nft_encap_type {
+	NFT_ENCAP_VLAN	= 0,
+};
+
+/**
+ * enum nft_decap_attributes - nf_tables decapsulation expression netlink attributes
+ *
+ * @NFTA_DECAP_TYPE: decapsulation type (NLA_U32)
+ */
+enum nft_decap_attributes {
+	NFTA_DECAP_UNSPEC,
+	NFTA_DECAP_TYPE,
+	__NFTA_DECAP_MAX,
+};
+#define NFTA_DECAP_MAX	(__NFTA_DECAP_MAX - 1)
+
 /**
  * enum nft_trace_attributes - nf_tables trace netlink attributes
  *
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 91efae88e8c2..573ea56aecfe 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -489,6 +489,12 @@ config NFT_CT
 	  This option adds the "ct" expression that you can use to match
 	  connection tracking information such as the flow state.
 
+config NFT_ENCAP
+	tristate "Netfilter nf_tables encapsulation/decapsulation module"
+	help
+	  This option adds the encapsulation expression used to decapsulate
+	  and to encapsulate packets through VLAN.
+
 config NFT_FLOW_OFFLOAD
 	depends on NF_CONNTRACK && NF_FLOW_TABLE
 	tristate "Netfilter nf_tables hardware flow offload module"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 4fc075b612fe..be8345c14a6e 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_NFT_COMPAT)	+= nft_compat.o
 obj-$(CONFIG_NFT_CONNLIMIT)	+= nft_connlimit.o
 obj-$(CONFIG_NFT_NUMGEN)	+= nft_numgen.o
 obj-$(CONFIG_NFT_CT)		+= nft_ct.o
+obj-$(CONFIG_NFT_ENCAP)		+= nft_encap.o
 obj-$(CONFIG_NFT_FLOW_OFFLOAD)	+= nft_flow_offload.o
 obj-$(CONFIG_NFT_LIMIT)		+= nft_limit.o
 obj-$(CONFIG_NFT_NAT)		+= nft_nat.o
diff --git a/net/netfilter/nft_encap.c b/net/netfilter/nft_encap.c
new file mode 100644
index 000000000000..657a62e4c283
--- /dev/null
+++ b/net/netfilter/nft_encap.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_core.h>
+#include <net/netfilter/nf_tables.h>
+
+struct nft_decap {
+	enum nft_encap_type	type;
+};
+
+void nft_decap_eval(const struct nft_expr *expr,
+		    struct nft_regs *regs,
+		    const struct nft_pktinfo *pkt)
+{
+	const struct nft_decap *priv = nft_expr_priv(expr);
+	int err;
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		err = skb_vlan_pop(pkt->skb);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		err = -1;
+	}
+
+	if (err < 0)
+		goto decap_error;
+
+	return;
+decap_error:
+	regs->verdict.code = NFT_BREAK;
+}
+
+static const struct nla_policy nft_decap_policy[NFTA_DECAP_MAX + 1] = {
+	[NFTA_DECAP_TYPE]	= { .type = NLA_U32 },
+};
+
+static int nft_decap_init(const struct nft_ctx *ctx,
+			  const struct nft_expr *expr,
+			  const struct nlattr * const tb[])
+{
+	struct nft_decap *priv = nft_expr_priv(expr);
+
+	if (!tb[NFTA_DECAP_TYPE])
+		return -EINVAL;
+
+	priv->type = ntohl(nla_get_be32(tb[NFTA_DECAP_TYPE]));
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int nft_decap_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	const struct nft_decap *priv = nft_expr_priv(expr);
+
+	if (nla_put_be32(skb, NFTA_DECAP_TYPE, htonl(priv->type)))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int nft_decap_validate(const struct nft_ctx *ctx,
+			      const struct nft_expr *expr,
+			      const struct nft_data **data)
+{
+	if (ctx->family != NFPROTO_NETDEV)
+		return -EOPNOTSUPP;
+
+	return nft_chain_validate_hooks(ctx->chain, 1 << NF_NETDEV_INGRESS);
+}
+
+static struct nft_expr_type nft_decap_type;
+static const struct nft_expr_ops nft_decap_ops = {
+	.type		= &nft_decap_type,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nft_decap)),
+	.eval		= nft_decap_eval,
+	.init		= nft_decap_init,
+	.dump		= nft_decap_dump,
+	.validate	= nft_decap_validate,
+};
+
+static struct nft_expr_type nft_decap_type __read_mostly = {
+	.name		= "decap",
+	.ops		= &nft_decap_ops,
+	.policy		= nft_decap_policy,
+	.maxattr	= NFTA_DECAP_MAX,
+	.owner		= THIS_MODULE,
+};
+
+static int __init nft_encap_netdev_module_init(void)
+{
+	return nft_register_expr(&nft_decap_type);
+}
+
+static void __exit nft_encap_netdev_module_exit(void)
+{
+	nft_unregister_expr(&nft_decap_type);
+}
+
+module_init(nft_encap_netdev_module_init);
+module_exit(nft_encap_netdev_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+MODULE_ALIAS_NFT_AF_EXPR(5, "decap");
-- 
2.11.0


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

* [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support
  2019-10-22 15:47 [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
  2019-10-22 15:47 ` [PATCH nf-next,RFC 1/2] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
@ 2019-10-22 15:47 ` Pablo Neira Ayuso
  2019-10-23  3:37   ` wenxu
  2019-10-23  3:49 ` [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support wenxu
  2 siblings, 1 reply; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-10-22 15:47 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, wenxu

This patch adds encapsulation support through the encapsulation object,
that specifies the encapsulation policy.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |  40 +++++-
 net/netfilter/nft_encap.c                | 224 ++++++++++++++++++++++++++++++-
 2 files changed, 262 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 25e26340a0ba..e5997a13ba71 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1484,7 +1484,8 @@ enum nft_ct_expectation_attributes {
 #define NFT_OBJECT_SECMARK	8
 #define NFT_OBJECT_CT_EXPECT	9
 #define NFT_OBJECT_SYNPROXY	10
-#define __NFT_OBJECT_MAX	11
+#define NFT_OBJECT_ENCAP	11
+#define __NFT_OBJECT_MAX	12
 #define NFT_OBJECT_MAX		(__NFT_OBJECT_MAX - 1)
 
 /**
@@ -1629,6 +1630,43 @@ enum nft_encap_type {
 	NFT_ENCAP_VLAN	= 0,
 };
 
+enum nft_encap_op {
+	NFT_ENCAP_ADD	= 0,
+	NFT_ENCAP_UPDATE,
+};
+
+/**
+ * enum nft_encap_vlan_attributes - nf_tables VLAN encapsulation expression netlink attributes
+ *
+ * @NFTA_ENCAP_VLAN_ID: VLAN id (NLA_U16)
+ * @NFTA_ENCAP_VLAN_PROTO: VLAN protocol (NLA_U16)
+ * @NFTA_ENCAP_VLAN_PRIO: VLAN priority (NLA_U8)
+ */
+enum nft_encap_vlan_attributes {
+	NFTA_ENCAP_VLAN_UNSPEC,
+	NFTA_ENCAP_VLAN_ID,
+	NFTA_ENCAP_VLAN_PROTO,
+	NFTA_ENCAP_VLAN_PRIO,
+	__NFTA_ENCAP_VLAN_MAX
+};
+#define NFTA_ENCAP_VLAN_MAX	(__NFTA_ENCAP_VLAN_MAX - 1)
+
+/**
+ * enum nft_encap_attributes - nf_tables encapsulation expression netlink attributes
+ *
+ * @NFTA_ENCAP_TYPE: encapsulation type (NLA_U32)
+ * @NFTA_ENCAP_OP: encapsulation operation (NLA_U32)
+ * @NFTA_ENCAP_DATA: encapsulation data (NLA_NESTED)
+ */
+enum nft_encap_attributes {
+	NFTA_ENCAP_UNSPEC,
+	NFTA_ENCAP_TYPE,
+	NFTA_ENCAP_OP,
+	NFTA_ENCAP_DATA,
+	__NFTA_ENCAP_MAX
+};
+#define NFTA_ENCAP_MAX	(__NFTA_ENCAP_MAX - 1)
+
 /**
  * enum nft_decap_attributes - nf_tables decapsulation expression netlink attributes
  *
diff --git a/net/netfilter/nft_encap.c b/net/netfilter/nft_encap.c
index 657a62e4c283..13643b3daf85 100644
--- a/net/netfilter/nft_encap.c
+++ b/net/netfilter/nft_encap.c
@@ -2,6 +2,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/if_vlan.h>
 #include <linux/netlink.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
@@ -101,14 +102,235 @@ static struct nft_expr_type nft_decap_type __read_mostly = {
 	.owner		= THIS_MODULE,
 };
 
+struct nft_encap {
+	enum nft_encap_type	type;
+	enum nft_encap_op	op;
+
+	union {
+		struct {
+			__u16	id;
+			__be16	proto;
+			__u8	prio;
+		} vlan;
+	};
+};
+
+static u16 nft_encap_vlan_tci(struct nft_encap *priv)
+{
+	return priv->vlan.id | (priv->vlan.prio << VLAN_PRIO_SHIFT);
+}
+
+static int nft_encap_vlan_eval(struct nft_encap *priv,
+			       struct nft_regs *regs,
+			       const struct nft_pktinfo *pkt)
+{
+	struct sk_buff *skb = pkt->skb;
+	int err;
+	u16 tci;
+
+	switch (priv->op) {
+	case NFT_ENCAP_ADD:
+		err = skb_vlan_push(skb, priv->vlan.proto,
+				    nft_encap_vlan_tci(priv));
+		if (err)
+			return err;
+		break;
+	case NFT_ENCAP_UPDATE:
+		if (!skb_vlan_tagged(skb))
+			return -1;
+
+		err = 0;
+		if (skb_vlan_tag_present(skb)) {
+			tci = skb_vlan_tag_get(skb);
+			__vlan_hwaccel_clear_tag(skb);
+		} else {
+			err = __skb_vlan_pop(skb, &tci);
+		}
+		if (err)
+			return err;
+
+		tci = (tci & ~VLAN_VID_MASK) | priv->vlan.id;
+		if (priv->vlan.prio) {
+			tci &= ~VLAN_PRIO_MASK;
+			tci |= priv->vlan.prio << VLAN_PRIO_SHIFT;
+		}
+
+		__vlan_hwaccel_put_tag(skb, priv->vlan.proto, tci);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void nft_encap_obj_eval(struct nft_object *obj,
+			       struct nft_regs *regs,
+			       const struct nft_pktinfo *pkt)
+{
+	struct nft_encap *priv = nft_obj_data(obj);
+	int err;
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		err = nft_encap_vlan_eval(priv, regs, pkt);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		err = -1;
+	}
+
+	if (err < 0)
+		regs->verdict.code = NFT_BREAK;
+}
+
+static const struct nla_policy nft_encap_vlan_policy[NFTA_ENCAP_VLAN_MAX + 1] = {
+	[NFTA_ENCAP_VLAN_ID]	= { .type = NLA_U16 },
+	[NFTA_ENCAP_VLAN_PROTO]	= { .type = NLA_U16 },
+	[NFTA_ENCAP_VLAN_PRIO]	= { .type = NLA_U8 },
+};
+
+static int nft_encap_vlan_parse(const struct nlattr *attr,
+				struct nft_encap *priv)
+{
+	struct nlattr *tb[NFTA_ENCAP_VLAN_MAX + 1];
+	int err;
+
+	err = nla_parse_nested_deprecated(tb, NFTA_ENCAP_VLAN_MAX, attr,
+					  nft_encap_vlan_policy, NULL);
+	if (err < 0)
+		return err;
+
+	if (!tb[NFTA_ENCAP_VLAN_PRIO] ||
+	    !tb[NFTA_ENCAP_VLAN_PROTO] ||
+	    !tb[NFTA_ENCAP_VLAN_ID])
+		return -EINVAL;
+
+	priv->vlan.id = ntohs(nla_get_be16(tb[NFTA_ENCAP_VLAN_ID]));
+	priv->vlan.proto = nla_get_be16(tb[NFTA_ENCAP_VLAN_PROTO]);
+	priv->vlan.prio = nla_get_u8(tb[NFTA_ENCAP_VLAN_PRIO]);
+
+	return 0;
+}
+
+static int nft_encap_obj_init(const struct nft_ctx *ctx,
+			      const struct nlattr * const tb[],
+			      struct nft_object *obj)
+{
+	struct nft_encap *priv = nft_obj_data(obj);
+	int err = 0;
+
+	if (!tb[NFTA_ENCAP_TYPE] ||
+	    !tb[NFTA_ENCAP_OP])
+		return -EINVAL;
+
+	priv->type = ntohl(nla_get_be32(tb[NFTA_ENCAP_TYPE]));
+	priv->op = ntohl(nla_get_be32(tb[NFTA_ENCAP_OP]));
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		if (priv->op != NFT_ENCAP_ADD &&
+		    priv->op != NFT_ENCAP_UPDATE)
+			return -EOPNOTSUPP;
+
+		err = nft_encap_vlan_parse(tb[NFTA_ENCAP_DATA], priv);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return err;
+}
+
+static int nft_encap_type_dump(struct sk_buff *skb, struct nft_encap *priv)
+{
+	struct nlattr *nest;
+
+	nest = nla_nest_start_noflag(skb, NFTA_ENCAP_DATA);
+	if (!nest)
+		goto nla_put_failure;
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		if (nla_put_be16(skb, NFTA_ENCAP_VLAN_ID, htons(priv->vlan.id)) ||
+		    nla_put_be16(skb, NFTA_ENCAP_VLAN_PROTO, priv->vlan.proto) ||
+		    nla_put_u8(skb, NFTA_ENCAP_VLAN_PRIO, priv->vlan.prio))
+			goto nla_put_failure;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		break;
+	}
+	nla_nest_end(skb, nest);
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int nft_encap_obj_dump(struct sk_buff *skb, struct nft_object *obj,
+			      bool reset)
+{
+	struct nft_encap *priv = nft_obj_data(obj);
+
+	if (nla_put_be32(skb, NFTA_ENCAP_TYPE, htonl(priv->type)) ||
+	    nla_put_be32(skb, NFTA_ENCAP_OP, htonl(priv->op)) ||
+	    nft_encap_type_dump(skb, priv))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static const struct nla_policy nft_encap_policy[NFTA_ENCAP_MAX + 1] = {
+	[NFTA_ENCAP_TYPE]	= { .type = NLA_U32 },
+	[NFTA_ENCAP_OP]		= { .type = NLA_U32 },
+	[NFTA_ENCAP_DATA]	= { .type = NLA_NESTED },
+};
+
+static struct nft_object_type nft_encap_obj_type;
+static const struct nft_object_ops nft_encap_obj_ops = {
+	.type		= &nft_encap_obj_type,
+	.size		= sizeof(struct nft_encap),
+	.eval		= nft_encap_obj_eval,
+	.init		= nft_encap_obj_init,
+	.dump		= nft_encap_obj_dump,
+};
+
+static struct nft_object_type nft_encap_obj_type __read_mostly = {
+	.type           = NFT_OBJECT_ENCAP,
+	.ops            = &nft_encap_obj_ops,
+	.maxattr        = NFTA_ENCAP_MAX,
+	.policy         = nft_encap_policy,
+	.owner          = THIS_MODULE,
+};
+
 static int __init nft_encap_netdev_module_init(void)
 {
-	return nft_register_expr(&nft_decap_type);
+	int err;
+
+	err = nft_register_obj(&nft_encap_obj_type);
+	if (err < 0)
+		return err;
+
+	err = nft_register_expr(&nft_decap_type);
+	if (err < 0)
+		goto err_unregister;
+
+	return 0;
+
+err_unregister:
+	nft_unregister_obj(&nft_encap_obj_type);
+	return err;
 }
 
 static void __exit nft_encap_netdev_module_exit(void)
 {
 	nft_unregister_expr(&nft_decap_type);
+	nft_unregister_obj(&nft_encap_obj_type);
 }
 
 module_init(nft_encap_netdev_module_init);
-- 
2.11.0


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

* Re: [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support
  2019-10-22 15:47 ` [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
@ 2019-10-23  3:37   ` wenxu
  0 siblings, 0 replies; 8+ messages in thread
From: wenxu @ 2019-10-23  3:37 UTC (permalink / raw)
  To: Pablo Neira Ayuso, netfilter-devel; +Cc: fw


On 10/22/2019 11:47 PM, Pablo Neira Ayuso wrote:
> This patch adds encapsulation support through the encapsulation object,
> that specifies the encapsulation policy.
>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
>  include/uapi/linux/netfilter/nf_tables.h |  40 +++++-
>  net/netfilter/nft_encap.c                | 224 ++++++++++++++++++++++++++++++-
>  2 files changed, 262 insertions(+), 2 deletions(-)
>
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index 25e26340a0ba..e5997a13ba71 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -1484,7 +1484,8 @@ enum nft_ct_expectation_attributes {
>  #define NFT_OBJECT_SECMARK	8
>  #define NFT_OBJECT_CT_EXPECT	9
>  #define NFT_OBJECT_SYNPROXY	10
> -#define __NFT_OBJECT_MAX	11
> +#define NFT_OBJECT_ENCAP	11
> +#define __NFT_OBJECT_MAX	12
>  #define NFT_OBJECT_MAX		(__NFT_OBJECT_MAX - 1)
>  
>  /**
> @@ -1629,6 +1630,43 @@ enum nft_encap_type {
>  	NFT_ENCAP_VLAN	= 0,
>  };
>  
> +enum nft_encap_op {
> +	NFT_ENCAP_ADD	= 0,
> +	NFT_ENCAP_UPDATE,
> +};
> +
> +/**
> + * enum nft_encap_vlan_attributes - nf_tables VLAN encapsulation expression netlink attributes
> + *
> + * @NFTA_ENCAP_VLAN_ID: VLAN id (NLA_U16)
> + * @NFTA_ENCAP_VLAN_PROTO: VLAN protocol (NLA_U16)
> + * @NFTA_ENCAP_VLAN_PRIO: VLAN priority (NLA_U8)
> + */
> +enum nft_encap_vlan_attributes {
> +	NFTA_ENCAP_VLAN_UNSPEC,
> +	NFTA_ENCAP_VLAN_ID,
> +	NFTA_ENCAP_VLAN_PROTO,
> +	NFTA_ENCAP_VLAN_PRIO,
> +	__NFTA_ENCAP_VLAN_MAX
> +};
> +#define NFTA_ENCAP_VLAN_MAX	(__NFTA_ENCAP_VLAN_MAX - 1)
> +
> +/**
> + * enum nft_encap_attributes - nf_tables encapsulation expression netlink attributes
> + *
> + * @NFTA_ENCAP_TYPE: encapsulation type (NLA_U32)
> + * @NFTA_ENCAP_OP: encapsulation operation (NLA_U32)
> + * @NFTA_ENCAP_DATA: encapsulation data (NLA_NESTED)
> + */
> +enum nft_encap_attributes {
> +	NFTA_ENCAP_UNSPEC,
> +	NFTA_ENCAP_TYPE,
> +	NFTA_ENCAP_OP,
> +	NFTA_ENCAP_DATA,
> +	__NFTA_ENCAP_MAX
> +};
> +#define NFTA_ENCAP_MAX	(__NFTA_ENCAP_MAX - 1)
> +
>  /**
>   * enum nft_decap_attributes - nf_tables decapsulation expression netlink attributes
>   *
> diff --git a/net/netfilter/nft_encap.c b/net/netfilter/nft_encap.c
> index 657a62e4c283..13643b3daf85 100644
> --- a/net/netfilter/nft_encap.c
> +++ b/net/netfilter/nft_encap.c
> @@ -2,6 +2,7 @@
>  #include <linux/kernel.h>
>  #include <linux/init.h>
>  #include <linux/module.h>
> +#include <linux/if_vlan.h>
>  #include <linux/netlink.h>
>  #include <linux/netfilter.h>
>  #include <linux/netfilter/nf_tables.h>
> @@ -101,14 +102,235 @@ static struct nft_expr_type nft_decap_type __read_mostly = {
>  	.owner		= THIS_MODULE,
>  };
>  
> +struct nft_encap {
> +	enum nft_encap_type	type;
> +	enum nft_encap_op	op;
> +
> +	union {
> +		struct {
> +			__u16	id;
> +			__be16	proto;
> +			__u8	prio;
> +		} vlan;
> +	};
> +};
> +
> +static u16 nft_encap_vlan_tci(struct nft_encap *priv)
> +{
> +	return priv->vlan.id | (priv->vlan.prio << VLAN_PRIO_SHIFT);
> +}
> +
> +static int nft_encap_vlan_eval(struct nft_encap *priv,
> +			       struct nft_regs *regs,
> +			       const struct nft_pktinfo *pkt)
> +{
> +	struct sk_buff *skb = pkt->skb;
> +	int err;
> +	u16 tci;
> +
> +	switch (priv->op) {
> +	case NFT_ENCAP_ADD:
> +		err = skb_vlan_push(skb, priv->vlan.proto,
> +				    nft_encap_vlan_tci(priv));
> +		if (err)
> +			return err;
> +		break;
> +	case NFT_ENCAP_UPDATE:
> +		if (!skb_vlan_tagged(skb))
> +			return -1;
> +
> +		err = 0;
> +		if (skb_vlan_tag_present(skb)) {
> +			tci = skb_vlan_tag_get(skb);
> +			__vlan_hwaccel_clear_tag(skb);
> +		} else {
> +			err = __skb_vlan_pop(skb, &tci);
> +		}
> +		if (err)
> +			return err;
> +
> +		tci = (tci & ~VLAN_VID_MASK) | priv->vlan.id;
> +		if (priv->vlan.prio) {
> +			tci &= ~VLAN_PRIO_MASK;
> +			tci |= priv->vlan.prio << VLAN_PRIO_SHIFT;
> +		}
> +
> +		__vlan_hwaccel_put_tag(skb, priv->vlan.proto, tci);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static void nft_encap_obj_eval(struct nft_object *obj,
> +			       struct nft_regs *regs,
> +			       const struct nft_pktinfo *pkt)
> +{
> +	struct nft_encap *priv = nft_obj_data(obj);
> +	int err;
> +
> +	switch (priv->type) {
> +	case NFT_ENCAP_VLAN:
> +		err = nft_encap_vlan_eval(priv, regs, pkt);
> +		break;
> +	default:
> +		WARN_ON_ONCE(1);
> +		err = -1;
> +	}
> +
> +	if (err < 0)
> +		regs->verdict.code = NFT_BREAK;
> +}
> +
> +static const struct nla_policy nft_encap_vlan_policy[NFTA_ENCAP_VLAN_MAX + 1] = {
> +	[NFTA_ENCAP_VLAN_ID]	= { .type = NLA_U16 },
> +	[NFTA_ENCAP_VLAN_PROTO]	= { .type = NLA_U16 },
> +	[NFTA_ENCAP_VLAN_PRIO]	= { .type = NLA_U8 },
> +};
> +
> +static int nft_encap_vlan_parse(const struct nlattr *attr,
> +				struct nft_encap *priv)
> +{
> +	struct nlattr *tb[NFTA_ENCAP_VLAN_MAX + 1];
> +	int err;
> +
> +	err = nla_parse_nested_deprecated(tb, NFTA_ENCAP_VLAN_MAX, attr,
> +					  nft_encap_vlan_policy, NULL);
> +	if (err < 0)
> +		return err;
> +
> +	if (!tb[NFTA_ENCAP_VLAN_PRIO] ||
> +	    !tb[NFTA_ENCAP_VLAN_PROTO] ||
> +	    !tb[NFTA_ENCAP_VLAN_ID])
> +		return -EINVAL;
> +
> +	priv->vlan.id = ntohs(nla_get_be16(tb[NFTA_ENCAP_VLAN_ID]));
> +	priv->vlan.proto = nla_get_be16(tb[NFTA_ENCAP_VLAN_PROTO]);

Maybe it is better to check the vlan.proto is ETH_P_8021Q or ETH_P_8021AD?

> +	priv->vlan.prio = nla_get_u8(tb[NFTA_ENCAP_VLAN_PRIO]);
> +
> +	return 0;
> +}
> +
> +static int nft_encap_obj_init(const struct nft_ctx *ctx,
> +			      const struct nlattr * const tb[],
> +			      struct nft_object *obj)
> +{
> +	struct nft_encap *priv = nft_obj_data(obj);
> +	int err = 0;
> +
> +	if (!tb[NFTA_ENCAP_TYPE] ||
> +	    !tb[NFTA_ENCAP_OP])
> +		return -EINVAL;
> +
> +	priv->type = ntohl(nla_get_be32(tb[NFTA_ENCAP_TYPE]));
> +	priv->op = ntohl(nla_get_be32(tb[NFTA_ENCAP_OP]));
> +
> +	switch (priv->type) {
> +	case NFT_ENCAP_VLAN:
> +		if (priv->op != NFT_ENCAP_ADD &&
> +		    priv->op != NFT_ENCAP_UPDATE)
> +			return -EOPNOTSUPP;
> +
> +		err = nft_encap_vlan_parse(tb[NFTA_ENCAP_DATA], priv);
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return err;
> +}
> +
>

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

* Re: [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support
  2019-10-22 15:47 [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
  2019-10-22 15:47 ` [PATCH nf-next,RFC 1/2] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
  2019-10-22 15:47 ` [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
@ 2019-10-23  3:49 ` wenxu
  2019-10-23 10:16   ` Pablo Neira Ayuso
  2 siblings, 1 reply; 8+ messages in thread
From: wenxu @ 2019-10-23  3:49 UTC (permalink / raw)
  To: Pablo Neira Ayuso, netfilter-devel; +Cc: fw


On 10/22/2019 11:47 PM, Pablo Neira Ayuso wrote:
> Hi,
>
> This is a RFC patchset, untested, to introduce new infrastructure to
> specify protocol decapsulation and encapsulation actions. This patchset
> comes with initial support for VLAN, eg.
>
> 1) VLAN decapsulation:
>
> 	... meta iif . vlan id { eth0 . 10, eth1 . 11} decap vlan
>
> The decapsulation is a single statement with no extra options.

Currently there is no vlan meta match expr.  So it is better to extend the meta expr or add new

ntf_vlan_get_expr?

>
> 2) VLAN encapsulation:
>
> 	add vlan "network0" { type push; id 100; proto 0x8100; }
>         add vlan "network1" { type update; id 101; }
> 	... encap vlan set ip daddr map { 192.168.0.0/24 : "network0",
> 					  192.168.1.0/24 : "network1" }
>
> The idea is that the user specifies the vlan policy through object
> definition, eg. "network0" and "network1", then it applies this policy
> via the "encap vlan set" statement.
>
> This infrastructure should allow for more encapsulation protocols
> with little work, eg. MPLS.

So the tunnel already exist in nft_tunnel also can add in this encapsulation protocols

as ip.

like ip-route

encap ip id 100 dst 10.0.0.1?

>
> I have places the encap object and the decap expression in the same
> nft_encap module.
>
> I'm still considering to extend the object infrastructure to specify
> the operation type through the rule, ie.
>
> 	add vlan "network0" { id 100; proto 0x8100; }
>         add vlan "network1" { id 101; }
> 	... encap vlan push ip daddr map { 192.168.0.0/24 : "network0",
> 					   192.168.1.0/24 : "network1" }
>
> So the VLAN object does not come with the operation type, instead this
> is specified through the encap statement, that would require a bit more
> work on the object infrastructure which is probably a good idea.
>
> This is work-in-progress, syntax is tentative, comments welcome.
>
> Thanks.
>
> Pablo Neira Ayuso (2):
>   netfilter: nf_tables: add decapsulation support
>   netfilter: nf_tables: add encapsulation support
>
>  include/uapi/linux/netfilter/nf_tables.h |  56 ++++-
>  net/netfilter/Kconfig                    |   6 +
>  net/netfilter/Makefile                   |   1 +
>  net/netfilter/nft_encap.c                | 341 +++++++++++++++++++++++++++++++
>  4 files changed, 403 insertions(+), 1 deletion(-)
>  create mode 100644 net/netfilter/nft_encap.c
>
> --
> 2.11.0
>
>

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

* Re: [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support
  2019-10-23  3:49 ` [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support wenxu
@ 2019-10-23 10:16   ` Pablo Neira Ayuso
  2019-10-23 14:00     ` wenxu
  2019-10-23 14:45     ` wenxu
  0 siblings, 2 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-10-23 10:16 UTC (permalink / raw)
  To: wenxu; +Cc: netfilter-devel, fw

On Wed, Oct 23, 2019 at 11:49:57AM +0800, wenxu wrote:
> 
> On 10/22/2019 11:47 PM, Pablo Neira Ayuso wrote:
> > Hi,
> >
> > This is a RFC patchset, untested, to introduce new infrastructure to
> > specify protocol decapsulation and encapsulation actions. This patchset
> > comes with initial support for VLAN, eg.
> >
> > 1) VLAN decapsulation:
> >
> > 	... meta iif . vlan id { eth0 . 10, eth1 . 11} decap vlan
> >
> > The decapsulation is a single statement with no extra options.
> 
> Currently there is no vlan meta match expr.  So it is better to
> extend the meta expr or add new ntf_vlan_get_expr?

There's nft_payload to get the vlan information.

> > 2) VLAN encapsulation:
> >
> > 	add vlan "network0" { type push; id 100; proto 0x8100; }
> >         add vlan "network1" { type update; id 101; }
> > 	... encap vlan set ip daddr map { 192.168.0.0/24 : "network0",
> > 					  192.168.1.0/24 : "network1" }
> >
> > The idea is that the user specifies the vlan policy through object
> > definition, eg. "network0" and "network1", then it applies this policy
> > via the "encap vlan set" statement.
> >
> > This infrastructure should allow for more encapsulation protocols
> > with little work, eg. MPLS.
> 
> So the tunnel already exist in nft_tunnel also can add in this encapsulation protocols
> as ip.
> 
> like ip-route
> 
> encap ip id 100 dst 10.0.0.1?

Not sure what you mean, please, extend your coment.

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

* Re: [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support
  2019-10-23 10:16   ` Pablo Neira Ayuso
@ 2019-10-23 14:00     ` wenxu
  2019-10-23 14:45     ` wenxu
  1 sibling, 0 replies; 8+ messages in thread
From: wenxu @ 2019-10-23 14:00 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, fw


在 2019/10/23 18:16, Pablo Neira Ayuso 写道:

>>> 2) VLAN encapsulation:
>>>
>>> 	add vlan "network0" { type push; id 100; proto 0x8100; }
>>>         add vlan "network1" { type update; id 101; }
>>> 	... encap vlan set ip daddr map { 192.168.0.0/24 : "network0",
>>> 					  192.168.1.0/24 : "network1" }
>>>
>>> The idea is that the user specifies the vlan policy through object
>>> definition, eg. "network0" and "network1", then it applies this policy
>>> via the "encap vlan set" statement.
>>>
>>> This infrastructure should allow for more encapsulation protocols
>>> with little work, eg. MPLS.
>> So the tunnel already exist in nft_tunnel also can add in this encapsulation protocols
>> as ip.
>>
>> like ip-route
>>
>> encap ip id 100 dst 10.0.0.1?
> Not sure what you mean, please, extend your coment.

For the future there maybe can add a new nft_encap_type NFT_ENCAP_IP which contain all

the ip tunnels such as vxlan, gre etc. This type of encap already in the nft_tunnel.

>

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

* Re: [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support
  2019-10-23 10:16   ` Pablo Neira Ayuso
  2019-10-23 14:00     ` wenxu
@ 2019-10-23 14:45     ` wenxu
  1 sibling, 0 replies; 8+ messages in thread
From: wenxu @ 2019-10-23 14:45 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, fw


在 2019/10/23 18:16, Pablo Neira Ayuso 写道:
> On Wed, Oct 23, 2019 at 11:49:57AM +0800, wenxu wrote:
>> On 10/22/2019 11:47 PM, Pablo Neira Ayuso wrote:
>>> Hi,
>>>
>>> This is a RFC patchset, untested, to introduce new infrastructure to
>>> specify protocol decapsulation and encapsulation actions. This patchset
>>> comes with initial support for VLAN, eg.
>>>
>>> 1) VLAN decapsulation:
>>>
>>> 	... meta iif . vlan id { eth0 . 10, eth1 . 11} decap vlan
>>>
>>> The decapsulation is a single statement with no extra options.
>> Currently there is no vlan meta match expr.  So it is better to
>> extend the meta expr or add new ntf_vlan_get_expr?
> There's nft_payload to get the vlan information.
>
There are some limtaion for geting the vlan information through nft_payload

1. It can't get the inner vlan(cvlan) information

2. geting the vlan information is based on offset on link header, There is no good way

to offload the vlan match expr.


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

end of thread, other threads:[~2019-10-23 14:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-22 15:47 [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
2019-10-22 15:47 ` [PATCH nf-next,RFC 1/2] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
2019-10-22 15:47 ` [PATCH nf-next,RFC 2/2] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
2019-10-23  3:37   ` wenxu
2019-10-23  3:49 ` [PATCH nf-next,RFC 0/2] nf_tables encapsulation/decapsulation support wenxu
2019-10-23 10:16   ` Pablo Neira Ayuso
2019-10-23 14:00     ` wenxu
2019-10-23 14:45     ` wenxu

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.