net/netfilter/nf_conntrack_bpf.c

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

File Facts

System
Linux kernel
Corpus path
net/netfilter/nf_conntrack_bpf.c
Extension
.c
Size
16306 bytes
Lines
546
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

struct bpf_ct_opts {
	s32 netns_id;
	s32 error;
	u8 l4proto;
	u8 dir;
	u16 ct_zone_id;
	u8 ct_zone_dir;
	u8 reserved[3];
};

enum {
	NF_BPF_CT_OPTS_SZ = 16,
};

static int bpf_nf_ct_tuple_parse(struct bpf_sock_tuple *bpf_tuple,
				 u32 tuple_len, u8 protonum, u8 dir,
				 struct nf_conntrack_tuple *tuple)
{
	union nf_inet_addr *src = dir ? &tuple->dst.u3 : &tuple->src.u3;
	union nf_inet_addr *dst = dir ? &tuple->src.u3 : &tuple->dst.u3;
	union nf_conntrack_man_proto *sport = dir ? (void *)&tuple->dst.u
						  : &tuple->src.u;
	union nf_conntrack_man_proto *dport = dir ? &tuple->src.u
						  : (void *)&tuple->dst.u;

	if (unlikely(protonum != IPPROTO_TCP && protonum != IPPROTO_UDP))
		return -EPROTO;

	memset(tuple, 0, sizeof(*tuple));

	switch (tuple_len) {
	case sizeof(bpf_tuple->ipv4):
		tuple->src.l3num = AF_INET;
		src->ip = bpf_tuple->ipv4.saddr;
		sport->tcp.port = bpf_tuple->ipv4.sport;
		dst->ip = bpf_tuple->ipv4.daddr;
		dport->tcp.port = bpf_tuple->ipv4.dport;
		break;
	case sizeof(bpf_tuple->ipv6):
		tuple->src.l3num = AF_INET6;
		memcpy(src->ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr));
		sport->tcp.port = bpf_tuple->ipv6.sport;
		memcpy(dst->ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr));
		dport->tcp.port = bpf_tuple->ipv6.dport;
		break;
	default:
		return -EAFNOSUPPORT;
	}
	tuple->dst.protonum = protonum;
	tuple->dst.dir = dir;

	return 0;
}

static struct nf_conn *
__bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
			u32 tuple_len, struct bpf_ct_opts *opts, u32 opts_len,
			u32 timeout)
{
	struct nf_conntrack_tuple otuple, rtuple;
	struct nf_conntrack_zone ct_zone;
	struct nf_conn *ct;
	int err;

	if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
		return ERR_PTR(-EINVAL);
	if (opts_len == NF_BPF_CT_OPTS_SZ) {
		if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
			return ERR_PTR(-EINVAL);
	} else {
		if (opts->ct_zone_id)
			return ERR_PTR(-EINVAL);
	}

	if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
		return ERR_PTR(-EINVAL);

	err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
				    IP_CT_DIR_ORIGINAL, &otuple);
	if (err < 0)
		return ERR_PTR(err);

	err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
				    IP_CT_DIR_REPLY, &rtuple);
	if (err < 0)
		return ERR_PTR(err);

	if (opts->netns_id >= 0) {
		net = get_net_ns_by_id(net, opts->netns_id);
		if (unlikely(!net))

Annotation

Implementation Notes