Commit 75b64b68 authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Alexei Starovoitov
Browse files

bpf: Change bpf_setsockopt(SOL_IPV6) to reuse do_ipv6_setsockopt()



After the prep work in the previous patches,
this patch removes the dup code from bpf_setsockopt(SOL_IPV6)
and reuses the implementation in do_ipv6_setsockopt().

ipv6 could be compiled as a module.  Like how other code solved it
with stubs in ipv6_stubs.h, this patch adds the do_ipv6_setsockopt
to the ipv6_bpf_stub.

The current bpf_setsockopt(IPV6_TCLASS) does not take the
INET_ECN_MASK into the account for tcp.  The
do_ipv6_setsockopt(IPV6_TCLASS) will handle it correctly.

The existing optname white-list is refactored into a new
function sol_ipv6_setsockopt().

After this last SOL_IPV6 dup code removal, the __bpf_setsockopt()
is simplified enough that the extra "{ }" around the if statement
can be removed.

Reviewed-by: default avatarStanislav Fomichev <sdf@google.com>
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/r/20220817061834.4181198-1-kafai@fb.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent ee7f1e13
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1156,6 +1156,8 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
 */
DECLARE_STATIC_KEY_FALSE(ip6_min_hopcount);

int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
		       unsigned int optlen);
int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
		    unsigned int optlen);
int ipv6_getsockopt(struct sock *sk, int level, int optname,
+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,8 @@ struct ipv6_bpf_stub {
				     const struct in6_addr *daddr, __be16 dport,
				     int dif, int sdif, struct udp_table *tbl,
				     struct sk_buff *skb);
	int (*ipv6_setsockopt)(struct sock *sk, int level, int optname,
			       sockptr_t optval, unsigned int optlen);
};
extern const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly;

+26 −30
Original line number Diff line number Diff line
@@ -5133,45 +5133,41 @@ static int sol_ip_setsockopt(struct sock *sk, int optname,
				KERNEL_SOCKPTR(optval), optlen);
}

static int __bpf_setsockopt(struct sock *sk, int level, int optname,
static int sol_ipv6_setsockopt(struct sock *sk, int optname,
			       char *optval, int optlen)
{
	int val, ret = 0;

	if (!sk_fullsock(sk))
		return -EINVAL;

	if (level == SOL_SOCKET) {
		return sol_socket_setsockopt(sk, optname, optval, optlen);
	} else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) {
		return sol_ip_setsockopt(sk, optname, optval, optlen);
	} else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) {
		if (optlen != sizeof(int) || sk->sk_family != AF_INET6)
	if (sk->sk_family != AF_INET6)
		return -EINVAL;

		val = *((int *)optval);
		/* Only some options are supported */
	switch (optname) {
	case IPV6_TCLASS:
			if (val < -1 || val > 0xff) {
				ret = -EINVAL;
			} else {
				struct ipv6_pinfo *np = inet6_sk(sk);

				if (val == -1)
					val = 0;
				np->tclass = val;
			}
		if (optlen != sizeof(int))
			return -EINVAL;
		break;
	default:
			ret = -EINVAL;
		return -EINVAL;
	}
	} else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP) {
		return sol_tcp_setsockopt(sk, optname, optval, optlen);
	} else {
		ret = -EINVAL;

	return ipv6_bpf_stub->ipv6_setsockopt(sk, SOL_IPV6, optname,
					      KERNEL_SOCKPTR(optval), optlen);
}
	return ret;

static int __bpf_setsockopt(struct sock *sk, int level, int optname,
			    char *optval, int optlen)
{
	if (!sk_fullsock(sk))
		return -EINVAL;

	if (level == SOL_SOCKET)
		return sol_socket_setsockopt(sk, optname, optval, optlen);
	else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP)
		return sol_ip_setsockopt(sk, optname, optval, optlen);
	else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6)
		return sol_ipv6_setsockopt(sk, optname, optval, optlen);
	else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP)
		return sol_tcp_setsockopt(sk, optname, optval, optlen);

	return -EINVAL;
}

static int _bpf_setsockopt(struct sock *sk, int level, int optname,
+1 −0
Original line number Diff line number Diff line
@@ -1057,6 +1057,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
	.inet6_bind = __inet6_bind,
	.udp6_lib_lookup = __udp6_lib_lookup,
	.ipv6_setsockopt = do_ipv6_setsockopt,
};

static int __init inet6_init(void)
+2 −2
Original line number Diff line number Diff line
@@ -391,7 +391,7 @@ static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
	return err;
}

static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
		       sockptr_t optval, unsigned int optlen)
{
	struct ipv6_pinfo *np = inet6_sk(sk);