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;
};
};
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;
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;
}
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) {
switch (type) {
case NFTNL_TUNNEL_TYPE_VXLAN:
case NFTNL_TUNNEL_TYPE_ERSPAN:
+ case NFTNL_TUNNEL_TYPE_GENEVE:
break;
default:
errno = EOPNOTSUPP;
return -1;
}
break;
+ case NFTNL_TUNNEL_TYPE_GENEVE:
+ break;
default:
errno = EOPNOTSUPP;
return -1;
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;
switch (type) {
case NFTNL_TUNNEL_TYPE_VXLAN:
case NFTNL_TUNNEL_TYPE_ERSPAN:
+ case NFTNL_TUNNEL_TYPE_GENEVE:
break;
default:
errno = EOPNOTSUPP;
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)
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;
}
}
+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)
{
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);