From f127a93dc7f965317176ad0a61125bd55085fb93 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Jul 2014 23:53:30 +0200 Subject: set_elem: add nft_set_elems_nlmsg_build_payload_iter() This new interface allows you to put as many set elements as possible into a netlink message. The iterator stores the last element that has fit into a netlink message, so you can continue adding more set elements across several netlink messages. Signed-off-by: Pablo Neira Ayuso --- src/libnftnl.map | 4 +++ src/set_elem.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/libnftnl.map b/src/libnftnl.map index b11db67..e8c634f 100644 --- a/src/libnftnl.map +++ b/src/libnftnl.map @@ -206,3 +206,7 @@ LIBNFTNL_1.1 { nft_set_attr_set_data; nft_set_attr_get_data; } LIBNFTNL_1.0; + +LIBNFTNL_1.2 { + nft_set_elems_nlmsg_build_payload_iter; +} LIBNFTNL_1.1; diff --git a/src/set_elem.c b/src/set_elem.c index 197da73..93ecac6 100644 --- a/src/set_elem.c +++ b/src/set_elem.c @@ -197,27 +197,41 @@ void nft_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh, } } -void nft_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s) +static void nft_set_elem_nlmsg_build_def(struct nlmsghdr *nlh, + struct nft_set *s) { - struct nft_set_elem *elem; - struct nlattr *nest1; - int i = 0; - if (s->flags & (1 << NFT_SET_ATTR_NAME)) mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET, s->name); if (s->flags & (1 << NFT_SET_ATTR_ID)) mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID, htonl(s->id)); if (s->flags & (1 << NFT_SET_ATTR_TABLE)) mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE, s->table); +} + +static struct nlattr *nft_set_elem_attr_build(struct nlmsghdr *nlh, + struct nft_set_elem *elem, int i) +{ + struct nlattr *nest2; + + nest2 = mnl_attr_nest_start(nlh, i); + nft_set_elem_nlmsg_build_payload(nlh, elem); + mnl_attr_nest_end(nlh, nest2); + + return nest2; +} + +void nft_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s) +{ + struct nft_set_elem *elem; + struct nlattr *nest1; + int i = 0; + + nft_set_elem_nlmsg_build_def(nlh, s); nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS); - list_for_each_entry(elem, &s->element_list, head) { - struct nlattr *nest2; + list_for_each_entry(elem, &s->element_list, head) + nft_set_elem_attr_build(nlh, elem, ++i); - nest2 = mnl_attr_nest_start(nlh, ++i); - nft_set_elem_nlmsg_build_payload(nlh, elem); - mnl_attr_nest_end(nlh, nest2); - } mnl_attr_nest_end(nlh, nest1); } EXPORT_SYMBOL(nft_set_elems_nlmsg_build_payload); @@ -661,6 +675,7 @@ int nft_set_elem_foreach(struct nft_set *s, EXPORT_SYMBOL(nft_set_elem_foreach); struct nft_set_elems_iter { + struct nft_set *set; struct list_head *list; struct nft_set_elem *cur; }; @@ -673,6 +688,7 @@ struct nft_set_elems_iter *nft_set_elems_iter_create(struct nft_set *s) if (iter == NULL) return NULL; + iter->set = s; iter->list = &s->element_list; iter->cur = list_entry(s->element_list.next, struct nft_set_elem, head); @@ -703,3 +719,48 @@ void nft_set_elems_iter_destroy(struct nft_set_elems_iter *iter) xfree(iter); } EXPORT_SYMBOL(nft_set_elems_iter_destroy); + +static bool nft_attr_nest_overflow(struct nlmsghdr *nlh, + const struct nlattr *from, + const struct nlattr *to) +{ + int len = (void *)to + to->nla_len - (void *)from; + + /* The attribute length field is 16 bits long, thus the maximum payload + * that an attribute can convey is UINT16_MAX. In case of overflow, + * discard the last that did not fit into the attribute. + */ + if (len > UINT16_MAX) { + nlh->nlmsg_len -= to->nla_len; + return true; + } + return false; +} + +int nft_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh, + struct nft_set_elems_iter *iter) +{ + struct nft_set_elem *elem; + struct nlattr *nest1, *nest2; + int i = 0, ret = 0; + + nft_set_elem_nlmsg_build_def(nlh, iter->set); + + nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS); + elem = nft_set_elems_iter_next(iter); + while (elem != NULL) { + nest2 = nft_set_elem_attr_build(nlh, elem, ++i); + if (nft_attr_nest_overflow(nlh, nest1, nest2)) { + /* Go back to previous not to miss this element */ + iter->cur = list_entry(iter->cur->head.prev, + struct nft_set_elem, head); + ret = 1; + break; + } + elem = nft_set_elems_iter_next(iter); + } + mnl_attr_nest_end(nlh, nest1); + + return ret; +} +EXPORT_SYMBOL(nft_set_elems_nlmsg_build_payload_iter); -- cgit v1.2.3