net/xfrm/xfrm_state.c

Source file repositories/reference/linux-study-clean/net/xfrm/xfrm_state.c

File Facts

System
Linux kernel
Corpus path
net/xfrm/xfrm_state.c
Extension
.c
Size
88509 bytes
Lines
3559
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 xfrm_hash_state_ptrs {
	const struct hlist_head *bydst;
	const struct hlist_head *bysrc;
	const struct hlist_head *byspi;
	unsigned int hmask;
};

static void xfrm_hash_ptrs_get(const struct net *net, struct xfrm_hash_state_ptrs *ptrs)
{
	unsigned int sequence;

	do {
		sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);

		ptrs->bydst = xfrm_state_deref_check(net->xfrm.state_bydst, net);
		ptrs->bysrc = xfrm_state_deref_check(net->xfrm.state_bysrc, net);
		ptrs->byspi = xfrm_state_deref_check(net->xfrm.state_byspi, net);
		ptrs->hmask = net->xfrm.state_hmask;
	} while (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence));
}

static struct xfrm_state *__xfrm_state_lookup_all(const struct xfrm_hash_state_ptrs *state_ptrs,
						  u32 mark,
						  const xfrm_address_t *daddr,
						  __be32 spi, u8 proto,
						  unsigned short family,
						  struct xfrm_dev_offload *xdo)
{
	unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask);
	struct xfrm_state *x;

	hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) {
#ifdef CONFIG_XFRM_OFFLOAD
		if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) {
			if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
				/* HW states are in the head of list, there is
				 * no need to iterate further.
				 */
				break;

			/* Packet offload: both policy and SA should
			 * have same device.
			 */
			if (xdo->dev != x->xso.dev)
				continue;
		} else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
			/* Skip HW policy for SW lookups */
			continue;
#endif
		if (x->props.family != family ||
		    x->id.spi       != spi ||
		    x->id.proto     != proto ||
		    !xfrm_addr_equal(&x->id.daddr, daddr, family))
			continue;

		if ((mark & x->mark.m) != x->mark.v)
			continue;
		if (!xfrm_state_hold_rcu(x))
			continue;
		return x;
	}

	return NULL;
}

static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs *state_ptrs,
					      u32 mark,
					      const xfrm_address_t *daddr,
					      __be32 spi, u8 proto,
					      unsigned short family)
{
	unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask);
	struct xfrm_state *x;

	hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) {
		if (x->props.family != family ||
		    x->id.spi       != spi ||
		    x->id.proto     != proto ||
		    !xfrm_addr_equal(&x->id.daddr, daddr, family))
			continue;

		if ((mark & x->mark.m) != x->mark.v)
			continue;
		if (!xfrm_state_hold_rcu(x))
			continue;
		return x;
	}

	return NULL;
}

Annotation

Implementation Notes