xref: /kvmtool/virtio/net.c (revision cb83de6f9db657b4414820b24e1e83794fd9b649)
131638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h"
2b5ee1ea7SAsias He #include "kvm/virtio-net.h"
34f56d42cSAsias He #include "kvm/virtio.h"
44f56d42cSAsias He #include "kvm/ioport.h"
54f56d42cSAsias He #include "kvm/types.h"
64f56d42cSAsias He #include "kvm/mutex.h"
74f56d42cSAsias He #include "kvm/util.h"
84f56d42cSAsias He #include "kvm/kvm.h"
94f56d42cSAsias He #include "kvm/pci.h"
102449f6e3SSasha Levin #include "kvm/irq.h"
11b5ee1ea7SAsias He #include "kvm/uip.h"
1227ab67f5SSasha Levin #include "kvm/ioeventfd.h"
13*cb83de6fSSasha Levin #include "kvm/guest_compat.h"
144f56d42cSAsias He 
154f56d42cSAsias He #include <linux/virtio_net.h>
164f56d42cSAsias He #include <linux/if_tun.h>
17c229370aSIngo Molnar 
18c229370aSIngo Molnar #include <arpa/inet.h>
194f56d42cSAsias He #include <net/if.h>
20c229370aSIngo Molnar 
21c229370aSIngo Molnar #include <unistd.h>
224f56d42cSAsias He #include <assert.h>
234f56d42cSAsias He #include <fcntl.h>
24c229370aSIngo Molnar 
25cb7202c1SSasha Levin #include <sys/socket.h>
26c229370aSIngo Molnar #include <sys/ioctl.h>
27c229370aSIngo Molnar #include <sys/types.h>
2873b7d038SAmos Kong #include <sys/wait.h>
294f56d42cSAsias He 
304f56d42cSAsias He #define VIRTIO_NET_QUEUE_SIZE		128
314f56d42cSAsias He #define VIRTIO_NET_NUM_QUEUES		2
324f56d42cSAsias He #define VIRTIO_NET_RX_QUEUE		0
334f56d42cSAsias He #define VIRTIO_NET_TX_QUEUE		1
344f56d42cSAsias He 
35c229370aSIngo Molnar static struct pci_device_header pci_header = {
362449f6e3SSasha Levin 	.vendor_id			= PCI_VENDOR_ID_REDHAT_QUMRANET,
372449f6e3SSasha Levin 	.device_id			= PCI_DEVICE_ID_VIRTIO_NET,
382449f6e3SSasha Levin 	.header_type			= PCI_HEADER_TYPE_NORMAL,
392449f6e3SSasha Levin 	.revision_id			= 0,
402449f6e3SSasha Levin 	.class				= 0x020000,
412449f6e3SSasha Levin 	.subsys_vendor_id		= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
420a7ab0c6SSasha Levin 	.subsys_id			= VIRTIO_ID_NET,
432449f6e3SSasha Levin };
442449f6e3SSasha Levin 
45b4fdde6dSAsias He struct net_dev;
46b4fdde6dSAsias He 
47b4fdde6dSAsias He struct net_dev_operations {
48b4fdde6dSAsias He 	int (*rx)(struct iovec *iov, u16 in, struct net_dev *ndev);
49b4fdde6dSAsias He 	int (*tx)(struct iovec *iov, u16 in, struct net_dev *ndev);
50b4fdde6dSAsias He };
51b4fdde6dSAsias He 
528626798bSAsias He struct net_dev {
534f56d42cSAsias He 	pthread_mutex_t			mutex;
544f56d42cSAsias He 
554f56d42cSAsias He 	struct virt_queue		vqs[VIRTIO_NET_NUM_QUEUES];
56c229370aSIngo Molnar 	struct virtio_net_config	config;
573fdf659dSSasha Levin 	u32				host_features;
583fdf659dSSasha Levin 	u32				guest_features;
593fdf659dSSasha Levin 	u16				config_vector;
603fdf659dSSasha Levin 	u8				status;
617f5ffaf5SAsias He 	u8				isr;
623fdf659dSSasha Levin 	u16				queue_selector;
6307f90696SSasha Levin 	u16				base_addr;
643395f880SSasha Levin 	u32				vq_vector[VIRTIO_NET_NUM_QUEUES];
653395f880SSasha Levin 	u32				gsis[VIRTIO_NET_NUM_QUEUES];
663395f880SSasha Levin 	u32				msix_io_block;
67*cb83de6fSSasha Levin 	int				compat_id;
684f56d42cSAsias He 
69c4aa7c02SPekka Enberg 	pthread_t			io_rx_thread;
70c229370aSIngo Molnar 	pthread_mutex_t			io_rx_lock;
71c4aa7c02SPekka Enberg 	pthread_cond_t			io_rx_cond;
72c4aa7c02SPekka Enberg 
73c4aa7c02SPekka Enberg 	pthread_t			io_tx_thread;
74c229370aSIngo Molnar 	pthread_mutex_t			io_tx_lock;
75c4aa7c02SPekka Enberg 	pthread_cond_t			io_tx_cond;
76c4aa7c02SPekka Enberg 
774f56d42cSAsias He 	int				tap_fd;
784f56d42cSAsias He 	char				tap_name[IFNAMSIZ];
79bb1a32f1SAsias He 
80bb1a32f1SAsias He 	int				mode;
81bb1a32f1SAsias He 
82b5ee1ea7SAsias He 	struct uip_info			info;
83b4fdde6dSAsias He 	struct net_dev_operations	*ops;
844f56d42cSAsias He };
854f56d42cSAsias He 
868626798bSAsias He static struct net_dev ndev = {
874f56d42cSAsias He 	.mutex	= PTHREAD_MUTEX_INITIALIZER,
884f56d42cSAsias He 
89c229370aSIngo Molnar 	.config = {
904f56d42cSAsias He 		.status			= VIRTIO_NET_S_LINK_UP,
914f56d42cSAsias He 	},
92407475bfSPekka Enberg 	.host_features			= 1UL << VIRTIO_NET_F_MAC
93407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_CSUM
94407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_UFO
95407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_TSO4
96407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_TSO6
97407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_UFO
98407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_TSO4
99407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_TSO6,
100b5ee1ea7SAsias He 	.info = {
101b5ee1ea7SAsias He 		.buf_nr			= 20,
102b5ee1ea7SAsias He 	}
1034f56d42cSAsias He };
1044f56d42cSAsias He 
105c4aa7c02SPekka Enberg static void *virtio_net_rx_thread(void *p)
1064f56d42cSAsias He {
1074f56d42cSAsias He 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
1084f56d42cSAsias He 	struct virt_queue *vq;
10943835ac9SSasha Levin 	struct kvm *kvm;
1103fdf659dSSasha Levin 	u16 out, in;
1113fdf659dSSasha Levin 	u16 head;
1124f56d42cSAsias He 	int len;
1134f56d42cSAsias He 
11443835ac9SSasha Levin 	kvm	= p;
115c229370aSIngo Molnar 	vq	= &ndev.vqs[VIRTIO_NET_RX_QUEUE];
116c4aa7c02SPekka Enberg 
117c4aa7c02SPekka Enberg 	while (1) {
118b5ee1ea7SAsias He 
119c229370aSIngo Molnar 		mutex_lock(&ndev.io_rx_lock);
120c4aa7c02SPekka Enberg 		if (!virt_queue__available(vq))
121c229370aSIngo Molnar 			pthread_cond_wait(&ndev.io_rx_cond, &ndev.io_rx_lock);
122c229370aSIngo Molnar 		mutex_unlock(&ndev.io_rx_lock);
1234f56d42cSAsias He 
1244f56d42cSAsias He 		while (virt_queue__available(vq)) {
125b5ee1ea7SAsias He 
12643835ac9SSasha Levin 			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
127b5ee1ea7SAsias He 
128b4fdde6dSAsias He 			len = ndev.ops->rx(iov, in, &ndev);
129b5ee1ea7SAsias He 
130246c8347SAsias He 			virt_queue__set_used_elem(vq, head, len);
1317f5ffaf5SAsias He 
132c4aa7c02SPekka Enberg 			/* We should interrupt guest right now, otherwise latency is huge. */
1333395f880SSasha Levin 			kvm__irq_trigger(kvm, ndev.gsis[VIRTIO_NET_RX_QUEUE]);
1344f56d42cSAsias He 		}
1354f56d42cSAsias He 
136c4aa7c02SPekka Enberg 	}
137c4aa7c02SPekka Enberg 
138c4aa7c02SPekka Enberg 	pthread_exit(NULL);
139c4aa7c02SPekka Enberg 	return NULL;
140c4aa7c02SPekka Enberg 
141c4aa7c02SPekka Enberg }
142c4aa7c02SPekka Enberg 
143c4aa7c02SPekka Enberg static void *virtio_net_tx_thread(void *p)
1444f56d42cSAsias He {
1454f56d42cSAsias He 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
1464f56d42cSAsias He 	struct virt_queue *vq;
14743835ac9SSasha Levin 	struct kvm *kvm;
1483fdf659dSSasha Levin 	u16 out, in;
1493fdf659dSSasha Levin 	u16 head;
1504f56d42cSAsias He 	int len;
1514f56d42cSAsias He 
15243835ac9SSasha Levin 	kvm	= p;
153c229370aSIngo Molnar 	vq	= &ndev.vqs[VIRTIO_NET_TX_QUEUE];
154c4aa7c02SPekka Enberg 
155c4aa7c02SPekka Enberg 	while (1) {
156c229370aSIngo Molnar 		mutex_lock(&ndev.io_tx_lock);
157c4aa7c02SPekka Enberg 		if (!virt_queue__available(vq))
158c229370aSIngo Molnar 			pthread_cond_wait(&ndev.io_tx_cond, &ndev.io_tx_lock);
159c229370aSIngo Molnar 		mutex_unlock(&ndev.io_tx_lock);
1604f56d42cSAsias He 
1614f56d42cSAsias He 		while (virt_queue__available(vq)) {
162b5ee1ea7SAsias He 
16343835ac9SSasha Levin 			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
164b5ee1ea7SAsias He 
165b4fdde6dSAsias He 			len = ndev.ops->tx(iov, out, &ndev);
166b5ee1ea7SAsias He 
1674f56d42cSAsias He 			virt_queue__set_used_elem(vq, head, len);
1684f56d42cSAsias He 		}
1694f56d42cSAsias He 
1703395f880SSasha Levin 		kvm__irq_trigger(kvm, ndev.gsis[VIRTIO_NET_TX_QUEUE]);
1714f56d42cSAsias He 	}
1724f56d42cSAsias He 
173c4aa7c02SPekka Enberg 	pthread_exit(NULL);
174407475bfSPekka Enberg 
175c4aa7c02SPekka Enberg 	return NULL;
176c4aa7c02SPekka Enberg 
177c4aa7c02SPekka Enberg }
178407475bfSPekka Enberg 
179c9f6a037SXiao Guangrong static bool virtio_net_pci_io_device_specific_in(void *data, unsigned long offset, int size)
1804f56d42cSAsias He {
181c229370aSIngo Molnar 	u8 *config_space = (u8 *)&ndev.config;
1824f56d42cSAsias He 
183c9f6a037SXiao Guangrong 	if (size != 1)
1844f56d42cSAsias He 		return false;
1854f56d42cSAsias He 
186b8f43678SSasha Levin 	if ((offset - VIRTIO_MSI_CONFIG_VECTOR) > sizeof(struct virtio_net_config))
1874542f276SCyrill Gorcunov 		pr_error("config offset is too big: %li", offset - VIRTIO_MSI_CONFIG_VECTOR);
1884f56d42cSAsias He 
189b8f43678SSasha Levin 	ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
1904f56d42cSAsias He 
1914f56d42cSAsias He 	return true;
1924f56d42cSAsias He }
1934f56d42cSAsias He 
194c9f6a037SXiao Guangrong static bool virtio_net_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
1954f56d42cSAsias He {
19607f90696SSasha Levin 	unsigned long	offset	= port - ndev.base_addr;
1974f56d42cSAsias He 	bool		ret	= true;
1984f56d42cSAsias He 
199c229370aSIngo Molnar 	mutex_lock(&ndev.mutex);
2004f56d42cSAsias He 
2014f56d42cSAsias He 	switch (offset) {
2024f56d42cSAsias He 	case VIRTIO_PCI_HOST_FEATURES:
203c229370aSIngo Molnar 		ioport__write32(data, ndev.host_features);
2044f56d42cSAsias He 		break;
2054f56d42cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
2064f56d42cSAsias He 		ret = false;
2074f56d42cSAsias He 		break;
2084f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_PFN:
209c229370aSIngo Molnar 		ioport__write32(data, ndev.vqs[ndev.queue_selector].pfn);
2104f56d42cSAsias He 		break;
2114f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_NUM:
2124f56d42cSAsias He 		ioport__write16(data, VIRTIO_NET_QUEUE_SIZE);
2134f56d42cSAsias He 		break;
2144f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_SEL:
2154f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_NOTIFY:
2164f56d42cSAsias He 		ret = false;
2174f56d42cSAsias He 		break;
2184f56d42cSAsias He 	case VIRTIO_PCI_STATUS:
219c229370aSIngo Molnar 		ioport__write8(data, ndev.status);
2204f56d42cSAsias He 		break;
2214f56d42cSAsias He 	case VIRTIO_PCI_ISR:
222c229370aSIngo Molnar 		ioport__write8(data, ndev.isr);
223c229370aSIngo Molnar 		kvm__irq_line(kvm, pci_header.irq_line, VIRTIO_IRQ_LOW);
224c229370aSIngo Molnar 		ndev.isr = VIRTIO_IRQ_LOW;
2254f56d42cSAsias He 		break;
2264f56d42cSAsias He 	default:
227c9f6a037SXiao Guangrong 		ret = virtio_net_pci_io_device_specific_in(data, offset, size);
2284f56d42cSAsias He 	};
2294f56d42cSAsias He 
230c229370aSIngo Molnar 	mutex_unlock(&ndev.mutex);
2314f56d42cSAsias He 
2324f56d42cSAsias He 	return ret;
2334f56d42cSAsias He }
2344f56d42cSAsias He 
23543835ac9SSasha Levin static void virtio_net_handle_callback(struct kvm *kvm, u16 queue_index)
2364f56d42cSAsias He {
237407475bfSPekka Enberg 	switch (queue_index) {
238b5ee1ea7SAsias He 	case VIRTIO_NET_TX_QUEUE:
239c229370aSIngo Molnar 		mutex_lock(&ndev.io_tx_lock);
240c229370aSIngo Molnar 		pthread_cond_signal(&ndev.io_tx_cond);
241c229370aSIngo Molnar 		mutex_unlock(&ndev.io_tx_lock);
242407475bfSPekka Enberg 		break;
243b5ee1ea7SAsias He 	case VIRTIO_NET_RX_QUEUE:
244c229370aSIngo Molnar 		mutex_lock(&ndev.io_rx_lock);
245c229370aSIngo Molnar 		pthread_cond_signal(&ndev.io_rx_cond);
246c229370aSIngo Molnar 		mutex_unlock(&ndev.io_rx_lock);
247407475bfSPekka Enberg 		break;
248407475bfSPekka Enberg 	default:
2494542f276SCyrill Gorcunov 		pr_warning("Unknown queue index %u", queue_index);
250c4aa7c02SPekka Enberg 	}
2514f56d42cSAsias He }
2524f56d42cSAsias He 
253c9f6a037SXiao Guangrong static bool virtio_net_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
2544f56d42cSAsias He {
25507f90696SSasha Levin 	unsigned long	offset		= port - ndev.base_addr;
2564f56d42cSAsias He 	bool		ret		= true;
2574f56d42cSAsias He 
258c229370aSIngo Molnar 	mutex_lock(&ndev.mutex);
2594f56d42cSAsias He 
2604f56d42cSAsias He 	switch (offset) {
2614f56d42cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
262c229370aSIngo Molnar 		ndev.guest_features	= ioport__read32(data);
2634f56d42cSAsias He 		break;
2644f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_PFN: {
2654f56d42cSAsias He 		struct virt_queue *queue;
2664f56d42cSAsias He 		void *p;
2674f56d42cSAsias He 
268c229370aSIngo Molnar 		assert(ndev.queue_selector < VIRTIO_NET_NUM_QUEUES);
2694f56d42cSAsias He 
270*cb83de6fSSasha Levin 		compat__remove_message(ndev.compat_id);
271*cb83de6fSSasha Levin 
272c229370aSIngo Molnar 		queue			= &ndev.vqs[ndev.queue_selector];
2734f56d42cSAsias He 		queue->pfn		= ioport__read32(data);
27443835ac9SSasha Levin 		p			= guest_pfn_to_host(kvm, queue->pfn);
2754f56d42cSAsias He 
276b8f43678SSasha Levin 		vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
2774f56d42cSAsias He 
2784f56d42cSAsias He 		break;
2794f56d42cSAsias He 	}
2804f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_SEL:
281c229370aSIngo Molnar 		ndev.queue_selector	= ioport__read16(data);
2824f56d42cSAsias He 		break;
2834f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_NOTIFY: {
2843fdf659dSSasha Levin 		u16 queue_index;
285c229370aSIngo Molnar 
2864f56d42cSAsias He 		queue_index		= ioport__read16(data);
28743835ac9SSasha Levin 		virtio_net_handle_callback(kvm, queue_index);
2884f56d42cSAsias He 		break;
2894f56d42cSAsias He 	}
2904f56d42cSAsias He 	case VIRTIO_PCI_STATUS:
291c229370aSIngo Molnar 		ndev.status		= ioport__read8(data);
2924f56d42cSAsias He 		break;
2934f56d42cSAsias He 	case VIRTIO_MSI_CONFIG_VECTOR:
2943395f880SSasha Levin 		ndev.config_vector	= ioport__read16(data);
2954f56d42cSAsias He 		break;
2963395f880SSasha Levin 	case VIRTIO_MSI_QUEUE_VECTOR: {
2973395f880SSasha Levin 		u32 gsi;
2983395f880SSasha Levin 		u32 vec;
2993395f880SSasha Levin 
3003395f880SSasha Levin 		vec = ndev.vq_vector[ndev.queue_selector] = ioport__read16(data);
3013395f880SSasha Levin 
3023395f880SSasha Levin 		gsi = irq__add_msix_route(kvm,
3033395f880SSasha Levin 					  pci_header.msix.table[vec].low,
3043395f880SSasha Levin 					  pci_header.msix.table[vec].high,
3053395f880SSasha Levin 					  pci_header.msix.table[vec].data);
3063395f880SSasha Levin 
3073395f880SSasha Levin 		ndev.gsis[ndev.queue_selector] = gsi;
3084f56d42cSAsias He 		break;
3093395f880SSasha Levin 	}
3104f56d42cSAsias He 	default:
3114f56d42cSAsias He 		ret			= false;
3124f56d42cSAsias He 	};
3134f56d42cSAsias He 
314c229370aSIngo Molnar 	mutex_unlock(&ndev.mutex);
315407475bfSPekka Enberg 
3164f56d42cSAsias He 	return ret;
3174f56d42cSAsias He }
3184f56d42cSAsias He 
31927ab67f5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param)
32027ab67f5SSasha Levin {
321926e0e2fSIngo Molnar 	virtio_net_handle_callback(kvm, (u64)(long)param);
32227ab67f5SSasha Levin }
32327ab67f5SSasha Levin 
3244f56d42cSAsias He static struct ioport_operations virtio_net_io_ops = {
3254f56d42cSAsias He 	.io_in	= virtio_net_pci_io_in,
3264f56d42cSAsias He 	.io_out	= virtio_net_pci_io_out,
3274f56d42cSAsias He };
3284f56d42cSAsias He 
3293395f880SSasha Levin static void callback_mmio(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
3303395f880SSasha Levin {
3313395f880SSasha Levin 	void *table = pci_header.msix.table;
3323395f880SSasha Levin 	if (is_write)
3333395f880SSasha Levin 		memcpy(table + addr - ndev.msix_io_block, data, len);
3343395f880SSasha Levin 	else
3353395f880SSasha Levin 		memcpy(data, table + addr - ndev.msix_io_block, len);
3363395f880SSasha Levin }
3373395f880SSasha Levin 
3383b02f580SSasha Levin static bool virtio_net__tap_init(const struct virtio_net_parameters *params)
3394f56d42cSAsias He {
340cb7202c1SSasha Levin 	int sock = socket(AF_INET, SOCK_STREAM, 0);
341f715177dSAsias He 	int pid, status, offload, hdr_len;
342cb7202c1SSasha Levin 	struct sockaddr_in sin = {0};
343246c8347SAsias He 	struct ifreq ifr;
3444f56d42cSAsias He 
345c229370aSIngo Molnar 	ndev.tap_fd = open("/dev/net/tun", O_RDWR);
346c229370aSIngo Molnar 	if (ndev.tap_fd < 0) {
3474542f276SCyrill Gorcunov 		pr_warning("Unable to open /dev/net/tun");
3483b02f580SSasha Levin 		goto fail;
3493b02f580SSasha Levin 	}
3504f56d42cSAsias He 
3514f56d42cSAsias He 	memset(&ifr, 0, sizeof(ifr));
352246c8347SAsias He 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
353c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETIFF, &ifr) < 0) {
3544542f276SCyrill Gorcunov 		pr_warning("Config tap device error. Are you root?");
3553b02f580SSasha Levin 		goto fail;
3563b02f580SSasha Levin 	}
3574f56d42cSAsias He 
358c229370aSIngo Molnar 	strncpy(ndev.tap_name, ifr.ifr_name, sizeof(ndev.tap_name));
3594f56d42cSAsias He 
360c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETNOCSUM, 1) < 0) {
3614542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETNOCSUM error");
362246c8347SAsias He 		goto fail;
363246c8347SAsias He 	}
364246c8347SAsias He 
365246c8347SAsias He 	hdr_len = sizeof(struct virtio_net_hdr);
366c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0) {
3674542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETVNETHDRSZ error");
368246c8347SAsias He 	}
369246c8347SAsias He 
370246c8347SAsias He 	offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
371c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETOFFLOAD, offload) < 0) {
3724542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETOFFLOAD error");
373246c8347SAsias He 		goto fail;
374246c8347SAsias He 	}
3754f56d42cSAsias He 
37673b7d038SAmos Kong 	if (strcmp(params->script, "none")) {
37773b7d038SAmos Kong 		pid = fork();
37873b7d038SAmos Kong 		if (pid == 0) {
379c229370aSIngo Molnar 			execl(params->script, params->script, ndev.tap_name, NULL);
38073b7d038SAmos Kong 			_exit(1);
38173b7d038SAmos Kong 		} else {
38273b7d038SAmos Kong 			waitpid(pid, &status, 0);
38373b7d038SAmos Kong 			if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
3844542f276SCyrill Gorcunov 				pr_warning("Fail to setup tap by %s", params->script);
38573b7d038SAmos Kong 				goto fail;
38673b7d038SAmos Kong 			}
38773b7d038SAmos Kong 		}
38873b7d038SAmos Kong 	} else {
389cb7202c1SSasha Levin 		memset(&ifr, 0, sizeof(ifr));
390c229370aSIngo Molnar 		strncpy(ifr.ifr_name, ndev.tap_name, sizeof(ndev.tap_name));
391bdfcfca6SSasha Levin 		sin.sin_addr.s_addr = inet_addr(params->host_ip);
392cb7202c1SSasha Levin 		memcpy(&(ifr.ifr_addr), &sin, sizeof(ifr.ifr_addr));
393cb7202c1SSasha Levin 		ifr.ifr_addr.sa_family = AF_INET;
3943b02f580SSasha Levin 		if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
3954542f276SCyrill Gorcunov 			pr_warning("Could not set ip address on tap device");
3963b02f580SSasha Levin 			goto fail;
3973b02f580SSasha Levin 		}
39873b7d038SAmos Kong 	}
399cb7202c1SSasha Levin 
400cb7202c1SSasha Levin 	memset(&ifr, 0, sizeof(ifr));
401c229370aSIngo Molnar 	strncpy(ifr.ifr_name, ndev.tap_name, sizeof(ndev.tap_name));
402cb7202c1SSasha Levin 	ioctl(sock, SIOCGIFFLAGS, &ifr);
403cb7202c1SSasha Levin 	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
404cb7202c1SSasha Levin 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0)
4054542f276SCyrill Gorcunov 		pr_warning("Could not bring tap device up");
406cb7202c1SSasha Levin 
407cb7202c1SSasha Levin 	close(sock);
4083b02f580SSasha Levin 
4093b02f580SSasha Levin 	return 1;
4103b02f580SSasha Levin 
4113b02f580SSasha Levin fail:
4123b02f580SSasha Levin 	if (sock >= 0)
4133b02f580SSasha Levin 		close(sock);
414c229370aSIngo Molnar 	if (ndev.tap_fd >= 0)
415c229370aSIngo Molnar 		close(ndev.tap_fd);
4163b02f580SSasha Levin 
4173b02f580SSasha Levin 	return 0;
4184f56d42cSAsias He }
4194f56d42cSAsias He 
42043835ac9SSasha Levin static void virtio_net__io_thread_init(struct kvm *kvm)
421c4aa7c02SPekka Enberg {
422c229370aSIngo Molnar 	pthread_mutex_init(&ndev.io_rx_lock, NULL);
423c229370aSIngo Molnar 	pthread_cond_init(&ndev.io_tx_cond, NULL);
424c4aa7c02SPekka Enberg 
425c229370aSIngo Molnar 	pthread_mutex_init(&ndev.io_rx_lock, NULL);
426c229370aSIngo Molnar 	pthread_cond_init(&ndev.io_tx_cond, NULL);
427c4aa7c02SPekka Enberg 
428c229370aSIngo Molnar 	pthread_create(&ndev.io_rx_thread, NULL, virtio_net_rx_thread, (void *)kvm);
429c229370aSIngo Molnar 	pthread_create(&ndev.io_tx_thread, NULL, virtio_net_tx_thread, (void *)kvm);
430c4aa7c02SPekka Enberg }
431c4aa7c02SPekka Enberg 
432b4fdde6dSAsias He static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
433b4fdde6dSAsias He {
434b4fdde6dSAsias He 	return writev(ndev->tap_fd, iov, out);
435b4fdde6dSAsias He }
436b4fdde6dSAsias He 
437b4fdde6dSAsias He static inline int tap_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
438b4fdde6dSAsias He {
439b4fdde6dSAsias He 	return readv(ndev->tap_fd, iov, in);
440b4fdde6dSAsias He }
441b4fdde6dSAsias He 
442b4fdde6dSAsias He static inline int uip_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
443b4fdde6dSAsias He {
444b4fdde6dSAsias He 	return uip_tx(iov, out, &ndev->info);
445b4fdde6dSAsias He }
446b4fdde6dSAsias He 
447b4fdde6dSAsias He static inline int uip_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
448b4fdde6dSAsias He {
449b4fdde6dSAsias He 	return uip_rx(iov, in, &ndev->info);
450b4fdde6dSAsias He }
451b4fdde6dSAsias He 
452b4fdde6dSAsias He static struct net_dev_operations tap_ops = {
453b4fdde6dSAsias He 	.rx	= tap_ops_rx,
454b4fdde6dSAsias He 	.tx	= tap_ops_tx,
455b4fdde6dSAsias He };
456b4fdde6dSAsias He 
457b4fdde6dSAsias He static struct net_dev_operations uip_ops = {
458b4fdde6dSAsias He 	.rx	= uip_ops_rx,
459b4fdde6dSAsias He 	.tx	= uip_ops_tx,
460b4fdde6dSAsias He };
461b4fdde6dSAsias He 
462bdfcfca6SSasha Levin void virtio_net__init(const struct virtio_net_parameters *params)
4634f56d42cSAsias He {
464b5ee1ea7SAsias He 	struct ioevent ioevent;
4652449f6e3SSasha Levin 	u8 dev, line, pin;
46607f90696SSasha Levin 	u16 net_base_addr;
467b5ee1ea7SAsias He 	int i;
4682449f6e3SSasha Levin 
4690a7ab0c6SSasha Levin 	if (irq__register_device(VIRTIO_ID_NET, &dev, &pin, &line) < 0)
4702449f6e3SSasha Levin 		return;
4712449f6e3SSasha Levin 
472c229370aSIngo Molnar 	pci_header.irq_pin  = pin;
473c229370aSIngo Molnar 	pci_header.irq_line = line;
47407f90696SSasha Levin 	net_base_addr	    = ioport__register(IOPORT_EMPTY, &virtio_net_io_ops, IOPORT_SIZE, NULL);
47507f90696SSasha Levin 	pci_header.bar[0]   = net_base_addr | PCI_BASE_ADDRESS_SPACE_IO;
47607f90696SSasha Levin 	ndev.base_addr	    = net_base_addr;
477c229370aSIngo Molnar 	pci__register(&pci_header, dev);
478c4aa7c02SPekka Enberg 
4790c54698eSAsias He 	for (i = 0 ; i < 6 ; i++) {
480f715177dSAsias He 		ndev.config.mac[i]		= params->guest_mac[i];
4810c54698eSAsias He 		ndev.info.guest_mac.addr[i]	= params->guest_mac[i];
4820c54698eSAsias He 		ndev.info.host_mac.addr[i]	= params->host_mac[i];
4830c54698eSAsias He 	}
484f715177dSAsias He 
485b5ee1ea7SAsias He 	ndev.mode = params->mode;
486b4fdde6dSAsias He 	if (ndev.mode == NET_MODE_TAP) {
487b5ee1ea7SAsias He 		virtio_net__tap_init(params);
488b4fdde6dSAsias He 		ndev.ops = &tap_ops;
489b4fdde6dSAsias He 	} else {
4900c54698eSAsias He 		ndev.info.host_ip		= ntohl(inet_addr(params->host_ip));
4910c54698eSAsias He 		ndev.info.guest_ip		= ntohl(inet_addr(params->guest_ip));
4920c54698eSAsias He 		ndev.info.guest_netmask		= ntohl(inet_addr("255.255.255.0"));
493b5ee1ea7SAsias He 		uip_init(&ndev.info);
494b4fdde6dSAsias He 		ndev.ops = &uip_ops;
495b4fdde6dSAsias He 	}
496b5ee1ea7SAsias He 
4973395f880SSasha Levin 	ndev.msix_io_block = pci_get_io_space_block();
4983395f880SSasha Levin 	kvm__register_mmio(params->kvm, ndev.msix_io_block, 0x100, callback_mmio, NULL);
4993395f880SSasha Levin 	pci_header.bar[1]	= ndev.msix_io_block |
5003395f880SSasha Levin 				PCI_BASE_ADDRESS_SPACE_MEMORY |
5013395f880SSasha Levin 				PCI_BASE_ADDRESS_MEM_TYPE_64;
5023395f880SSasha Levin 	/* bar[2] is the continuation of bar[1] for 64bit addressing */
5033395f880SSasha Levin 	pci_header.bar[2]	= 0;
5043395f880SSasha Levin 	pci_header.status	= PCI_STATUS_CAP_LIST;
5053395f880SSasha Levin 	pci_header.capabilities	= (void *)&pci_header.msix - (void *)&pci_header;
5063395f880SSasha Levin 
5073395f880SSasha Levin 	pci_header.msix.cap = PCI_CAP_ID_MSIX;
5083395f880SSasha Levin 	pci_header.msix.next = 0;
5093395f880SSasha Levin 	pci_header.msix.table_size = (VIRTIO_NET_NUM_QUEUES + 1) | PCI_MSIX_FLAGS_ENABLE;
5103395f880SSasha Levin 	pci_header.msix.table_offset = 1; /* Use BAR 1 */
5113395f880SSasha Levin 
51243835ac9SSasha Levin 	virtio_net__io_thread_init(params->kvm);
51327ab67f5SSasha Levin 
51427ab67f5SSasha Levin 	for (i = 0; i < VIRTIO_NET_NUM_QUEUES; i++) {
51527ab67f5SSasha Levin 		ioevent = (struct ioevent) {
51627ab67f5SSasha Levin 			.io_addr	= net_base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
51727ab67f5SSasha Levin 			.io_len		= sizeof(u16),
51827ab67f5SSasha Levin 			.fn		= ioevent_callback,
51927ab67f5SSasha Levin 			.datamatch	= i,
520926e0e2fSIngo Molnar 			.fn_ptr		= (void *)(long)i,
52127ab67f5SSasha Levin 			.fn_kvm		= params->kvm,
52227ab67f5SSasha Levin 			.fd		= eventfd(0, 0),
52327ab67f5SSasha Levin 		};
52427ab67f5SSasha Levin 
52527ab67f5SSasha Levin 		ioeventfd__add_event(&ioevent);
52627ab67f5SSasha Levin 	}
527*cb83de6fSSasha Levin 
528*cb83de6fSSasha Levin 	ndev.compat_id = compat__add_message("virtio-net device was not detected",
529*cb83de6fSSasha Levin 						"While you have requested a virtio-net device, "
530*cb83de6fSSasha Levin 						"the guest kernel didn't seem to detect it.\n"
531*cb83de6fSSasha Levin 						"Please make sure that the kernel was compiled"
532*cb83de6fSSasha Levin 						"with CONFIG_VIRTIO_NET.");
5334f56d42cSAsias He }
534