Commit 4a0614e1 authored by Jordan Rife's avatar Jordan Rife Committed by Martin KaFai Lau
Browse files

selftests/bpf: Return socket cookies from sock_iter_batch progs



Extend the iter_udp_soreuse and iter_tcp_soreuse programs to write the
cookie of the current socket, so that we can track the identity of the
sockets that the iterator has seen so far. Update the existing do_test
function to account for this change to the iterator program output. At
the same time, teach both programs to work with AF_INET as well.

Signed-off-by: default avatarJordan Rife <jordan@jrife.io>
Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent 5668f73f
Loading
Loading
Loading
Loading
+20 −13
Original line number Diff line number Diff line
@@ -9,12 +9,18 @@

static const int nr_soreuse = 4;

struct iter_out {
	int idx;
	__u64 cookie;
} __packed;

static void do_test(int sock_type, bool onebyone)
{
	int err, i, nread, to_read, total_read, iter_fd = -1;
	int first_idx, second_idx, indices[nr_soreuse];
	struct iter_out outputs[nr_soreuse];
	struct bpf_link *link = NULL;
	struct sock_iter_batch *skel;
	int first_idx, second_idx;
	int *fds[2] = {};

	skel = sock_iter_batch__open();
@@ -34,6 +40,7 @@ static void do_test(int sock_type, bool onebyone)
			goto done;
		skel->rodata->ports[i] = ntohs(local_port);
	}
	skel->rodata->sf = AF_INET6;

	err = sock_iter_batch__load(skel);
	if (!ASSERT_OK(err, "sock_iter_batch__load"))
@@ -55,38 +62,38 @@ static void do_test(int sock_type, bool onebyone)
	 * from a bucket and leave one socket out from
	 * that bucket on purpose.
	 */
	to_read = (nr_soreuse - 1) * sizeof(*indices);
	to_read = (nr_soreuse - 1) * sizeof(*outputs);
	total_read = 0;
	first_idx = -1;
	do {
		nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
		if (nread <= 0 || nread % sizeof(*indices))
		nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read);
		if (nread <= 0 || nread % sizeof(*outputs))
			break;
		total_read += nread;

		if (first_idx == -1)
			first_idx = indices[0];
		for (i = 0; i < nread / sizeof(*indices); i++)
			ASSERT_EQ(indices[i], first_idx, "first_idx");
			first_idx = outputs[0].idx;
		for (i = 0; i < nread / sizeof(*outputs); i++)
			ASSERT_EQ(outputs[i].idx, first_idx, "first_idx");
	} while (total_read < to_read);
	ASSERT_EQ(nread, onebyone ? sizeof(*indices) : to_read, "nread");
	ASSERT_EQ(nread, onebyone ? sizeof(*outputs) : to_read, "nread");
	ASSERT_EQ(total_read, to_read, "total_read");

	free_fds(fds[first_idx], nr_soreuse);
	fds[first_idx] = NULL;

	/* Read the "whole" second bucket */
	to_read = nr_soreuse * sizeof(*indices);
	to_read = nr_soreuse * sizeof(*outputs);
	total_read = 0;
	second_idx = !first_idx;
	do {
		nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
		if (nread <= 0 || nread % sizeof(*indices))
		nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read);
		if (nread <= 0 || nread % sizeof(*outputs))
			break;
		total_read += nread;

		for (i = 0; i < nread / sizeof(*indices); i++)
			ASSERT_EQ(indices[i], second_idx, "second_idx");
		for (i = 0; i < nread / sizeof(*outputs); i++)
			ASSERT_EQ(outputs[i].idx, second_idx, "second_idx");
	} while (total_read <= to_read);
	ASSERT_EQ(nread, 0, "nread");
	/* Both so_reuseport ports should be in different buckets, so
+1 −0
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@
#define sk_refcnt		__sk_common.skc_refcnt
#define sk_state		__sk_common.skc_state
#define sk_net			__sk_common.skc_net
#define sk_rcv_saddr		__sk_common.skc_rcv_saddr
#define sk_v6_daddr		__sk_common.skc_v6_daddr
#define sk_v6_rcv_saddr		__sk_common.skc_v6_rcv_saddr
#define sk_flags		__sk_common.skc_flags
+20 −4
Original line number Diff line number Diff line
@@ -17,6 +17,12 @@ static bool ipv6_addr_loopback(const struct in6_addr *a)
		a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0;
}

static bool ipv4_addr_loopback(__be32 a)
{
	return a == bpf_ntohl(0x7f000001);
}

volatile const unsigned int sf;
volatile const __u16 ports[2];
unsigned int bucket[2];

@@ -26,16 +32,20 @@ int iter_tcp_soreuse(struct bpf_iter__tcp *ctx)
	struct sock *sk = (struct sock *)ctx->sk_common;
	struct inet_hashinfo *hinfo;
	unsigned int hash;
	__u64 sock_cookie;
	struct net *net;
	int idx;

	if (!sk)
		return 0;

	sock_cookie = bpf_get_socket_cookie(sk);
	sk = bpf_core_cast(sk, struct sock);
	if (sk->sk_family != AF_INET6 ||
	if (sk->sk_family != sf ||
	    sk->sk_state != TCP_LISTEN ||
	    !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
	    sk->sk_family == AF_INET6 ?
	    !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) :
	    !ipv4_addr_loopback(sk->sk_rcv_saddr))
		return 0;

	if (sk->sk_num == ports[0])
@@ -52,6 +62,7 @@ int iter_tcp_soreuse(struct bpf_iter__tcp *ctx)
	hinfo = net->ipv4.tcp_death_row.hashinfo;
	bucket[idx] = hash & hinfo->lhash2_mask;
	bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
	bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie));

	return 0;
}
@@ -63,14 +74,18 @@ int iter_udp_soreuse(struct bpf_iter__udp *ctx)
{
	struct sock *sk = (struct sock *)ctx->udp_sk;
	struct udp_table *udptable;
	__u64 sock_cookie;
	int idx;

	if (!sk)
		return 0;

	sock_cookie = bpf_get_socket_cookie(sk);
	sk = bpf_core_cast(sk, struct sock);
	if (sk->sk_family != AF_INET6 ||
	    !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
	if (sk->sk_family != sf ||
	    sk->sk_family == AF_INET6 ?
	    !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) :
	    !ipv4_addr_loopback(sk->sk_rcv_saddr))
		return 0;

	if (sk->sk_num == ports[0])
@@ -84,6 +99,7 @@ int iter_udp_soreuse(struct bpf_iter__udp *ctx)
	udptable = sk->sk_net.net->ipv4.udp_table;
	bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask;
	bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
	bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie));

	return 0;
}