Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'vsock-sockmap-support'

Bobby Eshleman says:

====================
Add support for sockmap to vsock.

We're testing usage of vsock as a way to redirect guest-local UDS
requests to the host and this patch series greatly improves the
performance of such a setup.

Compared to copying packets via userspace, this improves throughput by
121% in basic testing.

Tested as follows.

Setup: guest unix dgram sender -> guest vsock redirector -> host vsock
server
Threads: 1
Payload: 64k
No sockmap:
- 76.3 MB/s
- The guest vsock redirector was
"socat VSOCK-CONNECT:2:1234 UNIX-RECV:/path/to/sock"
Using sockmap (this patch):
- 168.8 MB/s (+121%)
- The guest redirector was a simple sockmap echo server,
redirecting unix ingress to vsock 2:1234 egress.
- Same sender and server programs

*Note: these numbers are from RFC v1

Only the virtio transport has been tested. The loopback transport was
used in writing bpf/selftests, but not thoroughly tested otherwise.

This series requires the skb patch.

Changes in v4:
- af_vsock: fix parameter alignment in vsock_dgram_recvmsg()
- af_vsock: add TCP_ESTABLISHED comment in vsock_dgram_connect()
- vsock/bpf: change ret type to bool

Changes in v3:
- vsock/bpf: Refactor wait logic in vsock_bpf_recvmsg() to avoid
backwards goto
- vsock/bpf: Check psock before acquiring slock
- vsock/bpf: Return bool instead of int of 0 or 1
- vsock/bpf: Wrap macro args __sk/__psock in parens
- vsock/bpf: Place comment trailer */ on separate line

Changes in v2:
- vsock/bpf: rename vsock_dgram_* -> vsock_*
- vsock/bpf: change sk_psock_{get,put} and {lock,release}_sock() order
to minimize slock hold time
- vsock/bpf: use "new style" wait
- vsock/bpf: fix bug in wait log
- vsock/bpf: add check that recvmsg sk_type is one dgram, seqpacket, or
stream. Return error if not one of the three.
- virtio/vsock: comment __skb_recv_datagram() usage
- virtio/vsock: do not init copied in read_skb()
- vsock/bpf: add ifdef guard around struct proto in dgram_recvmsg()
- selftests/bpf: add vsock loopback config for aarch64
- selftests/bpf: add vsock loopback config for s390x
- selftests/bpf: remove vsock device from vmtest.sh qemu machine
- selftests/bpf: remove CONFIG_VIRTIO_VSOCKETS=y from config.x86_64
- vsock/bpf: move transport-related (e.g., if (!vsk->transport)) checks
out of fast path
====================

Signed-off-by: Bobby Eshleman <bobby.eshleman@bytedance.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

+452 -6
+1
drivers/vhost/vsock.c
··· 439 439 .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 440 440 .notify_buffer_size = virtio_transport_notify_buffer_size, 441 441 442 + .read_skb = virtio_transport_read_skb, 442 443 }, 443 444 444 445 .send_pkt = vhost_transport_send_pkt,
+1
include/linux/virtio_vsock.h
··· 245 245 void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit); 246 246 void virtio_transport_deliver_tap_pkt(struct sk_buff *skb); 247 247 int virtio_transport_purge_skbs(void *vsk, struct sk_buff_head *list); 248 + int virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t read_actor); 248 249 #endif /* _LINUX_VIRTIO_VSOCK_H */
+17
include/net/af_vsock.h
··· 75 75 void *trans; 76 76 }; 77 77 78 + s64 vsock_connectible_has_data(struct vsock_sock *vsk); 78 79 s64 vsock_stream_has_data(struct vsock_sock *vsk); 79 80 s64 vsock_stream_has_space(struct vsock_sock *vsk); 80 81 struct sock *vsock_create_connected(struct sock *parent); ··· 174 173 175 174 /* Addressing. */ 176 175 u32 (*get_local_cid)(void); 176 + 177 + /* Read a single skb */ 178 + int (*read_skb)(struct vsock_sock *, skb_read_actor_t); 177 179 }; 178 180 179 181 /**** CORE ****/ ··· 229 225 int vsock_add_tap(struct vsock_tap *vt); 230 226 int vsock_remove_tap(struct vsock_tap *vt); 231 227 void vsock_deliver_tap(struct sk_buff *build_skb(void *opaque), void *opaque); 228 + int vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 229 + int flags); 230 + int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg, 231 + size_t len, int flags); 232 + 233 + #ifdef CONFIG_BPF_SYSCALL 234 + extern struct proto vsock_proto; 235 + int vsock_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore); 236 + void __init vsock_bpf_build_proto(void); 237 + #else 238 + static inline void __init vsock_bpf_build_proto(void) 239 + {} 240 + #endif 232 241 233 242 #endif /* __AF_VSOCK_H__ */
+1
net/vmw_vsock/Makefile
··· 8 8 obj-$(CONFIG_VSOCKETS_LOOPBACK) += vsock_loopback.o 9 9 10 10 vsock-y += af_vsock.o af_vsock_tap.o vsock_addr.o 11 + vsock-$(CONFIG_BPF_SYSCALL) += vsock_bpf.o 11 12 12 13 vsock_diag-y += diag.o 13 14
+58 -6
net/vmw_vsock/af_vsock.c
··· 116 116 static int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); 117 117 118 118 /* Protocol family. */ 119 - static struct proto vsock_proto = { 119 + struct proto vsock_proto = { 120 120 .name = "AF_VSOCK", 121 121 .owner = THIS_MODULE, 122 122 .obj_size = sizeof(struct vsock_sock), 123 + #ifdef CONFIG_BPF_SYSCALL 124 + .psock_update_sk_prot = vsock_bpf_update_proto, 125 + #endif 123 126 }; 124 127 125 128 /* The default peer timeout indicates how long we will wait for a peer response ··· 868 865 } 869 866 EXPORT_SYMBOL_GPL(vsock_stream_has_data); 870 867 871 - static s64 vsock_connectible_has_data(struct vsock_sock *vsk) 868 + s64 vsock_connectible_has_data(struct vsock_sock *vsk) 872 869 { 873 870 struct sock *sk = sk_vsock(vsk); 874 871 ··· 877 874 else 878 875 return vsock_stream_has_data(vsk); 879 876 } 877 + EXPORT_SYMBOL_GPL(vsock_connectible_has_data); 880 878 881 879 s64 vsock_stream_has_space(struct vsock_sock *vsk) 882 880 { ··· 1135 1131 return mask; 1136 1132 } 1137 1133 1134 + static int vsock_read_skb(struct sock *sk, skb_read_actor_t read_actor) 1135 + { 1136 + struct vsock_sock *vsk = vsock_sk(sk); 1137 + 1138 + return vsk->transport->read_skb(vsk, read_actor); 1139 + } 1140 + 1138 1141 static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg, 1139 1142 size_t len) 1140 1143 { ··· 1253 1242 memcpy(&vsk->remote_addr, remote_addr, sizeof(vsk->remote_addr)); 1254 1243 sock->state = SS_CONNECTED; 1255 1244 1245 + /* sock map disallows redirection of non-TCP sockets with sk_state != 1246 + * TCP_ESTABLISHED (see sock_map_redirect_allowed()), so we set 1247 + * TCP_ESTABLISHED here to allow redirection of connected vsock dgrams. 1248 + * 1249 + * This doesn't seem to be abnormal state for datagram sockets, as the 1250 + * same approach can be see in other datagram socket types as well 1251 + * (such as unix sockets). 1252 + */ 1253 + sk->sk_state = TCP_ESTABLISHED; 1254 + 1256 1255 out: 1257 1256 release_sock(sk); 1258 1257 return err; 1259 1258 } 1260 1259 1261 - static int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg, 1262 - size_t len, int flags) 1260 + int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg, 1261 + size_t len, int flags) 1263 1262 { 1264 - struct vsock_sock *vsk = vsock_sk(sock->sk); 1263 + #ifdef CONFIG_BPF_SYSCALL 1264 + const struct proto *prot; 1265 + #endif 1266 + struct vsock_sock *vsk; 1267 + struct sock *sk; 1268 + 1269 + sk = sock->sk; 1270 + vsk = vsock_sk(sk); 1271 + 1272 + #ifdef CONFIG_BPF_SYSCALL 1273 + prot = READ_ONCE(sk->sk_prot); 1274 + if (prot != &vsock_proto) 1275 + return prot->recvmsg(sk, msg, len, flags, NULL); 1276 + #endif 1265 1277 1266 1278 return vsk->transport->dgram_dequeue(vsk, msg, len, flags); 1267 1279 } 1280 + EXPORT_SYMBOL_GPL(vsock_dgram_recvmsg); 1268 1281 1269 1282 static const struct proto_ops vsock_dgram_ops = { 1270 1283 .family = PF_VSOCK, ··· 1307 1272 .recvmsg = vsock_dgram_recvmsg, 1308 1273 .mmap = sock_no_mmap, 1309 1274 .sendpage = sock_no_sendpage, 1275 + .read_skb = vsock_read_skb, 1310 1276 }; 1311 1277 1312 1278 static int vsock_transport_cancel_pkt(struct vsock_sock *vsk) ··· 2122 2086 return err; 2123 2087 } 2124 2088 2125 - static int 2089 + int 2126 2090 vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 2127 2091 int flags) 2128 2092 { 2129 2093 struct sock *sk; 2130 2094 struct vsock_sock *vsk; 2131 2095 const struct vsock_transport *transport; 2096 + #ifdef CONFIG_BPF_SYSCALL 2097 + const struct proto *prot; 2098 + #endif 2132 2099 int err; 2133 2100 2134 2101 sk = sock->sk; ··· 2178 2139 goto out; 2179 2140 } 2180 2141 2142 + #ifdef CONFIG_BPF_SYSCALL 2143 + prot = READ_ONCE(sk->sk_prot); 2144 + if (prot != &vsock_proto) { 2145 + release_sock(sk); 2146 + return prot->recvmsg(sk, msg, len, flags, NULL); 2147 + } 2148 + #endif 2149 + 2181 2150 if (sk->sk_type == SOCK_STREAM) 2182 2151 err = __vsock_stream_recvmsg(sk, msg, len, flags); 2183 2152 else ··· 2195 2148 release_sock(sk); 2196 2149 return err; 2197 2150 } 2151 + EXPORT_SYMBOL_GPL(vsock_connectible_recvmsg); 2198 2152 2199 2153 static int vsock_set_rcvlowat(struct sock *sk, int val) 2200 2154 { ··· 2236 2188 .mmap = sock_no_mmap, 2237 2189 .sendpage = sock_no_sendpage, 2238 2190 .set_rcvlowat = vsock_set_rcvlowat, 2191 + .read_skb = vsock_read_skb, 2239 2192 }; 2240 2193 2241 2194 static const struct proto_ops vsock_seqpacket_ops = { ··· 2258 2209 .recvmsg = vsock_connectible_recvmsg, 2259 2210 .mmap = sock_no_mmap, 2260 2211 .sendpage = sock_no_sendpage, 2212 + .read_skb = vsock_read_skb, 2261 2213 }; 2262 2214 2263 2215 static int vsock_create(struct net *net, struct socket *sock, ··· 2397 2347 AF_VSOCK, err); 2398 2348 goto err_unregister_proto; 2399 2349 } 2350 + 2351 + vsock_bpf_build_proto(); 2400 2352 2401 2353 return 0; 2402 2354
+2
net/vmw_vsock/virtio_transport.c
··· 457 457 .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, 458 458 .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 459 459 .notify_buffer_size = virtio_transport_notify_buffer_size, 460 + 461 + .read_skb = virtio_transport_read_skb, 460 462 }, 461 463 462 464 .send_pkt = virtio_transport_send_pkt,
+25
net/vmw_vsock/virtio_transport_common.c
··· 1418 1418 } 1419 1419 EXPORT_SYMBOL_GPL(virtio_transport_purge_skbs); 1420 1420 1421 + int virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t recv_actor) 1422 + { 1423 + struct virtio_vsock_sock *vvs = vsk->trans; 1424 + struct sock *sk = sk_vsock(vsk); 1425 + struct sk_buff *skb; 1426 + int off = 0; 1427 + int copied; 1428 + int err; 1429 + 1430 + spin_lock_bh(&vvs->rx_lock); 1431 + /* Use __skb_recv_datagram() for race-free handling of the receive. It 1432 + * works for types other than dgrams. 1433 + */ 1434 + skb = __skb_recv_datagram(sk, &vvs->rx_queue, MSG_DONTWAIT, &off, &err); 1435 + spin_unlock_bh(&vvs->rx_lock); 1436 + 1437 + if (!skb) 1438 + return err; 1439 + 1440 + copied = recv_actor(sk, skb); 1441 + kfree_skb(skb); 1442 + return copied; 1443 + } 1444 + EXPORT_SYMBOL_GPL(virtio_transport_read_skb); 1445 + 1421 1446 MODULE_LICENSE("GPL v2"); 1422 1447 MODULE_AUTHOR("Asias He"); 1423 1448 MODULE_DESCRIPTION("common code for virtio vsock");
+174
net/vmw_vsock/vsock_bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2022 Bobby Eshleman <bobby.eshleman@bytedance.com> 3 + * 4 + * Based off of net/unix/unix_bpf.c 5 + */ 6 + 7 + #include <linux/bpf.h> 8 + #include <linux/module.h> 9 + #include <linux/skmsg.h> 10 + #include <linux/socket.h> 11 + #include <linux/wait.h> 12 + #include <net/af_vsock.h> 13 + #include <net/sock.h> 14 + 15 + #define vsock_sk_has_data(__sk, __psock) \ 16 + ({ !skb_queue_empty(&(__sk)->sk_receive_queue) || \ 17 + !skb_queue_empty(&(__psock)->ingress_skb) || \ 18 + !list_empty(&(__psock)->ingress_msg); \ 19 + }) 20 + 21 + static struct proto *vsock_prot_saved __read_mostly; 22 + static DEFINE_SPINLOCK(vsock_prot_lock); 23 + static struct proto vsock_bpf_prot; 24 + 25 + static bool vsock_has_data(struct sock *sk, struct sk_psock *psock) 26 + { 27 + struct vsock_sock *vsk = vsock_sk(sk); 28 + s64 ret; 29 + 30 + ret = vsock_connectible_has_data(vsk); 31 + if (ret > 0) 32 + return true; 33 + 34 + return vsock_sk_has_data(sk, psock); 35 + } 36 + 37 + static bool vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo) 38 + { 39 + bool ret; 40 + 41 + DEFINE_WAIT_FUNC(wait, woken_wake_function); 42 + 43 + if (sk->sk_shutdown & RCV_SHUTDOWN) 44 + return true; 45 + 46 + if (!timeo) 47 + return false; 48 + 49 + add_wait_queue(sk_sleep(sk), &wait); 50 + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); 51 + ret = vsock_has_data(sk, psock); 52 + if (!ret) { 53 + wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); 54 + ret = vsock_has_data(sk, psock); 55 + } 56 + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); 57 + remove_wait_queue(sk_sleep(sk), &wait); 58 + return ret; 59 + } 60 + 61 + static int __vsock_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags) 62 + { 63 + struct socket *sock = sk->sk_socket; 64 + int err; 65 + 66 + if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) 67 + err = vsock_connectible_recvmsg(sock, msg, len, flags); 68 + else if (sk->sk_type == SOCK_DGRAM) 69 + err = vsock_dgram_recvmsg(sock, msg, len, flags); 70 + else 71 + err = -EPROTOTYPE; 72 + 73 + return err; 74 + } 75 + 76 + static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg, 77 + size_t len, int flags, int *addr_len) 78 + { 79 + struct sk_psock *psock; 80 + int copied; 81 + 82 + psock = sk_psock_get(sk); 83 + if (unlikely(!psock)) 84 + return __vsock_recvmsg(sk, msg, len, flags); 85 + 86 + lock_sock(sk); 87 + if (vsock_has_data(sk, psock) && sk_psock_queue_empty(psock)) { 88 + release_sock(sk); 89 + sk_psock_put(sk, psock); 90 + return __vsock_recvmsg(sk, msg, len, flags); 91 + } 92 + 93 + copied = sk_msg_recvmsg(sk, psock, msg, len, flags); 94 + while (copied == 0) { 95 + long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 96 + 97 + if (!vsock_msg_wait_data(sk, psock, timeo)) { 98 + copied = -EAGAIN; 99 + break; 100 + } 101 + 102 + if (sk_psock_queue_empty(psock)) { 103 + release_sock(sk); 104 + sk_psock_put(sk, psock); 105 + return __vsock_recvmsg(sk, msg, len, flags); 106 + } 107 + 108 + copied = sk_msg_recvmsg(sk, psock, msg, len, flags); 109 + } 110 + 111 + release_sock(sk); 112 + sk_psock_put(sk, psock); 113 + 114 + return copied; 115 + } 116 + 117 + /* Copy of original proto with updated sock_map methods */ 118 + static struct proto vsock_bpf_prot = { 119 + .close = sock_map_close, 120 + .recvmsg = vsock_bpf_recvmsg, 121 + .sock_is_readable = sk_msg_is_readable, 122 + .unhash = sock_map_unhash, 123 + }; 124 + 125 + static void vsock_bpf_rebuild_protos(struct proto *prot, const struct proto *base) 126 + { 127 + *prot = *base; 128 + prot->close = sock_map_close; 129 + prot->recvmsg = vsock_bpf_recvmsg; 130 + prot->sock_is_readable = sk_msg_is_readable; 131 + } 132 + 133 + static void vsock_bpf_check_needs_rebuild(struct proto *ops) 134 + { 135 + /* Paired with the smp_store_release() below. */ 136 + if (unlikely(ops != smp_load_acquire(&vsock_prot_saved))) { 137 + spin_lock_bh(&vsock_prot_lock); 138 + if (likely(ops != vsock_prot_saved)) { 139 + vsock_bpf_rebuild_protos(&vsock_bpf_prot, ops); 140 + /* Make sure proto function pointers are updated before publishing the 141 + * pointer to the struct. 142 + */ 143 + smp_store_release(&vsock_prot_saved, ops); 144 + } 145 + spin_unlock_bh(&vsock_prot_lock); 146 + } 147 + } 148 + 149 + int vsock_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore) 150 + { 151 + struct vsock_sock *vsk; 152 + 153 + if (restore) { 154 + sk->sk_write_space = psock->saved_write_space; 155 + sock_replace_proto(sk, psock->sk_proto); 156 + return 0; 157 + } 158 + 159 + vsk = vsock_sk(sk); 160 + if (!vsk->transport) 161 + return -ENODEV; 162 + 163 + if (!vsk->transport->read_skb) 164 + return -EOPNOTSUPP; 165 + 166 + vsock_bpf_check_needs_rebuild(psock->sk_proto); 167 + sock_replace_proto(sk, &vsock_bpf_prot); 168 + return 0; 169 + } 170 + 171 + void __init vsock_bpf_build_proto(void) 172 + { 173 + vsock_bpf_rebuild_protos(&vsock_bpf_prot, &vsock_proto); 174 + }
+2
net/vmw_vsock/vsock_loopback.c
··· 94 94 .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, 95 95 .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 96 96 .notify_buffer_size = virtio_transport_notify_buffer_size, 97 + 98 + .read_skb = virtio_transport_read_skb, 97 99 }, 98 100 99 101 .send_pkt = vsock_loopback_send_pkt,
+2
tools/testing/selftests/bpf/config.aarch64
··· 176 176 CONFIG_VIRTIO_MMIO=y 177 177 CONFIG_VIRTIO_NET=y 178 178 CONFIG_VIRTIO_PCI=y 179 + CONFIG_VIRTIO_VSOCKETS_COMMON=y 179 180 CONFIG_VLAN_8021Q=y 180 181 CONFIG_VSOCKETS=y 182 + CONFIG_VSOCKETS_LOOPBACK=y 181 183 CONFIG_XFRM_USER=y
+3
tools/testing/selftests/bpf/config.s390x
··· 140 140 CONFIG_VIRTIO_BLK=y 141 141 CONFIG_VIRTIO_NET=y 142 142 CONFIG_VIRTIO_PCI=y 143 + CONFIG_VIRTIO_VSOCKETS_COMMON=y 143 144 CONFIG_VLAN_8021Q=y 145 + CONFIG_VSOCKETS=y 146 + CONFIG_VSOCKETS_LOOPBACK=y 144 147 CONFIG_XFRM_USER=y
+3
tools/testing/selftests/bpf/config.x86_64
··· 234 234 CONFIG_VIRTIO_CONSOLE=y 235 235 CONFIG_VIRTIO_NET=y 236 236 CONFIG_VIRTIO_PCI=y 237 + CONFIG_VIRTIO_VSOCKETS_COMMON=y 237 238 CONFIG_VLAN_8021Q=y 239 + CONFIG_VSOCKETS=y 240 + CONFIG_VSOCKETS_LOOPBACK=y 238 241 CONFIG_X86_ACPI_CPUFREQ=y 239 242 CONFIG_X86_CPUID=y 240 243 CONFIG_X86_MSR=y
+163
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
··· 18 18 #include <string.h> 19 19 #include <sys/select.h> 20 20 #include <unistd.h> 21 + #include <linux/vm_sockets.h> 21 22 22 23 #include <bpf/bpf.h> 23 24 #include <bpf/libbpf.h> ··· 252 251 *len = sizeof(*addr6); 253 252 } 254 253 254 + static void init_addr_loopback_vsock(struct sockaddr_storage *ss, socklen_t *len) 255 + { 256 + struct sockaddr_vm *addr = memset(ss, 0, sizeof(*ss)); 257 + 258 + addr->svm_family = AF_VSOCK; 259 + addr->svm_port = VMADDR_PORT_ANY; 260 + addr->svm_cid = VMADDR_CID_LOCAL; 261 + *len = sizeof(*addr); 262 + } 263 + 255 264 static void init_addr_loopback(int family, struct sockaddr_storage *ss, 256 265 socklen_t *len) 257 266 { ··· 271 260 return; 272 261 case AF_INET6: 273 262 init_addr_loopback6(ss, len); 263 + return; 264 + case AF_VSOCK: 265 + init_addr_loopback_vsock(ss, len); 274 266 return; 275 267 default: 276 268 FAIL("unsupported address family %d", family); ··· 1492 1478 return "IPv6"; 1493 1479 case AF_UNIX: 1494 1480 return "Unix"; 1481 + case AF_VSOCK: 1482 + return "VSOCK"; 1495 1483 default: 1496 1484 return "unknown"; 1497 1485 } ··· 1703 1687 if (!test__start_subtest(s)) 1704 1688 return; 1705 1689 unix_skb_redir_to_connected(skel, map, sotype); 1690 + } 1691 + 1692 + /* Returns two connected loopback vsock sockets */ 1693 + static int vsock_socketpair_connectible(int sotype, int *v0, int *v1) 1694 + { 1695 + struct sockaddr_storage addr; 1696 + socklen_t len = sizeof(addr); 1697 + int s, p, c; 1698 + 1699 + s = socket_loopback(AF_VSOCK, sotype); 1700 + if (s < 0) 1701 + return -1; 1702 + 1703 + c = xsocket(AF_VSOCK, sotype | SOCK_NONBLOCK, 0); 1704 + if (c == -1) 1705 + goto close_srv; 1706 + 1707 + if (getsockname(s, sockaddr(&addr), &len) < 0) 1708 + goto close_cli; 1709 + 1710 + if (connect(c, sockaddr(&addr), len) < 0 && errno != EINPROGRESS) { 1711 + FAIL_ERRNO("connect"); 1712 + goto close_cli; 1713 + } 1714 + 1715 + len = sizeof(addr); 1716 + p = accept_timeout(s, sockaddr(&addr), &len, IO_TIMEOUT_SEC); 1717 + if (p < 0) 1718 + goto close_cli; 1719 + 1720 + *v0 = p; 1721 + *v1 = c; 1722 + 1723 + return 0; 1724 + 1725 + close_cli: 1726 + close(c); 1727 + close_srv: 1728 + close(s); 1729 + 1730 + return -1; 1731 + } 1732 + 1733 + static void vsock_unix_redir_connectible(int sock_mapfd, int verd_mapfd, 1734 + enum redir_mode mode, int sotype) 1735 + { 1736 + const char *log_prefix = redir_mode_str(mode); 1737 + char a = 'a', b = 'b'; 1738 + int u0, u1, v0, v1; 1739 + int sfd[2]; 1740 + unsigned int pass; 1741 + int err, n; 1742 + u32 key; 1743 + 1744 + zero_verdict_count(verd_mapfd); 1745 + 1746 + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sfd)) 1747 + return; 1748 + 1749 + u0 = sfd[0]; 1750 + u1 = sfd[1]; 1751 + 1752 + err = vsock_socketpair_connectible(sotype, &v0, &v1); 1753 + if (err) { 1754 + FAIL("vsock_socketpair_connectible() failed"); 1755 + goto close_uds; 1756 + } 1757 + 1758 + err = add_to_sockmap(sock_mapfd, u0, v0); 1759 + if (err) { 1760 + FAIL("add_to_sockmap failed"); 1761 + goto close_vsock; 1762 + } 1763 + 1764 + n = write(v1, &a, sizeof(a)); 1765 + if (n < 0) 1766 + FAIL_ERRNO("%s: write", log_prefix); 1767 + if (n == 0) 1768 + FAIL("%s: incomplete write", log_prefix); 1769 + if (n < 1) 1770 + goto out; 1771 + 1772 + n = recv(mode == REDIR_INGRESS ? u0 : u1, &b, sizeof(b), MSG_DONTWAIT); 1773 + if (n < 0) 1774 + FAIL("%s: recv() err, errno=%d", log_prefix, errno); 1775 + if (n == 0) 1776 + FAIL("%s: incomplete recv", log_prefix); 1777 + if (b != a) 1778 + FAIL("%s: vsock socket map failed, %c != %c", log_prefix, a, b); 1779 + 1780 + key = SK_PASS; 1781 + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); 1782 + if (err) 1783 + goto out; 1784 + if (pass != 1) 1785 + FAIL("%s: want pass count 1, have %d", log_prefix, pass); 1786 + out: 1787 + key = 0; 1788 + bpf_map_delete_elem(sock_mapfd, &key); 1789 + key = 1; 1790 + bpf_map_delete_elem(sock_mapfd, &key); 1791 + 1792 + close_vsock: 1793 + close(v0); 1794 + close(v1); 1795 + 1796 + close_uds: 1797 + close(u0); 1798 + close(u1); 1799 + } 1800 + 1801 + static void vsock_unix_skb_redir_connectible(struct test_sockmap_listen *skel, 1802 + struct bpf_map *inner_map, 1803 + int sotype) 1804 + { 1805 + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); 1806 + int verdict_map = bpf_map__fd(skel->maps.verdict_map); 1807 + int sock_map = bpf_map__fd(inner_map); 1808 + int err; 1809 + 1810 + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_VERDICT, 0); 1811 + if (err) 1812 + return; 1813 + 1814 + skel->bss->test_ingress = false; 1815 + vsock_unix_redir_connectible(sock_map, verdict_map, REDIR_EGRESS, sotype); 1816 + skel->bss->test_ingress = true; 1817 + vsock_unix_redir_connectible(sock_map, verdict_map, REDIR_INGRESS, sotype); 1818 + 1819 + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); 1820 + } 1821 + 1822 + static void test_vsock_redir(struct test_sockmap_listen *skel, struct bpf_map *map) 1823 + { 1824 + const char *family_name, *map_name; 1825 + char s[MAX_TEST_NAME]; 1826 + 1827 + family_name = family_str(AF_VSOCK); 1828 + map_name = map_type_str(map); 1829 + snprintf(s, sizeof(s), "%s %s %s", map_name, family_name, __func__); 1830 + if (!test__start_subtest(s)) 1831 + return; 1832 + 1833 + vsock_unix_skb_redir_connectible(skel, map, SOCK_STREAM); 1834 + vsock_unix_skb_redir_connectible(skel, map, SOCK_SEQPACKET); 1706 1835 } 1707 1836 1708 1837 static void test_reuseport(struct test_sockmap_listen *skel, ··· 2221 2060 run_tests(skel, skel->maps.sock_map, AF_INET6); 2222 2061 test_unix_redir(skel, skel->maps.sock_map, SOCK_DGRAM); 2223 2062 test_unix_redir(skel, skel->maps.sock_map, SOCK_STREAM); 2063 + test_vsock_redir(skel, skel->maps.sock_map); 2224 2064 2225 2065 skel->bss->test_sockmap = false; 2226 2066 run_tests(skel, skel->maps.sock_hash, AF_INET); 2227 2067 run_tests(skel, skel->maps.sock_hash, AF_INET6); 2228 2068 test_unix_redir(skel, skel->maps.sock_hash, SOCK_DGRAM); 2229 2069 test_unix_redir(skel, skel->maps.sock_hash, SOCK_STREAM); 2070 + test_vsock_redir(skel, skel->maps.sock_hash); 2230 2071 2231 2072 test_sockmap_listen__destroy(skel); 2232 2073 }