}
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
- const struct nlattr *attr, u32 nlmsg_flags,
- bool last)
+ const struct nlattr *attr, u32 nlmsg_flags)
{
struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
if (flags)
*nft_set_ext_flags(ext) = flags;
- if (last)
- elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
- else
- elem.flags = 0;
-
if (obj)
*nft_set_ext_obj(ext) = obj;
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags,
- nla_is_last(attr, rem));
+ err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
if (err < 0) {
NL_SET_BAD_ATTR(extack, attr);
return err;
}
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
- const struct nlattr *attr, bool last)
+ const struct nlattr *attr)
{
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_set_ext_tmpl tmpl;
if (flags)
*nft_set_ext_flags(ext) = flags;
- if (last)
- elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
- else
- elem.flags = 0;
-
trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (trans == NULL)
goto fail_trans;
return nft_set_flush(&ctx, set, genmask);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- err = nft_del_setelem(&ctx, set, attr,
- nla_is_last(attr, rem));
+ err = nft_del_setelem(&ctx, set, attr);
if (err == -ENOENT &&
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
continue;
priv->start_rbe_cookie = (unsigned long)rbe;
}
-static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv,
- const struct nft_rbtree_elem *rbe,
- unsigned long open_interval)
-{
- priv->start_rbe_cookie = (unsigned long)rbe | open_interval;
-}
-
-#define NFT_RBTREE_OPEN_INTERVAL 1UL
-
static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv,
const struct nft_rbtree_elem *rbe)
{
- return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe;
+ return priv->start_rbe_cookie == (unsigned long)rbe;
}
static bool nft_rbtree_insert_same_interval(const struct net *net,
static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_rbtree_elem *new,
- struct nft_elem_priv **elem_priv, u64 tstamp, bool last)
+ struct nft_elem_priv **elem_priv, u64 tstamp)
{
struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
struct rb_node *node, *next, *parent, **p, *first = NULL;
struct nft_rbtree *priv = nft_set_priv(set);
u8 cur_genmask = nft_genmask_cur(net);
u8 genmask = nft_genmask_next(net);
- unsigned long open_interval = 0;
int d;
/* Descend the tree to search for an existing element greater than the
}
}
- if (nft_rbtree_interval_null(set, new)) {
+ if (nft_rbtree_interval_null(set, new))
+ priv->start_rbe_cookie = 0;
+ else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie)
priv->start_rbe_cookie = 0;
- } else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) {
- if (nft_set_is_anonymous(set)) {
- priv->start_rbe_cookie = 0;
- } else if (priv->start_rbe_cookie & NFT_RBTREE_OPEN_INTERVAL) {
- /* Previous element is an open interval that partially
- * overlaps with an existing non-open interval.
- */
- return -ENOTEMPTY;
- }
- }
/* - new start element matching existing start element: full overlap
* reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
*elem_priv = &rbe_ge->priv;
-
- /* - Corner case: new start element of open interval (which
- * comes as last element in the batch) overlaps the start of
- * an existing interval with an end element: partial overlap.
- */
- node = rb_first(&priv->root);
- rbe = __nft_rbtree_next_active(node, genmask);
- if (rbe && nft_rbtree_interval_end(rbe)) {
- rbe = nft_rbtree_next_active(rbe, genmask);
- if (rbe &&
- nft_rbtree_interval_start(rbe) &&
- !nft_rbtree_cmp(set, new, rbe)) {
- if (last)
- return -ENOTEMPTY;
-
- /* Maybe open interval? */
- open_interval = NFT_RBTREE_OPEN_INTERVAL;
- }
- }
- nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval);
-
+ nft_rbtree_set_start_cookie(priv, rbe_ge);
return -EEXIST;
}
nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
return -ENOTEMPTY;
- /* - start element overlaps an open interval but end element is new:
- * partial overlap, reported as -ENOEMPTY.
- */
- if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new))
- return -ENOTEMPTY;
-
/* Accepted element: pick insertion point depending on key value */
parent = NULL;
p = &priv->root.rb_node;
struct nft_elem_priv **elem_priv)
{
struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv);
- bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
struct nft_rbtree *priv = nft_set_priv(set);
u64 tstamp = nft_net_tstamp(net);
int err;
cond_resched();
write_lock_bh(&priv->lock);
- err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last);
+ err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp);
write_unlock_bh(&priv->lock);
-
- if (nft_rbtree_interval_end(rbe))
- priv->start_rbe_cookie = 0;
-
} while (err == -EAGAIN);
return err;
const struct nft_set_elem *elem)
{
struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv);
- bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node;
u8 genmask = nft_genmask_next(net);
continue;
}
- if (nft_rbtree_interval_start(rbe)) {
- if (!last)
- nft_rbtree_set_start_cookie(priv, rbe);
- } else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
+ if (nft_rbtree_interval_start(rbe))
+ nft_rbtree_set_start_cookie(priv, rbe);
+ else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
return NULL;
nft_rbtree_flush(net, set, &rbe->priv);