Delete unsupported entries for userspace MSR handling.
[akaros.git] / user / vmm / virtio_net.c
1 /* Virtio helper functions from linux/tools/lguest/lguest.c
2  *
3  * Copyright (C) 1991-2016, the Linux Kernel authors
4  * Copyright (c) 2016 Google Inc.
5  *
6  * Author:
7  *  Rusty Russell <rusty@rustcorp.com.au>
8  *  Kyle Milka <kmilka@google.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * The code from lguest.c has been modified for Akaros.
21  *
22  * Original linux/tools/lguest/lguest.c:
23  *   https://github.com/torvalds/linux/blob/v4.5/tools/lguest/lguest.c
24  *   most recent hash on the file as of v4.5 tag:
25  *     e523caa601f4a7c2fa1ecd040db921baf7453798
26  */
27
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <vmm/virtio.h>
33 #include <vmm/virtio_mmio.h>
34 #include <vmm/virtio_net.h>
35
36 #define VIRTIO_HEADER_SIZE      12
37
38 static int ctlfd;
39 static int etherfd;
40 static char data_path[128];
41 static char clone_path[64];
42
43 void net_init_fn(struct virtio_vq_dev *vqdev, int nic)
44 {
45         char type[] = "connect -1";
46         char buf[8];
47         char addr_path[32];
48         char addr_buf[3];
49         int addr_fd;
50         uint8_t addr_bytes;
51         int num_read;
52         int total_read = 0;
53
54         snprintf(addr_path, sizeof(addr_path), "/net/ether%d/addr", nic);
55         addr_fd = open(addr_path, O_RDONLY);
56         if (addr_fd < 0)
57                 VIRTIO_DEV_ERRX(vqdev, "Bad addr_fd\n");
58
59         for (int i = 0; i < ETH_ALEN; ++i) {
60                 assert(read(addr_fd, addr_buf, 2) == 2);
61                 addr_buf[2] = 0;
62                 addr_bytes = (uint8_t)(strtol(addr_buf, 0, 16));
63                 ((struct virtio_net_config *)(vqdev->cfg))->mac[i] = addr_bytes;
64                 ((struct virtio_net_config *)(vqdev->cfg_d))->mac[i] = addr_bytes;
65         }
66
67         snprintf(clone_path, sizeof(clone_path), "/net/ether%d/clone", nic);
68         ctlfd = open(clone_path, O_RDWR);
69         if (ctlfd < 0)
70                 VIRTIO_DEV_ERRX(vqdev, "%s", clone_path);
71
72         do {
73                 num_read = read(ctlfd, buf + total_read, sizeof(buf) - total_read);
74                 total_read += num_read;
75         } while (num_read > 0);
76
77         etherfd = strtol(buf, 0, 10);
78         if (etherfd < 0)
79                 VIRTIO_DEV_ERRX(vqdev, "bad etherfd %d (%s)", etherfd, buf);
80
81         snprintf(data_path, sizeof(data_path),
82                  "/net/ether%d/%d/data", nic, etherfd);
83
84         if (write(ctlfd, type, sizeof(type)) != sizeof(type))
85                 VIRTIO_DEV_ERRX(vqdev, "write to ctlfd failed");
86 }
87
88 /* net_receiveq_fn receives packets for the guest through the virtio networking
89  * device and the _vq virtio queue.
90  */
91 void net_receiveq_fn(void *_vq)
92 {
93         struct virtio_vq *vq = _vq;
94         uint32_t head;
95         uint32_t olen, ilen;
96         int num_read;
97         struct iovec *iov;
98         struct virtio_mmio_dev *dev = vq->vqdev->transport_dev;
99         int fd;
100         struct virtio_net_hdr_v1 *net_header;
101
102         fd = open(data_path, O_RDWR);
103         if (fd == -1)
104                 VIRTIO_DEV_ERRX(vq->vqdev, "Could not open data file for ether1.");
105
106         if (!vq)
107                 VIRTIO_DEV_ERRX(vq->vqdev,
108                         "\n  %s:%d\n"
109                         "  Virtio device: (not sure which one): Error, device behavior.\n"
110                         "  The device must provide a valid virtio_vq as an argument to %s."
111                         , __FILE__, __LINE__, __func__);
112
113         if (vq->qready == 0x0)
114                 VIRTIO_DEV_ERRX(vq->vqdev,
115                         "The service function for queue '%s' was launched before the driver set QueueReady to 0x1.",
116                         vq->name);
117
118         iov = malloc(vq->qnum_max * sizeof(struct iovec));
119         assert(iov != NULL);
120
121         if (!dev->poke_guest) {
122                 free(iov);
123                 VIRTIO_DEV_ERRX(vq->vqdev,
124                                 "The 'poke_guest' function pointer was not set.");
125         }
126
127         for (;;) {
128                 head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen);
129                 if (olen) {
130                         free(iov);
131                         VIRTIO_DRI_ERRX(vq->vqdev,
132                                 "The driver placed a device-readable buffer in the net device's receiveq.\n"
133                                 "  See virtio-v1.0-cs04 s5.3.6.1 Device Operation");
134                 }
135
136                 /* For receive the virtio header is in iov[0], so we only want
137                  * the packet to be read into iov[1] and above.
138                  */
139                 num_read = readv(fd, iov + 1, ilen - 1);
140                 if (num_read < 0) {
141                         free(iov);
142                         VIRTIO_DEV_ERRX(vq->vqdev,
143                                 "Encountered an error trying to read input from the ethernet device.");
144                 }
145
146                 /* See virtio spec virtio-v1.0-cs04 s5.1.6.3.2 Device Requirements:
147                  * Setting Up Receive Buffers
148                  *
149                  * VIRTIO_NET_F_MRG_RXBUF is not currently negotiated.
150                  * num_buffers will always be 1 if VIRTIO_NET_F_MRG_RXBUF is not
151                  * negotiated.
152                  */
153                 net_header = iov[0].iov_base;
154                 net_header->num_buffers = 1;
155                 virtio_add_used_desc(vq, head, num_read + VIRTIO_HEADER_SIZE);
156
157                 virtio_mmio_set_vring_irq(dev);
158                 dev->poke_guest(dev->vec);
159         }
160 }
161
162 /* net_transmitq_fn transmits packets from the guest through the virtio
163  * networking device through the _vq virtio queue.
164  */
165 void net_transmitq_fn(void *_vq)
166 {
167         struct virtio_vq *vq = _vq;
168         uint32_t head;
169         uint32_t olen, ilen;
170         struct iovec *iov;
171         struct virtio_mmio_dev *dev = vq->vqdev->transport_dev;
172         void *stripped;
173         int ret;
174         int fd = open(data_path, O_RDWR);
175
176         if (fd == -1)
177                 VIRTIO_DEV_ERRX(vq->vqdev, "Could not open data file for ether1.");
178
179         iov = malloc(vq->qnum_max * sizeof(struct iovec));
180         assert(iov != NULL);
181
182         if (!dev->poke_guest) {
183                 free(iov);
184                 VIRTIO_DEV_ERRX(vq->vqdev,
185                                 "The 'poke_guest' function pointer was not set.");
186         }
187
188         for (;;) {
189                 head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen);
190
191                 if (ilen) {
192                         free(iov);
193                         VIRTIO_DRI_ERRX(vq->vqdev,
194                                         "The driver placed a device-writeable buffer in the network device's transmitq.\n"
195                                     "  See virtio-v1.0-cs04 s5.3.6.1 Device Operation");
196                 }
197
198                 /* Strip off the virtio header (the first 12 bytes), as it is
199                  * not a part of the actual ethernet frame.
200                  */
201                 for (int i = 0; i < olen; i++) {
202                         stripped = iov[i].iov_base + VIRTIO_HEADER_SIZE;
203                         ret = write(fd, stripped, iov[i].iov_len - VIRTIO_HEADER_SIZE);
204                         assert(ret == iov[i].iov_len - VIRTIO_HEADER_SIZE);
205                 }
206
207                 virtio_add_used_desc(vq, head, 0);
208
209                 virtio_mmio_set_vring_irq(dev);
210                 dev->poke_guest(dev->vec);
211         }
212 }