net/ipv4/bpf_tcp_ca.c

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

File Facts

System
Linux kernel
Corpus path
net/ipv4/bpf_tcp_ca.c
Extension
.c
Size
9369 bytes
Lines
355
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Facebook  */

#include <linux/init.h>
#include <linux/types.h>
#include <linux/bpf_verifier.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
#include <linux/filter.h>
#include <net/tcp.h>
#include <net/bpf_sk_storage.h>

/* "extern" is to avoid sparse warning.  It is only used in bpf_struct_ops.c. */
static struct bpf_struct_ops bpf_tcp_congestion_ops;

static const struct btf_type *tcp_sock_type;
static u32 tcp_sock_id, sock_id;
static const struct btf_type *tcp_congestion_ops_type;

static int bpf_tcp_ca_init(struct btf *btf)
{
	s32 type_id;

	type_id = btf_find_by_name_kind(btf, "sock", BTF_KIND_STRUCT);
	if (type_id < 0)
		return -EINVAL;
	sock_id = type_id;

	type_id = btf_find_by_name_kind(btf, "tcp_sock", BTF_KIND_STRUCT);
	if (type_id < 0)
		return -EINVAL;
	tcp_sock_id = type_id;
	tcp_sock_type = btf_type_by_id(btf, tcp_sock_id);

	type_id = btf_find_by_name_kind(btf, "tcp_congestion_ops", BTF_KIND_STRUCT);
	if (type_id < 0)
		return -EINVAL;
	tcp_congestion_ops_type = btf_type_by_id(btf, type_id);

	return 0;
}

static bool bpf_tcp_ca_is_valid_access(int off, int size,
				       enum bpf_access_type type,
				       const struct bpf_prog *prog,
				       struct bpf_insn_access_aux *info)
{
	if (!bpf_tracing_btf_ctx_access(off, size, type, prog, info))
		return false;

	if (base_type(info->reg_type) == PTR_TO_BTF_ID &&
	    !bpf_type_has_unsafe_modifiers(info->reg_type) &&
	    info->btf_id == sock_id)
		/* promote it to tcp_sock */
		info->btf_id = tcp_sock_id;

	return true;
}

static int bpf_tcp_ca_btf_struct_access(struct bpf_verifier_log *log,
					const struct bpf_reg_state *reg,
					int off, int size)
{
	const struct btf_type *t;
	size_t end;

	t = btf_type_by_id(reg->btf, reg->btf_id);
	if (t != tcp_sock_type) {
		bpf_log(log, "only read is supported\n");
		return -EACCES;
	}

	switch (off) {
	case offsetof(struct sock, sk_pacing_rate):
		end = offsetofend(struct sock, sk_pacing_rate);
		break;
	case offsetof(struct sock, sk_pacing_status):
		end = offsetofend(struct sock, sk_pacing_status);
		break;
	case bpf_ctx_range(struct inet_connection_sock, icsk_ca_priv):
		end = offsetofend(struct inet_connection_sock, icsk_ca_priv);
		break;
	case offsetof(struct inet_connection_sock, icsk_ack.pending):
		end = offsetofend(struct inet_connection_sock,
				  icsk_ack.pending);
		break;
	case offsetof(struct tcp_sock, snd_cwnd):
		end = offsetofend(struct tcp_sock, snd_cwnd);
		break;

Annotation

Implementation Notes