When adding or removing ranges from named sets, the kernel sends separate netlink events for the lower and upper boundary of the range, so 'nft monitor' incorrectly treated them as separate elements. An intuitive approach to fix this is to cache the first element reported for sets with 'interval' flag set and use it to reconstruct the range when the second one is reported. Though this does not work for unclosed intervals: If a range's upper boundary aligns with the maximum value allowed for the given set datatype, an unclosed interval is created which consists of only the lower boundary. The kernel then reports this range as a single element (which does not have EXPR_F_INTERVAL_END flag set). This patch solves both cases: netlink_events_setelem_cb() caches the first reported element of a range. If the upper boundary is reported afterwards, the same function takes care of the reassembling and cache removal. If not, 'nft monitor' will eventually receive a NEWGEN message indicating the end of the transaction. To convert the cached lower boundary into an unclosed range element, a new callback netlink_events_setelem_newgen_cb() is introduced which after printing the element also clears the cache. Signed-off-by: Phil Sutter <phil@xxxxxx> --- src/netlink.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 2e30622de4bb1..65c6f05a57649 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -2196,6 +2196,14 @@ out: return MNL_CB_OK; } +static struct { + int type; + uint32_t family; + char *table; + char *setname; + struct set *set; +} setelem_cache; + static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { @@ -2227,10 +2235,15 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, * modify the original cached set. This path is only * used by named sets, so use a dummy set. */ - dummyset = set_alloc(monh->loc); - dummyset->keytype = set->keytype; - dummyset->datatype = set->datatype; - dummyset->init = set_expr_alloc(monh->loc, set); + if (setelem_cache.set) { + dummyset = setelem_cache.set; + } else { + 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); if (nlsei == NULL) @@ -2247,6 +2260,22 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, } nftnl_set_elems_iter_destroy(nlsei); + if (set->flags & NFT_SET_INTERVAL) { + if (setelem_cache.set) { + interval_map_decompose(dummyset->init); + setelem_cache.set = NULL; + free(setelem_cache.table); + free(setelem_cache.setname); + } else { + setelem_cache.type = type; + setelem_cache.family = family; + setelem_cache.table = xstrdup(table); + setelem_cache.setname = xstrdup(setname); + setelem_cache.set = dummyset; + goto out; + } + } + switch (type) { case NFT_MSG_NEWSETELEM: printf("add "); @@ -2276,6 +2305,39 @@ out: return MNL_CB_OK; } +static int netlink_events_setelem_newgen_cb(const struct nlmsghdr *nlh, + int type, + struct netlink_mon_handler *monh) +{ + if (!setelem_cache.set || + monh->format != NFTNL_OUTPUT_DEFAULT) + return MNL_CB_OK; + + interval_map_decompose(setelem_cache.set->init); + + switch (setelem_cache.type) { + case NFT_MSG_NEWSETELEM: + printf("add "); + break; + case NFT_MSG_DELSETELEM: + printf("delete "); + break; + default: + goto out; + } + printf("element %s %s %s ", family2str(setelem_cache.family), + setelem_cache.table, setelem_cache.setname); + expr_print(setelem_cache.set->init, monh->ctx->octx); + printf("\n"); + +out: + set_free(setelem_cache.set); + free(setelem_cache.table); + free(setelem_cache.setname); + setelem_cache.set = NULL; + return MNL_CB_OK; +} + static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { @@ -2914,6 +2976,8 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data) case NFT_MSG_DELOBJ: ret = netlink_events_obj_cb(nlh, type, monh); break; + case NFT_MSG_NEWGEN: + ret = netlink_events_setelem_newgen_cb(nlh, type, monh); } fflush(stdout); -- 2.13.1 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html