diff options
-rw-r--r-- | include/rule.h | 2 | ||||
-rw-r--r-- | src/netlink.c | 68 |
2 files changed, 70 insertions, 0 deletions
diff --git a/include/rule.h b/include/rule.h index a25e99bd..6acd5fa8 100644 --- a/include/rule.h +++ b/include/rule.h @@ -217,6 +217,7 @@ extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle); * @datalen: mapping data len * @objtype: mapping object type * @init: initializer + * @rg_cache: cached range element (left) * @policy: set mechanism policy * @desc: set mechanism desc */ @@ -234,6 +235,7 @@ struct set { unsigned int datalen; uint32_t objtype; struct expr *init; + struct expr *rg_cache; uint32_t policy; struct { uint32_t size; 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 "); |