[PATCH 2/2 libnftnl v3] tunnel: add support to geneve options

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

 



In addition, modifies the netlink parsing to loop through the nested
array of NFTA_TUNNEL_KEY_OPTS.

Signed-off-by: Fernando Fernandez Mancera <fmancera@xxxxxxx>
---
 include/libnftnl/object.h |   9 +++
 src/obj/tunnel.c          | 166 +++++++++++++++++++++++++++++++++-----
 2 files changed, 156 insertions(+), 19 deletions(-)

diff --git a/include/libnftnl/object.h b/include/libnftnl/object.h
index 6d0aab0..490e8b4 100644
--- a/include/libnftnl/object.h
+++ b/include/libnftnl/object.h
@@ -119,9 +119,12 @@ enum {
 #define NFTNL_TUNNEL_TYPE	0
 #define NFTNL_TUNNEL_BASE	4
 
+#define NFTNL_TUNNEL_GENEVE_DATA_MAXLEN		127
+
 enum nftnl_tunnel_type {
 	NFTNL_TUNNEL_TYPE_VXLAN,
 	NFTNL_TUNNEL_TYPE_ERSPAN,
+	NFTNL_TUNNEL_TYPE_GENEVE,
 };
 
 enum {
@@ -137,6 +140,12 @@ enum {
 	__NFTNL_TUNNEL_ERSPAN_MAX,
 };
 
+enum {
+	NFTNL_TUNNEL_GENEVE_CLASS	= NFTNL_TUNNEL_BASE,
+	NFTNL_TUNNEL_GENEVE_TYPE,
+	NFTNL_TUNNEL_GENEVE_DATA,
+};
+
 struct nftnl_tunnel_opt;
 struct nftnl_tunnel_opts;
 
diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c
index 4e3c16b..c21599c 100644
--- a/src/obj/tunnel.c
+++ b/src/obj/tunnel.c
@@ -308,6 +308,12 @@ struct nftnl_tunnel_opt {
 				uint8_t		dir;
 			} v2;
 		} erspan;
+		struct {
+			uint16_t	geneve_class;
+			uint8_t		type;
+			uint8_t		data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN];
+			uint32_t	data_len;
+		} geneve;
 	};
 };
 
@@ -358,12 +364,15 @@ nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne,
 	case NFTNL_TUNNEL_TYPE_GENEVE:
 		switch (attr) {
 			case NFTNL_TUNNEL_GENEVE_CLASS:
+				*data_len = sizeof(uint16_t);
 				return &ne->geneve.geneve_class;
 			break;
 			case NFTNL_TUNNEL_GENEVE_TYPE:
+				*data_len = sizeof(uint8_t);
 				return &ne->geneve.type;
 			break;
 			case NFTNL_TUNNEL_GENEVE_DATA:
+				*data_len = ne->geneve.data_len;
 				return &ne->geneve.data;
 			break;
 		}
@@ -541,18 +550,25 @@ nftnl_obj_tunnel_parse_erspan(struct nftnl_tunnel_opts *opts, struct nlattr *att
 	return 0;
 }
 
-static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
+static int nftnl_obj_tunnel_geneve_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)
+	if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_GENEVE_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)
+	case NFTA_TUNNEL_KEY_GENEVE_CLASS:
+		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_GENEVE_TYPE:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TUNNEL_KEY_GENEVE_DATA:
+		if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
 			abi_breakage();
 		break;
 	}
@@ -561,31 +577,85 @@ static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
 	return MNL_CB_OK;
 }
 
+static int
+nftnl_obj_tunnel_parse_geneve(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
+{
+	struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {};
+	struct nftnl_tunnel_opt *opt;
+
+	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0)
+		return -1;
+
+	opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
+	if (!opt)
+		return -1;
+
+	if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) {
+		opt->geneve.geneve_class =
+			ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]));
+		opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_CLASS);
+	}
+
+	if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) {
+		opt->geneve.type =
+			mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]);
+		opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_TYPE);
+	}
+
+	if (tb[NFTA_TUNNEL_KEY_GENEVE_DATA]) {
+		uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]);
+
+		memcpy(opt->geneve.data,
+		       mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
+		       len);
+		opt->geneve.data_len = len;
+		opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA);
+	}
+
+	list_add_tail(&opt->list, &opts->opts_list);
+
+	return 0;
+}
+
 struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type);
 
 static int
-nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *attr,
+nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest,
 			    struct nftnl_obj_tunnel *tun)
 {
-	struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {};
+	struct nlattr *attr;
 	struct nftnl_tunnel_opts *opts = NULL;
 	int err = 0;
 
-	if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_opts_cb, tb) < 0)
-		return -1;
+	mnl_attr_for_each_nested(attr, nest) {
+		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+			abi_breakage();
 
-	if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) {
-		opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
-		if (!opts)
-			return -1;
+		switch(mnl_attr_get_type(attr)) {
+			case NFTA_TUNNEL_KEY_OPTS_VXLAN:
+				opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
+				if (!opts)
+					return -1;
 
-		err = nftnl_obj_tunnel_parse_vxlan(opts, tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]);
-	} else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
-		opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
-		if (!opts)
-			return -1;
+				err = nftnl_obj_tunnel_parse_vxlan(opts, attr);
+			break;
+			case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
+				opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
+				if (!opts)
+					return -1;
 
-		err = nftnl_obj_tunnel_parse_erspan(opts, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]);
+				err = nftnl_obj_tunnel_parse_erspan(opts, attr);
+			break;
+			case NFTA_TUNNEL_KEY_OPTS_GENEVE:
+				if (!opts)
+					opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
+
+				if (!opts)
+					return -1;
+
+				err = nftnl_obj_tunnel_parse_geneve(opts, attr);
+			break;
+		}
 	}
 
 	if (opts) {
@@ -665,6 +735,7 @@ struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
 	switch (type) {
 	case NFTNL_TUNNEL_TYPE_VXLAN:
 	case NFTNL_TUNNEL_TYPE_ERSPAN:
+	case NFTNL_TUNNEL_TYPE_GENEVE:
 		break;
 	default:
 		errno = EOPNOTSUPP;
@@ -698,6 +769,8 @@ int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
 			return -1;
 		}
 		break;
+	case NFTNL_TUNNEL_TYPE_GENEVE:
+		break;
 	default:
 		errno = EOPNOTSUPP;
 		return -1;
@@ -717,6 +790,7 @@ void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
 		switch(opts->type) {
 		case NFTNL_TUNNEL_TYPE_VXLAN:
 		case NFTNL_TUNNEL_TYPE_ERSPAN:
+		case NFTNL_TUNNEL_TYPE_GENEVE:
 			list_del(&opt->list);
 			xfree(opt);
 			break;
@@ -732,6 +806,7 @@ struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
 	switch (type) {
 	case NFTNL_TUNNEL_TYPE_VXLAN:
 	case NFTNL_TUNNEL_TYPE_ERSPAN:
+	case NFTNL_TUNNEL_TYPE_GENEVE:
 		break;
 	default:
 		errno = EOPNOTSUPP;
@@ -790,6 +865,34 @@ static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t ty
 	return 0;
 }
 
+static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type,
+				       const void *data, uint32_t data_len)
+{
+	switch(type) {
+	case NFTNL_TUNNEL_GENEVE_CLASS:
+		memcpy(&opt->geneve.geneve_class, data, data_len);
+		break;
+	case NFTNL_TUNNEL_GENEVE_TYPE:
+		memcpy(&opt->geneve.type, data, data_len);
+		break;
+	case NFTNL_TUNNEL_GENEVE_DATA:
+		if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
+			errno = EINVAL;
+			return -1;
+		}
+		memcpy(&opt->geneve.data, data, data_len);
+		opt->geneve.data_len = data_len;
+		break;
+	default:
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	opt->flags |= (1 << type);
+
+	return 0;
+}
+
 EXPORT_SYMBOL(nftnl_tunnel_opt_set);
 int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
 			 const void *data, uint32_t data_len)
@@ -799,6 +902,8 @@ int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
 		return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len);
 	case NFTNL_TUNNEL_TYPE_ERSPAN:
 		return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len);
+	case NFTNL_TUNNEL_TYPE_GENEVE:
+		return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len);
 	default:
 		errno = EOPNOTSUPP;
 		return -1;
@@ -845,6 +950,26 @@ static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
 	}
 }
 
+static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh,
+					  const struct nftnl_tunnel_opt *opt)
+{
+	struct nlattr *nest_inner;
+
+	if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) &&
+	    opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) &&
+	    opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
+		nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
+		mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
+				 htons(opt->geneve.geneve_class));
+		mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
+				opt->geneve.type);
+		mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
+			     opt->geneve.data_len,
+			     opt->geneve.data);
+		mnl_attr_nest_end(nlh, nest_inner);
+	}
+}
+
 void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
 			     struct nftnl_tunnel_opts *opts)
 {
@@ -861,6 +986,9 @@ void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
 		case NFTNL_TUNNEL_TYPE_ERSPAN:
 			nftnl_tunnel_opt_build_erspan(nlh, opt);
 			break;
+		case NFTNL_TUNNEL_TYPE_GENEVE:
+			nftnl_tunnel_opt_build_geneve(nlh, opt);
+			break;
 		}
 	}
 	mnl_attr_nest_end(nlh, nest);
-- 
2.50.1





[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux