enum {
NFTNL_OBJ_SECMARK_CTX = NFTNL_OBJ_BASE,
__NFTNL_OBJ_SECMARK_MAX,
diff --git a/include/obj.h b/include/obj.h
index fc78e2a..e6c1cbf 100644
--- a/include/obj.h
+++ b/include/obj.h
@@ -92,6 +92,12 @@ struct nftnl_obj {
} v2;
} u;
} tun_erspan;
+ struct {
+ uint16_t geneve_class;
+ uint8_t type;
+ uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN];
+ uint32_t data_len;
+ } tun_geneve;
} u;
} tunnel;
struct nftnl_obj_secmark {
diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c
index 8941e39..27a6acd 100644
--- a/src/obj/tunnel.c
+++ b/src/obj/tunnel.c
@@ -72,6 +72,16 @@ nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type,
case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
memcpy(&tun->u.tun_erspan.u.v2.dir, data, data_len);
break;
+ case NFTNL_OBJ_TUNNEL_GENEVE_CLASS:
+ memcpy(&tun->u.tun_geneve.geneve_class, data, data_len);
+ break;
+ case NFTNL_OBJ_TUNNEL_GENEVE_TYPE:
+ memcpy(&tun->u.tun_geneve.type, data, data_len);
+ break;
+ case NFTNL_OBJ_TUNNEL_GENEVE_DATA:
+ memcpy(&tun->u.tun_geneve.data, data, data_len);
+ tun->u.tun_geneve.data_len = data_len;
+ break;
}
return 0;
}
@@ -131,6 +141,15 @@ nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
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_GENEVE_CLASS:
+ *data_len = sizeof(tun->u.tun_geneve.geneve_class);
+ return &tun->u.tun_geneve.geneve_class;
+ case NFTNL_OBJ_TUNNEL_GENEVE_TYPE:
+ *data_len = sizeof(tun->u.tun_geneve.type);
+ return &tun->u.tun_geneve.type;
+ case NFTNL_OBJ_TUNNEL_GENEVE_DATA:
+ *data_len = tun->u.tun_geneve.data_len;
+ return &tun->u.tun_geneve.data;
}
return NULL;
}
@@ -240,6 +259,21 @@ nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
mnl_attr_nest_end(nlh, nest_inner);
mnl_attr_nest_end(nlh, nest);
}
+ if (e->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_CLASS) &&
+ e->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_TYPE) &&
+ e->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_DATA)) {
+ nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
+ nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
+ mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ htons(tun->u.tun_geneve.geneve_class));
+ mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ tun->u.tun_geneve.type);
+ mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
+ tun->u.tun_geneve.data_len,
+ tun->u.tun_geneve.data);
+ 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)
@@ -335,6 +369,68 @@ static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
return 0;
}
+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_GENEVE_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch (type) {
+ 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;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int
+nftnl_obj_tunnel_parse_geneve(struct nftnl_obj *e, struct nlattr *attr,
+ struct nftnl_obj_tunnel *tun)
+{
+ struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {};
+
+ if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0)
+ return -1;
+
+ if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) {
+ tun->u.tun_geneve.geneve_class =
+ ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]));
+ e->flags |= (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_CLASS);
+ }
+
+ if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) {
+ tun->u.tun_geneve.type =
+ mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]);
+ e->flags |= (1ULL << NFTNL_OBJ_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(tun->u.tun_geneve.data,
+ mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
+ len);
+ tun->u.tun_geneve.data_len = len;
+
+ e->flags |= (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_DATA);
+ }
+
+ return 0;
+}
+
static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
@@ -441,6 +537,7 @@ static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
switch (type) {
case NFTA_TUNNEL_KEY_OPTS_VXLAN:
case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
+ case NFTA_TUNNEL_KEY_OPTS_GENEVE:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -466,6 +563,9 @@ nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *attr,
} else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
tun);
+ } else if (tb[NFTA_TUNNEL_KEY_OPTS_GENEVE]) {
+ err = nftnl_obj_tunnel_parse_geneve(e, tb[NFTA_TUNNEL_KEY_OPTS_GENEVE],
+ tun);
}
return err;
@@ -549,6 +649,9 @@ static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
[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_GENEVE_CLASS] = { .maxlen = sizeof(uint16_t) },
+ [NFTNL_OBJ_TUNNEL_GENEVE_TYPE] = { .maxlen = sizeof(uint8_t) },
+ [NFTNL_OBJ_TUNNEL_GENEVE_DATA] = { .maxlen = NFTNL_TUNNEL_GENEVE_DATA_MAXLEN},
};
struct obj_ops obj_ops_tunnel = {