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