[PATCH libnftnl 1/2] obj: add tunnel support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 include/libnftnl/object.h           |  19 ++
 include/linux/netfilter/nf_tables.h |  69 ++++-
 include/obj.h                       |  29 ++
 src/Makefile.am                     |   1 +
 src/obj/tunnel.c                    | 581 ++++++++++++++++++++++++++++++++++++
 src/object.c                        |   1 +
 6 files changed, 699 insertions(+), 1 deletion(-)
 create mode 100644 src/obj/tunnel.c

diff --git a/include/libnftnl/object.h b/include/libnftnl/object.h
index 93a40d0f15ee..6f9edfd14aa6 100644
--- a/include/libnftnl/object.h
+++ b/include/libnftnl/object.h
@@ -49,6 +49,25 @@ enum {
 	NFTNL_OBJ_LIMIT_FLAGS,
 };
 
+enum {
+	NFTNL_OBJ_TUNNEL_ID	= NFTNL_OBJ_BASE,
+	NFTNL_OBJ_TUNNEL_IPV4_SRC,
+	NFTNL_OBJ_TUNNEL_IPV4_DST,
+	NFTNL_OBJ_TUNNEL_IPV6_SRC,
+	NFTNL_OBJ_TUNNEL_IPV6_DST,
+	NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL,
+	NFTNL_OBJ_TUNNEL_SPORT,
+	NFTNL_OBJ_TUNNEL_DPORT,
+	NFTNL_OBJ_TUNNEL_FLAGS,
+	NFTNL_OBJ_TUNNEL_TOS,
+	NFTNL_OBJ_TUNNEL_TTL,
+	NFTNL_OBJ_TUNNEL_VXLAN_GBP,
+	NFTNL_OBJ_TUNNEL_ERSPAN_VERSION,
+	NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX,
+	NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID,
+	NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR,
+};
+
 struct nftnl_obj;
 
 struct nftnl_obj *nftnl_obj_alloc(void);
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index cc21ef082cd2..0450fc0731b5 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1401,7 +1401,8 @@ enum nft_ct_helper_attributes {
 #define NFT_OBJECT_CT_HELPER	3
 #define NFT_OBJECT_LIMIT	4
 #define NFT_OBJECT_CONNLIMIT	5
-#define __NFT_OBJECT_MAX	6
+#define NFT_OBJECT_TUNNEL	6
+#define __NFT_OBJECT_MAX	7
 #define NFT_OBJECT_MAX		(__NFT_OBJECT_MAX - 1)
 
 /**
@@ -1562,4 +1563,70 @@ enum nft_ng_types {
 };
 #define NFT_NG_MAX	(__NFT_NG_MAX - 1)
 
+enum nft_tunnel_key_ip_attributes {
+	NFTA_TUNNEL_KEY_IP_UNSPEC,
+	NFTA_TUNNEL_KEY_IP_SRC,
+	NFTA_TUNNEL_KEY_IP_DST,
+	__NFTA_TUNNEL_KEY_IP_MAX
+};
+#define NFTA_TUNNEL_KEY_IP_MAX	(__NFTA_TUNNEL_KEY_IP_MAX - 1)
+
+enum nft_tunnel_ip6_attributes {
+	NFTA_TUNNEL_KEY_IP6_UNSPEC,
+	NFTA_TUNNEL_KEY_IP6_SRC,
+	NFTA_TUNNEL_KEY_IP6_DST,
+	NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
+	__NFTA_TUNNEL_KEY_IP6_MAX
+};
+#define NFTA_TUNNEL_KEY_IP6_MAX	(__NFTA_TUNNEL_KEY_IP6_MAX - 1)
+
+enum nft_tunnel_opts_attributes {
+	NFTA_TUNNEL_KEY_OPTS_UNSPEC,
+	NFTA_TUNNEL_KEY_OPTS_VXLAN,
+	NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+	__NFTA_TUNNEL_KEY_OPTS_MAX
+};
+#define NFTA_TUNNEL_KEY_OPTS_MAX	(__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
+
+enum nft_tunnel_opts_vxlan_attributes {
+	NFTA_TUNNEL_KEY_VXLAN_UNSPEC,
+	NFTA_TUNNEL_KEY_VXLAN_GBP,
+	__NFTA_TUNNEL_KEY_VXLAN_MAX
+};
+#define NFTA_TUNNEL_KEY_VXLAN_MAX	(__NFTA_TUNNEL_KEY_VXLAN_MAX - 1)
+
+enum nft_tunnel_opts_erspan_attributes {
+	NFTA_TUNNEL_KEY_ERSPAN_UNSPEC,
+	NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+	NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+	NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+	NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+	__NFTA_TUNNEL_KEY_ERSPAN_MAX
+};
+#define NFTA_TUNNEL_KEY_ERSPAN_MAX	(__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+
+enum nft_tunnel_flags {
+	NFT_TUNNEL_F_ZERO_CSUM_TX	= (1 << 0),
+	NFT_TUNNEL_F_DONT_FRAGMENT	= (1 << 1),
+	NFT_TUNNEL_F_SEQ_NUMBER		= (1 << 2),
+};
+#define NFT_TUNNEL_F_MASK	(NFT_TUNNEL_F_ZERO_CSUM_TX | \
+				 NFT_TUNNEL_F_DONT_FRAGMENT | \
+				 NFT_TUNNEL_F_SEQ_NUMBER)
+
+enum nft_tunnel_key_attributes {
+	NFTA_TUNNEL_KEY_UNSPEC,
+	NFTA_TUNNEL_KEY_ID,
+	NFTA_TUNNEL_KEY_IP,
+	NFTA_TUNNEL_KEY_IP6,
+	NFTA_TUNNEL_KEY_FLAGS,
+	NFTA_TUNNEL_KEY_TOS,
+	NFTA_TUNNEL_KEY_TTL,
+	NFTA_TUNNEL_KEY_SPORT,
+	NFTA_TUNNEL_KEY_DPORT,
+	NFTA_TUNNEL_KEY_OPTS,
+	__NFTA_TUNNEL_KEY_MAX
+};
+#define NFTA_TUNNEL_KEY_MAX	(__NFTA_TUNNEL_KEY_MAX - 1)
+
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/include/obj.h b/include/obj.h
index 4a728c8b765b..9363a69fa744 100644
--- a/include/obj.h
+++ b/include/obj.h
@@ -43,6 +43,34 @@ struct nftnl_obj {
 			uint32_t	type;
 			uint32_t	flags;
 		} limit;
+		struct nftnl_obj_tunnel {
+			uint32_t	id;
+			uint32_t	src_v4;
+			uint32_t	dst_v4;
+			struct in6_addr src_v6;
+			struct in6_addr dst_v6;
+			uint16_t	sport;
+			uint16_t	dport;
+			uint32_t	flowlabel;
+			uint32_t	tun_flags;
+			uint8_t		tun_tos;
+			uint8_t		tun_ttl;
+			union {
+				struct {
+					uint32_t	gbp;
+				} tun_vxlan;
+				struct {
+					uint32_t	version;
+					union {
+						uint32_t	v1_index;
+						struct {
+							uint8_t	hwid;
+							uint8_t	dir;
+						} v2;
+					} u;
+				} tun_erspan;
+			} u;
+		} tunnel;
 	} data;
 };
 
@@ -64,6 +92,7 @@ extern struct obj_ops obj_ops_counter;
 extern struct obj_ops obj_ops_quota;
 extern struct obj_ops obj_ops_ct_helper;
 extern struct obj_ops obj_ops_limit;
+extern struct obj_ops obj_ops_tunnel;
 
 #define nftnl_obj_data(obj) (void *)&obj->data
 
diff --git a/src/Makefile.am b/src/Makefile.am
index f92b4d2d214d..30511066cffe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,5 +61,6 @@ libnftnl_la_SOURCES = utils.c		\
 		      obj/counter.c	\
 		      obj/ct_helper.c	\
 		      obj/quota.c	\
+		      obj/tunnel.c	\
 		      obj/limit.c	\
 		      libnftnl.map
diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c
new file mode 100644
index 000000000000..32ca0fd59717
--- /dev/null
+++ b/src/obj/tunnel.c
@@ -0,0 +1,581 @@
+/*
+ * (C) 2018 by Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftnl/object.h>
+
+#include "internal.h"
+#include "obj.h"
+
+static int
+nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type,
+		     const void *data, uint32_t data_len)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+
+	switch (type) {
+	case NFTNL_OBJ_TUNNEL_ID:
+		tun->id = *((uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV4_SRC:
+		tun->src_v4 = *((uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV4_DST:
+		tun->dst_v4 = *((uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV6_SRC:
+		memcpy(&tun->src_v6, data, sizeof(struct in6_addr));
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV6_DST:
+		memcpy(&tun->dst_v6, data, sizeof(struct in6_addr));
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
+		tun->flowlabel = (*(uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_SPORT:
+		tun->sport = (*(uint16_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_DPORT:
+		tun->dport = (*(uint16_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_FLAGS:
+		tun->tun_flags = (*(uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_TOS:
+		tun->tun_tos = (*(uint8_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_TTL:
+		tun->tun_ttl = (*(uint8_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_VXLAN_GBP:
+		tun->u.tun_vxlan.gbp = (*(uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION:
+		tun->u.tun_erspan.version = (*(uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX:
+		tun->u.tun_erspan.u.v1_index = (*(uint32_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID:
+		tun->u.tun_erspan.u.v2.hwid = (*(uint8_t *)data);
+		break;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
+		tun->u.tun_erspan.u.v2.dir = (*(uint8_t *)data);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+static const void *
+nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
+		     uint32_t *data_len)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+
+	switch (type) {
+	case NFTNL_OBJ_TUNNEL_ID:
+		*data_len = sizeof(tun->id);
+		return &tun->id;
+	case NFTNL_OBJ_TUNNEL_IPV4_SRC:
+		*data_len = sizeof(tun->src_v4);
+		return &tun->src_v4;
+	case NFTNL_OBJ_TUNNEL_IPV4_DST:
+		*data_len = sizeof(tun->dst_v4);
+		return &tun->dst_v4;
+	case NFTNL_OBJ_TUNNEL_IPV6_SRC:
+		*data_len = sizeof(tun->src_v6);
+		return &tun->src_v6;
+	case NFTNL_OBJ_TUNNEL_IPV6_DST:
+		*data_len = sizeof(tun->dst_v6);
+		return &tun->dst_v6;
+	case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
+		*data_len = sizeof(tun->flowlabel);
+		return &tun->flowlabel;
+	case NFTNL_OBJ_TUNNEL_SPORT:
+		*data_len = sizeof(tun->sport);
+		return &tun->sport;
+	case NFTNL_OBJ_TUNNEL_DPORT:
+		*data_len = sizeof(tun->dport);
+		return &tun->dport;
+	case NFTNL_OBJ_TUNNEL_FLAGS:
+		*data_len = sizeof(tun->tun_flags);
+		return &tun->tun_flags;
+	case NFTNL_OBJ_TUNNEL_TOS:
+		*data_len = sizeof(tun->tun_tos);
+		return &tun->tun_tos;
+	case NFTNL_OBJ_TUNNEL_TTL:
+		*data_len = sizeof(tun->tun_ttl);
+		return &tun->tun_ttl;
+	case NFTNL_OBJ_TUNNEL_VXLAN_GBP:
+		*data_len = sizeof(tun->u.tun_vxlan.gbp);
+		return &tun->u.tun_vxlan.gbp;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION:
+		*data_len = sizeof(tun->u.tun_erspan.version);
+		return &tun->u.tun_erspan.version;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX:
+		*data_len = sizeof(tun->u.tun_erspan.u.v1_index);
+		return &tun->u.tun_erspan.u.v1_index;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID:
+		*data_len = sizeof(tun->u.tun_erspan.u.v2.hwid);
+		return &tun->u.tun_erspan.u.v2.hwid;
+	case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
+		*data_len = sizeof(tun->u.tun_erspan.u.v2.dir);
+		return &tun->u.tun_erspan.u.v2.dir;
+	}
+	return NULL;
+}
+
+static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFTA_TUNNEL_KEY_ID:
+	case NFTA_TUNNEL_KEY_FLAGS:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_IP:
+	case NFTA_TUNNEL_KEY_IP6:
+	case NFTA_TUNNEL_KEY_OPTS:
+		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_SPORT:
+	case NFTA_TUNNEL_KEY_DPORT:
+		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_TOS:
+	case NFTA_TUNNEL_KEY_TTL:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static void
+nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+	struct nlattr *nest;
+
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
+		mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ID, htonl(tun->id));
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC) ||
+	    e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST)) {
+		nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC))
+			mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_SRC, tun->src_v4);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST))
+			mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_DST, tun->dst_v4);
+		mnl_attr_nest_end(nlh, nest);
+	}
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC) ||
+	    e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST)) {
+		nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP6);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC))
+			mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_SRC,
+				     sizeof(tun->src_v6), &tun->src_v6);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST))
+			mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_DST,
+				     sizeof(tun->dst_v6), &tun->dst_v6);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL))
+			mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
+					 htonl(tun->flowlabel));
+		mnl_attr_nest_end(nlh, nest);
+	}
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_SPORT))
+		mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_SPORT, htons(tun->sport));
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_DPORT))
+		mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_DPORT, htons(tun->dport));
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TOS))
+		mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TOS, tun->tun_tos);
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TTL))
+		mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TTL, tun->tun_ttl);
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_FLAGS))
+		mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_FLAGS, htonl(tun->tun_flags));
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP)) {
+		nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
+		mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
+				 htonl(tun->u.tun_vxlan.gbp));
+		mnl_attr_nest_end(nlh, nest);
+	}
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION) &&
+	    (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX) ||
+	     (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID) &&
+	      e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR)))) {
+		struct nlattr *nest_inner;
+
+		nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
+		nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
+		mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+				 htonl(tun->u.tun_erspan.version));
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX))
+			mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+					 htonl(tun->u.tun_erspan.u.v1_index));
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID))
+			mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+					tun->u.tun_erspan.u.v2.hwid);
+		if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR))
+			mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+					tun->u.tun_erspan.u.v2.dir);
+		mnl_attr_nest_end(nlh, nest_inner);
+		mnl_attr_nest_end(nlh, nest);
+	}
+}
+
+static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case NFTA_TUNNEL_KEY_IP_SRC:
+	case NFTA_TUNNEL_KEY_IP_DST:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int nftnl_obj_tunnel_parse_ip(struct nftnl_obj *e, struct nlattr *attr,
+				     struct nftnl_obj_tunnel *tun)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_IP_SRC]) {
+		tun->src_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_SRC]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC);
+	}
+	if (tb[NFTA_TUNNEL_KEY_IP_DST]) {
+		tun->dst_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_DST]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_DST);
+	}
+
+	return 0;
+}
+
+static int nftnl_obj_tunnel_ip6_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFTA_TUNNEL_KEY_IP6_SRC:
+	case NFTA_TUNNEL_KEY_IP6_DST:
+		if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_IP6_FLOWLABEL:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
+				      struct nftnl_obj_tunnel *tun)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip6_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) {
+		memcpy(&tun->src_v6,
+		       mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_SRC]),
+		       sizeof(struct in6_addr));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC);
+	}
+	if (tb[NFTA_TUNNEL_KEY_IP6_DST]) {
+		memcpy(&tun->dst_v6,
+		       mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_DST]),
+		       sizeof(struct in6_addr));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_DST);
+	}
+	if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) {
+		tun->flowlabel =
+			ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL);
+	}
+
+	return 0;
+}
+
+static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_VXLAN_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case NFTA_TUNNEL_KEY_VXLAN_GBP:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int
+nftnl_obj_tunnel_parse_vxlan(struct nftnl_obj *e, struct nlattr *attr,
+			     struct nftnl_obj_tunnel *tun)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) {
+		tun->u.tun_vxlan.gbp =
+			ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP);
+	}
+
+	return 0;
+}
+
+static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_ERSPAN_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case NFTA_TUNNEL_KEY_ERSPAN_VERSION:
+	case NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_ERSPAN_V2_HWID:
+	case NFTA_TUNNEL_KEY_ERSPAN_V2_DIR:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int
+nftnl_obj_tunnel_parse_erspan(struct nftnl_obj *e, struct nlattr *attr,
+			      struct nftnl_obj_tunnel *tun)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) {
+		tun->u.tun_erspan.version =
+			ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION);
+	}
+	if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) {
+		tun->u.tun_erspan.u.v1_index =
+			ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX);
+	}
+	if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) {
+		tun->u.tun_erspan.u.v2.hwid =
+			mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID);
+	}
+	if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) {
+		tun->u.tun_erspan.u.v2.dir =
+			mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR);
+	}
+
+	return 0;
+}
+
+static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_OPTS_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case NFTA_TUNNEL_KEY_OPTS_VXLAN:
+	case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
+		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int
+nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *attr,
+			    struct nftnl_obj_tunnel *tun)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {};
+	int err = 0;
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_opts_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) {
+		err = nftnl_obj_tunnel_parse_vxlan(e, tb[NFTA_TUNNEL_KEY_OPTS_VXLAN],
+						   tun);
+	} else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
+		err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
+						    tun);
+	}
+
+	return err;
+}
+
+static int
+nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+	struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
+	int err;
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_ID]) {
+		tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
+	}
+	if (tb[NFTA_TUNNEL_KEY_IP]) {
+		err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
+		if (err < 0)
+			return err;
+	} else if (tb[NFTA_TUNNEL_KEY_IP6]) {
+		err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
+		if (err < 0)
+			return err;
+	}
+
+	if (tb[NFTA_TUNNEL_KEY_SPORT]) {
+		tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
+	}
+	if (tb[NFTA_TUNNEL_KEY_DPORT]) {
+		tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
+	}
+	if (tb[NFTA_TUNNEL_KEY_TOS]) {
+		tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
+	}
+	if (tb[NFTA_TUNNEL_KEY_TTL]) {
+		tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
+	}
+	if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
+		tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
+		e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
+	}
+	if (tb[NFTA_TUNNEL_KEY_OPTS]) {
+		err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int nftnl_obj_tunnel_export(char *buf, size_t size,
+				   const struct nftnl_obj *e, int type)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+	NFTNL_BUF_INIT(b, buf, size);
+
+	if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
+		nftnl_buf_u64(&b, type, tun->id, ID);
+
+	return nftnl_buf_done(&b);
+}
+
+static int nftnl_obj_tunnel_snprintf_default(char *buf, size_t len,
+					     const struct nftnl_obj *e)
+{
+	struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
+
+	return snprintf(buf, len, "id %u ", tun->id);
+}
+
+static int nftnl_obj_tunnel_snprintf(char *buf, size_t len, uint32_t type,
+				     uint32_t flags, const struct nftnl_obj *e)
+{
+	if (len)
+		buf[0] = '\0';
+
+	switch (type) {
+	case NFTNL_OUTPUT_DEFAULT:
+		return nftnl_obj_tunnel_snprintf_default(buf, len, e);
+	case NFTNL_OUTPUT_XML:
+	case NFTNL_OUTPUT_JSON:
+		return nftnl_obj_tunnel_export(buf, len, e, type);
+	default:
+		break;
+	}
+	return -1;
+}
+
+struct obj_ops obj_ops_tunnel = {
+	.name		= "tunnel",
+	.type		= NFT_OBJECT_TUNNEL,
+	.alloc_len	= sizeof(struct nftnl_obj_tunnel),
+	.max_attr	= NFTA_TUNNEL_KEY_MAX,
+	.set		= nftnl_obj_tunnel_set,
+	.get		= nftnl_obj_tunnel_get,
+	.parse		= nftnl_obj_tunnel_parse,
+	.build		= nftnl_obj_tunnel_build,
+	.snprintf	= nftnl_obj_tunnel_snprintf,
+};
diff --git a/src/object.c b/src/object.c
index d8278f3fdf39..803b056904a4 100644
--- a/src/object.c
+++ b/src/object.c
@@ -30,6 +30,7 @@ static struct obj_ops *obj_ops[] = {
 	[NFT_OBJECT_QUOTA]	= &obj_ops_quota,
 	[NFT_OBJECT_CT_HELPER]	= &obj_ops_ct_helper,
 	[NFT_OBJECT_LIMIT]	= &obj_ops_limit,
+	[NFT_OBJECT_TUNNEL]	= &obj_ops_tunnel,
 };
 
 static struct obj_ops *nftnl_obj_ops_lookup(uint32_t type)
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux