From 504439a02da3ca284e17b9755f3734e45a68cc44 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Gonzalez Date: Wed, 19 Jul 2017 15:05:28 +0200 Subject: monitor: Fix printing of range elements in named sets If you add set elements to interval sets, the output is wrong. Fix this by caching first element of the range (first event), then wait for the second element of the range (second event) to print them both at the same time. We also avoid printing the first null element required in the RB tree. Before this patch: % nft add element t s {10-20, 30-40} add element ip t s { 0 } add element ip t s { 10 } add element ip t s { ftp } add element ip t s { 30 } add element ip t s { 41 } After this patch: % nft add element t s {10-20, 30-40} add element ip t s { 10-20 } add element ip t s { 30-40 } Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'src/netlink.c') diff --git a/src/netlink.c b/src/netlink.c index 9649a2f1..2c472273 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -2202,6 +2202,63 @@ out: return MNL_CB_OK; } +/* returns true if the event should be ignored (i.e. null element) */ +static bool netlink_event_ignore_range_event(struct nftnl_set_elem *nlse) +{ + uint32_t flags = 0; + + if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS)) + flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS); + if (!(flags & NFT_SET_ELEM_INTERVAL_END)) + return false; + + if (nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_KEY) != 0) + return false; + + return true; +} + +static bool set_elem_is_open_interval(struct expr *elem) +{ + switch (elem->ops->type) { + case EXPR_SET_ELEM: + return elem->elem_flags & SET_ELEM_F_INTERVAL_OPEN; + case EXPR_MAPPING: + return set_elem_is_open_interval(elem->left); + default: + return false; + } +} + +/* returns true if the we cached the range element */ +static bool netlink_event_range_cache(struct set *cached_set, + struct set *dummyset) +{ + struct expr *elem; + + /* not an interval ? */ + if (!(cached_set->flags & NFT_SET_INTERVAL)) + return false; + + /* if cache exists, dummyset must contain the other end of the range */ + if (cached_set->rg_cache) { + compound_expr_add(dummyset->init, cached_set->rg_cache); + cached_set->rg_cache = NULL; + goto out_decompose; + } + + /* don't cache half-open range elements */ + elem = list_entry(dummyset->init->expressions.prev, struct expr, list); + if (!set_elem_is_open_interval(elem)) { + cached_set->rg_cache = expr_clone(elem); + return true; + } + +out_decompose: + interval_map_decompose(dummyset->init); + return false; +} + static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { @@ -2236,6 +2293,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, dummyset = set_alloc(monh->loc); dummyset->keytype = set->keytype; dummyset->datatype = set->datatype; + dummyset->flags = set->flags; dummyset->init = set_expr_alloc(monh->loc, set); nlsei = nftnl_set_elems_iter_create(nls); @@ -2244,6 +2302,11 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, nlse = nftnl_set_elems_iter_next(nlsei); while (nlse != NULL) { + if (netlink_event_ignore_range_event(nlse)) { + set_free(dummyset); + nftnl_set_elems_iter_destroy(nlsei); + goto out; + } if (netlink_delinearize_setelem(nlse, dummyset) < 0) { set_free(dummyset); nftnl_set_elems_iter_destroy(nlsei); @@ -2253,6 +2316,11 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, } nftnl_set_elems_iter_destroy(nlsei); + if (netlink_event_range_cache(set, dummyset)) { + set_free(dummyset); + goto out; + } + switch (type) { case NFT_MSG_NEWSETELEM: printf("add "); -- cgit v1.2.3