1 #include "kvm/virtio-pci-dev.h"
2 #include "kvm/virtio-net.h"
3 #include "kvm/virtio.h"
10 #include "kvm/guest_compat.h"
11 #include "kvm/virtio-pci.h"
13 #include <linux/virtio_net.h>
14 #include <linux/if_tun.h>
15 #include <linux/types.h>
17 #include <arpa/inet.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
29 #define VIRTIO_NET_QUEUE_SIZE 128
30 #define VIRTIO_NET_NUM_QUEUES 2
31 #define VIRTIO_NET_RX_QUEUE 0
32 #define VIRTIO_NET_TX_QUEUE 1
36 extern struct kvm
*kvm
;
38 struct net_dev_operations
{
39 int (*rx
)(struct iovec
*iov
, u16 in
, struct net_dev
*ndev
);
40 int (*tx
)(struct iovec
*iov
, u16 in
, struct net_dev
*ndev
);
44 pthread_mutex_t mutex
;
45 struct virtio_pci vpci
;
47 struct virt_queue vqs
[VIRTIO_NET_NUM_QUEUES
];
48 struct virtio_net_config config
;
52 pthread_t io_rx_thread
;
53 pthread_mutex_t io_rx_lock
;
54 pthread_cond_t io_rx_cond
;
56 pthread_t io_tx_thread
;
57 pthread_mutex_t io_tx_lock
;
58 pthread_cond_t io_tx_cond
;
61 char tap_name
[IFNAMSIZ
];
66 struct net_dev_operations
*ops
;
69 static struct net_dev ndev
= {
70 .mutex
= PTHREAD_MUTEX_INITIALIZER
,
73 .status
= VIRTIO_NET_S_LINK_UP
,
80 static void *virtio_net_rx_thread(void *p
)
82 struct iovec iov
[VIRTIO_NET_QUEUE_SIZE
];
83 struct virt_queue
*vq
;
90 vq
= &ndev
.vqs
[VIRTIO_NET_RX_QUEUE
];
94 mutex_lock(&ndev
.io_rx_lock
);
95 if (!virt_queue__available(vq
))
96 pthread_cond_wait(&ndev
.io_rx_cond
, &ndev
.io_rx_lock
);
97 mutex_unlock(&ndev
.io_rx_lock
);
99 while (virt_queue__available(vq
)) {
101 head
= virt_queue__get_iov(vq
, iov
, &out
, &in
, kvm
);
103 len
= ndev
.ops
->rx(iov
, in
, &ndev
);
105 virt_queue__set_used_elem(vq
, head
, len
);
107 /* We should interrupt guest right now, otherwise latency is huge. */
108 virtio_pci__signal_vq(kvm
, &ndev
.vpci
, VIRTIO_NET_RX_QUEUE
);
118 static void *virtio_net_tx_thread(void *p
)
120 struct iovec iov
[VIRTIO_NET_QUEUE_SIZE
];
121 struct virt_queue
*vq
;
128 vq
= &ndev
.vqs
[VIRTIO_NET_TX_QUEUE
];
131 mutex_lock(&ndev
.io_tx_lock
);
132 if (!virt_queue__available(vq
))
133 pthread_cond_wait(&ndev
.io_tx_cond
, &ndev
.io_tx_lock
);
134 mutex_unlock(&ndev
.io_tx_lock
);
136 while (virt_queue__available(vq
)) {
138 head
= virt_queue__get_iov(vq
, iov
, &out
, &in
, kvm
);
140 len
= ndev
.ops
->tx(iov
, out
, &ndev
);
142 virt_queue__set_used_elem(vq
, head
, len
);
145 virtio_pci__signal_vq(kvm
, &ndev
.vpci
, VIRTIO_NET_TX_QUEUE
);
154 static void virtio_net_handle_callback(struct kvm
*kvm
, u16 queue_index
)
156 switch (queue_index
) {
157 case VIRTIO_NET_TX_QUEUE
:
158 mutex_lock(&ndev
.io_tx_lock
);
159 pthread_cond_signal(&ndev
.io_tx_cond
);
160 mutex_unlock(&ndev
.io_tx_lock
);
162 case VIRTIO_NET_RX_QUEUE
:
163 mutex_lock(&ndev
.io_rx_lock
);
164 pthread_cond_signal(&ndev
.io_rx_cond
);
165 mutex_unlock(&ndev
.io_rx_lock
);
168 pr_warning("Unknown queue index %u", queue_index
);
172 static bool virtio_net__tap_init(const struct virtio_net_parameters
*params
)
174 int sock
= socket(AF_INET
, SOCK_STREAM
, 0);
175 int pid
, status
, offload
, hdr_len
;
176 struct sockaddr_in sin
= {0};
179 ndev
.tap_fd
= open("/dev/net/tun", O_RDWR
);
180 if (ndev
.tap_fd
< 0) {
181 pr_warning("Unable to open /dev/net/tun");
185 memset(&ifr
, 0, sizeof(ifr
));
186 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
| IFF_VNET_HDR
;
187 if (ioctl(ndev
.tap_fd
, TUNSETIFF
, &ifr
) < 0) {
188 pr_warning("Config tap device error. Are you root?");
192 strncpy(ndev
.tap_name
, ifr
.ifr_name
, sizeof(ndev
.tap_name
));
194 if (ioctl(ndev
.tap_fd
, TUNSETNOCSUM
, 1) < 0) {
195 pr_warning("Config tap device TUNSETNOCSUM error");
199 hdr_len
= sizeof(struct virtio_net_hdr
);
200 if (ioctl(ndev
.tap_fd
, TUNSETVNETHDRSZ
, &hdr_len
) < 0) {
201 pr_warning("Config tap device TUNSETVNETHDRSZ error");
204 offload
= TUN_F_CSUM
| TUN_F_TSO4
| TUN_F_TSO6
| TUN_F_UFO
;
205 if (ioctl(ndev
.tap_fd
, TUNSETOFFLOAD
, offload
) < 0) {
206 pr_warning("Config tap device TUNSETOFFLOAD error");
210 if (strcmp(params
->script
, "none")) {
213 execl(params
->script
, params
->script
, ndev
.tap_name
, NULL
);
216 waitpid(pid
, &status
, 0);
217 if (WIFEXITED(status
) && WEXITSTATUS(status
) != 0) {
218 pr_warning("Fail to setup tap by %s", params
->script
);
223 memset(&ifr
, 0, sizeof(ifr
));
224 strncpy(ifr
.ifr_name
, ndev
.tap_name
, sizeof(ndev
.tap_name
));
225 sin
.sin_addr
.s_addr
= inet_addr(params
->host_ip
);
226 memcpy(&(ifr
.ifr_addr
), &sin
, sizeof(ifr
.ifr_addr
));
227 ifr
.ifr_addr
.sa_family
= AF_INET
;
228 if (ioctl(sock
, SIOCSIFADDR
, &ifr
) < 0) {
229 pr_warning("Could not set ip address on tap device");
234 memset(&ifr
, 0, sizeof(ifr
));
235 strncpy(ifr
.ifr_name
, ndev
.tap_name
, sizeof(ndev
.tap_name
));
236 ioctl(sock
, SIOCGIFFLAGS
, &ifr
);
237 ifr
.ifr_flags
|= IFF_UP
| IFF_RUNNING
;
238 if (ioctl(sock
, SIOCSIFFLAGS
, &ifr
) < 0)
239 pr_warning("Could not bring tap device up");
248 if (ndev
.tap_fd
>= 0)
254 static void virtio_net__io_thread_init(struct kvm
*kvm
)
256 pthread_mutex_init(&ndev
.io_rx_lock
, NULL
);
257 pthread_cond_init(&ndev
.io_tx_cond
, NULL
);
259 pthread_mutex_init(&ndev
.io_rx_lock
, NULL
);
260 pthread_cond_init(&ndev
.io_tx_cond
, NULL
);
262 pthread_create(&ndev
.io_rx_thread
, NULL
, virtio_net_rx_thread
, (void *)kvm
);
263 pthread_create(&ndev
.io_tx_thread
, NULL
, virtio_net_tx_thread
, (void *)kvm
);
266 static inline int tap_ops_tx(struct iovec
*iov
, u16 out
, struct net_dev
*ndev
)
268 return writev(ndev
->tap_fd
, iov
, out
);
271 static inline int tap_ops_rx(struct iovec
*iov
, u16 in
, struct net_dev
*ndev
)
273 return readv(ndev
->tap_fd
, iov
, in
);
276 static inline int uip_ops_tx(struct iovec
*iov
, u16 out
, struct net_dev
*ndev
)
278 return uip_tx(iov
, out
, &ndev
->info
);
281 static inline int uip_ops_rx(struct iovec
*iov
, u16 in
, struct net_dev
*ndev
)
283 return uip_rx(iov
, in
, &ndev
->info
);
286 static struct net_dev_operations tap_ops
= {
291 static struct net_dev_operations uip_ops
= {
296 static void set_config(struct kvm
*kvm
, void *dev
, u8 data
, u32 offset
)
298 struct net_dev
*ndev
= dev
;
300 ((u8
*)(&ndev
->config
))[offset
] = data
;
303 static u8
get_config(struct kvm
*kvm
, void *dev
, u32 offset
)
305 struct net_dev
*ndev
= dev
;
307 return ((u8
*)(&ndev
->config
))[offset
];
310 static u32
get_host_features(struct kvm
*kvm
, void *dev
)
312 return 1UL << VIRTIO_NET_F_MAC
313 | 1UL << VIRTIO_NET_F_CSUM
314 | 1UL << VIRTIO_NET_F_HOST_UFO
315 | 1UL << VIRTIO_NET_F_HOST_TSO4
316 | 1UL << VIRTIO_NET_F_HOST_TSO6
317 | 1UL << VIRTIO_NET_F_GUEST_UFO
318 | 1UL << VIRTIO_NET_F_GUEST_TSO4
319 | 1UL << VIRTIO_NET_F_GUEST_TSO6
;
322 static void set_guest_features(struct kvm
*kvm
, void *dev
, u32 features
)
324 struct net_dev
*ndev
= dev
;
326 ndev
->features
= features
;
329 static int init_vq(struct kvm
*kvm
, void *dev
, u32 vq
, u32 pfn
)
331 struct net_dev
*ndev
= dev
;
332 struct virt_queue
*queue
;
335 compat__remove_message(ndev
->compat_id
);
337 queue
= &ndev
->vqs
[vq
];
339 p
= guest_pfn_to_host(kvm
, queue
->pfn
);
341 vring_init(&queue
->vring
, VIRTIO_NET_QUEUE_SIZE
, p
, VIRTIO_PCI_VRING_ALIGN
);
346 static int notify_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
348 virtio_net_handle_callback(kvm
, vq
);
353 static int get_pfn_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
355 struct net_dev
*ndev
= dev
;
357 return ndev
->vqs
[vq
].pfn
;
360 static int get_size_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
362 return VIRTIO_NET_QUEUE_SIZE
;
365 void virtio_net__init(const struct virtio_net_parameters
*params
)
369 for (i
= 0 ; i
< 6 ; i
++) {
370 ndev
.config
.mac
[i
] = params
->guest_mac
[i
];
371 ndev
.info
.guest_mac
.addr
[i
] = params
->guest_mac
[i
];
372 ndev
.info
.host_mac
.addr
[i
] = params
->host_mac
[i
];
375 ndev
.mode
= params
->mode
;
376 if (ndev
.mode
== NET_MODE_TAP
) {
377 virtio_net__tap_init(params
);
380 ndev
.info
.host_ip
= ntohl(inet_addr(params
->host_ip
));
381 ndev
.info
.guest_ip
= ntohl(inet_addr(params
->guest_ip
));
382 ndev
.info
.guest_netmask
= ntohl(inet_addr("255.255.255.0"));
383 uip_init(&ndev
.info
);
387 virtio_pci__init(kvm
, &ndev
.vpci
, &ndev
, PCI_DEVICE_ID_VIRTIO_NET
, VIRTIO_ID_NET
);
388 ndev
.vpci
.ops
= (struct virtio_pci_ops
) {
389 .set_config
= set_config
,
390 .get_config
= get_config
,
391 .get_host_features
= get_host_features
,
392 .set_guest_features
= set_guest_features
,
394 .notify_vq
= notify_vq
,
395 .get_pfn_vq
= get_pfn_vq
,
396 .get_size_vq
= get_size_vq
,
399 virtio_net__io_thread_init(params
->kvm
);
401 ndev
.compat_id
= compat__add_message("virtio-net device was not detected",
402 "While you have requested a virtio-net device, "
403 "the guest kernel didn't seem to detect it.\n"
404 "Please make sure that the kernel was compiled"
405 "with CONFIG_VIRTIO_NET.");