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 18077263fbSStefano Garzarella spinlock_t pkt_list_lock; /* protects pkt_list */ 19077263fbSStefano Garzarella struct list_head pkt_list; 20077263fbSStefano Garzarella struct work_struct pkt_work; 21077263fbSStefano Garzarella }; 22077263fbSStefano Garzarella 23077263fbSStefano Garzarella static struct vsock_loopback the_vsock_loopback; 24077263fbSStefano Garzarella 25077263fbSStefano Garzarella static u32 vsock_loopback_get_local_cid(void) 26077263fbSStefano Garzarella { 27077263fbSStefano Garzarella return VMADDR_CID_LOCAL; 28077263fbSStefano Garzarella } 29077263fbSStefano Garzarella 30077263fbSStefano Garzarella static int vsock_loopback_send_pkt(struct virtio_vsock_pkt *pkt) 31077263fbSStefano Garzarella { 32077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 33077263fbSStefano Garzarella int len = pkt->len; 34077263fbSStefano Garzarella 35077263fbSStefano Garzarella spin_lock_bh(&vsock->pkt_list_lock); 36077263fbSStefano Garzarella list_add_tail(&pkt->list, &vsock->pkt_list); 37077263fbSStefano Garzarella spin_unlock_bh(&vsock->pkt_list_lock); 38077263fbSStefano Garzarella 39077263fbSStefano Garzarella queue_work(vsock->workqueue, &vsock->pkt_work); 40077263fbSStefano Garzarella 41077263fbSStefano Garzarella return len; 42077263fbSStefano Garzarella } 43077263fbSStefano Garzarella 44077263fbSStefano Garzarella static int vsock_loopback_cancel_pkt(struct vsock_sock *vsk) 45077263fbSStefano Garzarella { 46077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 47077263fbSStefano Garzarella struct virtio_vsock_pkt *pkt, *n; 48077263fbSStefano Garzarella LIST_HEAD(freeme); 49077263fbSStefano Garzarella 50077263fbSStefano Garzarella spin_lock_bh(&vsock->pkt_list_lock); 51077263fbSStefano Garzarella list_for_each_entry_safe(pkt, n, &vsock->pkt_list, list) { 52077263fbSStefano Garzarella if (pkt->vsk != vsk) 53077263fbSStefano Garzarella continue; 54077263fbSStefano Garzarella list_move(&pkt->list, &freeme); 55077263fbSStefano Garzarella } 56077263fbSStefano Garzarella spin_unlock_bh(&vsock->pkt_list_lock); 57077263fbSStefano Garzarella 58077263fbSStefano Garzarella list_for_each_entry_safe(pkt, n, &freeme, list) { 59077263fbSStefano Garzarella list_del(&pkt->list); 60077263fbSStefano Garzarella virtio_transport_free_pkt(pkt); 61077263fbSStefano Garzarella } 62077263fbSStefano Garzarella 63077263fbSStefano Garzarella return 0; 64077263fbSStefano Garzarella } 65077263fbSStefano Garzarella 66*6e90a577SArseny Krasnov static bool vsock_loopback_seqpacket_allow(u32 remote_cid); 67*6e90a577SArseny Krasnov 68077263fbSStefano Garzarella static struct virtio_transport loopback_transport = { 69077263fbSStefano Garzarella .transport = { 70077263fbSStefano Garzarella .module = THIS_MODULE, 71077263fbSStefano Garzarella 72077263fbSStefano Garzarella .get_local_cid = vsock_loopback_get_local_cid, 73077263fbSStefano Garzarella 74077263fbSStefano Garzarella .init = virtio_transport_do_socket_init, 75077263fbSStefano Garzarella .destruct = virtio_transport_destruct, 76077263fbSStefano Garzarella .release = virtio_transport_release, 77077263fbSStefano Garzarella .connect = virtio_transport_connect, 78077263fbSStefano Garzarella .shutdown = virtio_transport_shutdown, 79077263fbSStefano Garzarella .cancel_pkt = vsock_loopback_cancel_pkt, 80077263fbSStefano Garzarella 81077263fbSStefano Garzarella .dgram_bind = virtio_transport_dgram_bind, 82077263fbSStefano Garzarella .dgram_dequeue = virtio_transport_dgram_dequeue, 83077263fbSStefano Garzarella .dgram_enqueue = virtio_transport_dgram_enqueue, 84077263fbSStefano Garzarella .dgram_allow = virtio_transport_dgram_allow, 85077263fbSStefano Garzarella 86077263fbSStefano Garzarella .stream_dequeue = virtio_transport_stream_dequeue, 87077263fbSStefano Garzarella .stream_enqueue = virtio_transport_stream_enqueue, 88077263fbSStefano Garzarella .stream_has_data = virtio_transport_stream_has_data, 89077263fbSStefano Garzarella .stream_has_space = virtio_transport_stream_has_space, 90077263fbSStefano Garzarella .stream_rcvhiwat = virtio_transport_stream_rcvhiwat, 91077263fbSStefano Garzarella .stream_is_active = virtio_transport_stream_is_active, 92077263fbSStefano Garzarella .stream_allow = virtio_transport_stream_allow, 93077263fbSStefano Garzarella 94*6e90a577SArseny Krasnov .seqpacket_dequeue = virtio_transport_seqpacket_dequeue, 95*6e90a577SArseny Krasnov .seqpacket_enqueue = virtio_transport_seqpacket_enqueue, 96*6e90a577SArseny Krasnov .seqpacket_allow = vsock_loopback_seqpacket_allow, 97*6e90a577SArseny Krasnov .seqpacket_has_data = virtio_transport_seqpacket_has_data, 98*6e90a577SArseny Krasnov 99077263fbSStefano Garzarella .notify_poll_in = virtio_transport_notify_poll_in, 100077263fbSStefano Garzarella .notify_poll_out = virtio_transport_notify_poll_out, 101077263fbSStefano Garzarella .notify_recv_init = virtio_transport_notify_recv_init, 102077263fbSStefano Garzarella .notify_recv_pre_block = virtio_transport_notify_recv_pre_block, 103077263fbSStefano Garzarella .notify_recv_pre_dequeue = virtio_transport_notify_recv_pre_dequeue, 104077263fbSStefano Garzarella .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue, 105077263fbSStefano Garzarella .notify_send_init = virtio_transport_notify_send_init, 106077263fbSStefano Garzarella .notify_send_pre_block = virtio_transport_notify_send_pre_block, 107077263fbSStefano Garzarella .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, 108077263fbSStefano Garzarella .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 109077263fbSStefano Garzarella .notify_buffer_size = virtio_transport_notify_buffer_size, 110077263fbSStefano Garzarella }, 111077263fbSStefano Garzarella 112077263fbSStefano Garzarella .send_pkt = vsock_loopback_send_pkt, 113077263fbSStefano Garzarella }; 114077263fbSStefano Garzarella 115*6e90a577SArseny Krasnov static bool vsock_loopback_seqpacket_allow(u32 remote_cid) 116*6e90a577SArseny Krasnov { 117*6e90a577SArseny Krasnov return true; 118*6e90a577SArseny Krasnov } 119*6e90a577SArseny Krasnov 120077263fbSStefano Garzarella static void vsock_loopback_work(struct work_struct *work) 121077263fbSStefano Garzarella { 122077263fbSStefano Garzarella struct vsock_loopback *vsock = 123077263fbSStefano Garzarella container_of(work, struct vsock_loopback, pkt_work); 124077263fbSStefano Garzarella LIST_HEAD(pkts); 125077263fbSStefano Garzarella 126077263fbSStefano Garzarella spin_lock_bh(&vsock->pkt_list_lock); 127077263fbSStefano Garzarella list_splice_init(&vsock->pkt_list, &pkts); 128077263fbSStefano Garzarella spin_unlock_bh(&vsock->pkt_list_lock); 129077263fbSStefano Garzarella 130077263fbSStefano Garzarella while (!list_empty(&pkts)) { 131077263fbSStefano Garzarella struct virtio_vsock_pkt *pkt; 132077263fbSStefano Garzarella 133077263fbSStefano Garzarella pkt = list_first_entry(&pkts, struct virtio_vsock_pkt, list); 134077263fbSStefano Garzarella list_del_init(&pkt->list); 135077263fbSStefano Garzarella 136077263fbSStefano Garzarella virtio_transport_deliver_tap_pkt(pkt); 137077263fbSStefano Garzarella virtio_transport_recv_pkt(&loopback_transport, pkt); 138077263fbSStefano Garzarella } 139077263fbSStefano Garzarella } 140077263fbSStefano Garzarella 141077263fbSStefano Garzarella static int __init vsock_loopback_init(void) 142077263fbSStefano Garzarella { 143077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 144077263fbSStefano Garzarella int ret; 145077263fbSStefano Garzarella 146077263fbSStefano Garzarella vsock->workqueue = alloc_workqueue("vsock-loopback", 0, 0); 147077263fbSStefano Garzarella if (!vsock->workqueue) 148077263fbSStefano Garzarella return -ENOMEM; 149077263fbSStefano Garzarella 150077263fbSStefano Garzarella spin_lock_init(&vsock->pkt_list_lock); 151077263fbSStefano Garzarella INIT_LIST_HEAD(&vsock->pkt_list); 152077263fbSStefano Garzarella INIT_WORK(&vsock->pkt_work, vsock_loopback_work); 153077263fbSStefano Garzarella 154077263fbSStefano Garzarella ret = vsock_core_register(&loopback_transport.transport, 155077263fbSStefano Garzarella VSOCK_TRANSPORT_F_LOCAL); 156077263fbSStefano Garzarella if (ret) 157077263fbSStefano Garzarella goto out_wq; 158077263fbSStefano Garzarella 159077263fbSStefano Garzarella return 0; 160077263fbSStefano Garzarella 161077263fbSStefano Garzarella out_wq: 162077263fbSStefano Garzarella destroy_workqueue(vsock->workqueue); 163077263fbSStefano Garzarella return ret; 164077263fbSStefano Garzarella } 165077263fbSStefano Garzarella 166077263fbSStefano Garzarella static void __exit vsock_loopback_exit(void) 167077263fbSStefano Garzarella { 168077263fbSStefano Garzarella struct vsock_loopback *vsock = &the_vsock_loopback; 169077263fbSStefano Garzarella struct virtio_vsock_pkt *pkt; 170077263fbSStefano Garzarella 171077263fbSStefano Garzarella vsock_core_unregister(&loopback_transport.transport); 172077263fbSStefano Garzarella 173077263fbSStefano Garzarella flush_work(&vsock->pkt_work); 174077263fbSStefano Garzarella 175077263fbSStefano Garzarella spin_lock_bh(&vsock->pkt_list_lock); 176077263fbSStefano Garzarella while (!list_empty(&vsock->pkt_list)) { 177077263fbSStefano Garzarella pkt = list_first_entry(&vsock->pkt_list, 178077263fbSStefano Garzarella struct virtio_vsock_pkt, list); 179077263fbSStefano Garzarella list_del(&pkt->list); 180077263fbSStefano Garzarella virtio_transport_free_pkt(pkt); 181077263fbSStefano Garzarella } 182077263fbSStefano Garzarella spin_unlock_bh(&vsock->pkt_list_lock); 183077263fbSStefano Garzarella 184077263fbSStefano Garzarella destroy_workqueue(vsock->workqueue); 185077263fbSStefano Garzarella } 186077263fbSStefano Garzarella 187077263fbSStefano Garzarella module_init(vsock_loopback_init); 188077263fbSStefano Garzarella module_exit(vsock_loopback_exit); 189077263fbSStefano Garzarella MODULE_LICENSE("GPL v2"); 190077263fbSStefano Garzarella MODULE_AUTHOR("Stefano Garzarella <sgarzare@redhat.com>"); 191077263fbSStefano Garzarella MODULE_DESCRIPTION("loopback transport for vsock"); 192077263fbSStefano Garzarella MODULE_ALIAS_NETPROTO(PF_VSOCK); 193