1077263fbSStefano Garzarella // SPDX-License-Identifier: GPL-2.0-only 2077263fbSStefano Garzarella /* loopback transport for vsock using virtio_transport_common APIs 3077263fbSStefano Garzarella * 4077263fbSStefano Garzarella * Copyright (C) 2013-2019 Red Hat, Inc. 5077263fbSStefano Garzarella * Authors: Asias He <asias@redhat.com> 6077263fbSStefano Garzarella * Stefan Hajnoczi <stefanha@redhat.com> 7077263fbSStefano Garzarella * Stefano Garzarella <sgarzare@redhat.com> 8077263fbSStefano Garzarella * 9077263fbSStefano Garzarella */ 10077263fbSStefano Garzarella #include <linux/spinlock.h> 11077263fbSStefano Garzarella #include <linux/module.h> 12077263fbSStefano Garzarella #include <linux/list.h> 13077263fbSStefano Garzarella #include <linux/virtio_vsock.h> 14077263fbSStefano Garzarella 15077263fbSStefano Garzarella struct vsock_loopback { 16077263fbSStefano Garzarella struct workqueue_struct *workqueue; 17077263fbSStefano Garzarella 1871dc9ec9SBobby Eshleman struct sk_buff_head pkt_queue; 19077263fbSStefano Garzarella struct work_struct pkt_work; 20077263fbSStefano Garzarella }; 21077263fbSStefano Garzarella 22077263fbSStefano Garzarella static struct vsock_loopback the_vsock_loopback; 23077263fbSStefano Garzarella 24077263fbSStefano Garzarella static u32 vsock_loopback_get_local_cid(void) 25077263fbSStefano Garzarella { 26077263fbSStefano Garzarella return VMADDR_CID_LOCAL; 27077263fbSStefano Garzarella } 28077263fbSStefano Garzarella 2971dc9ec9SBobby Eshleman static int vsock_loopback_send_pkt(struct sk_buff *skb) 30077263fbSStefano Garzarella { 31077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 3271dc9ec9SBobby Eshleman int len = skb->len; 33077263fbSStefano Garzarella 34*eaaa4e92SArseniy Krasnov virtio_vsock_skb_queue_tail(&vsock->pkt_queue, skb); 35077263fbSStefano Garzarella queue_work(vsock->workqueue, &vsock->pkt_work); 36077263fbSStefano Garzarella 37077263fbSStefano Garzarella return len; 38077263fbSStefano Garzarella } 39077263fbSStefano Garzarella 40077263fbSStefano Garzarella static int vsock_loopback_cancel_pkt(struct vsock_sock *vsk) 41077263fbSStefano Garzarella { 42077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 43077263fbSStefano Garzarella 4471dc9ec9SBobby Eshleman virtio_transport_purge_skbs(vsk, &vsock->pkt_queue); 45077263fbSStefano Garzarella 46077263fbSStefano Garzarella return 0; 47077263fbSStefano Garzarella } 48077263fbSStefano Garzarella 496e90a577SArseny Krasnov static bool vsock_loopback_seqpacket_allow(u32 remote_cid); 506e90a577SArseny Krasnov 51077263fbSStefano Garzarella static struct virtio_transport loopback_transport = { 52077263fbSStefano Garzarella .transport = { 53077263fbSStefano Garzarella .module = THIS_MODULE, 54077263fbSStefano Garzarella 55077263fbSStefano Garzarella .get_local_cid = vsock_loopback_get_local_cid, 56077263fbSStefano Garzarella 57077263fbSStefano Garzarella .init = virtio_transport_do_socket_init, 58077263fbSStefano Garzarella .destruct = virtio_transport_destruct, 59077263fbSStefano Garzarella .release = virtio_transport_release, 60077263fbSStefano Garzarella .connect = virtio_transport_connect, 61077263fbSStefano Garzarella .shutdown = virtio_transport_shutdown, 62077263fbSStefano Garzarella .cancel_pkt = vsock_loopback_cancel_pkt, 63077263fbSStefano Garzarella 64077263fbSStefano Garzarella .dgram_bind = virtio_transport_dgram_bind, 65077263fbSStefano Garzarella .dgram_dequeue = virtio_transport_dgram_dequeue, 66077263fbSStefano Garzarella .dgram_enqueue = virtio_transport_dgram_enqueue, 67077263fbSStefano Garzarella .dgram_allow = virtio_transport_dgram_allow, 68077263fbSStefano Garzarella 69077263fbSStefano Garzarella .stream_dequeue = virtio_transport_stream_dequeue, 70077263fbSStefano Garzarella .stream_enqueue = virtio_transport_stream_enqueue, 71077263fbSStefano Garzarella .stream_has_data = virtio_transport_stream_has_data, 72077263fbSStefano Garzarella .stream_has_space = virtio_transport_stream_has_space, 73077263fbSStefano Garzarella .stream_rcvhiwat = virtio_transport_stream_rcvhiwat, 74077263fbSStefano Garzarella .stream_is_active = virtio_transport_stream_is_active, 75077263fbSStefano Garzarella .stream_allow = virtio_transport_stream_allow, 76077263fbSStefano Garzarella 776e90a577SArseny Krasnov .seqpacket_dequeue = virtio_transport_seqpacket_dequeue, 786e90a577SArseny Krasnov .seqpacket_enqueue = virtio_transport_seqpacket_enqueue, 796e90a577SArseny Krasnov .seqpacket_allow = vsock_loopback_seqpacket_allow, 806e90a577SArseny Krasnov .seqpacket_has_data = virtio_transport_seqpacket_has_data, 816e90a577SArseny Krasnov 82077263fbSStefano Garzarella .notify_poll_in = virtio_transport_notify_poll_in, 83077263fbSStefano Garzarella .notify_poll_out = virtio_transport_notify_poll_out, 84077263fbSStefano Garzarella .notify_recv_init = virtio_transport_notify_recv_init, 85077263fbSStefano Garzarella .notify_recv_pre_block = virtio_transport_notify_recv_pre_block, 86077263fbSStefano Garzarella .notify_recv_pre_dequeue = virtio_transport_notify_recv_pre_dequeue, 87077263fbSStefano Garzarella .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue, 88077263fbSStefano Garzarella .notify_send_init = virtio_transport_notify_send_init, 89077263fbSStefano Garzarella .notify_send_pre_block = virtio_transport_notify_send_pre_block, 90077263fbSStefano Garzarella .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, 91077263fbSStefano Garzarella .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 92077263fbSStefano Garzarella .notify_buffer_size = virtio_transport_notify_buffer_size, 93634f1a71SBobby Eshleman 94634f1a71SBobby Eshleman .read_skb = virtio_transport_read_skb, 95077263fbSStefano Garzarella }, 96077263fbSStefano Garzarella 97077263fbSStefano Garzarella .send_pkt = vsock_loopback_send_pkt, 98077263fbSStefano Garzarella }; 99077263fbSStefano Garzarella 1006e90a577SArseny Krasnov static bool vsock_loopback_seqpacket_allow(u32 remote_cid) 1016e90a577SArseny Krasnov { 1026e90a577SArseny Krasnov return true; 1036e90a577SArseny Krasnov } 1046e90a577SArseny Krasnov 105077263fbSStefano Garzarella static void vsock_loopback_work(struct work_struct *work) 106077263fbSStefano Garzarella { 107077263fbSStefano Garzarella struct vsock_loopback *vsock = 108077263fbSStefano Garzarella container_of(work, struct vsock_loopback, pkt_work); 10971dc9ec9SBobby Eshleman struct sk_buff_head pkts; 11071dc9ec9SBobby Eshleman struct sk_buff *skb; 11171dc9ec9SBobby Eshleman 11271dc9ec9SBobby Eshleman skb_queue_head_init(&pkts); 113077263fbSStefano Garzarella 114b465518dSStefano Garzarella spin_lock_bh(&vsock->pkt_queue.lock); 11571dc9ec9SBobby Eshleman skb_queue_splice_init(&vsock->pkt_queue, &pkts); 116b465518dSStefano Garzarella spin_unlock_bh(&vsock->pkt_queue.lock); 117077263fbSStefano Garzarella 11871dc9ec9SBobby Eshleman while ((skb = __skb_dequeue(&pkts))) { 11971dc9ec9SBobby Eshleman virtio_transport_deliver_tap_pkt(skb); 12071dc9ec9SBobby Eshleman virtio_transport_recv_pkt(&loopback_transport, skb); 121077263fbSStefano Garzarella } 122077263fbSStefano Garzarella } 123077263fbSStefano Garzarella 124077263fbSStefano Garzarella static int __init vsock_loopback_init(void) 125077263fbSStefano Garzarella { 126077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 127077263fbSStefano Garzarella int ret; 128077263fbSStefano Garzarella 129077263fbSStefano Garzarella vsock->workqueue = alloc_workqueue("vsock-loopback", 0, 0); 130077263fbSStefano Garzarella if (!vsock->workqueue) 131077263fbSStefano Garzarella return -ENOMEM; 132077263fbSStefano Garzarella 13371dc9ec9SBobby Eshleman skb_queue_head_init(&vsock->pkt_queue); 134077263fbSStefano Garzarella INIT_WORK(&vsock->pkt_work, vsock_loopback_work); 135077263fbSStefano Garzarella 136077263fbSStefano Garzarella ret = vsock_core_register(&loopback_transport.transport, 137077263fbSStefano Garzarella VSOCK_TRANSPORT_F_LOCAL); 138077263fbSStefano Garzarella if (ret) 139077263fbSStefano Garzarella goto out_wq; 140077263fbSStefano Garzarella 141077263fbSStefano Garzarella return 0; 142077263fbSStefano Garzarella 143077263fbSStefano Garzarella out_wq: 144077263fbSStefano Garzarella destroy_workqueue(vsock->workqueue); 145077263fbSStefano Garzarella return ret; 146077263fbSStefano Garzarella } 147077263fbSStefano Garzarella 148077263fbSStefano Garzarella static void __exit vsock_loopback_exit(void) 149077263fbSStefano Garzarella { 150077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 151077263fbSStefano Garzarella 152077263fbSStefano Garzarella vsock_core_unregister(&loopback_transport.transport); 153077263fbSStefano Garzarella 154077263fbSStefano Garzarella flush_work(&vsock->pkt_work); 155077263fbSStefano Garzarella 15671dc9ec9SBobby Eshleman virtio_vsock_skb_queue_purge(&vsock->pkt_queue); 157077263fbSStefano Garzarella 158077263fbSStefano Garzarella destroy_workqueue(vsock->workqueue); 159077263fbSStefano Garzarella } 160077263fbSStefano Garzarella 161077263fbSStefano Garzarella module_init(vsock_loopback_init); 162077263fbSStefano Garzarella module_exit(vsock_loopback_exit); 163077263fbSStefano Garzarella MODULE_LICENSE("GPL v2"); 164077263fbSStefano Garzarella MODULE_AUTHOR("Stefano Garzarella <sgarzare@redhat.com>"); 165077263fbSStefano Garzarella MODULE_DESCRIPTION("loopback transport for vsock"); 166077263fbSStefano Garzarella MODULE_ALIAS_NETPROTO(PF_VSOCK); 167