Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 976afca1 authored by Yi-Hung Wei's avatar Yi-Hung Wei Committed by Pablo Neira Ayuso
Browse files

netfilter: nf_conncount: Early exit in nf_conncount_lookup() and cleanup



This patch is originally from Florian Westphal.

This patch does the following three tasks.

It applies the same early exit technique for nf_conncount_lookup().

Since now we keep the number of connections in 'struct nf_conncount_list',
we no longer need to return the count in nf_conncount_lookup().

Moreover, we expose the garbage collection function nf_conncount_gc_list()
for nft_connlimit.

Signed-off-by: default avatarYi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent cb2b36f5
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ unsigned int nf_conncount_count(struct net *net,
				const struct nf_conntrack_tuple *tuple,
				const struct nf_conntrack_zone *zone);

unsigned int nf_conncount_lookup(struct net *net, struct nf_conncount_list *list,
void nf_conncount_lookup(struct net *net, struct nf_conncount_list *list,
			 const struct nf_conntrack_tuple *tuple,
			 const struct nf_conntrack_zone *zone,
			 bool *addit);
@@ -32,6 +32,9 @@ bool nf_conncount_add(struct nf_conncount_list *list,
		      const struct nf_conntrack_tuple *tuple,
		      const struct nf_conntrack_zone *zone);

void nf_conncount_gc_list(struct net *net,
			  struct nf_conncount_list *list);

void nf_conncount_cache_free(struct nf_conncount_list *list);

#endif
+21 −17
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ find_or_evict(struct net *net, struct nf_conncount_list *list,
	return ERR_PTR(-EAGAIN);
}

unsigned int nf_conncount_lookup(struct net *net,
void nf_conncount_lookup(struct net *net,
			 struct nf_conncount_list *list,
			 const struct nf_conntrack_tuple *tuple,
			 const struct nf_conntrack_zone *zone,
@@ -153,17 +153,20 @@ unsigned int nf_conncount_lookup(struct net *net,
	const struct nf_conntrack_tuple_hash *found;
	struct nf_conncount_tuple *conn, *conn_n;
	struct nf_conn *found_ct;
	unsigned int length = 0;
	unsigned int collect = 0;

	/* best effort only */
	*addit = tuple ? true : false;

	/* check the saved connections */
	list_for_each_entry_safe(conn, conn_n, &list->head, node) {
		if (collect > CONNCOUNT_GC_MAX_NODES)
			break;

		found = find_or_evict(net, list, conn);
		if (IS_ERR(found)) {
			/* Not found, but might be about to be confirmed */
			if (PTR_ERR(found) == -EAGAIN) {
				length++;
				if (!tuple)
					continue;

@@ -171,8 +174,8 @@ unsigned int nf_conncount_lookup(struct net *net,
				    nf_ct_zone_id(&conn->zone, conn->zone.dir) ==
				    nf_ct_zone_id(zone, zone->dir))
					*addit = false;
			}

			} else if (PTR_ERR(found) == -ENOENT)
				collect++;
			continue;
		}

@@ -181,9 +184,10 @@ unsigned int nf_conncount_lookup(struct net *net,
		if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) &&
		    nf_ct_zone_equal(found_ct, zone, zone->dir)) {
			/*
			 * Just to be sure we have it only once in the list.
			 * We should not see tuples twice unless someone hooks
			 * this into a table without "-p tcp --syn".
			 *
			 * Attempt to avoid a re-add in this case.
			 */
			*addit = false;
		} else if (already_closed(found_ct)) {
@@ -193,14 +197,12 @@ unsigned int nf_conncount_lookup(struct net *net,
			 */
			nf_ct_put(found_ct);
			conn_free(list, conn);
			collect++;
			continue;
		}

		nf_ct_put(found_ct);
		length++;
	}

	return length;
}
EXPORT_SYMBOL_GPL(nf_conncount_lookup);

@@ -211,7 +213,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list)
}
EXPORT_SYMBOL_GPL(nf_conncount_list_init);

static void nf_conncount_gc_list(struct net *net,
void nf_conncount_gc_list(struct net *net,
			  struct nf_conncount_list *list)
{
	const struct nf_conntrack_tuple_hash *found;
@@ -244,6 +246,7 @@ static void nf_conncount_gc_list(struct net *net,
			return;
	}
}
EXPORT_SYMBOL_GPL(nf_conncount_gc_list);

static void tree_nodes_free(struct rb_root *root,
			    struct nf_conncount_rb *gc_nodes[],
@@ -291,8 +294,9 @@ count_tree(struct net *net, struct rb_root *root,
			/* same source network -> be counted! */
			unsigned int count;

			count = nf_conncount_lookup(net, &rbconn->list, tuple,
						    zone, &addit);
			nf_conncount_lookup(net, &rbconn->list, tuple, zone,
					    &addit);
			count = rbconn->list.count;

			tree_nodes_free(root, gc_nodes, gc_count);
			if (!addit)
+5 −4
Original line number Diff line number Diff line
@@ -46,8 +46,9 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
	}

	spin_lock_bh(&priv->lock);
	count = nf_conncount_lookup(nft_net(pkt), &priv->list, tuple_ptr, zone,
	nf_conncount_lookup(nft_net(pkt), &priv->list, tuple_ptr, zone,
			    &addit);
	count = priv->list.count;

	if (!addit)
		goto out;
@@ -231,10 +232,10 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx,
static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr)
{
	struct nft_connlimit *priv = nft_expr_priv(expr);
	bool addit, ret;
	bool ret;

	spin_lock_bh(&priv->lock);
	nf_conncount_lookup(net, &priv->list, NULL, &nf_ct_zone_dflt, &addit);
	nf_conncount_gc_list(net, &priv->list);

	ret = list_empty(&priv->list.head);
	spin_unlock_bh(&priv->lock);