All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support
@ 2019-11-20 13:18 Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 1/7] netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE Pablo Neira Ayuso
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

Hi,

This patchset introduces new infrastructure to specify protocol
decapsulation and encapsulation actions. This patchset comes with
initial support for VLAN.

1) VLAN decapsulation:

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

The decapsulation action is represented as a single statement with no
extra options.

2) VLAN encapsulation:

        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" }

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

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

I have placed the encap object and the decap expression in the same
nft_encap module for simplificity.

Patchset is composed of initial updates to allow to specify operation
type on objects:

1) Rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE.
2) Check for object type from map reference.
3 and 4) Add nft_object_ref and update code to use it.
5) Add support for operations on object reference.

Then, the actual decapsulation / encapsulation support:

6) Add decapsulation support though expression.
7) Add encapsulation support through object definition, this uses
   the operation when referencing the object from rule to specificy
   if this is a update or push vlan operation.

Userspace patchset update is still in progress, comments welcome.
Thanks.

Pablo Neira Ayuso (7):
  netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE
  netfilter: nft_objref: validate map object type
  netfilter: nft_objref: add nft_obj_ref structure and use it
  netfilter: nf_tables: pass nft_object_ref to object evaluation function
  netfilter: nft_objref: add support for operation on objects
  netfilter: nf_tables: add decapsulation support
  netfilter: nf_tables: add encapsulation support

 include/net/netfilter/nf_tables.h        |  10 +-
 include/uapi/linux/netfilter/nf_tables.h |  64 +++++-
 net/netfilter/Kconfig                    |   6 +
 net/netfilter/Makefile                   |   1 +
 net/netfilter/nf_tables_api.c            |   3 +-
 net/netfilter/nft_connlimit.c            |   4 +-
 net/netfilter/nft_counter.c              |   4 +-
 net/netfilter/nft_ct.c                   |  12 +-
 net/netfilter/nft_encap.c                | 333 +++++++++++++++++++++++++++++++
 net/netfilter/nft_limit.c                |   8 +-
 net/netfilter/nft_meta.c                 |   5 +-
 net/netfilter/nft_objref.c               |  69 +++++--
 net/netfilter/nft_quota.c                |   3 +-
 net/netfilter/nft_synproxy.c             |   4 +-
 net/netfilter/nft_tunnel.c               |   4 +-
 15 files changed, 486 insertions(+), 44 deletions(-)
 create mode 100644 net/netfilter/nft_encap.c

-- 
2.11.0


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

* [PATCH nf-next 1/7] netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 2/7] netfilter: nft_objref: validate map object type Pablo Neira Ayuso
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

Prepare this netlink attribute to be used from maps too.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |  5 +++--
 net/netfilter/nft_objref.c               | 10 +++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index bb9b049310df..100261902b1b 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1376,7 +1376,7 @@ enum nft_fwd_attributes {
 /**
  * enum nft_objref_attributes - nf_tables stateful object expression netlink attributes
  *
- * @NFTA_OBJREF_IMM_TYPE: object type for immediate reference (NLA_U32: nft_register)
+ * @NFTA_OBJREF_TYPE: object type for set reference (NLA_U32: nft_register)
  * @NFTA_OBJREF_IMM_NAME: object name for immediate reference (NLA_STRING)
  * @NFTA_OBJREF_SET_SREG: source register of the data to look for (NLA_U32: nft_registers)
  * @NFTA_OBJREF_SET_NAME: name of the set where to look for (NLA_STRING)
@@ -1384,7 +1384,8 @@ enum nft_fwd_attributes {
  */
 enum nft_objref_attributes {
 	NFTA_OBJREF_UNSPEC,
-	NFTA_OBJREF_IMM_TYPE,
+	NFTA_OBJREF_TYPE,
+#define NFTA_OBJREF_IMM_TYPE	NFTA_OBJREF_TYPE
 	NFTA_OBJREF_IMM_NAME,
 	NFTA_OBJREF_SET_SREG,
 	NFTA_OBJREF_SET_NAME,
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index bfd18d2b65a2..984f5b1810be 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -31,10 +31,10 @@ static int nft_objref_init(const struct nft_ctx *ctx,
 	u32 objtype;
 
 	if (!tb[NFTA_OBJREF_IMM_NAME] ||
-	    !tb[NFTA_OBJREF_IMM_TYPE])
+	    !tb[NFTA_OBJREF_TYPE])
 		return -EINVAL;
 
-	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
+	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_TYPE]));
 	obj = nft_obj_lookup(ctx->net, ctx->table,
 			     tb[NFTA_OBJREF_IMM_NAME], objtype,
 			     genmask);
@@ -52,7 +52,7 @@ static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	const struct nft_object *obj = nft_objref_priv(expr);
 
 	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
-	    nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
+	    nla_put_be32(skb, NFTA_OBJREF_TYPE,
 			 htonl(obj->ops->type->type)))
 		goto nla_put_failure;
 
@@ -212,7 +212,7 @@ nft_objref_select_ops(const struct nft_ctx *ctx,
 	     tb[NFTA_OBJREF_SET_ID]))
 		return &nft_objref_map_ops;
 	else if (tb[NFTA_OBJREF_IMM_NAME] &&
-		 tb[NFTA_OBJREF_IMM_TYPE])
+		 tb[NFTA_OBJREF_TYPE])
 		return &nft_objref_ops;
 
 	return ERR_PTR(-EOPNOTSUPP);
@@ -221,7 +221,7 @@ nft_objref_select_ops(const struct nft_ctx *ctx,
 static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
 	[NFTA_OBJREF_IMM_NAME]	= { .type = NLA_STRING,
 				    .len = NFT_OBJ_MAXNAMELEN - 1 },
-	[NFTA_OBJREF_IMM_TYPE]	= { .type = NLA_U32 },
+	[NFTA_OBJREF_TYPE]	= { .type = NLA_U32 },
 	[NFTA_OBJREF_SET_SREG]	= { .type = NLA_U32 },
 	[NFTA_OBJREF_SET_NAME]	= { .type = NLA_STRING,
 				    .len = NFT_SET_MAXNAMELEN - 1 },
-- 
2.11.0


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

* [PATCH nf-next 2/7] netfilter: nft_objref: validate map object type
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 1/7] netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 3/7] netfilter: nft_objref: add nft_obj_ref structure and use it Pablo Neira Ayuso
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

Allow to specify the NFTA_OBJREF_TYPE netlink attribute to validate the
object type in this reference.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nft_objref.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index 984f5b1810be..006c2ebd898a 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -125,6 +125,7 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,
 {
 	struct nft_objref_map *priv = nft_expr_priv(expr);
 	u8 genmask = nft_genmask_next(ctx->net);
+	u32 objtype = NFT_OBJECT_UNSPEC;
 	struct nft_set *set;
 	int err;
 
@@ -148,6 +149,13 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,
 	if (err < 0)
 		return err;
 
+	if (tb[NFTA_OBJREF_TYPE])
+		objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_TYPE]));
+
+	if (objtype != NFT_OBJECT_UNSPEC &&
+	    set->objtype != objtype)
+		return -EOPNOTSUPP;
+
 	priv->set = set;
 	return 0;
 }
-- 
2.11.0


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

* [PATCH nf-next 3/7] netfilter: nft_objref: add nft_obj_ref structure and use it
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 1/7] netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 2/7] netfilter: nft_objref: validate map object type Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 4/7] netfilter: nf_tables: pass nft_object_ref to object evaluation function Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

This allows to extend this private expression area with new fields.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h |  4 ++++
 net/netfilter/nft_objref.c        | 22 ++++++++++++----------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 87b758407868..04c3b2e7eb99 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1122,6 +1122,10 @@ struct nft_object_type {
 	const struct nla_policy		*policy;
 };
 
+struct nft_object_ref {
+	struct nft_object		*obj;
+};
+
 /**
  *	struct nft_object_ops - stateful object operations
  *
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index 006c2ebd898a..c9d8543fc97c 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -11,23 +11,22 @@
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
 
-#define nft_objref_priv(expr)	*((struct nft_object **)nft_expr_priv(expr))
-
 static void nft_objref_eval(const struct nft_expr *expr,
 			    struct nft_regs *regs,
 			    const struct nft_pktinfo *pkt)
 {
-	struct nft_object *obj = nft_objref_priv(expr);
+	struct nft_object_ref *priv = nft_expr_priv(expr);
 
-	obj->ops->eval(obj, regs, pkt);
+	priv->obj->ops->eval(priv->obj, regs, pkt);
 }
 
 static int nft_objref_init(const struct nft_ctx *ctx,
 			   const struct nft_expr *expr,
 			   const struct nlattr * const tb[])
 {
-	struct nft_object *obj = nft_objref_priv(expr);
+	struct nft_object_ref *priv = nft_expr_priv(expr);
 	u8 genmask = nft_genmask_next(ctx->net);
+	struct nft_object *obj;
 	u32 objtype;
 
 	if (!tb[NFTA_OBJREF_IMM_NAME] ||
@@ -41,15 +40,16 @@ static int nft_objref_init(const struct nft_ctx *ctx,
 	if (IS_ERR(obj))
 		return -ENOENT;
 
-	nft_objref_priv(expr) = obj;
 	obj->use++;
+	priv->obj = obj;
 
 	return 0;
 }
 
 static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
-	const struct nft_object *obj = nft_objref_priv(expr);
+	const struct nft_object_ref *priv = nft_expr_priv(expr);
+	const struct nft_object *obj = priv->obj;
 
 	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
 	    nla_put_be32(skb, NFTA_OBJREF_TYPE,
@@ -66,7 +66,8 @@ static void nft_objref_deactivate(const struct nft_ctx *ctx,
 				  const struct nft_expr *expr,
 				  enum nft_trans_phase phase)
 {
-	struct nft_object *obj = nft_objref_priv(expr);
+	struct nft_object_ref *priv = nft_expr_priv(expr);
+	struct nft_object *obj = priv->obj;
 
 	if (phase == NFT_TRANS_COMMIT)
 		return;
@@ -77,7 +78,8 @@ static void nft_objref_deactivate(const struct nft_ctx *ctx,
 static void nft_objref_activate(const struct nft_ctx *ctx,
 				const struct nft_expr *expr)
 {
-	struct nft_object *obj = nft_objref_priv(expr);
+	struct nft_object_ref *priv = nft_expr_priv(expr);
+	struct nft_object *obj = priv->obj;
 
 	obj->use++;
 }
@@ -85,7 +87,7 @@ static void nft_objref_activate(const struct nft_ctx *ctx,
 static struct nft_expr_type nft_objref_type;
 static const struct nft_expr_ops nft_objref_ops = {
 	.type		= &nft_objref_type,
-	.size		= NFT_EXPR_SIZE(sizeof(struct nft_object *)),
+	.size		= NFT_EXPR_SIZE(sizeof(struct nft_object_ref)),
 	.eval		= nft_objref_eval,
 	.init		= nft_objref_init,
 	.activate	= nft_objref_activate,
-- 
2.11.0


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

* [PATCH nf-next 4/7] netfilter: nf_tables: pass nft_object_ref to object evaluation function
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2019-11-20 13:18 ` [PATCH nf-next 3/7] netfilter: nft_objref: add nft_obj_ref structure and use it Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 5/7] netfilter: nft_objref: add support for operation on objects Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

This update comes in preparation to pass operation type on the object as
a follow patch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h |  2 +-
 net/netfilter/nft_connlimit.c     |  4 ++--
 net/netfilter/nft_counter.c       |  4 ++--
 net/netfilter/nft_ct.c            | 12 ++++++------
 net/netfilter/nft_limit.c         |  8 ++++----
 net/netfilter/nft_meta.c          |  5 +++--
 net/netfilter/nft_objref.c        |  6 ++++--
 net/netfilter/nft_quota.c         |  3 ++-
 net/netfilter/nft_synproxy.c      |  4 ++--
 net/netfilter/nft_tunnel.c        |  4 ++--
 10 files changed, 28 insertions(+), 24 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 04c3b2e7eb99..413eb650bafd 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1137,7 +1137,7 @@ struct nft_object_ref {
  *	@update: update stateful object
  */
 struct nft_object_ops {
-	void				(*eval)(struct nft_object *obj,
+	void				(*eval)(struct nft_object_ref *ref,
 						struct nft_regs *regs,
 						const struct nft_pktinfo *pkt);
 	unsigned int			size;
diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c
index 69d6173f91e2..838b5e62e36c 100644
--- a/net/netfilter/nft_connlimit.c
+++ b/net/netfilter/nft_connlimit.c
@@ -105,11 +105,11 @@ static int nft_connlimit_do_dump(struct sk_buff *skb,
 	return -1;
 }
 
-static inline void nft_connlimit_obj_eval(struct nft_object *obj,
+static inline void nft_connlimit_obj_eval(struct nft_object_ref *ref,
 					struct nft_regs *regs,
 					const struct nft_pktinfo *pkt)
 {
-	struct nft_connlimit *priv = nft_obj_data(obj);
+	struct nft_connlimit *priv = nft_obj_data(ref->obj);
 
 	nft_connlimit_do_eval(priv, regs, pkt, NULL);
 }
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
index f6d4d0fa23a6..e9d5cab5f189 100644
--- a/net/netfilter/nft_counter.c
+++ b/net/netfilter/nft_counter.c
@@ -45,11 +45,11 @@ static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv,
 	local_bh_enable();
 }
 
-static inline void nft_counter_obj_eval(struct nft_object *obj,
+static inline void nft_counter_obj_eval(struct nft_object_ref *ref,
 					struct nft_regs *regs,
 					const struct nft_pktinfo *pkt)
 {
-	struct nft_counter_percpu_priv *priv = nft_obj_data(obj);
+	struct nft_counter_percpu_priv *priv = nft_obj_data(ref->obj);
 
 	nft_counter_do_eval(priv, regs, pkt);
 }
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index 46ca8bcca1bd..be486c8bf6a7 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -823,11 +823,11 @@ struct nft_ct_timeout_obj {
 	u8			l4proto;
 };
 
-static void nft_ct_timeout_obj_eval(struct nft_object *obj,
+static void nft_ct_timeout_obj_eval(struct nft_object_ref *ref,
 				    struct nft_regs *regs,
 				    const struct nft_pktinfo *pkt)
 {
-	const struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
+	const struct nft_ct_timeout_obj *priv = nft_obj_data(ref->obj);
 	struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
 	struct nf_conn_timeout *timeout;
 	const unsigned int *values;
@@ -1059,11 +1059,11 @@ static void nft_ct_helper_obj_destroy(const struct nft_ctx *ctx,
 	nf_ct_netns_put(ctx->net, ctx->family);
 }
 
-static void nft_ct_helper_obj_eval(struct nft_object *obj,
+static void nft_ct_helper_obj_eval(struct nft_object_ref *ref,
 				   struct nft_regs *regs,
 				   const struct nft_pktinfo *pkt)
 {
-	const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
+	const struct nft_ct_helper_obj *priv = nft_obj_data(ref->obj);
 	struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
 	struct nf_conntrack_helper *to_assign = NULL;
 	struct nf_conn_help *help;
@@ -1207,11 +1207,11 @@ static int nft_ct_expect_obj_dump(struct sk_buff *skb,
 	return 0;
 }
 
-static void nft_ct_expect_obj_eval(struct nft_object *obj,
+static void nft_ct_expect_obj_eval(struct nft_object_ref *ref,
 				   struct nft_regs *regs,
 				   const struct nft_pktinfo *pkt)
 {
-	const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
+	const struct nft_ct_expect_obj *priv = nft_obj_data(ref->obj);
 	struct nf_conntrack_expect *exp;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn_help *help;
diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c
index 35b67d7e3694..6f5ffecb83fd 100644
--- a/net/netfilter/nft_limit.c
+++ b/net/netfilter/nft_limit.c
@@ -236,11 +236,11 @@ static struct nft_expr_type nft_limit_type __read_mostly = {
 	.owner		= THIS_MODULE,
 };
 
-static void nft_limit_obj_pkts_eval(struct nft_object *obj,
+static void nft_limit_obj_pkts_eval(struct nft_object_ref *ref,
 				    struct nft_regs *regs,
 				    const struct nft_pktinfo *pkt)
 {
-	struct nft_limit_pkts *priv = nft_obj_data(obj);
+	struct nft_limit_pkts *priv = nft_obj_data(ref->obj);
 
 	if (nft_limit_eval(&priv->limit, priv->cost))
 		regs->verdict.code = NFT_BREAK;
@@ -279,11 +279,11 @@ static const struct nft_object_ops nft_limit_obj_pkts_ops = {
 	.dump		= nft_limit_obj_pkts_dump,
 };
 
-static void nft_limit_obj_bytes_eval(struct nft_object *obj,
+static void nft_limit_obj_bytes_eval(struct nft_object_ref *ref,
 				     struct nft_regs *regs,
 				     const struct nft_pktinfo *pkt)
 {
-	struct nft_limit *priv = nft_obj_data(obj);
+	struct nft_limit *priv = nft_obj_data(ref->obj);
 	u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
 
 	if (nft_limit_eval(priv, cost))
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 8fbea031bd4a..419fb1e42885 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -639,10 +639,11 @@ static int nft_secmark_compute_secid(struct nft_secmark *priv)
 	return 0;
 }
 
-static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
+static void nft_secmark_obj_eval(struct nft_object_ref *ref,
+				 struct nft_regs *regs,
 				 const struct nft_pktinfo *pkt)
 {
-	const struct nft_secmark *priv = nft_obj_data(obj);
+	const struct nft_secmark *priv = nft_obj_data(ref->obj);
 	struct sk_buff *skb = pkt->skb;
 
 	skb->secmark = priv->secid;
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index c9d8543fc97c..21ef987d5ac4 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -17,7 +17,7 @@ static void nft_objref_eval(const struct nft_expr *expr,
 {
 	struct nft_object_ref *priv = nft_expr_priv(expr);
 
-	priv->obj->ops->eval(priv->obj, regs, pkt);
+	priv->obj->ops->eval(priv, regs, pkt);
 }
 
 static int nft_objref_init(const struct nft_ctx *ctx,
@@ -108,6 +108,7 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
 	struct nft_objref_map *priv = nft_expr_priv(expr);
 	const struct nft_set *set = priv->set;
 	const struct nft_set_ext *ext;
+	struct nft_object_ref ref;
 	struct nft_object *obj;
 	bool found;
 
@@ -118,7 +119,8 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
 		return;
 	}
 	obj = *nft_set_ext_obj(ext);
-	obj->ops->eval(obj, regs, pkt);
+	ref.obj = obj;
+	obj->ops->eval(&ref, regs, pkt);
 }
 
 static int nft_objref_map_init(const struct nft_ctx *ctx,
diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c
index 4413690591f2..17e6cab3dfad 100644
--- a/net/netfilter/nft_quota.c
+++ b/net/netfilter/nft_quota.c
@@ -46,10 +46,11 @@ static const struct nla_policy nft_quota_policy[NFTA_QUOTA_MAX + 1] = {
 
 #define NFT_QUOTA_DEPLETED_BIT	1	/* From NFT_QUOTA_F_DEPLETED. */
 
-static void nft_quota_obj_eval(struct nft_object *obj,
+static void nft_quota_obj_eval(struct nft_object_ref *ref,
 			       struct nft_regs *regs,
 			       const struct nft_pktinfo *pkt)
 {
+	struct nft_object *obj = ref->obj;
 	struct nft_quota *priv = nft_obj_data(obj);
 	bool overquota;
 
diff --git a/net/netfilter/nft_synproxy.c b/net/netfilter/nft_synproxy.c
index e2c1fc608841..2d43db7788ae 100644
--- a/net/netfilter/nft_synproxy.c
+++ b/net/netfilter/nft_synproxy.c
@@ -319,11 +319,11 @@ static int nft_synproxy_obj_dump(struct sk_buff *skb,
 	return nft_synproxy_do_dump(skb, priv);
 }
 
-static void nft_synproxy_obj_eval(struct nft_object *obj,
+static void nft_synproxy_obj_eval(struct nft_object_ref *ref,
 				  struct nft_regs *regs,
 				  const struct nft_pktinfo *pkt)
 {
-	const struct nft_synproxy *priv = nft_obj_data(obj);
+	const struct nft_synproxy *priv = nft_obj_data(ref->obj);
 
 	nft_synproxy_do_eval(priv, regs, pkt);
 }
diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
index 3d4c2ae605a8..5fee55aa981e 100644
--- a/net/netfilter/nft_tunnel.c
+++ b/net/netfilter/nft_tunnel.c
@@ -421,11 +421,11 @@ static int nft_tunnel_obj_init(const struct nft_ctx *ctx,
 	return 0;
 }
 
-static inline void nft_tunnel_obj_eval(struct nft_object *obj,
+static inline void nft_tunnel_obj_eval(struct nft_object_ref *ref,
 				       struct nft_regs *regs,
 				       const struct nft_pktinfo *pkt)
 {
-	struct nft_tunnel_obj *priv = nft_obj_data(obj);
+	struct nft_tunnel_obj *priv = nft_obj_data(ref->obj);
 	struct sk_buff *skb = pkt->skb;
 
 	skb_dst_drop(skb);
-- 
2.11.0


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

* [PATCH nf-next 5/7] netfilter: nft_objref: add support for operation on objects
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2019-11-20 13:18 ` [PATCH nf-next 4/7] netfilter: nf_tables: pass nft_object_ref to object evaluation function Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 6/7] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 7/7] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

This patch allows you to specify what kind of operation you want to
perform on an object. Operations are object type specific. All objects
are assumed to have defined at least one operation (type 0).

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h        |  4 ++++
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            |  3 ++-
 net/netfilter/nft_objref.c               | 27 ++++++++++++++++++++++++---
 4 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 413eb650bafd..7a3f408d4328 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1100,6 +1100,8 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
 		    struct nft_object *obj, u32 portid, u32 seq,
 		    int event, int family, int report, gfp_t gfp);
 
+const struct nft_object_type *__nft_obj_type_get(u32 objtype);
+
 /**
  *	struct nft_object_type - stateful object type
  *
@@ -1118,12 +1120,14 @@ struct nft_object_type {
 	struct list_head		list;
 	u32				type;
 	unsigned int                    maxattr;
+	u32				maxops;
 	struct module			*owner;
 	const struct nla_policy		*policy;
 };
 
 struct nft_object_ref {
 	struct nft_object		*obj;
+	u8				op;
 };
 
 /**
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 100261902b1b..93326a544184 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1390,6 +1390,7 @@ enum nft_objref_attributes {
 	NFTA_OBJREF_SET_SREG,
 	NFTA_OBJREF_SET_NAME,
 	NFTA_OBJREF_SET_ID,
+	NFTA_OBJREF_OP,
 	__NFTA_OBJREF_MAX
 };
 #define NFTA_OBJREF_MAX	(__NFTA_OBJREF_MAX - 1)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index ff04cdc87f76..b5051f4dbb26 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5370,7 +5370,7 @@ static int nft_object_dump(struct sk_buff *skb, unsigned int attr,
 	return -1;
 }
 
-static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
+const struct nft_object_type *__nft_obj_type_get(u32 objtype)
 {
 	const struct nft_object_type *type;
 
@@ -5380,6 +5380,7 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
 	}
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(__nft_obj_type_get);
 
 static const struct nft_object_type *
 nft_obj_type_get(struct net *net, u32 objtype)
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index 21ef987d5ac4..f3b99af031e2 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -40,6 +40,12 @@ static int nft_objref_init(const struct nft_ctx *ctx,
 	if (IS_ERR(obj))
 		return -ENOENT;
 
+	if (tb[NFTA_OBJREF_OP]) {
+		priv->op = ntohl(nla_get_be32(tb[NFTA_OBJREF_OP]));
+		if (priv->op > obj->ops->type->maxops)
+			return -EOPNOTSUPP;
+	}
+
 	obj->use++;
 	priv->obj = obj;
 
@@ -52,8 +58,8 @@ static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	const struct nft_object *obj = priv->obj;
 
 	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
-	    nla_put_be32(skb, NFTA_OBJREF_TYPE,
-			 htonl(obj->ops->type->type)))
+	    nla_put_be32(skb, NFTA_OBJREF_TYPE, htonl(obj->ops->type->type)) ||
+	    nla_put_be32(skb, NFTA_OBJREF_OP, htonl(priv->op)))
 		goto nla_put_failure;
 
 	return 0;
@@ -98,6 +104,7 @@ static const struct nft_expr_ops nft_objref_ops = {
 struct nft_objref_map {
 	struct nft_set		*set;
 	enum nft_registers	sreg:8;
+	u8			op;
 	struct nft_set_binding	binding;
 };
 
@@ -120,6 +127,7 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
 	}
 	obj = *nft_set_ext_obj(ext);
 	ref.obj = obj;
+	ref.op 	= priv->op;
 	obj->ops->eval(&ref, regs, pkt);
 }
 
@@ -160,6 +168,18 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,
 	    set->objtype != objtype)
 		return -EOPNOTSUPP;
 
+	if (tb[NFTA_OBJREF_OP]) {
+		const struct nft_object_type *type;
+
+		if (objtype == NFT_OBJECT_UNSPEC)
+			return -EOPNOTSUPP;
+
+		priv->op = ntohl(nla_get_be32(tb[NFTA_OBJREF_OP]));
+		type = __nft_obj_type_get(objtype);
+		if (!type || priv->op > type->maxops)
+			return -EOPNOTSUPP;
+	}
+
 	priv->set = set;
 	return 0;
 }
@@ -169,7 +189,8 @@ static int nft_objref_map_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	const struct nft_objref_map *priv = nft_expr_priv(expr);
 
 	if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
-	    nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
+	    nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name) ||
+	    nla_put_be32(skb, NFTA_OBJREF_OP, htonl(priv->op)))
 		goto nla_put_failure;
 
 	return 0;
-- 
2.11.0


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

* [PATCH nf-next 6/7] netfilter: nf_tables: add decapsulation support
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
                   ` (4 preceding siblings ...)
  2019-11-20 13:18 ` [PATCH nf-next 5/7] netfilter: nft_objref: add support for operation on objects Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  2019-11-20 13:18 ` [PATCH nf-next 7/7] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

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 93326a544184..07aa6bba1548 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1629,6 +1629,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 5e9b2eb24349..66befd2ac11d 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 7/7] netfilter: nf_tables: add encapsulation support
  2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
                   ` (5 preceding siblings ...)
  2019-11-20 13:18 ` [PATCH nf-next 6/7] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
@ 2019-11-20 13:18 ` Pablo Neira Ayuso
  6 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-20 13:18 UTC (permalink / raw)
  To: netfilter-devel

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 |  42 +++++-
 net/netfilter/nft_encap.c                | 216 ++++++++++++++++++++++++++++++-
 2 files changed, 256 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 07aa6bba1548..bb0ae2daad59 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1486,7 +1486,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)
 
 /**
@@ -1633,6 +1634,45 @@ enum nft_encap_type {
 	NFT_ENCAP_VLAN	= 0,
 };
 
+enum nft_encap_op {
+	NFT_ENCAP_ADD	= 0,
+	NFT_ENCAP_UPDATE,
+	__NFT_ENCAP_MAX
+};
+#define NFT_ENCAP_MAX	(__NFT_ENCAP_MAX - 1)
+
+/**
+ * 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..1294b25f28ef 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,227 @@ static struct nft_expr_type nft_decap_type __read_mostly = {
 	.owner		= THIS_MODULE,
 };
 
+struct nft_encap {
+	enum nft_encap_type	type;
+
+	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, u8 op,
+			       struct nft_regs *regs,
+			       const struct nft_pktinfo *pkt)
+{
+	struct sk_buff *skb = pkt->skb;
+	int err;
+	u16 tci;
+
+	switch (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_ref *ref,
+			       struct nft_regs *regs,
+			       const struct nft_pktinfo *pkt)
+{
+	struct nft_encap *priv = nft_obj_data(ref->obj);
+	int err;
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		err = nft_encap_vlan_eval(priv, ref->op, 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])
+		return -EINVAL;
+
+	priv->type = ntohl(nla_get_be32(tb[NFTA_ENCAP_TYPE]));
+
+	switch (priv->type) {
+	case NFT_ENCAP_VLAN:
+		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)) ||
+	    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_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,
+	.maxops		= NFT_ENCAP_MAX,
+	.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

end of thread, other threads:[~2019-11-20 13:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-20 13:18 [PATCH nf-next 0/7] nf_tables encapsulation/decapsulation support Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 1/7] netfilter: nft_objref: rename NFTA_OBJREF_IMM_TYPE to NFTA_OBJREF_TYPE Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 2/7] netfilter: nft_objref: validate map object type Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 3/7] netfilter: nft_objref: add nft_obj_ref structure and use it Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 4/7] netfilter: nf_tables: pass nft_object_ref to object evaluation function Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 5/7] netfilter: nft_objref: add support for operation on objects Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 6/7] netfilter: nf_tables: add decapsulation support Pablo Neira Ayuso
2019-11-20 13:18 ` [PATCH nf-next 7/7] netfilter: nf_tables: add encapsulation support Pablo Neira Ayuso

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.