net/netfilter/nft_lookup.c

Source file repositories/reference/linux-study-clean/net/netfilter/nft_lookup.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nft_lookup.c
Extension
.c
Size
7510 bytes
Lines
288
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct nft_lookup {
	struct nft_set			*set;
	u8				sreg;
	u8				dreg;
	bool				dreg_set;
	bool				invert;
	struct nft_set_binding		binding;
};

static const struct nft_set_ext *
__nft_set_do_lookup(const struct net *net, const struct nft_set *set,
		    const u32 *key)
{
#ifdef CONFIG_MITIGATION_RETPOLINE
	if (set->ops == &nft_set_hash_fast_type.ops)
		return nft_hash_lookup_fast(net, set, key);
	if (set->ops == &nft_set_hash_type.ops)
		return nft_hash_lookup(net, set, key);

	if (set->ops == &nft_set_rhash_type.ops)
		return nft_rhash_lookup(net, set, key);

	if (set->ops == &nft_set_bitmap_type.ops)
		return nft_bitmap_lookup(net, set, key);

	if (set->ops == &nft_set_pipapo_type.ops)
		return nft_pipapo_lookup(net, set, key);
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
	if (set->ops == &nft_set_pipapo_avx2_type.ops)
		return nft_pipapo_avx2_lookup(net, set, key);
#endif

	if (set->ops == &nft_set_rbtree_type.ops)
		return nft_rbtree_lookup(net, set, key);

	DEBUG_NET_WARN_ON_ONCE(1);
#endif
	return set->ops->lookup(net, set, key);
}

static unsigned int nft_base_seq(const struct net *net)
{
	/* pairs with smp_store_release() in nf_tables_commit() */
	return smp_load_acquire(&net->nft.base_seq);
}

static bool nft_lookup_should_retry(const struct net *net, unsigned int seq)
{
	return unlikely(seq != nft_base_seq(net));
}

const struct nft_set_ext *
nft_set_do_lookup(const struct net *net, const struct nft_set *set,
		  const u32 *key)
{
	const struct nft_set_ext *ext;
	unsigned int base_seq;

	do {
		base_seq = nft_base_seq(net);

		ext = __nft_set_do_lookup(net, set, key);
		if (ext)
			break;
		/* No match?  There is a small chance that lookup was
		 * performed in the old generation, but nf_tables_commit()
		 * already unlinked a (matching) element.
		 *
		 * We need to repeat the lookup to make sure that we didn't
		 * miss a matching element in the new generation.
		 */
	} while (nft_lookup_should_retry(net, base_seq));

	return ext;
}
EXPORT_SYMBOL_GPL(nft_set_do_lookup);

void nft_lookup_eval(const struct nft_expr *expr,
		     struct nft_regs *regs,
		     const struct nft_pktinfo *pkt)
{
	const struct nft_lookup *priv = nft_expr_priv(expr);
	const struct nft_set *set = priv->set;
	const struct net *net = nft_net(pkt);
	const struct nft_set_ext *ext;
	bool found;

	ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]);
	found = !!ext ^ priv->invert;
	if (!found) {

Annotation

Implementation Notes