brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 5eb25c6 Raw
185 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2018 Facebook */3 4#include <stdlib.h>5#include <linux/in.h>6#include <linux/ip.h>7#include <linux/ipv6.h>8#include <linux/tcp.h>9#include <linux/udp.h>10#include <linux/bpf.h>11#include <linux/types.h>12#include <linux/if_ether.h>13 14#include <bpf/bpf_endian.h>15#include <bpf/bpf_helpers.h>16#include "test_select_reuseport_common.h"17 18#ifndef offsetof19#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)20#endif21 22struct {23	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);24	__uint(max_entries, 1);25	__type(key, __u32);26	__type(value, __u32);27} outer_map SEC(".maps");28 29struct {30	__uint(type, BPF_MAP_TYPE_ARRAY);31	__uint(max_entries, NR_RESULTS);32	__type(key, __u32);33	__type(value, __u32);34} result_map SEC(".maps");35 36struct {37	__uint(type, BPF_MAP_TYPE_ARRAY);38	__uint(max_entries, 1);39	__type(key, __u32);40	__type(value, int);41} tmp_index_ovr_map SEC(".maps");42 43struct {44	__uint(type, BPF_MAP_TYPE_ARRAY);45	__uint(max_entries, 1);46	__type(key, __u32);47	__type(value, __u32);48} linum_map SEC(".maps");49 50struct {51	__uint(type, BPF_MAP_TYPE_ARRAY);52	__uint(max_entries, 1);53	__type(key, __u32);54	__type(value, struct data_check);55} data_check_map SEC(".maps");56 57#define GOTO_DONE(_result) ({			\58	result = (_result);			\59	linum = __LINE__;			\60	goto done;				\61})62 63SEC("sk_reuseport")64int _select_by_skb_data(struct sk_reuseport_md *reuse_md)65{66	__u32 linum, index = 0, flags = 0, index_zero = 0;67	__u32 *result_cnt;68	struct data_check data_check = {};69	struct cmd *cmd, cmd_copy;70	void *data, *data_end;71	void *reuseport_array;72	enum result result;73	int *index_ovr;74	int err;75 76	data = reuse_md->data;77	data_end = reuse_md->data_end;78	data_check.len = reuse_md->len;79	data_check.eth_protocol = reuse_md->eth_protocol;80	data_check.ip_protocol = reuse_md->ip_protocol;81	data_check.hash = reuse_md->hash;82	data_check.bind_inany = reuse_md->bind_inany;83	if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) {84		if (bpf_skb_load_bytes_relative(reuse_md,85						offsetof(struct iphdr, saddr),86						data_check.skb_addrs, 8,87						BPF_HDR_START_NET))88			GOTO_DONE(DROP_MISC);89	} else {90		if (bpf_skb_load_bytes_relative(reuse_md,91						offsetof(struct ipv6hdr, saddr),92						data_check.skb_addrs, 32,93						BPF_HDR_START_NET))94			GOTO_DONE(DROP_MISC);95	}96 97	/*98	 * The ip_protocol could be a compile time decision99	 * if the bpf_prog.o is dedicated to either TCP or100	 * UDP.101	 *102	 * Otherwise, reuse_md->ip_protocol or103	 * the protocol field in the iphdr can be used.104	 */105	if (data_check.ip_protocol == IPPROTO_TCP) {106		struct tcphdr *th = data;107 108		if (th + 1 > data_end)109			GOTO_DONE(DROP_MISC);110 111		data_check.skb_ports[0] = th->source;112		data_check.skb_ports[1] = th->dest;113 114		if (th->fin)115			/* The connection is being torn down at the end of a116			 * test. It can't contain a cmd, so return early.117			 */118			return SK_PASS;119 120		if ((th->doff << 2) + sizeof(*cmd) > data_check.len)121			GOTO_DONE(DROP_ERR_SKB_DATA);122		if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,123				       sizeof(cmd_copy)))124			GOTO_DONE(DROP_MISC);125		cmd = &cmd_copy;126	} else if (data_check.ip_protocol == IPPROTO_UDP) {127		struct udphdr *uh = data;128 129		if (uh + 1 > data_end)130			GOTO_DONE(DROP_MISC);131 132		data_check.skb_ports[0] = uh->source;133		data_check.skb_ports[1] = uh->dest;134 135		if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len)136			GOTO_DONE(DROP_ERR_SKB_DATA);137		if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) {138			if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr),139					       &cmd_copy, sizeof(cmd_copy)))140				GOTO_DONE(DROP_MISC);141			cmd = &cmd_copy;142		} else {143			cmd = data + sizeof(struct udphdr);144		}145	} else {146		GOTO_DONE(DROP_MISC);147	}148 149	reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero);150	if (!reuseport_array)151		GOTO_DONE(DROP_ERR_INNER_MAP);152 153	index = cmd->reuseport_index;154	index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero);155	if (!index_ovr)156		GOTO_DONE(DROP_MISC);157 158	if (*index_ovr != -1) {159		index = *index_ovr;160		*index_ovr = -1;161	}162	err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index,163				      flags);164	if (!err)165		GOTO_DONE(PASS);166 167	if (cmd->pass_on_failure)168		GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT);169	else170		GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT);171 172done:173	result_cnt = bpf_map_lookup_elem(&result_map, &result);174	if (!result_cnt)175		return SK_DROP;176 177	bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY);178	bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY);179 180	(*result_cnt)++;181	return result < PASS ? SK_DROP : SK_PASS;182}183 184char _license[] SEC("license") = "GPL";185