0001
0002
0003
0004
0005
0006
0007
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;
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);