net/ipv4/inet_hashtables.c

Source file repositories/reference/linux-study-clean/net/ipv4/inet_hashtables.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/inet_hashtables.c
Extension
.c
Size
36884 bytes
Lines
1392
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

inet_bind_bucket_for_each(tb, &head->chain) {
			if (inet_bind_bucket_match(tb, net, port, l3mdev))
				break;
		}
		if (!tb) {
			tb = inet_bind_bucket_create(table->bind_bucket_cachep,
						     net, head, port, l3mdev);
			if (!tb) {
				spin_unlock(&head2->lock);
				spin_unlock(&head->lock);
				return -ENOMEM;
			}
			created_inet_bind_bucket = true;
		}
		update_fastreuse = true;

		goto bhash2_find;
	} else if (!inet_bind2_bucket_addr_match(tb2, child)) {
		l3mdev = inet_sk_bound_l3mdev(sk);

bhash2_find:
		tb2 = inet_bind2_bucket_find(head2, net, port, l3mdev, child);
		if (!tb2) {
			tb2 = inet_bind2_bucket_create(table->bind2_bucket_cachep,
						       net, head2, tb, child);
			if (!tb2)
				goto error;
		}
	}
	if (update_fastreuse)
		inet_csk_update_fastreuse(child, tb, tb2);
	inet_bind_hash(child, tb, tb2, port);
	spin_unlock(&head2->lock);
	spin_unlock(&head->lock);

	return 0;

error:
	if (created_inet_bind_bucket)
		inet_bind_bucket_destroy(tb);
	spin_unlock(&head2->lock);
	spin_unlock(&head->lock);
	return -ENOMEM;
}

static struct inet_listen_hashbucket *
inet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk)
{
	u32 hash;

#if IS_ENABLED(CONFIG_IPV6)
	if (sk->sk_family == AF_INET6)
		hash = ipv6_portaddr_hash(sock_net(sk),
					  &sk->sk_v6_rcv_saddr,
					  inet_sk(sk)->inet_num);
	else
#endif
		hash = ipv4_portaddr_hash(sock_net(sk),
					  inet_sk(sk)->inet_rcv_saddr,
					  inet_sk(sk)->inet_num);
	return inet_lhash2_bucket(h, hash);
}

static inline int compute_score(struct sock *sk, const struct net *net,
				const unsigned short hnum, const __be32 daddr,
				const int dif, const int sdif)
{
	int score = -1;

	if (net_eq(sock_net(sk), net) && READ_ONCE(sk->sk_num) == hnum &&
			!ipv6_only_sock(sk)) {
		if (sk->sk_rcv_saddr != daddr)
			return -1;

		if (!inet_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
			return -1;
		score =  sk->sk_bound_dev_if ? 2 : 1;

		if (sk->sk_family == PF_INET)
			score++;
		if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
			score++;
	}
	return score;
}

/**
 * inet_lookup_reuseport() - execute reuseport logic on AF_INET socket if necessary.
 * @net: network namespace.
 * @sk: AF_INET socket, must be in TCP_LISTEN state for TCP or TCP_CLOSE for UDP.

Annotation

Implementation Notes