Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2019 Facebook */
  3
  4#include <linux/bpf.h>
  5#include <netinet/in.h>
  6#include <stdbool.h>
  7
  8#include <bpf/bpf_helpers.h>
  9#include <bpf/bpf_endian.h>
 10
 11enum bpf_addr_array_idx {
 12	ADDR_SRV_IDX,
 13	ADDR_CLI_IDX,
 14	__NR_BPF_ADDR_ARRAY_IDX,
 15};
 16
 17enum bpf_result_array_idx {
 18	EGRESS_SRV_IDX,
 19	EGRESS_CLI_IDX,
 20	INGRESS_LISTEN_IDX,
 21	__NR_BPF_RESULT_ARRAY_IDX,
 22};
 23
 24enum bpf_linum_array_idx {
 25	EGRESS_LINUM_IDX,
 26	INGRESS_LINUM_IDX,
 27	__NR_BPF_LINUM_ARRAY_IDX,
 28};
 29
 30struct {
 31	__uint(type, BPF_MAP_TYPE_ARRAY);
 32	__uint(max_entries, __NR_BPF_ADDR_ARRAY_IDX);
 33	__type(key, __u32);
 34	__type(value, struct sockaddr_in6);
 35} addr_map SEC(".maps");
 36
 37struct {
 38	__uint(type, BPF_MAP_TYPE_ARRAY);
 39	__uint(max_entries, __NR_BPF_RESULT_ARRAY_IDX);
 40	__type(key, __u32);
 41	__type(value, struct bpf_sock);
 42} sock_result_map SEC(".maps");
 43
 44struct {
 45	__uint(type, BPF_MAP_TYPE_ARRAY);
 46	__uint(max_entries, __NR_BPF_RESULT_ARRAY_IDX);
 47	__type(key, __u32);
 48	__type(value, struct bpf_tcp_sock);
 49} tcp_sock_result_map SEC(".maps");
 50
 51struct {
 52	__uint(type, BPF_MAP_TYPE_ARRAY);
 53	__uint(max_entries, __NR_BPF_LINUM_ARRAY_IDX);
 54	__type(key, __u32);
 55	__type(value, __u32);
 56} linum_map SEC(".maps");
 57
 58struct bpf_spinlock_cnt {
 59	struct bpf_spin_lock lock;
 60	__u32 cnt;
 61};
 62
 63struct {
 64	__uint(type, BPF_MAP_TYPE_SK_STORAGE);
 65	__uint(map_flags, BPF_F_NO_PREALLOC);
 66	__type(key, int);
 67	__type(value, struct bpf_spinlock_cnt);
 68} sk_pkt_out_cnt SEC(".maps");
 69
 70struct {
 71	__uint(type, BPF_MAP_TYPE_SK_STORAGE);
 72	__uint(map_flags, BPF_F_NO_PREALLOC);
 73	__type(key, int);
 74	__type(value, struct bpf_spinlock_cnt);
 75} sk_pkt_out_cnt10 SEC(".maps");
 76
 77static bool is_loopback6(__u32 *a6)
 78{
 79	return !a6[0] && !a6[1] && !a6[2] && a6[3] == bpf_htonl(1);
 80}
 81
 82static void skcpy(struct bpf_sock *dst,
 83		  const struct bpf_sock *src)
 84{
 85	dst->bound_dev_if = src->bound_dev_if;
 86	dst->family = src->family;
 87	dst->type = src->type;
 88	dst->protocol = src->protocol;
 89	dst->mark = src->mark;
 90	dst->priority = src->priority;
 91	dst->src_ip4 = src->src_ip4;
 92	dst->src_ip6[0] = src->src_ip6[0];
 93	dst->src_ip6[1] = src->src_ip6[1];
 94	dst->src_ip6[2] = src->src_ip6[2];
 95	dst->src_ip6[3] = src->src_ip6[3];
 96	dst->src_port = src->src_port;
 97	dst->dst_ip4 = src->dst_ip4;
 98	dst->dst_ip6[0] = src->dst_ip6[0];
 99	dst->dst_ip6[1] = src->dst_ip6[1];
100	dst->dst_ip6[2] = src->dst_ip6[2];
101	dst->dst_ip6[3] = src->dst_ip6[3];
102	dst->dst_port = src->dst_port;
103	dst->state = src->state;
104}
105
106static void tpcpy(struct bpf_tcp_sock *dst,
107		  const struct bpf_tcp_sock *src)
108{
109	dst->snd_cwnd = src->snd_cwnd;
110	dst->srtt_us = src->srtt_us;
111	dst->rtt_min = src->rtt_min;
112	dst->snd_ssthresh = src->snd_ssthresh;
113	dst->rcv_nxt = src->rcv_nxt;
114	dst->snd_nxt = src->snd_nxt;
115	dst->snd_una = src->snd_una;
116	dst->mss_cache = src->mss_cache;
117	dst->ecn_flags = src->ecn_flags;
118	dst->rate_delivered = src->rate_delivered;
119	dst->rate_interval_us = src->rate_interval_us;
120	dst->packets_out = src->packets_out;
121	dst->retrans_out = src->retrans_out;
122	dst->total_retrans = src->total_retrans;
123	dst->segs_in = src->segs_in;
124	dst->data_segs_in = src->data_segs_in;
125	dst->segs_out = src->segs_out;
126	dst->data_segs_out = src->data_segs_out;
127	dst->lost_out = src->lost_out;
128	dst->sacked_out = src->sacked_out;
129	dst->bytes_received = src->bytes_received;
130	dst->bytes_acked = src->bytes_acked;
131}
132
133#define RETURN {						\
134	linum = __LINE__;					\
135	bpf_map_update_elem(&linum_map, &linum_idx, &linum, 0);	\
136	return 1;						\
137}
138
139SEC("cgroup_skb/egress")
140int egress_read_sock_fields(struct __sk_buff *skb)
141{
142	struct bpf_spinlock_cnt cli_cnt_init = { .lock = 0, .cnt = 0xeB9F };
143	__u32 srv_idx = ADDR_SRV_IDX, cli_idx = ADDR_CLI_IDX, result_idx;
144	struct bpf_spinlock_cnt *pkt_out_cnt, *pkt_out_cnt10;
145	struct sockaddr_in6 *srv_sa6, *cli_sa6;
146	struct bpf_tcp_sock *tp, *tp_ret;
147	struct bpf_sock *sk, *sk_ret;
148	__u32 linum, linum_idx;
149
150	linum_idx = EGRESS_LINUM_IDX;
151
152	sk = skb->sk;
153	if (!sk || sk->state == 10)
154		RETURN;
155
156	sk = bpf_sk_fullsock(sk);
157	if (!sk || sk->family != AF_INET6 || sk->protocol != IPPROTO_TCP ||
158	    !is_loopback6(sk->src_ip6))
159		RETURN;
160
161	tp = bpf_tcp_sock(sk);
162	if (!tp)
163		RETURN;
164
165	srv_sa6 = bpf_map_lookup_elem(&addr_map, &srv_idx);
166	cli_sa6 = bpf_map_lookup_elem(&addr_map, &cli_idx);
167	if (!srv_sa6 || !cli_sa6)
168		RETURN;
169
170	if (sk->src_port == bpf_ntohs(srv_sa6->sin6_port))
171		result_idx = EGRESS_SRV_IDX;
172	else if (sk->src_port == bpf_ntohs(cli_sa6->sin6_port))
173		result_idx = EGRESS_CLI_IDX;
174	else
175		RETURN;
176
177	sk_ret = bpf_map_lookup_elem(&sock_result_map, &result_idx);
178	tp_ret = bpf_map_lookup_elem(&tcp_sock_result_map, &result_idx);
179	if (!sk_ret || !tp_ret)
180		RETURN;
181
182	skcpy(sk_ret, sk);
183	tpcpy(tp_ret, tp);
184
185	if (result_idx == EGRESS_SRV_IDX) {
186		/* The userspace has created it for srv sk */
187		pkt_out_cnt = bpf_sk_storage_get(&sk_pkt_out_cnt, sk, 0, 0);
188		pkt_out_cnt10 = bpf_sk_storage_get(&sk_pkt_out_cnt10, sk,
189						   0, 0);
190	} else {
191		pkt_out_cnt = bpf_sk_storage_get(&sk_pkt_out_cnt, sk,
192						 &cli_cnt_init,
193						 BPF_SK_STORAGE_GET_F_CREATE);
194		pkt_out_cnt10 = bpf_sk_storage_get(&sk_pkt_out_cnt10,
195						   sk, &cli_cnt_init,
196						   BPF_SK_STORAGE_GET_F_CREATE);
197	}
198
199	if (!pkt_out_cnt || !pkt_out_cnt10)
200		RETURN;
201
202	/* Even both cnt and cnt10 have lock defined in their BTF,
203	 * intentionally one cnt takes lock while one does not
204	 * as a test for the spinlock support in BPF_MAP_TYPE_SK_STORAGE.
205	 */
206	pkt_out_cnt->cnt += 1;
207	bpf_spin_lock(&pkt_out_cnt10->lock);
208	pkt_out_cnt10->cnt += 10;
209	bpf_spin_unlock(&pkt_out_cnt10->lock);
210
211	RETURN;
212}
213
214SEC("cgroup_skb/ingress")
215int ingress_read_sock_fields(struct __sk_buff *skb)
216{
217	__u32 srv_idx = ADDR_SRV_IDX, result_idx = INGRESS_LISTEN_IDX;
218	struct bpf_tcp_sock *tp, *tp_ret;
219	struct bpf_sock *sk, *sk_ret;
220	struct sockaddr_in6 *srv_sa6;
221	__u32 linum, linum_idx;
222
223	linum_idx = INGRESS_LINUM_IDX;
224
225	sk = skb->sk;
226	if (!sk || sk->family != AF_INET6 || !is_loopback6(sk->src_ip6))
227		RETURN;
228
229	srv_sa6 = bpf_map_lookup_elem(&addr_map, &srv_idx);
230	if (!srv_sa6 || sk->src_port != bpf_ntohs(srv_sa6->sin6_port))
231		RETURN;
232
233	if (sk->state != 10 && sk->state != 12)
234		RETURN;
235
236	sk = bpf_get_listener_sock(sk);
237	if (!sk)
238		RETURN;
239
240	tp = bpf_tcp_sock(sk);
241	if (!tp)
242		RETURN;
243
244	sk_ret = bpf_map_lookup_elem(&sock_result_map, &result_idx);
245	tp_ret = bpf_map_lookup_elem(&tcp_sock_result_map, &result_idx);
246	if (!sk_ret || !tp_ret)
247		RETURN;
248
249	skcpy(sk_ret, sk);
250	tpcpy(tp_ret, tp);
251
252	RETURN;
253}
254
255char _license[] SEC("license") = "GPL";