Signed-off-by: Fernando Fernandez Mancera <fmancera@xxxxxxx> --- include/libnftnl/object.h | 7 ++ include/obj.h | 9 +++ src/libnftnl.map | 4 + src/obj/tunnel.c | 156 ++++++++++++++++++++++++++++++-------- src/object.c | 10 +++ 5 files changed, 156 insertions(+), 30 deletions(-) diff --git a/include/libnftnl/object.h b/include/libnftnl/object.h index 9930355..14a42cd 100644 --- a/include/libnftnl/object.h +++ b/include/libnftnl/object.h @@ -117,15 +117,19 @@ enum { NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX, NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID, NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR, + NFTNL_OBJ_TUNNEL_GENEVE_OPTS, __NFTNL_OBJ_TUNNEL_MAX, }; +#define NFTNL_TUNNEL_GENEVE_DATA_MAXLEN 127 + enum { NFTNL_OBJ_SECMARK_CTX = NFTNL_OBJ_BASE, __NFTNL_OBJ_SECMARK_MAX, }; struct nftnl_obj; +struct nftnl_obj_tunnel_geneve; struct nftnl_obj *nftnl_obj_alloc(void); void nftnl_obj_free(const struct nftnl_obj *ne); @@ -171,6 +175,9 @@ void nftnl_obj_list_del(struct nftnl_obj *t); int nftnl_obj_list_foreach(struct nftnl_obj_list *table_list, int (*cb)(struct nftnl_obj *t, void *data), void *data); +int nftnl_obj_tunnel_geneve_opts_foreach(struct nftnl_obj *e, + int (*cb)(struct nftnl_obj_tunnel_geneve *e, void *data), + void *data); struct nftnl_obj_list_iter; struct nftnl_obj_list_iter *nftnl_obj_list_iter_create(struct nftnl_obj_list *l); diff --git a/include/obj.h b/include/obj.h index fc78e2a..7c9898e 100644 --- a/include/obj.h +++ b/include/obj.h @@ -9,6 +9,14 @@ struct nlattr; struct nlmsghdr; struct nftnl_obj; +struct nftnl_obj_tunnel_geneve { + struct list_head list; + uint16_t geneve_class; + uint8_t type; + uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN]; + uint32_t data_len; +}; + struct nftnl_obj { struct list_head head; struct obj_ops *ops; @@ -92,6 +100,7 @@ struct nftnl_obj { } v2; } u; } tun_erspan; + struct list_head tun_geneve; } u; } tunnel; struct nftnl_obj_secmark { diff --git a/src/libnftnl.map b/src/libnftnl.map index 8fffff1..e125017 100644 --- a/src/libnftnl.map +++ b/src/libnftnl.map @@ -383,3 +383,7 @@ LIBNFTNL_16 { LIBNFTNL_17 { nftnl_set_elem_nlmsg_build; } LIBNFTNL_16; + +LIBNFTNL_18 { + nftnl_obj_tunnel_geneve_opts_foreach; +} LIBNFTNL_17; diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c index 8941e39..b8c07b7 100644 --- a/src/obj/tunnel.c +++ b/src/obj/tunnel.c @@ -22,6 +22,7 @@ nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type, const void *data, uint32_t data_len) { struct nftnl_obj_tunnel *tun = nftnl_obj_data(e); + struct nftnl_obj_tunnel_geneve *geneve; switch (type) { case NFTNL_OBJ_TUNNEL_ID: @@ -72,6 +73,15 @@ 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_OPTS: + geneve = malloc(sizeof(struct nftnl_obj_tunnel_geneve)); + memcpy(geneve, data, data_len); + + if (!(e->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_OPTS))) + INIT_LIST_HEAD(&tun->u.tun_geneve); + + list_add_tail(&geneve->list, &tun->u.tun_geneve); + break; } return 0; } @@ -135,6 +145,23 @@ nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type, return NULL; } +EXPORT_SYMBOL(nftnl_obj_tunnel_geneve_opts_foreach); +int nftnl_obj_tunnel_geneve_opts_foreach(struct nftnl_obj *e, + int (*cb)(struct nftnl_obj_tunnel_geneve *e, void *data), + void *data) +{ + struct nftnl_obj_tunnel *tun = nftnl_obj_data(e); + struct nftnl_obj_tunnel_geneve *cur, *tmp; + int ret; + + list_for_each_entry_safe(cur, tmp, &tun->u.tun_geneve, list) { + ret = cb(cur, data); + if (ret < 0) + return ret; + } + return 0; +} + static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -240,6 +267,23 @@ 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_OPTS)) { + struct nftnl_obj_tunnel_geneve *geneve; + + nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS); + list_for_each_entry(geneve, &tun->u.tun_geneve, list) { + nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE); + mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS, + htons(geneve->geneve_class)); + mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE, + geneve->type); + mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA, + geneve->data_len, + 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 +379,72 @@ 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] = {}; + struct nftnl_obj_tunnel_geneve *geneve; + + if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0) + return -1; + + geneve = malloc(sizeof(struct nftnl_obj_tunnel_geneve)); + + if (!(e->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_OPTS))) { + INIT_LIST_HEAD(&tun->u.tun_geneve); + e->flags |= (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_OPTS); + } + + if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) + geneve->geneve_class = + ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS])); + + if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) + geneve->type = + mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]); + + if (tb[NFTA_TUNNEL_KEY_GENEVE_DATA]) { + uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]); + + memcpy(geneve->data, + mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]), + len); + geneve->data_len = len; + } + + list_add_tail(&geneve->list, &tun->u.tun_geneve); + + return 0; +} + static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -430,42 +540,28 @@ nftnl_obj_tunnel_parse_erspan(struct nftnl_obj *e, struct nlattr *attr, return 0; } -static int nftnl_obj_tunnel_opts_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) - 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) - abi_breakage(); - break; - } - - tb[type] = attr; - return MNL_CB_OK; -} - 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; 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]) { - err = nftnl_obj_tunnel_parse_vxlan(e, tb[NFTA_TUNNEL_KEY_OPTS_VXLAN], - tun); - } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) { - err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN], - tun); + switch (mnl_attr_get_type(attr)) { + case NFTA_TUNNEL_KEY_OPTS_VXLAN: + err = nftnl_obj_tunnel_parse_vxlan(e, attr, tun); + break; + case NFTA_TUNNEL_KEY_OPTS_ERSPAN: + err = nftnl_obj_tunnel_parse_erspan(e, attr, tun); + break; + case NFTA_TUNNEL_KEY_OPTS_GENEVE: + err = nftnl_obj_tunnel_parse_geneve(e, attr, tun); + break; + } } return err; diff --git a/src/object.c b/src/object.c index f307815..b5bdbbf 100644 --- a/src/object.c +++ b/src/object.c @@ -49,12 +49,22 @@ struct nftnl_obj *nftnl_obj_alloc(void) EXPORT_SYMBOL(nftnl_obj_free); void nftnl_obj_free(const struct nftnl_obj *obj) { + struct nftnl_obj_tunnel_geneve *geneve, *next; + if (obj->flags & (1 << NFTNL_OBJ_TABLE)) xfree(obj->table); if (obj->flags & (1 << NFTNL_OBJ_NAME)) xfree(obj->name); if (obj->flags & (1 << NFTNL_OBJ_USERDATA)) xfree(obj->user.data); + if (obj->flags & (1ULL << NFTNL_OBJ_TUNNEL_GENEVE_OPTS)) { + list_for_each_entry_safe(geneve, next, + &obj->data.tunnel.u.tun_geneve, + list) { + list_del(&geneve->list); + xfree(geneve); + } + } xfree(obj); } -- 2.49.0