File Index
Files and directories
Sign in
FILE

nft_set_rbtree.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_set_rbtree.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   4 *
   5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/init.h>
  10#include <linux/module.h>
  11#include <linux/list.h>
  12#include <linux/rbtree.h>
  13#include <linux/bsearch.h>
  14#include <linux/netlink.h>
  15#include <linux/netfilter.h>
  16#include <linux/netfilter/nf_tables.h>
  17#include <net/netfilter/nf_tables_core.h>
  18
  19struct nft_array_interval {
  20	struct nft_set_ext	*from;
  21	struct nft_set_ext	*to;
  22};
  23
  24struct nft_array {
  25	u32			max_intervals;
  26	u32			num_intervals;
  27	struct nft_array_interval *intervals;
  28	struct rcu_head		rcu_head;
  29};
  30
  31struct nft_rbtree {
  32	struct rb_root		root;
  33	rwlock_t		lock;
  34	struct nft_array __rcu	*array;
  35	struct nft_array	*array_next;
  36	unsigned long		start_rbe_cookie;
  37	unsigned long		last_gc;
  38	struct list_head	expired;
  39	u64			last_tstamp;
  40};
  41
  42struct nft_rbtree_elem {
  43	struct nft_elem_priv	priv;
  44	union {
  45		struct rb_node	node;
  46		struct list_head list;
  47	};
  48	struct nft_set_ext	ext;
  49};
  50
  51static bool nft_rbtree_interval_end(const struct nft_rbtree_elem *rbe)
  52{
  53	return nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) &&
  54	       (*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END);
  55}
  56
  57static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe)
  58{
  59	return !nft_rbtree_interval_end(rbe);
  60}
  61
  62static bool nft_rbtree_interval_null(const struct nft_set *set,
  63				     const struct nft_rbtree_elem *rbe)
  64{
  65	return (!memchr_inv(nft_set_ext_key(&rbe->ext), 0, set->klen) &&
  66		nft_rbtree_interval_end(rbe));
  67}
  68
  69static int nft_rbtree_cmp(const struct nft_set *set,
  70			  const struct nft_rbtree_elem *e1,
  71			  const struct nft_rbtree_elem *e2)
  72{
  73	return memcmp(nft_set_ext_key(&e1->ext), nft_set_ext_key(&e2->ext),
  74		      set->klen);
  75}
  76
  77struct nft_array_lookup_ctx {
  78	const u32	*key;
  79	u32		klen;
  80};
  81
  82static int nft_array_lookup_cmp(const void *pkey, const void *entry)
  83{
  84	const struct nft_array_interval *interval = entry;
  85	const struct nft_array_lookup_ctx *ctx = pkey;
  86	int a, b;
  87
  88	if (!interval->from)
  89		return 1;
  90
  91	a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen);
  92	if (!interval->to)
  93		b = -1;
  94	else
  95		b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen);
  96
  97	if (a >= 0 && b < 0)
  98		return 0;
  99
 100	if (a < 0)
 101		return -1;
 102
 103	return 1;
 104}
 105
 106INDIRECT_CALLABLE_SCOPE
 107const struct nft_set_ext *
 108nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
 109		  const u32 *key)
 110{
 111	struct nft_rbtree *priv = nft_set_priv(set);
 112	struct nft_array *array = rcu_dereference(priv->array);
 113	const struct nft_array_interval *interval;
 114	struct nft_array_lookup_ctx ctx = {
 115		.key	= key,
 116		.klen	= set->klen,
 117	};
 118
 119	if (!array)
 120		return NULL;
 121
 122	interval = bsearch(&ctx, array->intervals, array->num_intervals,
 123			   sizeof(struct nft_array_interval),
 124			   nft_array_lookup_cmp);
 125	if (!interval || nft_set_elem_expired(interval->from))
 126		return NULL;
 127
 128	return interval->from;
 129}
 130
 131struct nft_array_get_ctx {
 132	const u32	*key;
 133	unsigned int	flags;
 134	u32		klen;
 135};
 136
 137static int nft_array_get_cmp(const void *pkey, const void *entry)
 138{
 139	const struct nft_array_interval *interval = entry;
 140	const struct nft_array_get_ctx *ctx = pkey;
 141	int a, b;
 142
 143	if (!interval->from)
 144		return 1;
 145
 146	a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen);
 147	if (!interval->to)
 148		b = -1;
 149	else
 150		b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen);
 151
 152	if (a >= 0) {
 153		if (ctx->flags & NFT_SET_ELEM_INTERVAL_END && b <= 0)
 154			return 0;
 155		else if (b < 0)
 156			return 0;
 157	}
 158
 159	if (a < 0)
 160		return -1;
 161
 162	return 1;
 163}
 164
 165static struct nft_elem_priv *
 166nft_rbtree_get(const struct net *net, const struct nft_set *set,
 167	       const struct nft_set_elem *elem, unsigned int flags)
 168{
 169	struct nft_rbtree *priv = nft_set_priv(set);
 170	struct nft_array *array = rcu_dereference(priv->array);
 171	const struct nft_array_interval *interval;
 172	struct nft_array_get_ctx ctx = {
 173		.key	= (const u32 *)&elem->key.val,
 174		.flags	= flags,
 175		.klen	= set->klen,
 176	};
 177	struct nft_rbtree_elem *rbe;
 178
 179	if (!array)
 180		return ERR_PTR(-ENOENT);
 181
 182	interval = bsearch(&ctx, array->intervals, array->num_intervals,
 183			   sizeof(struct nft_array_interval), nft_array_get_cmp);
 184	if (!interval || nft_set_elem_expired(interval->from))
 185		return ERR_PTR(-ENOENT);
 186
 187	if (flags & NFT_SET_ELEM_INTERVAL_END)
 188		rbe = container_of(interval->to, struct nft_rbtree_elem, ext);
 189	else
 190		rbe = container_of(interval->from, struct nft_rbtree_elem, ext);
 191
 192	return &rbe->priv;
 193}
 194
 195static void nft_rbtree_gc_elem_move(struct net *net, struct nft_set *set,
 196				    struct nft_rbtree *priv,
 197				    struct nft_rbtree_elem *rbe)
 198{
 199	lockdep_assert_held_write(&priv->lock);
 200	nft_setelem_data_deactivate(net, set, &rbe->priv);
 201	rb_erase(&rbe->node, &priv->root);
 202
 203	/* collected later on in commit callback */
 204	list_add(&rbe->list, &priv->expired);
 205}
 206
 207static const struct nft_rbtree_elem *
 208nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv,
 209		   struct nft_rbtree_elem *rbe)
 210{
 211	struct nft_set *set = (struct nft_set *)__set;
 212	struct rb_node *prev = rb_prev(&rbe->node);
 213	struct net *net = read_pnet(&set->net);
 214	struct nft_rbtree_elem *rbe_prev;
 215
 216	/* search for end interval coming before this element.
 217	 * end intervals don't carry a timeout extension, they
 218	 * are coupled with the interval start element.
 219	 */
 220	while (prev) {
 221		rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node);
 222		if (nft_rbtree_interval_end(rbe_prev) &&
 223		    nft_set_elem_active(&rbe_prev->ext, NFT_GENMASK_ANY))
 224			break;
 225
 226		prev = rb_prev(prev);
 227	}
 228
 229	rbe_prev = NULL;
 230	if (prev) {
 231		rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node);
 232		nft_rbtree_gc_elem_move(net, set, priv, rbe_prev);
 233	}
 234
 235	nft_rbtree_gc_elem_move(net, set, priv, rbe);
 236
 237	return rbe_prev;
 238}
 239
 240static bool nft_rbtree_update_first(const struct nft_set *set,
 241				    struct nft_rbtree_elem *rbe,
 242				    struct rb_node *first)
 243{
 244	struct nft_rbtree_elem *first_elem;
 245
 246	first_elem = rb_entry(first, struct nft_rbtree_elem, node);
 247	/* this element is closest to where the new element is to be inserted:
 248	 * update the first element for the node list path.
 249	 */
 250	if (nft_rbtree_cmp(set, rbe, first_elem) < 0)
 251		return true;
 252
 253	return false;
 254}
 255
 256/* Only for anonymous sets which do not allow updates, all element are active. */
 257static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe)
 258{
 259	struct rb_node *node;
 260
 261	node = rb_prev(&rbe->node);
 262	if (!node)
 263		return NULL;
 264
 265	return rb_entry(node, struct nft_rbtree_elem, node);
 266}
 267
 268static struct nft_rbtree_elem *
 269__nft_rbtree_next_active(struct rb_node *node, u8 genmask)
 270{
 271	struct nft_rbtree_elem *next_rbe;
 272
 273	while (node) {
 274		next_rbe = rb_entry(node, struct nft_rbtree_elem, node);
 275		if (!nft_set_elem_active(&next_rbe->ext, genmask)) {
 276			node = rb_next(node);
 277			continue;
 278		}
 279
 280		return next_rbe;
 281	}
 282
 283	return NULL;
 284}
 285
 286static struct nft_rbtree_elem *
 287nft_rbtree_next_active(struct nft_rbtree_elem *rbe, u8 genmask)
 288{
 289	return __nft_rbtree_next_active(rb_next(&rbe->node), genmask);
 290}
 291
 292static void nft_rbtree_maybe_reset_start_cookie(struct nft_rbtree *priv,
 293						u64 tstamp)
 294{
 295	if (priv->last_tstamp != tstamp) {
 296		priv->start_rbe_cookie = 0;
 297		priv->last_tstamp = tstamp;
 298	}
 299}
 300
 301static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv,
 302					const struct nft_rbtree_elem *rbe)
 303{
 304	priv->start_rbe_cookie = (unsigned long)rbe;
 305}
 306
 307static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv,
 308					const struct nft_rbtree_elem *rbe)
 309{
 310	return priv->start_rbe_cookie == (unsigned long)rbe;
 311}
 312
 313static bool nft_rbtree_insert_same_interval(const struct net *net,
 314					    struct nft_rbtree *priv,
 315					    struct nft_rbtree_elem *rbe)
 316{
 317	u8 genmask = nft_genmask_next(net);
 318	struct nft_rbtree_elem *next_rbe;
 319
 320	if (!priv->start_rbe_cookie)
 321		return true;
 322
 323	next_rbe = nft_rbtree_next_active(rbe, genmask);
 324	if (next_rbe) {
 325		/* Closest start element differs from last element added. */
 326		if (nft_rbtree_interval_start(next_rbe) &&
 327		    nft_rbtree_cmp_start_cookie(priv, next_rbe)) {
 328			priv->start_rbe_cookie = 0;
 329			return true;
 330		}
 331	}
 332
 333	priv->start_rbe_cookie = 0;
 334
 335	return false;
 336}
 337
 338static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
 339			       struct nft_rbtree_elem *new,
 340			       struct nft_elem_priv **elem_priv, u64 tstamp)
 341{
 342	struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
 343	struct rb_node *node, *next, *parent, **p, *first = NULL;
 344	struct nft_rbtree *priv = nft_set_priv(set);
 345	u8 cur_genmask = nft_genmask_cur(net);
 346	u8 genmask = nft_genmask_next(net);
 347	int d;
 348
 349	/* Descend the tree to search for an existing element greater than the
 350	 * key value to insert that is greater than the new element. This is the
 351	 * first element to walk the ordered elements to find possible overlap.
 352	 */
 353	parent = NULL;
 354	p = &priv->root.rb_node;
 355	while (*p != NULL) {
 356		parent = *p;
 357		rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 358		d = nft_rbtree_cmp(set, rbe, new);
 359
 360		if (d < 0) {
 361			p = &parent->rb_left;
 362		} else if (d > 0) {
 363			if (!first ||
 364			    nft_rbtree_update_first(set, rbe, first))
 365				first = &rbe->node;
 366
 367			p = &parent->rb_right;
 368		} else {
 369			if (nft_rbtree_interval_end(rbe))
 370				p = &parent->rb_left;
 371			else
 372				p = &parent->rb_right;
 373		}
 374	}
 375
 376	if (!first)
 377		first = rb_first(&priv->root);
 378
 379	/* Detect overlap by going through the list of valid tree nodes.
 380	 * Values stored in the tree are in reversed order, starting from
 381	 * highest to lowest value.
 382	 */
 383	for (node = first; node != NULL; node = next) {
 384		next = rb_next(node);
 385
 386		rbe = rb_entry(node, struct nft_rbtree_elem, node);
 387
 388		if (!nft_set_elem_active(&rbe->ext, genmask))
 389			continue;
 390
 391		/* perform garbage collection to avoid bogus overlap reports
 392		 * but skip new elements in this transaction.
 393		 */
 394		if (__nft_set_elem_expired(&rbe->ext, tstamp) &&
 395		    nft_set_elem_active(&rbe->ext, cur_genmask)) {
 396			const struct nft_rbtree_elem *removed_end;
 397
 398			removed_end = nft_rbtree_gc_elem(set, priv, rbe);
 399			if (IS_ERR(removed_end))
 400				return PTR_ERR(removed_end);
 401
 402			if (removed_end == rbe_le || removed_end == rbe_ge)
 403				return -EAGAIN;
 404
 405			continue;
 406		}
 407
 408		d = nft_rbtree_cmp(set, rbe, new);
 409		if (d == 0) {
 410			/* Matching end element: no need to look for an
 411			 * overlapping greater or equal element.
 412			 */
 413			if (nft_rbtree_interval_end(rbe)) {
 414				rbe_le = rbe;
 415				break;
 416			}
 417
 418			/* first element that is greater or equal to key value. */
 419			if (!rbe_ge) {
 420				rbe_ge = rbe;
 421				continue;
 422			}
 423
 424			/* this is a closer more or equal element, update it. */
 425			if (nft_rbtree_cmp(set, rbe_ge, new) != 0) {
 426				rbe_ge = rbe;
 427				continue;
 428			}
 429
 430			/* element is equal to key value, make sure flags are
 431			 * the same, an existing more or equal start element
 432			 * must not be replaced by more or equal end element.
 433			 */
 434			if ((nft_rbtree_interval_start(new) &&
 435			     nft_rbtree_interval_start(rbe_ge)) ||
 436			    (nft_rbtree_interval_end(new) &&
 437			     nft_rbtree_interval_end(rbe_ge))) {
 438				rbe_ge = rbe;
 439				continue;
 440			}
 441		} else if (d > 0) {
 442			/* annotate element greater than the new element. */
 443			rbe_ge = rbe;
 444			continue;
 445		} else if (d < 0) {
 446			/* annotate element less than the new element. */
 447			rbe_le = rbe;
 448			break;
 449		}
 450	}
 451
 452	if (nft_rbtree_interval_null(set, new))
 453		priv->start_rbe_cookie = 0;
 454	else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie)
 455		priv->start_rbe_cookie = 0;
 456
 457	/* - new start element matching existing start element: full overlap
 458	 *   reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
 459	 */
 460	if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
 461	    nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
 462		*elem_priv = &rbe_ge->priv;
 463		nft_rbtree_set_start_cookie(priv, rbe_ge);
 464		return -EEXIST;
 465	}
 466
 467	/* - new end element matching existing end element: full overlap
 468	 *   reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
 469	 */
 470	if (rbe_le && !nft_rbtree_cmp(set, new, rbe_le) &&
 471	    nft_rbtree_interval_end(rbe_le) == nft_rbtree_interval_end(new)) {
 472		/* - ignore null interval, otherwise NLM_F_CREATE bogusly
 473		 *   reports EEXIST.
 474		 */
 475		if (nft_rbtree_interval_null(set, new))
 476			return -ECANCELED;
 477
 478		*elem_priv = &rbe_le->priv;
 479
 480		/* - start and end element belong to the same interval. */
 481		if (!nft_rbtree_insert_same_interval(net, priv, rbe_le))
 482			return -ENOTEMPTY;
 483
 484		return -EEXIST;
 485	}
 486
 487	/* - new start element with existing closest, less or equal key value
 488	 *   being a start element: partial overlap, reported as -ENOTEMPTY.
 489	 *   Anonymous sets allow for two consecutive start element since they
 490	 *   are constant, but validate that this new start element does not
 491	 *   sit in between an existing start and end elements: partial overlap,
 492	 *   reported as -ENOTEMPTY.
 493	 */
 494	if (rbe_le &&
 495	    nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) {
 496		if (!nft_set_is_anonymous(set))
 497			return -ENOTEMPTY;
 498
 499		rbe_prev = nft_rbtree_prev_active(rbe_le);
 500		if (rbe_prev && nft_rbtree_interval_end(rbe_prev))
 501			return -ENOTEMPTY;
 502	}
 503
 504	/* - new end element with existing closest, less or equal key value
 505	 *   being a end element: partial overlap, reported as -ENOTEMPTY.
 506	 */
 507	if (rbe_le &&
 508	    nft_rbtree_interval_end(rbe_le) && nft_rbtree_interval_end(new))
 509		return -ENOTEMPTY;
 510
 511	/* - new end element with existing closest, greater or equal key value
 512	 *   being an end element: partial overlap, reported as -ENOTEMPTY
 513	 */
 514	if (rbe_ge &&
 515	    nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
 516		return -ENOTEMPTY;
 517
 518	/* Accepted element: pick insertion point depending on key value */
 519	parent = NULL;
 520	p = &priv->root.rb_node;
 521	while (*p != NULL) {
 522		parent = *p;
 523		rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 524		d = nft_rbtree_cmp(set, rbe, new);
 525
 526		if (d < 0)
 527			p = &parent->rb_left;
 528		else if (d > 0)
 529			p = &parent->rb_right;
 530		else if (nft_rbtree_interval_end(rbe))
 531			p = &parent->rb_left;
 532		else
 533			p = &parent->rb_right;
 534	}
 535
 536	rb_link_node_rcu(&new->node, parent, p);
 537	rb_insert_color(&new->node, &priv->root);
 538	return 0;
 539}
 540
 541static int nft_array_intervals_alloc(struct nft_array *array, u32 max_intervals)
 542{
 543	struct nft_array_interval *intervals;
 544
 545	intervals = kvcalloc(max_intervals, sizeof(struct nft_array_interval),
 546			     GFP_KERNEL_ACCOUNT);
 547	if (!intervals)
 548		return -ENOMEM;
 549
 550	if (array->intervals)
 551		kvfree(array->intervals);
 552
 553	array->intervals = intervals;
 554	array->max_intervals = max_intervals;
 555
 556	return 0;
 557}
 558
 559static struct nft_array *nft_array_alloc(u32 max_intervals)
 560{
 561	struct nft_array *array;
 562
 563	array = kzalloc(sizeof(*array), GFP_KERNEL_ACCOUNT);
 564	if (!array)
 565		return NULL;
 566
 567	if (nft_array_intervals_alloc(array, max_intervals) < 0) {
 568		kfree(array);
 569		return NULL;
 570	}
 571
 572	return array;
 573}
 574
 575/* Similar to nft_rbtree_{u,k}size to hide details to userspace, but consider
 576 * packed representation coming from userspace for anonymous sets too.
 577 */
 578static u32 nft_array_elems(const struct nft_set *set)
 579{
 580	u32 nelems = atomic_read(&set->nelems) - set->ndeact;
 581
 582	/* Adjacent intervals are represented with a single start element in
 583	 * anonymous sets, use the current element counter as is.
 584	 */
 585	if (nft_set_is_anonymous(set))
 586		return nelems;
 587
 588	/* Add extra room for never matching interval at the beginning and open
 589	 * interval at the end which only use a single element to represent it.
 590	 * The conversion to array will compact intervals, this allows reduce
 591	 * memory consumption.
 592	 */
 593	return (nelems / 2) + 2;
 594}
 595
 596#define NFT_ARRAY_INITIAL_SIZE		1024
 597#define NFT_ARRAY_INITIAL_ANON_SIZE	16
 598#define NFT_ARRAY_INITIAL_ANON_THRESH	(8192U / sizeof(struct nft_array_interval))
 599
 600static int nft_array_may_resize(const struct nft_set *set, bool flush)
 601{
 602	u32 initial_intervals, max_intervals, new_max_intervals, delta;
 603	u32 shrinked_max_intervals, nelems = nft_array_elems(set);
 604	struct nft_rbtree *priv = nft_set_priv(set);
 605	struct nft_array *array;
 606
 607	if (nft_set_is_anonymous(set))
 608		initial_intervals = NFT_ARRAY_INITIAL_ANON_SIZE;
 609	else
 610		initial_intervals = NFT_ARRAY_INITIAL_SIZE;
 611
 612	if (priv->array_next) {
 613		max_intervals = priv->array_next->max_intervals;
 614		new_max_intervals = priv->array_next->max_intervals;
 615	} else {
 616		if (priv->array) {
 617			max_intervals = priv->array->max_intervals;
 618			new_max_intervals = priv->array->max_intervals;
 619		} else {
 620			max_intervals = 0;
 621			new_max_intervals = initial_intervals;
 622		}
 623	}
 624
 625	if (nft_set_is_anonymous(set))
 626		goto maybe_grow;
 627
 628	if (flush) {
 629		/* Set flush just started, nelems still report elements.*/
 630		nelems = 0;
 631		new_max_intervals = NFT_ARRAY_INITIAL_SIZE;
 632		goto realloc_array;
 633	}
 634
 635	if (check_add_overflow(new_max_intervals, new_max_intervals,
 636			       &shrinked_max_intervals))
 637		return -EOVERFLOW;
 638
 639	shrinked_max_intervals = DIV_ROUND_UP(shrinked_max_intervals, 3);
 640
 641	if (shrinked_max_intervals > NFT_ARRAY_INITIAL_SIZE &&
 642	    nelems < shrinked_max_intervals) {
 643		new_max_intervals = shrinked_max_intervals;
 644		goto realloc_array;
 645	}
 646maybe_grow:
 647	if (nelems > new_max_intervals) {
 648		if (nft_set_is_anonymous(set) &&
 649		    new_max_intervals < NFT_ARRAY_INITIAL_ANON_THRESH) {
 650			new_max_intervals <<= 1;
 651		} else {
 652			delta = new_max_intervals >> 1;
 653			if (check_add_overflow(new_max_intervals, delta,
 654					       &new_max_intervals))
 655				return -EOVERFLOW;
 656		}
 657	}
 658
 659realloc_array:
 660	if (WARN_ON_ONCE(nelems > new_max_intervals))
 661		return -ENOMEM;
 662
 663	if (priv->array_next) {
 664		if (max_intervals == new_max_intervals)
 665			return 0;
 666
 667		if (nft_array_intervals_alloc(priv->array_next, new_max_intervals) < 0)
 668			return -ENOMEM;
 669	} else {
 670		array = nft_array_alloc(new_max_intervals);
 671		if (!array)
 672			return -ENOMEM;
 673
 674		priv->array_next = array;
 675	}
 676
 677	return 0;
 678}
 679
 680static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
 681			     const struct nft_set_elem *elem,
 682			     struct nft_elem_priv **elem_priv)
 683{
 684	struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv);
 685	struct nft_rbtree *priv = nft_set_priv(set);
 686	u64 tstamp = nft_net_tstamp(net);
 687	int err;
 688
 689	nft_rbtree_maybe_reset_start_cookie(priv, tstamp);
 690
 691	if (nft_array_may_resize(set, false) < 0)
 692		return -ENOMEM;
 693
 694	do {
 695		if (fatal_signal_pending(current))
 696			return -EINTR;
 697
 698		cond_resched();
 699
 700		write_lock_bh(&priv->lock);
 701		err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp);
 702		write_unlock_bh(&priv->lock);
 703	} while (err == -EAGAIN);
 704
 705	return err;
 706}
 707
 708static void nft_rbtree_erase(struct nft_rbtree *priv, struct nft_rbtree_elem *rbe)
 709{
 710	write_lock_bh(&priv->lock);
 711	rb_erase(&rbe->node, &priv->root);
 712	write_unlock_bh(&priv->lock);
 713}
 714
 715static void nft_rbtree_remove(const struct net *net,
 716			      const struct nft_set *set,
 717			      struct nft_elem_priv *elem_priv)
 718{
 719	struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem_priv);
 720	struct nft_rbtree *priv = nft_set_priv(set);
 721
 722	nft_rbtree_erase(priv, rbe);
 723}
 724
 725static void nft_rbtree_activate(const struct net *net,
 726				const struct nft_set *set,
 727				struct nft_elem_priv *elem_priv)
 728{
 729	struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem_priv);
 730
 731	nft_clear(net, &rbe->ext);
 732}
 733
 734static struct nft_rbtree_elem *
 735nft_rbtree_next_inactive(struct nft_rbtree_elem *rbe, u8 genmask)
 736{
 737	struct nft_rbtree_elem *next_rbe;
 738	struct rb_node *node;
 739
 740	node = rb_next(&rbe->node);
 741	if (node) {
 742		next_rbe = rb_entry(node, struct nft_rbtree_elem, node);
 743		if (nft_rbtree_interval_start(next_rbe) &&
 744		    !nft_set_elem_active(&next_rbe->ext, genmask))
 745			return next_rbe;
 746	}
 747
 748	return NULL;
 749}
 750
 751static bool nft_rbtree_deactivate_same_interval(const struct net *net,
 752						struct nft_rbtree *priv,
 753						struct nft_rbtree_elem *rbe)
 754{
 755	u8 genmask = nft_genmask_next(net);
 756	struct nft_rbtree_elem *next_rbe;
 757
 758	if (!priv->start_rbe_cookie)
 759		return true;
 760
 761	next_rbe = nft_rbtree_next_inactive(rbe, genmask);
 762	if (next_rbe) {
 763		/* Closest start element differs from last element added. */
 764		if (nft_rbtree_interval_start(next_rbe) &&
 765		    nft_rbtree_cmp_start_cookie(priv, next_rbe)) {
 766			priv->start_rbe_cookie = 0;
 767			return true;
 768		}
 769	}
 770
 771	priv->start_rbe_cookie = 0;
 772
 773	return false;
 774}
 775
 776static void nft_rbtree_flush(const struct net *net,
 777			     const struct nft_set *set,
 778			     struct nft_elem_priv *elem_priv)
 779{
 780	struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem_priv);
 781
 782	nft_set_elem_change_active(net, set, &rbe->ext);
 783}
 784
 785static struct nft_elem_priv *
 786nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
 787		      const struct nft_set_elem *elem)
 788{
 789	struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv);
 790	struct nft_rbtree *priv = nft_set_priv(set);
 791	const struct rb_node *parent = priv->root.rb_node;
 792	u8 genmask = nft_genmask_next(net);
 793	u64 tstamp = nft_net_tstamp(net);
 794	int d;
 795
 796	nft_rbtree_maybe_reset_start_cookie(priv, tstamp);
 797
 798	if (nft_rbtree_interval_start(this) ||
 799	    nft_rbtree_interval_null(set, this))
 800		priv->start_rbe_cookie = 0;
 801
 802	if (nft_array_may_resize(set, false) < 0)
 803		return NULL;
 804
 805	while (parent != NULL) {
 806		rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 807
 808		d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key.val,
 809					   set->klen);
 810		if (d < 0)
 811			parent = parent->rb_left;
 812		else if (d > 0)
 813			parent = parent->rb_right;
 814		else {
 815			if (nft_rbtree_interval_end(rbe) &&
 816			    nft_rbtree_interval_start(this)) {
 817				parent = parent->rb_left;
 818				continue;
 819			} else if (nft_rbtree_interval_start(rbe) &&
 820				   nft_rbtree_interval_end(this)) {
 821				parent = parent->rb_right;
 822				continue;
 823			} else if (__nft_set_elem_expired(&rbe->ext, tstamp)) {
 824				break;
 825			} else if (!nft_set_elem_active(&rbe->ext, genmask)) {
 826				parent = parent->rb_left;
 827				continue;
 828			}
 829
 830			if (nft_rbtree_interval_start(rbe))
 831				nft_rbtree_set_start_cookie(priv, rbe);
 832			else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
 833				return NULL;
 834
 835			nft_rbtree_flush(net, set, &rbe->priv);
 836			return &rbe->priv;
 837		}
 838	}
 839	return NULL;
 840}
 841
 842static void nft_rbtree_do_walk(const struct nft_ctx *ctx,
 843			       struct nft_set *set,
 844			       struct nft_set_iter *iter)
 845{
 846	struct nft_rbtree *priv = nft_set_priv(set);
 847	struct nft_rbtree_elem *rbe;
 848	struct rb_node *node;
 849
 850	for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
 851		rbe = rb_entry(node, struct nft_rbtree_elem, node);
 852
 853		if (iter->count < iter->skip)
 854			goto cont;
 855
 856		iter->err = iter->fn(ctx, set, iter, &rbe->priv);
 857		if (iter->err < 0)
 858			return;
 859cont:
 860		iter->count++;
 861	}
 862}
 863
 864static void nft_rbtree_walk(const struct nft_ctx *ctx,
 865			    struct nft_set *set,
 866			    struct nft_set_iter *iter)
 867{
 868	struct nft_rbtree *priv = nft_set_priv(set);
 869
 870	switch (iter->type) {
 871	case NFT_ITER_UPDATE_CLONE:
 872		if (nft_array_may_resize(set, true) < 0) {
 873			iter->err = -ENOMEM;
 874			break;
 875		}
 876		fallthrough;
 877	case NFT_ITER_UPDATE:
 878		lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex);
 879
 880		nft_rbtree_do_walk(ctx, set, iter);
 881		break;
 882	case NFT_ITER_READ:
 883		read_lock_bh(&priv->lock);
 884		nft_rbtree_do_walk(ctx, set, iter);
 885		read_unlock_bh(&priv->lock);
 886		break;
 887	default:
 888		iter->err = -EINVAL;
 889		WARN_ON_ONCE(1);
 890		break;
 891	}
 892}
 893
 894static void nft_rbtree_gc_scan(struct nft_set *set)
 895{
 896	struct nft_rbtree *priv = nft_set_priv(set);
 897	struct nft_rbtree_elem *rbe, *rbe_end = NULL;
 898	struct net *net = read_pnet(&set->net);
 899	u64 tstamp = nft_net_tstamp(net);
 900	struct rb_node *node, *next;
 901
 902	for (node = rb_first(&priv->root); node ; node = next) {
 903		next = rb_next(node);
 904
 905		rbe = rb_entry(node, struct nft_rbtree_elem, node);
 906
 907		/* elements are reversed in the rbtree for historical reasons,
 908		 * from highest to lowest value, that is why end element is
 909		 * always visited before the start element.
 910		 */
 911		if (nft_rbtree_interval_end(rbe)) {
 912			rbe_end = rbe;
 913			continue;
 914		}
 915		if (!__nft_set_elem_expired(&rbe->ext, tstamp))
 916			continue;
 917
 918		/* end element needs to be removed first, it has
 919		 * no timeout extension.
 920		 */
 921		write_lock_bh(&priv->lock);
 922		if (rbe_end) {
 923			nft_rbtree_gc_elem_move(net, set, priv, rbe_end);
 924			rbe_end = NULL;
 925		}
 926
 927		nft_rbtree_gc_elem_move(net, set, priv, rbe);
 928		write_unlock_bh(&priv->lock);
 929	}
 930
 931	priv->last_gc = jiffies;
 932}
 933
 934static void nft_rbtree_gc_queue(struct nft_set *set)
 935{
 936	struct nft_rbtree *priv = nft_set_priv(set);
 937	struct nft_rbtree_elem *rbe, *rbe_end;
 938	struct nft_trans_gc *gc;
 939
 940	if (list_empty(&priv->expired))
 941		return;
 942
 943	gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL);
 944	if (!gc)
 945		return;
 946
 947	list_for_each_entry_safe(rbe, rbe_end, &priv->expired, list) {
 948		list_del(&rbe->list);
 949		nft_trans_gc_elem_add(gc, rbe);
 950
 951		gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
 952		if (!gc)
 953			return;
 954	}
 955
 956	gc = nft_trans_gc_catchall_sync(gc);
 957	nft_trans_gc_queue_sync_done(gc);
 958}
 959
 960static u64 nft_rbtree_privsize(const struct nlattr * const nla[],
 961			       const struct nft_set_desc *desc)
 962{
 963	return sizeof(struct nft_rbtree);
 964}
 965
 966static int nft_rbtree_init(const struct nft_set *set,
 967			   const struct nft_set_desc *desc,
 968			   const struct nlattr * const nla[])
 969{
 970	struct nft_rbtree *priv = nft_set_priv(set);
 971
 972	BUILD_BUG_ON(offsetof(struct nft_rbtree_elem, priv) != 0);
 973
 974	rwlock_init(&priv->lock);
 975	priv->root = RB_ROOT;
 976	INIT_LIST_HEAD(&priv->expired);
 977
 978	priv->array = NULL;
 979	priv->array_next = NULL;
 980
 981	return 0;
 982}
 983
 984static void __nft_array_free(struct nft_array *array)
 985{
 986	kvfree(array->intervals);
 987	kfree(array);
 988}
 989
 990static void nft_rbtree_destroy(const struct nft_ctx *ctx,
 991			       const struct nft_set *set)
 992{
 993	struct nft_rbtree *priv = nft_set_priv(set);
 994	struct nft_rbtree_elem *rbe, *next;
 995	struct nft_array *array;
 996	struct rb_node *node;
 997
 998	list_for_each_entry_safe(rbe, next, &priv->expired, list) {
 999		list_del(&rbe->list);
1000		nf_tables_set_elem_destroy(ctx, set, &rbe->priv);
1001	}
1002
1003	while ((node = priv->root.rb_node) != NULL) {
1004		rb_erase(node, &priv->root);
1005		rbe = rb_entry(node, struct nft_rbtree_elem, node);
1006		nf_tables_set_elem_destroy(ctx, set, &rbe->priv);
1007	}
1008
1009	array = rcu_dereference_protected(priv->array, true);
1010	if (array)
1011		__nft_array_free(array);
1012	if (priv->array_next)
1013		__nft_array_free(priv->array_next);
1014}
1015
1016static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
1017				struct nft_set_estimate *est)
1018{
1019	if (desc->field_count > 1)
1020		return false;
1021
1022	if (desc->size)
1023		est->size = sizeof(struct nft_rbtree) +
1024			    desc->size * sizeof(struct nft_rbtree_elem);
1025	else
1026		est->size = ~0;
1027
1028	est->lookup = NFT_SET_CLASS_O_LOG_N;
1029	est->space  = NFT_SET_CLASS_O_N;
1030
1031	return true;
1032}
1033
1034static void nft_array_free_rcu(struct rcu_head *rcu_head)
1035{
1036	struct nft_array *array = container_of(rcu_head, struct nft_array, rcu_head);
1037
1038	__nft_array_free(array);
1039}
1040
1041static void nft_rbtree_commit(struct nft_set *set)
1042{
1043	struct nft_rbtree *priv = nft_set_priv(set);
1044	struct nft_rbtree_elem *rbe, *prev_rbe;
1045	struct nft_array *old;
1046	u32 num_intervals = 0;
1047	struct rb_node *node;
1048
1049	/* No changes, skip, eg. elements updates only. */
1050	if (!priv->array_next)
1051		return;
1052
1053	/* GC can be performed if the binary search blob is going
1054	 * to be rebuilt.  It has to be done in two phases: first
1055	 * scan tree and move all expired elements to the expired
1056	 * list.
1057	 *
1058	 * Then, after blob has been re-built and published to other
1059	 * CPUs, queue collected entries for freeing.
1060	 */
1061	if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
1062		nft_rbtree_gc_scan(set);
1063
1064	/* Reverse walk to create an array from smaller to largest interval. */
1065	node = rb_last(&priv->root);
1066	if (node)
1067		prev_rbe = rb_entry(node, struct nft_rbtree_elem, node);
1068	else
1069		prev_rbe = NULL;
1070
1071	while (prev_rbe) {
1072		rbe = prev_rbe;
1073
1074		if (nft_rbtree_interval_start(rbe))
1075			priv->array_next->intervals[num_intervals].from = &rbe->ext;
1076		else if (nft_rbtree_interval_end(rbe))
1077			priv->array_next->intervals[num_intervals++].to = &rbe->ext;
1078
1079		if (num_intervals >= priv->array_next->max_intervals) {
1080			pr_warn_once("malformed interval set from userspace?");
1081			goto err_out;
1082		}
1083
1084		node = rb_prev(node);
1085		if (!node)
1086			break;
1087
1088		prev_rbe = rb_entry(node, struct nft_rbtree_elem, node);
1089
1090		/* For anonymous sets, when adjacent ranges are found,
1091		 * the end element is not added to the set to pack the set
1092		 * representation. Use next start element to complete this
1093		 * interval.
1094		 */
1095		if (nft_rbtree_interval_start(rbe) &&
1096		    nft_rbtree_interval_start(prev_rbe) &&
1097		    priv->array_next->intervals[num_intervals].from)
1098			priv->array_next->intervals[num_intervals++].to = &prev_rbe->ext;
1099
1100		if (num_intervals >= priv->array_next->max_intervals) {
1101			pr_warn_once("malformed interval set from userspace?");
1102			goto err_out;
1103		}
1104	}
1105
1106	if (priv->array_next->intervals[num_intervals].from)
1107		num_intervals++;
1108err_out:
1109	priv->array_next->num_intervals = num_intervals;
1110	old = rcu_replace_pointer(priv->array, priv->array_next,
1111				  lockdep_is_held(&nft_pernet(read_pnet(&set->net))->commit_mutex));
1112	priv->array_next = NULL;
1113	if (old)
1114		call_rcu(&old->rcu_head, nft_array_free_rcu);
1115
1116	/* New blob is public, queue collected entries for freeing.
1117	 * call_rcu ensures elements stay around until readers are done.
1118	 */
1119	nft_rbtree_gc_queue(set);
1120}
1121
1122static void nft_rbtree_abort(const struct nft_set *set)
1123{
1124	struct nft_rbtree *priv = nft_set_priv(set);
1125	struct nft_array *array_next;
1126
1127	if (!priv->array_next)
1128		return;
1129
1130	array_next = priv->array_next;
1131	priv->array_next = NULL;
1132	__nft_array_free(array_next);
1133}
1134
1135static void nft_rbtree_gc_init(const struct nft_set *set)
1136{
1137	struct nft_rbtree *priv = nft_set_priv(set);
1138
1139	priv->last_gc = jiffies;
1140}
1141
1142/* rbtree stores ranges as singleton elements, each range is composed of two
1143 * elements ...
1144 */
1145static u32 nft_rbtree_ksize(u32 size)
1146{
1147	return size * 2;
1148}
1149
1150/* ... hide this detail to userspace. */
1151static u32 nft_rbtree_usize(u32 size)
1152{
1153	if (!size)
1154		return 0;
1155
1156	return size / 2;
1157}
1158
1159static u32 nft_rbtree_adjust_maxsize(const struct nft_set *set)
1160{
1161	struct nft_rbtree *priv = nft_set_priv(set);
1162	struct nft_rbtree_elem *rbe;
1163	struct rb_node *node;
1164	const void *key;
1165
1166	node = rb_last(&priv->root);
1167	if (!node)
1168		return 0;
1169
1170	rbe = rb_entry(node, struct nft_rbtree_elem, node);
1171	if (!nft_rbtree_interval_end(rbe))
1172		return 0;
1173
1174	key = nft_set_ext_key(&rbe->ext);
1175	if (memchr(key, 1, set->klen))
1176		return 0;
1177
1178	/* this is the all-zero no-match element. */
1179	return 1;
1180}
1181
1182const struct nft_set_type nft_set_rbtree_type = {
1183	.features	= NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT | NFT_SET_TIMEOUT,
1184	.ops		= {
1185		.privsize	= nft_rbtree_privsize,
1186		.elemsize	= offsetof(struct nft_rbtree_elem, ext),
1187		.estimate	= nft_rbtree_estimate,
1188		.init		= nft_rbtree_init,
1189		.destroy	= nft_rbtree_destroy,
1190		.insert		= nft_rbtree_insert,
1191		.remove		= nft_rbtree_remove,
1192		.deactivate	= nft_rbtree_deactivate,
1193		.flush		= nft_rbtree_flush,
1194		.activate	= nft_rbtree_activate,
1195		.commit		= nft_rbtree_commit,
1196		.abort		= nft_rbtree_abort,
1197		.gc_init	= nft_rbtree_gc_init,
1198		.lookup		= nft_rbtree_lookup,
1199		.walk		= nft_rbtree_walk,
1200		.get		= nft_rbtree_get,
1201		.ksize		= nft_rbtree_ksize,
1202		.usize		= nft_rbtree_usize,
1203		.adjust_maxsize = nft_rbtree_adjust_maxsize,
1204	},
1205};
~/ Read-only file preview.