net/ipv4/udp_bpf.c

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

File Facts

System
Linux kernel
Corpus path
net/ipv4/udp_bpf.c
Extension
.c
Size
4197 bytes
Lines
180
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

if (data) {
			if (psock_has_data(psock))
				goto msg_bytes_ready;

			release_sock(sk);

			ret = sk_udp_recvmsg(sk, msg, len, flags);
			goto out;
		}
		copied = -EAGAIN;
	}

	release_sock(sk);

	ret = copied;
out:
	sk_psock_put(sk, psock);
	return ret;
}

enum {
	UDP_BPF_IPV4,
	UDP_BPF_IPV6,
	UDP_BPF_NUM_PROTS,
};

static DEFINE_SPINLOCK(udpv6_prot_lock);
static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS];

static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
{
	if (cmd != SIOCINQ)
		return udp_ioctl(sk, cmd, karg);

	/* Since we don't hold a lock, sk_receive_queue may contain data.
	 * BPF might only be processing this data at the moment. We only
	 * care about the data in the ingress_msg here.
	 */
	*karg = sk_msg_first_len(sk);
	return 0;
}

static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base)
{
	*prot			= *base;
	prot->close		= sock_map_close;
	prot->recvmsg		= udp_bpf_recvmsg;
	prot->sock_is_readable	= sk_msg_is_readable;
	prot->ioctl		= udp_bpf_ioctl;
}

static void udp_bpf_check_v6_needs_rebuild(struct proto *ops)
{
	if (unlikely(ops != smp_load_acquire(&udpv6_prot_saved))) {
		spin_lock_bh(&udpv6_prot_lock);
		if (likely(ops != udpv6_prot_saved)) {
			udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV6], ops);
			smp_store_release(&udpv6_prot_saved, ops);
		}
		spin_unlock_bh(&udpv6_prot_lock);
	}
}

static int __init udp_bpf_v4_build_proto(void)
{
	udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV4], &udp_prot);
	return 0;
}
late_initcall(udp_bpf_v4_build_proto);

int udp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
{
	int family = sk->sk_family == AF_INET ? UDP_BPF_IPV4 : UDP_BPF_IPV6;

	if (restore) {
		WRITE_ONCE(sk->sk_write_space, psock->saved_write_space);
		sock_replace_proto(sk, psock->sk_proto);
		return 0;
	}

	if (sk->sk_family == AF_INET6)
		udp_bpf_check_v6_needs_rebuild(psock->sk_proto);

	sock_replace_proto(sk, &udp_bpf_prots[family]);
	return 0;
}
EXPORT_SYMBOL_GPL(udp_bpf_update_proto);

Annotation

Implementation Notes