Commit c48a24f0 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpf_setsockopt-SO_BINDTODEVICE'



Ferenc Fejes says:

====================
This option makes it possible to programatically bind sockets
to netdevices. With the help of this option sockets
of VRF unaware applications could be distributed between
multiple VRFs with an eBPF program. This lets the applications
benefit from multiple possible routes.

v2:
- splitting up the patch to three parts
- lock_sk parameter for optional locking in sock_bindtoindex - Stanislav Fomichev
- testing the SO_BINDTODEVICE option - Andrii Nakryiko
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents bb2359f4 9c441fe4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2690,7 +2690,7 @@ static inline bool sk_dev_equal_l3scope(struct sock *sk, int dif)

void sock_def_readable(struct sock *sk);

int sock_bindtoindex(struct sock *sk, int ifindex);
int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk);
void sock_enable_timestamps(struct sock *sk);
void sock_no_linger(struct sock *sk);
void sock_set_keepalive(struct sock *sk);
+27 −1
Original line number Diff line number Diff line
@@ -4248,6 +4248,9 @@ static const struct bpf_func_proto bpf_get_socket_uid_proto = {
static int _bpf_setsockopt(struct sock *sk, int level, int optname,
			   char *optval, int optlen, u32 flags)
{
	char devname[IFNAMSIZ];
	struct net *net;
	int ifindex;
	int ret = 0;
	int val;

@@ -4257,7 +4260,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
	sock_owned_by_me(sk);

	if (level == SOL_SOCKET) {
		if (optlen != sizeof(int))
		if (optlen != sizeof(int) && optname != SO_BINDTODEVICE)
			return -EINVAL;
		val = *((int *)optval);

@@ -4298,6 +4301,29 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
				sk_dst_reset(sk);
			}
			break;
		case SO_BINDTODEVICE:
			ret = -ENOPROTOOPT;
#ifdef CONFIG_NETDEVICES
			optlen = min_t(long, optlen, IFNAMSIZ - 1);
			strncpy(devname, optval, optlen);
			devname[optlen] = 0;

			ifindex = 0;
			if (devname[0] != '\0') {
				struct net_device *dev;

				ret = -ENODEV;

				net = sock_net(sk);
				dev = dev_get_by_name(net, devname);
				if (!dev)
					break;
				ifindex = dev->ifindex;
				dev_put(dev);
			}
			ret = sock_bindtoindex(sk, ifindex, false);
#endif
			break;
		default:
			ret = -EINVAL;
		}
+6 −4
Original line number Diff line number Diff line
@@ -594,12 +594,14 @@ out:
	return ret;
}

int sock_bindtoindex(struct sock *sk, int ifindex)
int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk)
{
	int ret;

	if (lock_sk)
		lock_sock(sk);
	ret = sock_bindtoindex_locked(sk, ifindex);
	if (lock_sk)
		release_sock(sk);

	return ret;
@@ -646,7 +648,7 @@ static int sock_setbindtodevice(struct sock *sk, char __user *optval,
			goto out;
	}

	return sock_bindtoindex(sk, index);
	return sock_bindtoindex(sk, index, true);
out:
#endif

+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
		goto error;

	if (cfg->bind_ifindex) {
		err = sock_bindtoindex(sock->sk, cfg->bind_ifindex);
		err = sock_bindtoindex(sock->sk, cfg->bind_ifindex, true);
		if (err < 0)
			goto error;
	}
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
			goto error;
	}
	if (cfg->bind_ifindex) {
		err = sock_bindtoindex(sock->sk, cfg->bind_ifindex);
		err = sock_bindtoindex(sock->sk, cfg->bind_ifindex, true);
		if (err < 0)
			goto error;
	}
Loading