summaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2020-06-01 14:57:15 -0700
committerAlexei Starovoitov <ast@kernel.org>2020-06-01 15:00:20 -0700
commitc48a24f00e7a8b90c817e3f7aa800a3150bb83d0 (patch)
treebba2031049e20cce4e5ff3d21f6749c6b9e625b5 /net/core
parentbb2359f4dbe98e8863b4e885fc09269ef4682ec3 (diff)
parent9c441fe4c06a553ad770b6f21616327a3badf793 (diff)
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: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/filter.c28
-rw-r--r--net/core/sock.c10
2 files changed, 33 insertions, 5 deletions
diff --git a/net/core/filter.c b/net/core/filter.c
index 85ff827aab73b..ae82bcb031242 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -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;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 61ec573221a60..6c4acf1f0220b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -594,13 +594,15 @@ out:
return ret;
}
-int sock_bindtoindex(struct sock *sk, int ifindex)
+int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk)
{
int ret;
- lock_sock(sk);
+ if (lock_sk)
+ lock_sock(sk);
ret = sock_bindtoindex_locked(sk, ifindex);
- release_sock(sk);
+ 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