summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <fmancera@suse.de>2025-08-21 11:17:18 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2025-08-28 00:09:54 +0200
commit239fbdb8979dd4f322af187dc609f292a36c3ac6 (patch)
treedd94694a81fd5a9d42c79e65fceb9633c9248c45 /src
parente3b58fe8fcd876ceccef60f7784bb90267f36085 (diff)
tunnel: add support to geneve options
In addition, modifies the netlink parsing to loop through the nested array of NFTA_TUNNEL_KEY_OPTS. Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/obj/tunnel.c176
1 files changed, 157 insertions, 19 deletions
diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c
index bed0342..ea9cb02 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;
};
};
@@ -348,6 +354,19 @@ const void *nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne,
return &ne->vxlan.gbp;
}
break;
+ case NFTNL_TUNNEL_TYPE_GENEVE:
+ switch (attr) {
+ case NFTNL_TUNNEL_GENEVE_CLASS:
+ *data_len = sizeof(uint16_t);
+ return &ne->geneve.geneve_class;
+ case NFTNL_TUNNEL_GENEVE_TYPE:
+ *data_len = sizeof(uint8_t);
+ return &ne->geneve.type;
+ case NFTNL_TUNNEL_GENEVE_DATA:
+ *data_len = ne->geneve.data_len;
+ return &ne->geneve.data;
+ }
+ break;
}
errno = EOPNOTSUPP;
@@ -522,18 +541,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;
}
@@ -542,31 +568,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, attr);
+ break;
+ case NFTA_TUNNEL_KEY_OPTS_GENEVE:
+ if (!opts)
+ opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
- err = nftnl_obj_tunnel_parse_erspan(opts, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]);
+ if (!opts)
+ return -1;
+
+ err = nftnl_obj_tunnel_parse_geneve(opts, attr);
+ break;
+ }
}
if (opts) {
@@ -646,6 +726,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;
@@ -679,6 +760,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;
@@ -698,6 +781,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;
@@ -713,6 +797,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;
@@ -771,6 +856,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)
@@ -780,6 +893,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;
@@ -826,6 +941,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)
{
@@ -842,6 +977,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);