]> git.proxmox.com Git - qemu.git/blob - hw/virtio-net.c
524ef37134c9915c08a2cbcb87cd63a5b9e7f39c
[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 #define VIRTIO_NET_VM_VERSION 5
20
21 #define MAC_TABLE_ENTRIES 32
22
23 typedef struct VirtIONet
24 {
25 VirtIODevice vdev;
26 uint8_t mac[ETH_ALEN];
27 uint16_t status;
28 VirtQueue *rx_vq;
29 VirtQueue *tx_vq;
30 VirtQueue *ctrl_vq;
31 VLANClientState *vc;
32 QEMUTimer *tx_timer;
33 int tx_timer_active;
34 int mergeable_rx_bufs;
35 int promisc;
36 int allmulti;
37 struct {
38 int in_use;
39 uint8_t *macs;
40 } mac_table;
41 } VirtIONet;
42
43 /* TODO
44 * - we could suppress RX interrupt if we were so inclined.
45 */
46
47 static VirtIONet *to_virtio_net(VirtIODevice *vdev)
48 {
49 return (VirtIONet *)vdev;
50 }
51
52 static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
53 {
54 VirtIONet *n = to_virtio_net(vdev);
55 struct virtio_net_config netcfg;
56
57 netcfg.status = n->status;
58 memcpy(netcfg.mac, n->mac, ETH_ALEN);
59 memcpy(config, &netcfg, sizeof(netcfg));
60 }
61
62 static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
63 {
64 VirtIONet *n = to_virtio_net(vdev);
65 struct virtio_net_config netcfg;
66
67 memcpy(&netcfg, config, sizeof(netcfg));
68
69 if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
70 memcpy(n->mac, netcfg.mac, ETH_ALEN);
71 qemu_format_nic_info_str(n->vc, n->mac);
72 }
73 }
74
75 static void virtio_net_set_link_status(VLANClientState *vc)
76 {
77 VirtIONet *n = vc->opaque;
78 uint16_t old_status = n->status;
79
80 if (vc->link_down)
81 n->status &= ~VIRTIO_NET_S_LINK_UP;
82 else
83 n->status |= VIRTIO_NET_S_LINK_UP;
84
85 if (n->status != old_status)
86 virtio_notify_config(&n->vdev);
87 }
88
89 static void virtio_net_reset(VirtIODevice *vdev)
90 {
91 VirtIONet *n = to_virtio_net(vdev);
92
93 /* Reset back to compatibility mode */
94 n->promisc = 1;
95 n->allmulti = 0;
96
97 /* Flush any MAC filter table state */
98 n->mac_table.in_use = 0;
99 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
100 }
101
102 static uint32_t virtio_net_get_features(VirtIODevice *vdev)
103 {
104 uint32_t features = (1 << VIRTIO_NET_F_MAC) |
105 (1 << VIRTIO_NET_F_STATUS) |
106 (1 << VIRTIO_NET_F_CTRL_VQ) |
107 (1 << VIRTIO_NET_F_CTRL_RX);
108
109 return features;
110 }
111
112 static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
113 {
114 VirtIONet *n = to_virtio_net(vdev);
115
116 n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
117 }
118
119 static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
120 VirtQueueElement *elem)
121 {
122 uint8_t on;
123
124 if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
125 fprintf(stderr, "virtio-net ctrl invalid rx mode command\n");
126 exit(1);
127 }
128
129 on = ldub_p(elem->out_sg[1].iov_base);
130
131 if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC)
132 n->promisc = on;
133 else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI)
134 n->allmulti = on;
135 else
136 return VIRTIO_NET_ERR;
137
138 return VIRTIO_NET_OK;
139 }
140
141 static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
142 VirtQueueElement *elem)
143 {
144 struct virtio_net_ctrl_mac mac_data;
145
146 if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||
147 elem->out_sg[1].iov_len < sizeof(mac_data) ||
148 elem->out_sg[2].iov_len < sizeof(mac_data))
149 return VIRTIO_NET_ERR;
150
151 n->mac_table.in_use = 0;
152 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
153
154 mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
155
156 if (sizeof(mac_data.entries) +
157 (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
158 return VIRTIO_NET_ERR;
159
160 if (mac_data.entries <= MAC_TABLE_ENTRIES) {
161 memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),
162 mac_data.entries * ETH_ALEN);
163 n->mac_table.in_use += mac_data.entries;
164 } else {
165 n->promisc = 1;
166 return VIRTIO_NET_OK;
167 }
168
169 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
170
171 if (sizeof(mac_data.entries) +
172 (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
173 return VIRTIO_NET_ERR;
174
175 if (mac_data.entries) {
176 if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
177 memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
178 elem->out_sg[2].iov_base + sizeof(mac_data),
179 mac_data.entries * ETH_ALEN);
180 n->mac_table.in_use += mac_data.entries;
181 } else
182 n->allmulti = 1;
183 }
184
185 return VIRTIO_NET_OK;
186 }
187
188 static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
189 {
190 VirtIONet *n = to_virtio_net(vdev);
191 struct virtio_net_ctrl_hdr ctrl;
192 virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
193 VirtQueueElement elem;
194
195 while (virtqueue_pop(vq, &elem)) {
196 if ((elem.in_num < 1) || (elem.out_num < 1)) {
197 fprintf(stderr, "virtio-net ctrl missing headers\n");
198 exit(1);
199 }
200
201 if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
202 elem.out_sg[elem.in_num - 1].iov_len < sizeof(status)) {
203 fprintf(stderr, "virtio-net ctrl header not in correct element\n");
204 exit(1);
205 }
206
207 ctrl.class = ldub_p(elem.out_sg[0].iov_base);
208 ctrl.cmd = ldub_p(elem.out_sg[0].iov_base + sizeof(ctrl.class));
209
210 if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE)
211 status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem);
212 else if (ctrl.class == VIRTIO_NET_CTRL_MAC)
213 status = virtio_net_handle_mac(n, ctrl.cmd, &elem);
214
215 stb_p(elem.in_sg[elem.in_num - 1].iov_base, status);
216
217 virtqueue_push(vq, &elem, sizeof(status));
218 virtio_notify(vdev, vq);
219 }
220 }
221
222 /* RX */
223
224 static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
225 {
226 }
227
228 static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
229 {
230 if (!virtio_queue_ready(n->rx_vq) ||
231 !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
232 return 0;
233
234 if (virtio_queue_empty(n->rx_vq) ||
235 (n->mergeable_rx_bufs &&
236 !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
237 virtio_queue_set_notification(n->rx_vq, 1);
238 return 0;
239 }
240
241 virtio_queue_set_notification(n->rx_vq, 0);
242 return 1;
243 }
244
245 static int virtio_net_can_receive(void *opaque)
246 {
247 VirtIONet *n = opaque;
248
249 return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
250 }
251
252 static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
253 {
254 int offset, i;
255
256 offset = i = 0;
257 while (offset < count && i < iovcnt) {
258 int len = MIN(iov[i].iov_len, count - offset);
259 memcpy(iov[i].iov_base, buf + offset, len);
260 offset += len;
261 i++;
262 }
263
264 return offset;
265 }
266
267 static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
268 const void *buf, size_t size, size_t hdr_len)
269 {
270 struct virtio_net_hdr *hdr = iov[0].iov_base;
271 int offset = 0;
272
273 hdr->flags = 0;
274 hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
275
276 /* We only ever receive a struct virtio_net_hdr from the tapfd,
277 * but we may be passing along a larger header to the guest.
278 */
279 iov[0].iov_base += hdr_len;
280 iov[0].iov_len -= hdr_len;
281
282 return offset;
283 }
284
285 static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
286 {
287 static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
288 uint8_t *ptr = (uint8_t *)buf;
289 int i;
290
291 if (n->promisc)
292 return 1;
293
294 #ifdef TAP_VNET_HDR
295 if (tap_has_vnet_hdr(n->vc->vlan->first_client))
296 ptr += sizeof(struct virtio_net_hdr);
297 #endif
298
299 if ((ptr[0] & 1) && n->allmulti)
300 return 1;
301
302 if (!memcmp(ptr, bcast, sizeof(bcast)))
303 return 1;
304
305 if (!memcmp(ptr, n->mac, ETH_ALEN))
306 return 1;
307
308 for (i = 0; i < n->mac_table.in_use; i++) {
309 if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN))
310 return 1;
311 }
312
313 return 0;
314 }
315
316 static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
317 {
318 VirtIONet *n = opaque;
319 struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
320 size_t hdr_len, offset, i;
321
322 if (!do_virtio_net_can_receive(n, size))
323 return;
324
325 if (!receive_filter(n, buf, size))
326 return;
327
328 /* hdr_len refers to the header we supply to the guest */
329 hdr_len = n->mergeable_rx_bufs ?
330 sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
331
332 offset = i = 0;
333
334 while (offset < size) {
335 VirtQueueElement elem;
336 int len, total;
337 struct iovec sg[VIRTQUEUE_MAX_SIZE];
338
339 len = total = 0;
340
341 if ((i != 0 && !n->mergeable_rx_bufs) ||
342 virtqueue_pop(n->rx_vq, &elem) == 0) {
343 if (i == 0)
344 return;
345 fprintf(stderr, "virtio-net truncating packet\n");
346 exit(1);
347 }
348
349 if (elem.in_num < 1) {
350 fprintf(stderr, "virtio-net receive queue contains no in buffers\n");
351 exit(1);
352 }
353
354 if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {
355 fprintf(stderr, "virtio-net header not in first element\n");
356 exit(1);
357 }
358
359 memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);
360
361 if (i == 0) {
362 if (n->mergeable_rx_bufs)
363 mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
364
365 offset += receive_header(n, sg, elem.in_num,
366 buf + offset, size - offset, hdr_len);
367 total += hdr_len;
368 }
369
370 /* copy in packet. ugh */
371 len = iov_fill(sg, elem.in_num,
372 buf + offset, size - offset);
373 total += len;
374
375 /* signal other side */
376 virtqueue_fill(n->rx_vq, &elem, total, i++);
377
378 offset += len;
379 }
380
381 if (mhdr)
382 mhdr->num_buffers = i;
383
384 virtqueue_flush(n->rx_vq, i);
385 virtio_notify(&n->vdev, n->rx_vq);
386 }
387
388 /* TX */
389 static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
390 {
391 VirtQueueElement elem;
392 int has_vnet_hdr = 0;
393
394 if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
395 return;
396
397 while (virtqueue_pop(vq, &elem)) {
398 ssize_t len = 0;
399 unsigned int out_num = elem.out_num;
400 struct iovec *out_sg = &elem.out_sg[0];
401 unsigned hdr_len;
402
403 /* hdr_len refers to the header received from the guest */
404 hdr_len = n->mergeable_rx_bufs ?
405 sizeof(struct virtio_net_hdr_mrg_rxbuf) :
406 sizeof(struct virtio_net_hdr);
407
408 if (out_num < 1 || out_sg->iov_len != hdr_len) {
409 fprintf(stderr, "virtio-net header not in first element\n");
410 exit(1);
411 }
412
413 /* ignore the header if GSO is not supported */
414 if (!has_vnet_hdr) {
415 out_num--;
416 out_sg++;
417 len += hdr_len;
418 } else if (n->mergeable_rx_bufs) {
419 /* tapfd expects a struct virtio_net_hdr */
420 hdr_len -= sizeof(struct virtio_net_hdr);
421 out_sg->iov_len -= hdr_len;
422 len += hdr_len;
423 }
424
425 len += qemu_sendv_packet(n->vc, out_sg, out_num);
426
427 virtqueue_push(vq, &elem, len);
428 virtio_notify(&n->vdev, vq);
429 }
430 }
431
432 static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
433 {
434 VirtIONet *n = to_virtio_net(vdev);
435
436 if (n->tx_timer_active) {
437 virtio_queue_set_notification(vq, 1);
438 qemu_del_timer(n->tx_timer);
439 n->tx_timer_active = 0;
440 virtio_net_flush_tx(n, vq);
441 } else {
442 qemu_mod_timer(n->tx_timer,
443 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
444 n->tx_timer_active = 1;
445 virtio_queue_set_notification(vq, 0);
446 }
447 }
448
449 static void virtio_net_tx_timer(void *opaque)
450 {
451 VirtIONet *n = opaque;
452
453 n->tx_timer_active = 0;
454
455 /* Just in case the driver is not ready on more */
456 if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
457 return;
458
459 virtio_queue_set_notification(n->tx_vq, 1);
460 virtio_net_flush_tx(n, n->tx_vq);
461 }
462
463 static void virtio_net_save(QEMUFile *f, void *opaque)
464 {
465 VirtIONet *n = opaque;
466
467 virtio_save(&n->vdev, f);
468
469 qemu_put_buffer(f, n->mac, ETH_ALEN);
470 qemu_put_be32(f, n->tx_timer_active);
471 qemu_put_be32(f, n->mergeable_rx_bufs);
472 qemu_put_be16(f, n->status);
473 qemu_put_be32(f, n->promisc);
474 qemu_put_be32(f, n->allmulti);
475 qemu_put_be32(f, n->mac_table.in_use);
476 qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
477 }
478
479 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
480 {
481 VirtIONet *n = opaque;
482
483 if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
484 return -EINVAL;
485
486 virtio_load(&n->vdev, f);
487
488 qemu_get_buffer(f, n->mac, ETH_ALEN);
489 n->tx_timer_active = qemu_get_be32(f);
490 n->mergeable_rx_bufs = qemu_get_be32(f);
491
492 if (version_id >= 3)
493 n->status = qemu_get_be16(f);
494
495 if (version_id >= 4) {
496 n->promisc = qemu_get_be32(f);
497 n->allmulti = qemu_get_be32(f);
498 }
499
500 if (version_id >= 5) {
501 n->mac_table.in_use = qemu_get_be32(f);
502 /* MAC_TABLE_ENTRIES may be different from the saved image */
503 if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
504 qemu_get_buffer(f, n->mac_table.macs,
505 n->mac_table.in_use * ETH_ALEN);
506 } else if (n->mac_table.in_use) {
507 qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
508 n->promisc = 1;
509 n->mac_table.in_use = 0;
510 }
511 }
512
513 if (n->tx_timer_active) {
514 qemu_mod_timer(n->tx_timer,
515 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
516 }
517
518 return 0;
519 }
520
521 void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
522 {
523 VirtIONet *n;
524 static int virtio_net_id;
525
526 n = (VirtIONet *)virtio_init_pci(bus, "virtio-net",
527 PCI_VENDOR_ID_REDHAT_QUMRANET,
528 PCI_DEVICE_ID_VIRTIO_NET,
529 PCI_VENDOR_ID_REDHAT_QUMRANET,
530 VIRTIO_ID_NET,
531 PCI_CLASS_NETWORK_ETHERNET, 0x00,
532 sizeof(struct virtio_net_config),
533 sizeof(VirtIONet));
534 if (!n)
535 return;
536
537 n->vdev.get_config = virtio_net_get_config;
538 n->vdev.set_config = virtio_net_set_config;
539 n->vdev.get_features = virtio_net_get_features;
540 n->vdev.set_features = virtio_net_set_features;
541 n->vdev.reset = virtio_net_reset;
542 n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
543 n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
544 n->ctrl_vq = virtio_add_queue(&n->vdev, 16, virtio_net_handle_ctrl);
545 memcpy(n->mac, nd->macaddr, ETH_ALEN);
546 n->status = VIRTIO_NET_S_LINK_UP;
547 n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
548 virtio_net_receive, virtio_net_can_receive, n);
549 n->vc->link_status_changed = virtio_net_set_link_status;
550
551 qemu_format_nic_info_str(n->vc, n->mac);
552
553 n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
554 n->tx_timer_active = 0;
555 n->mergeable_rx_bufs = 0;
556 n->promisc = 1; /* for compatibility */
557
558 n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
559 if (!n->mac_table.macs)
560 return;
561
562 register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
563 virtio_net_save, virtio_net_load, n);
564 }