2 * Virtio Network Device
4 * Copyright IBM, Corp. 2007
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
17 #include "qemu-timer.h"
19 /* from Linux's virtio_net.h */
21 /* The ID for virtio_net */
22 #define VIRTIO_ID_NET 1
24 /* The feature bitmap for virtio net */
25 #define VIRTIO_NET_F_NO_CSUM 0
26 #define VIRTIO_NET_F_MAC 5
27 #define VIRTIO_NET_F_GS0 6
29 #define TX_TIMER_INTERVAL (1000 / 500)
31 /* The config defining mac address (6 bytes) */
32 struct virtio_net_config
35 } __attribute__((packed
));
37 /* This is the first element of the scatter-gather list. If you don't
38 * specify GSO or CSUM features, you can simply ignore the header. */
41 #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
43 #define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
44 #define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
45 /* FIXME: Do we need this? If they said they can handle ECN, do they care? */
46 #define VIRTIO_NET_HDR_GSO_TCPV4_ECN 2 // GSO frame, IPv4 TCP w/ ECN
47 #define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO)
48 #define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
49 #define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
57 typedef struct VirtIONet
66 struct VirtIONet
*next
;
72 static VirtIONet
*VirtIONetHead
= NULL
;
74 static VirtIONet
*to_virtio_net(VirtIODevice
*vdev
)
76 return (VirtIONet
*)vdev
;
79 static void virtio_net_update_config(VirtIODevice
*vdev
, uint8_t *config
)
81 VirtIONet
*n
= to_virtio_net(vdev
);
82 struct virtio_net_config netcfg
;
84 memcpy(netcfg
.mac
, n
->mac
, 6);
85 memcpy(config
, &netcfg
, sizeof(netcfg
));
88 static uint32_t virtio_net_get_features(VirtIODevice
*vdev
)
90 return (1 << VIRTIO_NET_F_MAC
);
95 static void virtio_net_handle_rx(VirtIODevice
*vdev
, VirtQueue
*vq
)
97 VirtIONet
*n
= to_virtio_net(vdev
);
101 static int virtio_net_can_receive(void *opaque
)
103 VirtIONet
*n
= opaque
;
105 return (n
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
) && n
->can_receive
;
108 /* -net user receive function */
109 static void virtio_net_receive(void *opaque
, const uint8_t *buf
, int size
)
111 VirtIONet
*n
= opaque
;
112 VirtQueueElement elem
;
113 struct virtio_net_hdr
*hdr
;
116 /* FIXME: the drivers really need to set their status better */
117 if (n
->rx_vq
->vring
.avail
== NULL
) {
122 if (virtqueue_pop(n
->rx_vq
, &elem
) == 0) {
123 /* wait until the guest adds some rx bufs */
128 hdr
= (void *)elem
.in_sg
[0].iov_base
;
130 hdr
->gso_type
= VIRTIO_NET_HDR_GSO_NONE
;
132 /* copy in packet. ugh */
135 while (offset
< size
&& i
< elem
.in_num
) {
136 int len
= MIN(elem
.in_sg
[i
].iov_len
, size
- offset
);
137 memcpy(elem
.in_sg
[i
].iov_base
, buf
+ offset
, len
);
142 /* signal other side */
143 virtqueue_push(n
->rx_vq
, &elem
, sizeof(*hdr
) + offset
);
144 virtio_notify(&n
->vdev
, n
->rx_vq
);
147 /* -net tap receive handler */
148 void virtio_net_poll(void)
155 VirtQueueElement elem
;
156 struct virtio_net_hdr
*hdr
;
165 // Prepare the set of device to select from
166 for (vnet
= VirtIONetHead
; vnet
; vnet
= vnet
->next
) {
168 if (vnet
->tap_fd
== -1)
172 //first check if the driver is ok
173 if (!virtio_net_can_receive(vnet
))
176 /* FIXME: the drivers really need to set their status better */
177 if (vnet
->rx_vq
->vring
.avail
== NULL
) {
178 vnet
->can_receive
= 0;
182 FD_SET(vnet
->tap_fd
, &rfds
);
183 if (max_fd
< vnet
->tap_fd
) max_fd
= vnet
->tap_fd
;
186 if (select(max_fd
+ 1, &rfds
, NULL
, NULL
, &tv
) <= 0)
189 // Now check who has data pending in the tap
190 for (vnet
= VirtIONetHead
; vnet
; vnet
= vnet
->next
) {
192 if (!FD_ISSET(vnet
->tap_fd
, &rfds
))
195 if (virtqueue_pop(vnet
->rx_vq
, &elem
) == 0) {
196 vnet
->can_receive
= 0;
200 hdr
= (void *)elem
.in_sg
[0].iov_base
;
202 hdr
->gso_type
= VIRTIO_NET_HDR_GSO_NONE
;
204 len
= readv(vnet
->tap_fd
, &elem
.in_sg
[1], elem
.in_num
- 1);
206 if (errno
== EINTR
|| errno
== EAGAIN
)
209 fprintf(stderr
, "reading network error %d", len
);
211 virtqueue_push(vnet
->rx_vq
, &elem
, sizeof(*hdr
) + len
);
215 /* signal other side */
217 for (vnet
= VirtIONetHead
; vnet
; vnet
= vnet
->next
)
218 if (vnet
->do_notify
) {
219 virtio_notify(&vnet
->vdev
, vnet
->rx_vq
);
229 static void virtio_net_flush_tx(VirtIONet
*n
, VirtQueue
*vq
)
231 VirtQueueElement elem
;
234 if (!(n
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
))
237 while (virtqueue_pop(vq
, &elem
)) {
241 /* ignore the header for now */
242 for (i
= 1; i
< elem
.out_num
; i
++) {
243 qemu_send_packet(n
->vc
, elem
.out_sg
[i
].iov_base
,
244 elem
.out_sg
[i
].iov_len
);
245 len
+= elem
.out_sg
[i
].iov_len
;
250 virtqueue_push(vq
, &elem
, sizeof(struct virtio_net_hdr
) + len
);
251 virtio_notify(&n
->vdev
, vq
);
255 static void virtio_net_handle_tx(VirtIODevice
*vdev
, VirtQueue
*vq
)
257 VirtIONet
*n
= to_virtio_net(vdev
);
259 if (n
->tx_timer_active
&&
260 (vq
->vring
.avail
->idx
- vq
->last_avail_idx
) == 64) {
261 vq
->vring
.used
->flags
&= ~VRING_USED_F_NO_NOTIFY
;
262 qemu_del_timer(n
->tx_timer
);
263 n
->tx_timer_active
= 0;
264 virtio_net_flush_tx(n
, vq
);
266 qemu_mod_timer(n
->tx_timer
,
267 qemu_get_clock(vm_clock
) + TX_TIMER_INTERVAL
);
268 n
->tx_timer_active
= 1;
269 vq
->vring
.used
->flags
|= VRING_USED_F_NO_NOTIFY
;
273 static void virtio_net_tx_timer(void *opaque
)
275 VirtIONet
*n
= opaque
;
277 n
->tx_vq
->vring
.used
->flags
&= ~VRING_USED_F_NO_NOTIFY
;
278 n
->tx_timer_active
= 0;
279 virtio_net_flush_tx(n
, n
->tx_vq
);
282 PCIDevice
*virtio_net_init(PCIBus
*bus
, NICInfo
*nd
, int devfn
)
286 n
= (VirtIONet
*)virtio_init_pci(bus
, "virtio-net", 6900, 0x1000,
289 6, sizeof(VirtIONet
));
291 n
->vdev
.update_config
= virtio_net_update_config
;
292 n
->vdev
.get_features
= virtio_net_get_features
;
293 n
->rx_vq
= virtio_add_queue(&n
->vdev
, 512, virtio_net_handle_rx
);
294 n
->tx_vq
= virtio_add_queue(&n
->vdev
, 128, virtio_net_handle_tx
);
296 memcpy(n
->mac
, nd
->macaddr
, 6);
297 n
->vc
= qemu_new_vlan_client(nd
->vlan
, virtio_net_receive
,
298 virtio_net_can_receive
, n
);
299 n
->tap_fd
= hack_around_tap(n
->vc
->vlan
->first_client
);
300 if (n
->tap_fd
!= -1) {
301 n
->next
= VirtIONetHead
;
302 //push the device on top of the list
306 n
->tx_timer
= qemu_new_timer(vm_clock
, virtio_net_tx_timer
, n
);
307 n
->tx_timer_active
= 0;
309 return (PCIDevice
*)n
;