Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* loopback transport for vsock using virtio_transport_common APIs
0003  *
0004  * Copyright (C) 2013-2019 Red Hat, Inc.
0005  * Authors: Asias He <asias@redhat.com>
0006  *          Stefan Hajnoczi <stefanha@redhat.com>
0007  *          Stefano Garzarella <sgarzare@redhat.com>
0008  *
0009  */
0010 #include <linux/spinlock.h>
0011 #include <linux/module.h>
0012 #include <linux/list.h>
0013 #include <linux/virtio_vsock.h>
0014 
0015 struct vsock_loopback {
0016     struct workqueue_struct *workqueue;
0017 
0018     spinlock_t pkt_list_lock; /* protects pkt_list */
0019     struct list_head pkt_list;
0020     struct work_struct pkt_work;
0021 };
0022 
0023 static struct vsock_loopback the_vsock_loopback;
0024 
0025 static u32 vsock_loopback_get_local_cid(void)
0026 {
0027     return VMADDR_CID_LOCAL;
0028 }
0029 
0030 static int vsock_loopback_send_pkt(struct virtio_vsock_pkt *pkt)
0031 {
0032     struct vsock_loopback *vsock = &the_vsock_loopback;
0033     int len = pkt->len;
0034 
0035     spin_lock_bh(&vsock->pkt_list_lock);
0036     list_add_tail(&pkt->list, &vsock->pkt_list);
0037     spin_unlock_bh(&vsock->pkt_list_lock);
0038 
0039     queue_work(vsock->workqueue, &vsock->pkt_work);
0040 
0041     return len;
0042 }
0043 
0044 static int vsock_loopback_cancel_pkt(struct vsock_sock *vsk)
0045 {
0046     struct vsock_loopback *vsock = &the_vsock_loopback;
0047     struct virtio_vsock_pkt *pkt, *n;
0048     LIST_HEAD(freeme);
0049 
0050     spin_lock_bh(&vsock->pkt_list_lock);
0051     list_for_each_entry_safe(pkt, n, &vsock->pkt_list, list) {
0052         if (pkt->vsk != vsk)
0053             continue;
0054         list_move(&pkt->list, &freeme);
0055     }
0056     spin_unlock_bh(&vsock->pkt_list_lock);
0057 
0058     list_for_each_entry_safe(pkt, n, &freeme, list) {
0059         list_del(&pkt->list);
0060         virtio_transport_free_pkt(pkt);
0061     }
0062 
0063     return 0;
0064 }
0065 
0066 static bool vsock_loopback_seqpacket_allow(u32 remote_cid);
0067 
0068 static struct virtio_transport loopback_transport = {
0069     .transport = {
0070         .module                   = THIS_MODULE,
0071 
0072         .get_local_cid            = vsock_loopback_get_local_cid,
0073 
0074         .init                     = virtio_transport_do_socket_init,
0075         .destruct                 = virtio_transport_destruct,
0076         .release                  = virtio_transport_release,
0077         .connect                  = virtio_transport_connect,
0078         .shutdown                 = virtio_transport_shutdown,
0079         .cancel_pkt               = vsock_loopback_cancel_pkt,
0080 
0081         .dgram_bind               = virtio_transport_dgram_bind,
0082         .dgram_dequeue            = virtio_transport_dgram_dequeue,
0083         .dgram_enqueue            = virtio_transport_dgram_enqueue,
0084         .dgram_allow              = virtio_transport_dgram_allow,
0085 
0086         .stream_dequeue           = virtio_transport_stream_dequeue,
0087         .stream_enqueue           = virtio_transport_stream_enqueue,
0088         .stream_has_data          = virtio_transport_stream_has_data,
0089         .stream_has_space         = virtio_transport_stream_has_space,
0090         .stream_rcvhiwat          = virtio_transport_stream_rcvhiwat,
0091         .stream_is_active         = virtio_transport_stream_is_active,
0092         .stream_allow             = virtio_transport_stream_allow,
0093 
0094         .seqpacket_dequeue        = virtio_transport_seqpacket_dequeue,
0095         .seqpacket_enqueue        = virtio_transport_seqpacket_enqueue,
0096         .seqpacket_allow          = vsock_loopback_seqpacket_allow,
0097         .seqpacket_has_data       = virtio_transport_seqpacket_has_data,
0098 
0099         .notify_poll_in           = virtio_transport_notify_poll_in,
0100         .notify_poll_out          = virtio_transport_notify_poll_out,
0101         .notify_recv_init         = virtio_transport_notify_recv_init,
0102         .notify_recv_pre_block    = virtio_transport_notify_recv_pre_block,
0103         .notify_recv_pre_dequeue  = virtio_transport_notify_recv_pre_dequeue,
0104         .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue,
0105         .notify_send_init         = virtio_transport_notify_send_init,
0106         .notify_send_pre_block    = virtio_transport_notify_send_pre_block,
0107         .notify_send_pre_enqueue  = virtio_transport_notify_send_pre_enqueue,
0108         .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue,
0109         .notify_buffer_size       = virtio_transport_notify_buffer_size,
0110     },
0111 
0112     .send_pkt = vsock_loopback_send_pkt,
0113 };
0114 
0115 static bool vsock_loopback_seqpacket_allow(u32 remote_cid)
0116 {
0117     return true;
0118 }
0119 
0120 static void vsock_loopback_work(struct work_struct *work)
0121 {
0122     struct vsock_loopback *vsock =
0123         container_of(work, struct vsock_loopback, pkt_work);
0124     LIST_HEAD(pkts);
0125 
0126     spin_lock_bh(&vsock->pkt_list_lock);
0127     list_splice_init(&vsock->pkt_list, &pkts);
0128     spin_unlock_bh(&vsock->pkt_list_lock);
0129 
0130     while (!list_empty(&pkts)) {
0131         struct virtio_vsock_pkt *pkt;
0132 
0133         pkt = list_first_entry(&pkts, struct virtio_vsock_pkt, list);
0134         list_del_init(&pkt->list);
0135 
0136         virtio_transport_deliver_tap_pkt(pkt);
0137         virtio_transport_recv_pkt(&loopback_transport, pkt);
0138     }
0139 }
0140 
0141 static int __init vsock_loopback_init(void)
0142 {
0143     struct vsock_loopback *vsock = &the_vsock_loopback;
0144     int ret;
0145 
0146     vsock->workqueue = alloc_workqueue("vsock-loopback", 0, 0);
0147     if (!vsock->workqueue)
0148         return -ENOMEM;
0149 
0150     spin_lock_init(&vsock->pkt_list_lock);
0151     INIT_LIST_HEAD(&vsock->pkt_list);
0152     INIT_WORK(&vsock->pkt_work, vsock_loopback_work);
0153 
0154     ret = vsock_core_register(&loopback_transport.transport,
0155                   VSOCK_TRANSPORT_F_LOCAL);
0156     if (ret)
0157         goto out_wq;
0158 
0159     return 0;
0160 
0161 out_wq:
0162     destroy_workqueue(vsock->workqueue);
0163     return ret;
0164 }
0165 
0166 static void __exit vsock_loopback_exit(void)
0167 {
0168     struct vsock_loopback *vsock = &the_vsock_loopback;
0169     struct virtio_vsock_pkt *pkt;
0170 
0171     vsock_core_unregister(&loopback_transport.transport);
0172 
0173     flush_work(&vsock->pkt_work);
0174 
0175     spin_lock_bh(&vsock->pkt_list_lock);
0176     while (!list_empty(&vsock->pkt_list)) {
0177         pkt = list_first_entry(&vsock->pkt_list,
0178                        struct virtio_vsock_pkt, list);
0179         list_del(&pkt->list);
0180         virtio_transport_free_pkt(pkt);
0181     }
0182     spin_unlock_bh(&vsock->pkt_list_lock);
0183 
0184     destroy_workqueue(vsock->workqueue);
0185 }
0186 
0187 module_init(vsock_loopback_init);
0188 module_exit(vsock_loopback_exit);
0189 MODULE_LICENSE("GPL v2");
0190 MODULE_AUTHOR("Stefano Garzarella <sgarzare@redhat.com>");
0191 MODULE_DESCRIPTION("loopback transport for vsock");
0192 MODULE_ALIAS_NETPROTO(PF_VSOCK);