summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libnftnl.map16
-rw-r--r--src/obj/tunnel.c473
-rw-r--r--src/object.c4
3 files changed, 412 insertions, 81 deletions
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 8fffff1..10c0e7f 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -383,3 +383,19 @@ LIBNFTNL_16 {
LIBNFTNL_17 {
nftnl_set_elem_nlmsg_build;
} LIBNFTNL_16;
+
+LIBNFTNL_18 {
+nftnl_tunnel_opt_get;
+nftnl_tunnel_opt_get_data;
+nftnl_tunnel_opt_get_u8;
+nftnl_tunnel_opt_get_u16;
+nftnl_tunnel_opt_get_u32;
+nftnl_tunnel_opt_set;
+nftnl_tunnel_opt_alloc;
+nftnl_tunnel_opt_get_type;
+nftnl_tunnel_opt_get_flags;
+nftnl_tunnel_opts_alloc;
+nftnl_obj_tunnel_opts_foreach;
+nftnl_tunnel_opts_add;
+nftnl_tunnel_opts_free;
+} LIBNFTNL_17;
diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c
index 8941e39..bed0342 100644
--- a/src/obj/tunnel.c
+++ b/src/obj/tunnel.c
@@ -57,20 +57,8 @@ nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type,
case NFTNL_OBJ_TUNNEL_TTL:
memcpy(&tun->tun_ttl, data, data_len);
break;
- case NFTNL_OBJ_TUNNEL_VXLAN_GBP:
- memcpy(&tun->u.tun_vxlan.gbp, data, data_len);
- break;
- case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION:
- memcpy(&tun->u.tun_erspan.version, data, data_len);
- break;
- case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX:
- memcpy(&tun->u.tun_erspan.u.v1_index, data, data_len);
- break;
- case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID:
- memcpy(&tun->u.tun_erspan.u.v2.hwid, data, data_len);
- break;
- case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
- memcpy(&tun->u.tun_erspan.u.v2.dir, data, data_len);
+ case NFTNL_OBJ_TUNNEL_OPTS:
+ memcpy(&tun->tun_opts, data, data_len);
break;
}
return 0;
@@ -116,21 +104,9 @@ nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
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;
+ case NFTNL_OBJ_TUNNEL_OPTS:
+ *data_len = sizeof(tun->tun_opts);
+ return &tun->tun_opts;
}
return NULL;
}
@@ -171,11 +147,14 @@ static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
+static void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
+ struct nftnl_tunnel_opts *opts);
+
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, *nest_inner;
+ struct nlattr *nest;
if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ID, htonl(tun->id));
@@ -212,34 +191,8 @@ nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
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);
- nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
- mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
- htonl(tun->u.tun_vxlan.gbp));
- mnl_attr_nest_end(nlh, nest_inner);
- 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 & (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR)))) {
- 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 & (1u << 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);
- }
+ if (e->flags & (1 << NFTNL_OBJ_TUNNEL_OPTS))
+ nftnl_tunnel_opts_build(nlh, tun->tun_opts);
}
static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data)
@@ -335,6 +288,131 @@ static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
return 0;
}
+struct nftnl_tunnel_opt {
+ struct list_head list;
+
+ enum nftnl_tunnel_type type;
+ uint32_t flags;
+
+ union {
+ struct {
+ uint32_t gbp;
+ } vxlan;
+ struct {
+ uint32_t version;
+ struct {
+ uint32_t index;
+ } v1;
+ struct {
+ uint8_t hwid;
+ uint8_t dir;
+ } v2;
+ } erspan;
+ };
+};
+
+struct nftnl_tunnel_opts {
+ enum nftnl_tunnel_type type;
+ uint32_t num;
+ struct list_head opts_list;
+};
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_data);
+const void *nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne,
+ uint16_t attr, uint32_t *data_len)
+{
+ if (!(ne->flags & (1 << attr)))
+ return NULL;
+
+ switch (ne->type) {
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ switch (attr) {
+ case NFTNL_TUNNEL_ERSPAN_VERSION:
+ *data_len = sizeof(uint32_t);
+ return &ne->erspan.version;
+ case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
+ *data_len = sizeof(uint32_t);
+ return &ne->erspan.v1.index;
+ case NFTNL_TUNNEL_ERSPAN_V2_HWID:
+ *data_len = sizeof(uint8_t);
+ return &ne->erspan.v2.hwid;
+ case NFTNL_TUNNEL_ERSPAN_V2_DIR:
+ *data_len = sizeof(uint8_t);
+ return &ne->erspan.v2.dir;
+ }
+ break;
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ switch (attr) {
+ case NFTNL_TUNNEL_VXLAN_GBP:
+ *data_len = sizeof(uint32_t);
+ return &ne->vxlan.gbp;
+ }
+ break;
+ }
+
+ errno = EOPNOTSUPP;
+ return NULL;
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get);
+const void *
+nftnl_tunnel_opt_get(const struct nftnl_tunnel_opt *ne, uint16_t attr)
+{
+ uint32_t data_len;
+ return nftnl_tunnel_opt_get_data(ne, attr, &data_len);
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_u8);
+uint8_t nftnl_tunnel_opt_get_u8(const struct nftnl_tunnel_opt *ne, uint16_t attr)
+{
+ const void *ret = nftnl_tunnel_opt_get(ne, attr);
+ return ret == NULL ? 0 : *((uint8_t *)ret);
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_u16);
+uint16_t nftnl_tunnel_opt_get_u16(const struct nftnl_tunnel_opt *ne, uint16_t attr)
+{
+ const void *ret = nftnl_tunnel_opt_get(ne, attr);
+ return ret == NULL ? 0 : *((uint16_t *)ret);
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_u32);
+uint32_t nftnl_tunnel_opt_get_u32(const struct nftnl_tunnel_opt *ne, uint16_t attr)
+{
+ const void *ret = nftnl_tunnel_opt_get(ne, attr);
+ return ret == NULL ? 0 : *((uint32_t *)ret);
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_type);
+enum nftnl_tunnel_type nftnl_tunnel_opt_get_type(const struct nftnl_tunnel_opt *ne)
+{
+ return ne->type;
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_get_flags);
+uint32_t nftnl_tunnel_opt_get_flags(const struct nftnl_tunnel_opt *ne)
+{
+ return ne->flags;
+}
+
+EXPORT_SYMBOL(nftnl_obj_tunnel_opts_foreach);
+int nftnl_obj_tunnel_opts_foreach(const struct nftnl_obj *ne,
+ int (*cb)(struct nftnl_tunnel_opt *opt, void *data),
+ void *data)
+{
+ struct nftnl_obj_tunnel *tun = nftnl_obj_data(ne);
+ struct nftnl_tunnel_opt *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &tun->tun_opts->opts_list, list) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
@@ -354,21 +432,29 @@ static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
+struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type);
+
static int
-nftnl_obj_tunnel_parse_vxlan(struct nftnl_obj *e, struct nlattr *attr,
- struct nftnl_obj_tunnel *tun)
+nftnl_obj_tunnel_parse_vxlan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
{
struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {};
+ struct nftnl_tunnel_opt *opt;
if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0)
return -1;
+ opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
+ if (!opt)
+ return -1;
+
if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) {
- tun->u.tun_vxlan.gbp =
+ opt->vxlan.gbp =
ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
- e->flags |= (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP);
+ opt->flags |= (1 << NFTNL_TUNNEL_VXLAN_GBP);
}
+ list_add_tail(&opt->list, &opts->opts_list);
+
return 0;
}
@@ -398,35 +484,41 @@ static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data)
}
static int
-nftnl_obj_tunnel_parse_erspan(struct nftnl_obj *e, struct nlattr *attr,
- struct nftnl_obj_tunnel *tun)
+nftnl_obj_tunnel_parse_erspan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
{
struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {};
+ struct nftnl_tunnel_opt *opt;
if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0)
return -1;
+ opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
+ if (!opt)
+ return -1;
+
if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) {
- tun->u.tun_erspan.version =
+ opt->erspan.version =
ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
- e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION);
+ opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_VERSION);
}
if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) {
- tun->u.tun_erspan.u.v1_index =
+ opt->erspan.v1.index =
ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]));
- e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX);
+ opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX);
}
if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) {
- tun->u.tun_erspan.u.v2.hwid =
+ opt->erspan.v2.hwid =
mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
- e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID);
+ opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID);
}
if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) {
- tun->u.tun_erspan.u.v2.dir =
+ opt->erspan.v2.dir =
mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
- e->flags |= (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR);
+ opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR);
}
+ list_add_tail(&opt->list, &opts->opts_list);
+
return 0;
}
@@ -450,22 +542,36 @@ static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
+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,
struct nftnl_obj_tunnel *tun)
{
struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {};
+ struct nftnl_tunnel_opts *opts = NULL;
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);
+ 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]) {
- err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
- tun);
+ 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]);
+ }
+
+ if (opts) {
+ tun->tun_opts = opts;
+ e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS);
}
return err;
@@ -532,6 +638,215 @@ static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
return snprintf(buf, len, "id %u ", tun->id);
}
+EXPORT_SYMBOL(nftnl_tunnel_opts_alloc);
+struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
+{
+ struct nftnl_tunnel_opts *opts;
+
+ switch (type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ return NULL;
+ }
+
+ opts = calloc(1, sizeof(struct nftnl_tunnel_opts));
+ if (!opts)
+ return NULL;
+
+ opts->type = type;
+ INIT_LIST_HEAD(&opts->opts_list);
+
+ return opts;
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opts_add);
+int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
+ struct nftnl_tunnel_opt *opt)
+{
+ if (opt->type != opts->type) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ switch (opts->type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ if (opts->num > 0) {
+ errno = EEXIST;
+ return -1;
+ }
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ list_add_tail(&opt->list, &opts->opts_list);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opts_free);
+void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
+{
+ struct nftnl_tunnel_opt *opt, *next;
+
+ list_for_each_entry_safe(opt, next, &opts->opts_list, list) {
+ switch(opts->type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ list_del(&opt->list);
+ xfree(opt);
+ break;
+ }
+ }
+}
+
+EXPORT_SYMBOL(nftnl_tunnel_opt_alloc);
+struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
+{
+ struct nftnl_tunnel_opt *opt;
+
+ switch (type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ return NULL;
+ }
+
+ opt = calloc(1, sizeof(struct nftnl_tunnel_opt));
+ if (!opt)
+ return NULL;
+
+ opt->type = type;
+
+ return opt;
+}
+
+static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
+ const void *data, uint32_t data_len)
+{
+ switch (type) {
+ case NFTNL_TUNNEL_VXLAN_GBP:
+ memcpy(&opt->vxlan.gbp, data, data_len);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ opt->flags |= (1 << type);
+
+ return 0;
+}
+
+static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
+ const void *data, uint32_t data_len)
+{
+ switch (type) {
+ case NFTNL_TUNNEL_ERSPAN_VERSION:
+ memcpy(&opt->erspan.version, data, data_len);
+ break;
+ case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
+ memcpy(&opt->erspan.v1.index, data, data_len);
+ break;
+ case NFTNL_TUNNEL_ERSPAN_V2_HWID:
+ memcpy(&opt->erspan.v2.hwid, data, data_len);
+ break;
+ case NFTNL_TUNNEL_ERSPAN_V2_DIR:
+ memcpy(&opt->erspan.v2.dir, data, 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)
+{
+ switch (opt->type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ 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);
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh,
+ const struct nftnl_tunnel_opt *opt)
+{
+ struct nlattr *nest_inner;
+
+ if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) {
+ nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
+ mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
+ htonl(opt->vxlan.gbp));
+ mnl_attr_nest_end(nlh, nest_inner);
+ }
+}
+
+static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
+ const struct nftnl_tunnel_opt *opt)
+{
+ struct nlattr *nest_inner;
+
+ if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) &&
+ (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) ||
+ (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) &&
+ opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) {
+ nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
+ mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+ htonl(opt->erspan.version));
+ if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX))
+ mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+ htonl(opt->erspan.v1.index));
+ if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID))
+ mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+ opt->erspan.v2.hwid);
+ if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR))
+ mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+ opt->erspan.v2.dir);
+ mnl_attr_nest_end(nlh, nest_inner);
+ }
+}
+
+void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
+ struct nftnl_tunnel_opts *opts)
+{
+ const struct nftnl_tunnel_opt *opt;
+ struct nlattr *nest;
+
+ nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
+
+ list_for_each_entry(opt, &opts->opts_list, list) {
+ switch (opts->type) {
+ case NFTNL_TUNNEL_TYPE_VXLAN:
+ nftnl_tunnel_opt_build_vxlan(nlh, opt);
+ break;
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ nftnl_tunnel_opt_build_erspan(nlh, opt);
+ break;
+ }
+ }
+ mnl_attr_nest_end(nlh, nest);
+}
+
static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
[NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
[NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
@@ -544,11 +859,7 @@ static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
[NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
[NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
[NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
- [NFTNL_OBJ_TUNNEL_VXLAN_GBP] = { .maxlen = sizeof(uint32_t) },
- [NFTNL_OBJ_TUNNEL_ERSPAN_VERSION] = { .maxlen = sizeof(uint32_t) },
- [NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX] = { .maxlen = sizeof(uint32_t) },
- [NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID] = { .maxlen = sizeof(uint8_t) },
- [NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR] = { .maxlen = sizeof(uint8_t) },
+ [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) },
};
struct obj_ops obj_ops_tunnel = {
diff --git a/src/object.c b/src/object.c
index bfcceb9..275a202 100644
--- a/src/object.c
+++ b/src/object.c
@@ -55,6 +55,10 @@ void nftnl_obj_free(const struct nftnl_obj *obj)
xfree(obj->name);
if (obj->flags & (1 << NFTNL_OBJ_USERDATA))
xfree(obj->user.data);
+ if (obj->flags & (1 << NFTNL_OBJ_TUNNEL_OPTS)) {
+ nftnl_tunnel_opts_free(obj->data.tunnel.tun_opts);
+ xfree(obj->data.tunnel.tun_opts);
+ }
xfree(obj);
}