]> git.proxmox.com Git - qemu.git/blob - hw/virtio-net.c
Add v{add, sub}{s, u}{b, h, w}s instructions
[qemu.git] / hw / virtio-net.c
1 /*
2 * Virtio Network Device
3 *
4 * Copyright IBM, Corp. 2007
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
12 */
13
14 #include "virtio.h"
15 #include "net.h"
16 #include "qemu-timer.h"
17 #include "virtio-net.h"
18
19 typedef struct VirtIONet
20 {
21 VirtIODevice vdev;
22 uint8_t mac[6];
23 uint16_t status;
24 VirtQueue *rx_vq;
25 VirtQueue *tx_vq;
26 VLANClientState *vc;
27 QEMUTimer *tx_timer;
28 int tx_timer_active;
29 int mergeable_rx_bufs;
30 } VirtIONet;
31
32 /* TODO
33 * - we could suppress RX interrupt if we were so inclined.
34 */
35
36 static VirtIONet *to_virtio_net(VirtIODevice *vdev)
37 {
38 return (VirtIONet *)vdev;
39 }
40
41 static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config)
42 {
43 VirtIONet *n = to_virtio_net(vdev);
44 struct virtio_net_config netcfg;
45
46 netcfg.status = n->status;
47 memcpy(netcfg.mac, n->mac, 6);
48 memcpy(config, &netcfg, sizeof(netcfg));
49 }
50
51 static void virtio_net_set_link_status(VLANClientState *vc)
52 {
53 VirtIONet *n = vc->opaque;
54 uint16_t old_status = n->status;
55
56 if (vc->link_down)
57 n->status &= ~VIRTIO_NET_S_LINK_UP;
58 else
59 n->status |= VIRTIO_NET_S_LINK_UP;
60
61 if (n->status != old_status)
62 virtio_notify_config(&n->vdev);
63 }
64
65 static uint32_t virtio_net_get_features(VirtIODevice *vdev)
66 {
67 uint32_t features = (1 << VIRTIO_NET_F_MAC) | (1 << VIRTIO_NET_F_STATUS);
68
69 return features;
70 }
71
72 static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
73 {
74 VirtIONet *n = to_virtio_net(vdev);
75
76 n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
77 }
78
79 /* RX */
80
81 static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
82 {
83 }
84
85 static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
86 {
87 if (!virtio_queue_ready(n->rx_vq) ||
88 !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
89 return 0;
90
91 if (virtio_queue_empty(n->rx_vq) ||
92 (n->mergeable_rx_bufs &&
93 !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
94 virtio_queue_set_notification(n->rx_vq, 1);
95 return 0;
96 }
97
98 virtio_queue_set_notification(n->rx_vq, 0);
99 return 1;
100 }
101
102 static int virtio_net_can_receive(void *opaque)
103 {
104 VirtIONet *n = opaque;
105
106 return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
107 }
108
109 static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
110 {
111 int offset, i;
112
113 offset = i = 0;
114 while (offset < count && i < iovcnt) {
115 int len = MIN(iov[i].iov_len, count - offset);
116 memcpy(iov[i].iov_base, buf + offset, len);
117 offset += len;
118 i++;
119 }
120
121 return offset;
122 }
123
124 static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
125 const void *buf, size_t size, size_t hdr_len)
126 {
127 struct virtio_net_hdr *hdr = iov[0].iov_base;
128 int offset = 0;
129
130 hdr->flags = 0;
131 hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
132
133 /* We only ever receive a struct virtio_net_hdr from the tapfd,
134 * but we may be passing along a larger header to the guest.
135 */
136 iov[0].iov_base += hdr_len;
137 iov[0].iov_len -= hdr_len;
138
139 return offset;
140 }
141
142 static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
143 {
144 VirtIONet *n = opaque;
145 struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
146 size_t hdr_len, offset, i;
147
148 if (!do_virtio_net_can_receive(n, size))
149 return;
150
151 /* hdr_len refers to the header we supply to the guest */
152 hdr_len = n->mergeable_rx_bufs ?
153 sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
154
155 offset = i = 0;
156
157 while (offset < size) {
158 VirtQueueElement elem;
159 int len, total;
160 struct iovec sg[VIRTQUEUE_MAX_SIZE];
161
162 len = total = 0;
163
164 if ((i != 0 && !n->mergeable_rx_bufs) ||
165 virtqueue_pop(n->rx_vq, &elem) == 0) {
166 if (i == 0)
167 return;
168 fprintf(stderr, "virtio-net truncating packet\n");
169 exit(1);
170 }
171
172 if (elem.in_num < 1) {
173 fprintf(stderr, "virtio-net receive queue contains no in buffers\n");
174 exit(1);
175 }
176
177 if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {
178 fprintf(stderr, "virtio-net header not in first element\n");
179 exit(1);
180 }
181
182 memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);
183
184 if (i == 0) {
185 if (n->mergeable_rx_bufs)
186 mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
187
188 offset += receive_header(n, sg, elem.in_num,
189 buf + offset, size - offset, hdr_len);
190 total += hdr_len;
191 }
192
193 /* copy in packet. ugh */
194 len = iov_fill(sg, elem.in_num,
195 buf + offset, size - offset);
196 total += len;
197
198 /* signal other side */
199 virtqueue_fill(n->rx_vq, &elem, total, i++);
200
201 offset += len;
202 }
203
204 if (mhdr)
205 mhdr->num_buffers = i;
206
207 virtqueue_flush(n->rx_vq, i);
208 virtio_notify(&n->vdev, n->rx_vq);
209 }
210
211 /* TX */
212 static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
213 {
214 VirtQueueElement elem;
215 int has_vnet_hdr = 0;
216
217 if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
218 return;
219
220 while (virtqueue_pop(vq, &elem)) {
221 ssize_t len = 0;
222 unsigned int out_num = elem.out_num;
223 struct iovec *out_sg = &elem.out_sg[0];
224 unsigned hdr_len;
225
226 /* hdr_len refers to the header received from the guest */
227 hdr_len = n->mergeable_rx_bufs ?
228 sizeof(struct virtio_net_hdr_mrg_rxbuf) :
229 sizeof(struct virtio_net_hdr);
230
231 if (out_num < 1 || out_sg->iov_len != hdr_len) {
232 fprintf(stderr, "virtio-net header not in first element\n");
233 exit(1);
234 }
235
236 /* ignore the header if GSO is not supported */
237 if (!has_vnet_hdr) {
238 out_num--;
239 out_sg++;
240 len += hdr_len;
241 } else if (n->mergeable_rx_bufs) {
242 /* tapfd expects a struct virtio_net_hdr */
243 hdr_len -= sizeof(struct virtio_net_hdr);
244 out_sg->iov_len -= hdr_len;
245 len += hdr_len;
246 }
247
248 len += qemu_sendv_packet(n->vc, out_sg, out_num);
249
250 virtqueue_push(vq, &elem, len);
251 virtio_notify(&n->vdev, vq);
252 }
253 }
254
255 static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
256 {
257 VirtIONet *n = to_virtio_net(vdev);
258
259 if (n->tx_timer_active) {
260 virtio_queue_set_notification(vq, 1);
261 qemu_del_timer(n->tx_timer);
262 n->tx_timer_active = 0;
263 virtio_net_flush_tx(n, vq);
264 } else {
265 qemu_mod_timer(n->tx_timer,
266 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
267 n->tx_timer_active = 1;
268 virtio_queue_set_notification(vq, 0);
269 }
270 }
271
272 static void virtio_net_tx_timer(void *opaque)
273 {
274 VirtIONet *n = opaque;
275
276 n->tx_timer_active = 0;
277
278 /* Just in case the driver is not ready on more */
279 if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
280 return;
281
282 virtio_queue_set_notification(n->tx_vq, 1);
283 virtio_net_flush_tx(n, n->tx_vq);
284 }
285
286 static void virtio_net_save(QEMUFile *f, void *opaque)
287 {
288 VirtIONet *n = opaque;
289
290 virtio_save(&n->vdev, f);
291
292 qemu_put_buffer(f, n->mac, 6);
293 qemu_put_be32(f, n->tx_timer_active);
294 qemu_put_be32(f, n->mergeable_rx_bufs);
295 }
296
297 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
298 {
299 VirtIONet *n = opaque;
300
301 if (version_id != 2)
302 return -EINVAL;
303
304 virtio_load(&n->vdev, f);
305
306 qemu_get_buffer(f, n->mac, 6);
307 n->tx_timer_active = qemu_get_be32(f);
308 n->mergeable_rx_bufs = qemu_get_be32(f);
309
310 if (n->tx_timer_active) {
311 qemu_mod_timer(n->tx_timer,
312 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
313 }
314
315 return 0;
316 }
317
318 PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
319 {
320 VirtIONet *n;
321 static int virtio_net_id;
322
323 n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
324 0, VIRTIO_ID_NET,
325 0x02, 0x00, 0x00,
326 sizeof(struct virtio_net_config),
327 sizeof(VirtIONet));
328 if (!n)
329 return NULL;
330
331 n->vdev.get_config = virtio_net_update_config;
332 n->vdev.get_features = virtio_net_get_features;
333 n->vdev.set_features = virtio_net_set_features;
334 n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
335 n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
336 memcpy(n->mac, nd->macaddr, 6);
337 n->status = VIRTIO_NET_S_LINK_UP;
338 n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
339 virtio_net_receive, virtio_net_can_receive, n);
340 n->vc->link_status_changed = virtio_net_set_link_status;
341
342 qemu_format_nic_info_str(n->vc, n->mac);
343
344 n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
345 n->tx_timer_active = 0;
346 n->mergeable_rx_bufs = 0;
347
348 register_savevm("virtio-net", virtio_net_id++, 2,
349 virtio_net_save, virtio_net_load, n);
350
351 return (PCIDevice *)n;
352 }