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.
16 #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
69 * - we could suppress RX interrupt if we were so inclined.
72 static VirtIONet
*to_virtio_net(VirtIODevice
*vdev
)
74 return (VirtIONet
*)vdev
;
77 static void virtio_net_update_config(VirtIODevice
*vdev
, uint8_t *config
)
79 VirtIONet
*n
= to_virtio_net(vdev
);
80 struct virtio_net_config netcfg
;
82 memcpy(netcfg
.mac
, n
->mac
, 6);
83 memcpy(config
, &netcfg
, sizeof(netcfg
));
86 static uint32_t virtio_net_get_features(VirtIODevice
*vdev
)
88 return (1 << VIRTIO_NET_F_MAC
);
93 static void virtio_net_handle_rx(VirtIODevice
*vdev
, VirtQueue
*vq
)
95 /* We now have RX buffers, signal to the IO thread to break out of the
96 select to re-poll the tap file descriptor */
98 qemu_kvm_notify_work();
101 static int virtio_net_can_receive(void *opaque
)
103 VirtIONet
*n
= opaque
;
105 if (n
->rx_vq
->vring
.avail
== NULL
||
106 !(n
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
))
109 if (n
->rx_vq
->vring
.avail
->idx
== n
->rx_vq
->last_avail_idx
)
115 static void virtio_net_receive(void *opaque
, const uint8_t *buf
, int size
)
117 VirtIONet
*n
= opaque
;
118 VirtQueueElement elem
;
119 struct virtio_net_hdr
*hdr
;
122 if (virtqueue_pop(n
->rx_vq
, &elem
) == 0)
125 if (elem
.in_num
< 1 || elem
.in_sg
[0].iov_len
!= sizeof(*hdr
)) {
126 fprintf(stderr
, "virtio-net header not in first element\n");
130 hdr
= (void *)elem
.in_sg
[0].iov_base
;
132 hdr
->gso_type
= VIRTIO_NET_HDR_GSO_NONE
;
134 /* copy in packet. ugh */
137 while (offset
< size
&& i
< elem
.in_num
) {
138 int len
= MIN(elem
.in_sg
[i
].iov_len
, size
- offset
);
139 memcpy(elem
.in_sg
[i
].iov_base
, buf
+ offset
, len
);
144 /* signal other side */
145 virtqueue_push(n
->rx_vq
, &elem
, sizeof(*hdr
) + offset
);
146 virtio_notify(&n
->vdev
, n
->rx_vq
);
150 static void virtio_net_flush_tx(VirtIONet
*n
, VirtQueue
*vq
)
152 VirtQueueElement elem
;
154 if (!(n
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
))
157 while (virtqueue_pop(vq
, &elem
)) {
160 if (elem
.out_num
< 1 ||
161 elem
.out_sg
[0].iov_len
!= sizeof(struct virtio_net_hdr
)) {
162 fprintf(stderr
, "virtio-net header not in first element\n");
166 /* ignore the header for now */
167 len
= qemu_sendv_packet(n
->vc
, &elem
.out_sg
[1], elem
.out_num
- 1);
169 virtqueue_push(vq
, &elem
, sizeof(struct virtio_net_hdr
) + len
);
170 virtio_notify(&n
->vdev
, vq
);
174 static void virtio_net_handle_tx(VirtIODevice
*vdev
, VirtQueue
*vq
)
176 VirtIONet
*n
= to_virtio_net(vdev
);
178 if (n
->tx_timer_active
&&
179 (vq
->vring
.avail
->idx
- vq
->last_avail_idx
) == 64) {
180 vq
->vring
.used
->flags
&= ~VRING_USED_F_NO_NOTIFY
;
181 qemu_del_timer(n
->tx_timer
);
182 n
->tx_timer_active
= 0;
183 virtio_net_flush_tx(n
, vq
);
185 qemu_mod_timer(n
->tx_timer
,
186 qemu_get_clock(vm_clock
) + TX_TIMER_INTERVAL
);
187 n
->tx_timer_active
= 1;
188 vq
->vring
.used
->flags
|= VRING_USED_F_NO_NOTIFY
;
192 static void virtio_net_tx_timer(void *opaque
)
194 VirtIONet
*n
= opaque
;
196 n
->tx_timer_active
= 0;
198 /* Just in case the driver is not ready on more */
199 if (!(n
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
))
202 n
->tx_vq
->vring
.used
->flags
&= ~VRING_USED_F_NO_NOTIFY
;
203 virtio_net_flush_tx(n
, n
->tx_vq
);
206 static void virtio_net_save(QEMUFile
*f
, void *opaque
)
208 VirtIONet
*n
= opaque
;
210 virtio_save(&n
->vdev
, f
);
212 qemu_put_buffer(f
, n
->mac
, 6);
213 qemu_put_be32(f
, n
->tx_timer_active
);
216 static int virtio_net_load(QEMUFile
*f
, void *opaque
, int version_id
)
218 VirtIONet
*n
= opaque
;
223 virtio_load(&n
->vdev
, f
);
225 qemu_get_buffer(f
, n
->mac
, 6);
226 n
->tx_timer_active
= qemu_get_be32(f
);
228 if (n
->tx_timer_active
) {
229 qemu_mod_timer(n
->tx_timer
,
230 qemu_get_clock(vm_clock
) + TX_TIMER_INTERVAL
);
236 PCIDevice
*virtio_net_init(PCIBus
*bus
, NICInfo
*nd
, int devfn
)
239 static int virtio_net_id
;
241 n
= (VirtIONet
*)virtio_init_pci(bus
, "virtio-net", 6900, 0x1000,
244 6, sizeof(VirtIONet
));
248 n
->vdev
.update_config
= virtio_net_update_config
;
249 n
->vdev
.get_features
= virtio_net_get_features
;
250 n
->rx_vq
= virtio_add_queue(&n
->vdev
, 128, virtio_net_handle_rx
);
251 n
->tx_vq
= virtio_add_queue(&n
->vdev
, 128, virtio_net_handle_tx
);
252 memcpy(n
->mac
, nd
->macaddr
, 6);
253 n
->vc
= qemu_new_vlan_client(nd
->vlan
, virtio_net_receive
,
254 virtio_net_can_receive
, n
);
256 n
->tx_timer
= qemu_new_timer(vm_clock
, virtio_net_tx_timer
, n
);
257 n
->tx_timer_active
= 0;
259 register_savevm("virtio-net", virtio_net_id
++, 1,
260 virtio_net_save
, virtio_net_load
, n
);
262 return (PCIDevice
*)n
;