xref: /kvmtool/virtio/net.c (revision b5ee1ea7a0542629bf33b7fefd3f2f76c50096aa)
131638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h"
2*b5ee1ea7SAsias 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"
11*b5ee1ea7SAsias He #include "kvm/uip.h"
1227ab67f5SSasha Levin #include "kvm/ioeventfd.h"
134f56d42cSAsias He 
144f56d42cSAsias He #include <linux/virtio_net.h>
154f56d42cSAsias He #include <linux/if_tun.h>
16c229370aSIngo Molnar 
17c229370aSIngo Molnar #include <arpa/inet.h>
184f56d42cSAsias He #include <net/if.h>
19c229370aSIngo Molnar 
20c229370aSIngo Molnar #include <unistd.h>
214f56d42cSAsias He #include <assert.h>
224f56d42cSAsias He #include <fcntl.h>
23c229370aSIngo Molnar 
24cb7202c1SSasha Levin #include <sys/socket.h>
25c229370aSIngo Molnar #include <sys/ioctl.h>
26c229370aSIngo Molnar #include <sys/types.h>
2773b7d038SAmos Kong #include <sys/wait.h>
284f56d42cSAsias He 
294f56d42cSAsias He #define VIRTIO_NET_QUEUE_SIZE		128
304f56d42cSAsias He #define VIRTIO_NET_NUM_QUEUES		2
314f56d42cSAsias He #define VIRTIO_NET_RX_QUEUE		0
324f56d42cSAsias He #define VIRTIO_NET_TX_QUEUE		1
334f56d42cSAsias He 
34c229370aSIngo Molnar static struct pci_device_header pci_header = {
352449f6e3SSasha Levin 	.vendor_id			= PCI_VENDOR_ID_REDHAT_QUMRANET,
362449f6e3SSasha Levin 	.device_id			= PCI_DEVICE_ID_VIRTIO_NET,
372449f6e3SSasha Levin 	.header_type			= PCI_HEADER_TYPE_NORMAL,
382449f6e3SSasha Levin 	.revision_id			= 0,
392449f6e3SSasha Levin 	.class				= 0x020000,
402449f6e3SSasha Levin 	.subsys_vendor_id		= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
410a7ab0c6SSasha Levin 	.subsys_id			= VIRTIO_ID_NET,
422449f6e3SSasha Levin };
432449f6e3SSasha Levin 
448626798bSAsias He struct net_dev {
454f56d42cSAsias He 	pthread_mutex_t			mutex;
464f56d42cSAsias He 
474f56d42cSAsias He 	struct virt_queue		vqs[VIRTIO_NET_NUM_QUEUES];
48c229370aSIngo Molnar 	struct virtio_net_config	config;
493fdf659dSSasha Levin 	u32				host_features;
503fdf659dSSasha Levin 	u32				guest_features;
513fdf659dSSasha Levin 	u16				config_vector;
523fdf659dSSasha Levin 	u8				status;
537f5ffaf5SAsias He 	u8				isr;
543fdf659dSSasha Levin 	u16				queue_selector;
5507f90696SSasha Levin 	u16				base_addr;
564f56d42cSAsias He 
57c4aa7c02SPekka Enberg 	pthread_t			io_rx_thread;
58c229370aSIngo Molnar 	pthread_mutex_t			io_rx_lock;
59c4aa7c02SPekka Enberg 	pthread_cond_t			io_rx_cond;
60c4aa7c02SPekka Enberg 
61c4aa7c02SPekka Enberg 	pthread_t			io_tx_thread;
62c229370aSIngo Molnar 	pthread_mutex_t			io_tx_lock;
63c4aa7c02SPekka Enberg 	pthread_cond_t			io_tx_cond;
64c4aa7c02SPekka Enberg 
654f56d42cSAsias He 	int				tap_fd;
664f56d42cSAsias He 	char				tap_name[IFNAMSIZ];
67bb1a32f1SAsias He 
68bb1a32f1SAsias He 	int				mode;
69bb1a32f1SAsias He 
70*b5ee1ea7SAsias He 	struct uip_info			info;
714f56d42cSAsias He };
724f56d42cSAsias He 
738626798bSAsias He 
748626798bSAsias He static struct net_dev ndev = {
754f56d42cSAsias He 	.mutex	= PTHREAD_MUTEX_INITIALIZER,
764f56d42cSAsias He 
77c229370aSIngo Molnar 	.config = {
78a0db70d9SAsias He 		.mac			= {0x00, 0x15, 0x15, 0x15, 0x15, 0x15},
794f56d42cSAsias He 		.status			= VIRTIO_NET_S_LINK_UP,
804f56d42cSAsias He 	},
81407475bfSPekka Enberg 	.host_features			= 1UL << VIRTIO_NET_F_MAC
82407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_CSUM
83407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_UFO
84407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_TSO4
85407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_HOST_TSO6
86407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_UFO
87407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_TSO4
88407475bfSPekka Enberg 					| 1UL << VIRTIO_NET_F_GUEST_TSO6,
89*b5ee1ea7SAsias He 	.info = {
90*b5ee1ea7SAsias He 		.host_mac.addr		= {0x00, 0x01, 0x01, 0x01, 0x01, 0x01},
91*b5ee1ea7SAsias He 		.guest_mac.addr		= {0x00, 0x15, 0x15, 0x15, 0x15, 0x15},
92*b5ee1ea7SAsias He 		.host_ip		= 0xc0a82101,
93*b5ee1ea7SAsias He 		.buf_nr			= 20,
94*b5ee1ea7SAsias He 	}
954f56d42cSAsias He };
964f56d42cSAsias He 
97c4aa7c02SPekka Enberg static void *virtio_net_rx_thread(void *p)
984f56d42cSAsias He {
994f56d42cSAsias He 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
1004f56d42cSAsias He 	struct virt_queue *vq;
10143835ac9SSasha Levin 	struct kvm *kvm;
1023fdf659dSSasha Levin 	u16 out, in;
1033fdf659dSSasha Levin 	u16 head;
1044f56d42cSAsias He 	int len;
1054f56d42cSAsias He 
10643835ac9SSasha Levin 	kvm	= p;
107c229370aSIngo Molnar 	vq	= &ndev.vqs[VIRTIO_NET_RX_QUEUE];
108c4aa7c02SPekka Enberg 
109c4aa7c02SPekka Enberg 	while (1) {
110*b5ee1ea7SAsias He 
111c229370aSIngo Molnar 		mutex_lock(&ndev.io_rx_lock);
112c4aa7c02SPekka Enberg 		if (!virt_queue__available(vq))
113c229370aSIngo Molnar 			pthread_cond_wait(&ndev.io_rx_cond, &ndev.io_rx_lock);
114c229370aSIngo Molnar 		mutex_unlock(&ndev.io_rx_lock);
1154f56d42cSAsias He 
1164f56d42cSAsias He 		while (virt_queue__available(vq)) {
117*b5ee1ea7SAsias He 
11843835ac9SSasha Levin 			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
119*b5ee1ea7SAsias He 
120*b5ee1ea7SAsias He 			if (ndev.mode == NET_MODE_TAP)
121c229370aSIngo Molnar 				len = readv(ndev.tap_fd, iov, in);
122*b5ee1ea7SAsias He 			else
123*b5ee1ea7SAsias He 				len = uip_rx(iov, in, &ndev.info);
124*b5ee1ea7SAsias He 
125246c8347SAsias He 			virt_queue__set_used_elem(vq, head, len);
1267f5ffaf5SAsias He 
127c4aa7c02SPekka Enberg 			/* We should interrupt guest right now, otherwise latency is huge. */
128c229370aSIngo Molnar 			virt_queue__trigger_irq(vq, pci_header.irq_line, &ndev.isr, kvm);
1294f56d42cSAsias He 		}
1304f56d42cSAsias He 
131c4aa7c02SPekka Enberg 	}
132c4aa7c02SPekka Enberg 
133c4aa7c02SPekka Enberg 	pthread_exit(NULL);
134c4aa7c02SPekka Enberg 	return NULL;
135c4aa7c02SPekka Enberg 
136c4aa7c02SPekka Enberg }
137c4aa7c02SPekka Enberg 
138c4aa7c02SPekka Enberg static void *virtio_net_tx_thread(void *p)
1394f56d42cSAsias He {
1404f56d42cSAsias He 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
1414f56d42cSAsias He 	struct virt_queue *vq;
14243835ac9SSasha Levin 	struct kvm *kvm;
1433fdf659dSSasha Levin 	u16 out, in;
1443fdf659dSSasha Levin 	u16 head;
1454f56d42cSAsias He 	int len;
1464f56d42cSAsias He 
14743835ac9SSasha Levin 	kvm	= p;
148c229370aSIngo Molnar 	vq	= &ndev.vqs[VIRTIO_NET_TX_QUEUE];
149c4aa7c02SPekka Enberg 
150c4aa7c02SPekka Enberg 	while (1) {
151c229370aSIngo Molnar 		mutex_lock(&ndev.io_tx_lock);
152c4aa7c02SPekka Enberg 		if (!virt_queue__available(vq))
153c229370aSIngo Molnar 			pthread_cond_wait(&ndev.io_tx_cond, &ndev.io_tx_lock);
154c229370aSIngo Molnar 		mutex_unlock(&ndev.io_tx_lock);
1554f56d42cSAsias He 
1564f56d42cSAsias He 		while (virt_queue__available(vq)) {
157*b5ee1ea7SAsias He 
15843835ac9SSasha Levin 			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
159*b5ee1ea7SAsias He 
160*b5ee1ea7SAsias He 			if (ndev.mode == NET_MODE_TAP)
161c229370aSIngo Molnar 				len = writev(ndev.tap_fd, iov, out);
162*b5ee1ea7SAsias He 			else
163*b5ee1ea7SAsias He 				len = uip_tx(iov, out, &ndev.info);
164*b5ee1ea7SAsias He 
1654f56d42cSAsias He 			virt_queue__set_used_elem(vq, head, len);
1664f56d42cSAsias He 		}
1674f56d42cSAsias He 
168c229370aSIngo Molnar 		virt_queue__trigger_irq(vq, pci_header.irq_line, &ndev.isr, kvm);
1697f5ffaf5SAsias He 
1704f56d42cSAsias He 	}
1714f56d42cSAsias He 
172c4aa7c02SPekka Enberg 	pthread_exit(NULL);
173407475bfSPekka Enberg 
174c4aa7c02SPekka Enberg 	return NULL;
175c4aa7c02SPekka Enberg 
176c4aa7c02SPekka Enberg }
177407475bfSPekka Enberg 
1783fdf659dSSasha Levin static bool virtio_net_pci_io_device_specific_in(void *data, unsigned long offset, int size, u32 count)
1794f56d42cSAsias He {
180c229370aSIngo Molnar 	u8 *config_space = (u8 *)&ndev.config;
1814f56d42cSAsias He 
1824f56d42cSAsias He 	if (size != 1 || count != 1)
1834f56d42cSAsias He 		return false;
1844f56d42cSAsias He 
185b8f43678SSasha Levin 	if ((offset - VIRTIO_MSI_CONFIG_VECTOR) > sizeof(struct virtio_net_config))
1864542f276SCyrill Gorcunov 		pr_error("config offset is too big: %li", offset - VIRTIO_MSI_CONFIG_VECTOR);
1874f56d42cSAsias He 
188b8f43678SSasha Levin 	ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
1894f56d42cSAsias He 
1904f56d42cSAsias He 	return true;
1914f56d42cSAsias He }
1924f56d42cSAsias He 
1933d62dea6SSasha Levin static bool virtio_net_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
1944f56d42cSAsias He {
19507f90696SSasha Levin 	unsigned long	offset	= port - ndev.base_addr;
1964f56d42cSAsias He 	bool		ret	= true;
1974f56d42cSAsias He 
198c229370aSIngo Molnar 	mutex_lock(&ndev.mutex);
1994f56d42cSAsias He 
2004f56d42cSAsias He 	switch (offset) {
2014f56d42cSAsias He 	case VIRTIO_PCI_HOST_FEATURES:
202c229370aSIngo Molnar 		ioport__write32(data, ndev.host_features);
2034f56d42cSAsias He 		break;
2044f56d42cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
2054f56d42cSAsias He 		ret = false;
2064f56d42cSAsias He 		break;
2074f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_PFN:
208c229370aSIngo Molnar 		ioport__write32(data, ndev.vqs[ndev.queue_selector].pfn);
2094f56d42cSAsias He 		break;
2104f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_NUM:
2114f56d42cSAsias He 		ioport__write16(data, VIRTIO_NET_QUEUE_SIZE);
2124f56d42cSAsias He 		break;
2134f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_SEL:
2144f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_NOTIFY:
2154f56d42cSAsias He 		ret = false;
2164f56d42cSAsias He 		break;
2174f56d42cSAsias He 	case VIRTIO_PCI_STATUS:
218c229370aSIngo Molnar 		ioport__write8(data, ndev.status);
2194f56d42cSAsias He 		break;
2204f56d42cSAsias He 	case VIRTIO_PCI_ISR:
221c229370aSIngo Molnar 		ioport__write8(data, ndev.isr);
222c229370aSIngo Molnar 		kvm__irq_line(kvm, pci_header.irq_line, VIRTIO_IRQ_LOW);
223c229370aSIngo Molnar 		ndev.isr = VIRTIO_IRQ_LOW;
2244f56d42cSAsias He 		break;
2254f56d42cSAsias He 	case VIRTIO_MSI_CONFIG_VECTOR:
226c229370aSIngo Molnar 		ioport__write16(data, ndev.config_vector);
2274f56d42cSAsias He 		break;
2284f56d42cSAsias He 	default:
2294f56d42cSAsias He 		ret = virtio_net_pci_io_device_specific_in(data, offset, size, count);
2304f56d42cSAsias He 	};
2314f56d42cSAsias He 
232c229370aSIngo Molnar 	mutex_unlock(&ndev.mutex);
2334f56d42cSAsias He 
2344f56d42cSAsias He 	return ret;
2354f56d42cSAsias He }
2364f56d42cSAsias He 
23743835ac9SSasha Levin static void virtio_net_handle_callback(struct kvm *kvm, u16 queue_index)
2384f56d42cSAsias He {
239407475bfSPekka Enberg 	switch (queue_index) {
240*b5ee1ea7SAsias He 	case VIRTIO_NET_TX_QUEUE:
241c229370aSIngo Molnar 		mutex_lock(&ndev.io_tx_lock);
242c229370aSIngo Molnar 		pthread_cond_signal(&ndev.io_tx_cond);
243c229370aSIngo Molnar 		mutex_unlock(&ndev.io_tx_lock);
244407475bfSPekka Enberg 		break;
245*b5ee1ea7SAsias He 	case VIRTIO_NET_RX_QUEUE:
246c229370aSIngo Molnar 		mutex_lock(&ndev.io_rx_lock);
247c229370aSIngo Molnar 		pthread_cond_signal(&ndev.io_rx_cond);
248c229370aSIngo Molnar 		mutex_unlock(&ndev.io_rx_lock);
249407475bfSPekka Enberg 		break;
250407475bfSPekka Enberg 	default:
2514542f276SCyrill Gorcunov 		pr_warning("Unknown queue index %u", queue_index);
252c4aa7c02SPekka Enberg 	}
2534f56d42cSAsias He }
2544f56d42cSAsias He 
2553d62dea6SSasha Levin static bool virtio_net_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
2564f56d42cSAsias He {
25707f90696SSasha Levin 	unsigned long	offset		= port - ndev.base_addr;
2584f56d42cSAsias He 	bool		ret		= true;
2594f56d42cSAsias He 
260c229370aSIngo Molnar 	mutex_lock(&ndev.mutex);
2614f56d42cSAsias He 
2624f56d42cSAsias He 	switch (offset) {
2634f56d42cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
264c229370aSIngo Molnar 		ndev.guest_features	= ioport__read32(data);
2654f56d42cSAsias He 		break;
2664f56d42cSAsias He 	case VIRTIO_PCI_QUEUE_PFN: {
2674f56d42cSAsias He 		struct virt_queue *queue;
2684f56d42cSAsias He 		void *p;
2694f56d42cSAsias He 
270c229370aSIngo Molnar 		assert(ndev.queue_selector < VIRTIO_NET_NUM_QUEUES);
2714f56d42cSAsias He 
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:
294c229370aSIngo Molnar 		ndev.config_vector	= VIRTIO_MSI_NO_VECTOR;
2954f56d42cSAsias He 		break;
2964f56d42cSAsias He 	case VIRTIO_MSI_QUEUE_VECTOR:
2974f56d42cSAsias He 		break;
2984f56d42cSAsias He 	default:
2994f56d42cSAsias He 		ret			= false;
3004f56d42cSAsias He 	};
3014f56d42cSAsias He 
302c229370aSIngo Molnar 	mutex_unlock(&ndev.mutex);
303407475bfSPekka Enberg 
3044f56d42cSAsias He 	return ret;
3054f56d42cSAsias He }
3064f56d42cSAsias He 
30727ab67f5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param)
30827ab67f5SSasha Levin {
309926e0e2fSIngo Molnar 	virtio_net_handle_callback(kvm, (u64)(long)param);
31027ab67f5SSasha Levin }
31127ab67f5SSasha Levin 
3124f56d42cSAsias He static struct ioport_operations virtio_net_io_ops = {
3134f56d42cSAsias He 	.io_in	= virtio_net_pci_io_in,
3144f56d42cSAsias He 	.io_out	= virtio_net_pci_io_out,
3154f56d42cSAsias He };
3164f56d42cSAsias He 
3173b02f580SSasha Levin static bool virtio_net__tap_init(const struct virtio_net_parameters *params)
3184f56d42cSAsias He {
319cb7202c1SSasha Levin 	int sock = socket(AF_INET, SOCK_STREAM, 0);
320246c8347SAsias He 	int i, pid, status, offload, hdr_len;
321cb7202c1SSasha Levin 	struct sockaddr_in sin = {0};
322246c8347SAsias He 	struct ifreq ifr;
3234f56d42cSAsias He 
324a4e724ddSSasha Levin 	for (i = 0 ; i < 6 ; i++)
325c229370aSIngo Molnar 		ndev.config.mac[i] = params->guest_mac[i];
326a4e724ddSSasha Levin 
327c229370aSIngo Molnar 	ndev.tap_fd = open("/dev/net/tun", O_RDWR);
328c229370aSIngo Molnar 	if (ndev.tap_fd < 0) {
3294542f276SCyrill Gorcunov 		pr_warning("Unable to open /dev/net/tun");
3303b02f580SSasha Levin 		goto fail;
3313b02f580SSasha Levin 	}
3324f56d42cSAsias He 
3334f56d42cSAsias He 	memset(&ifr, 0, sizeof(ifr));
334246c8347SAsias He 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
335c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETIFF, &ifr) < 0) {
3364542f276SCyrill Gorcunov 		pr_warning("Config tap device error. Are you root?");
3373b02f580SSasha Levin 		goto fail;
3383b02f580SSasha Levin 	}
3394f56d42cSAsias He 
340c229370aSIngo Molnar 	strncpy(ndev.tap_name, ifr.ifr_name, sizeof(ndev.tap_name));
3414f56d42cSAsias He 
342c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETNOCSUM, 1) < 0) {
3434542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETNOCSUM error");
344246c8347SAsias He 		goto fail;
345246c8347SAsias He 	}
346246c8347SAsias He 
347246c8347SAsias He 	hdr_len = sizeof(struct virtio_net_hdr);
348c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0) {
3494542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETVNETHDRSZ error");
350246c8347SAsias He 		goto fail;
351246c8347SAsias He 	}
352246c8347SAsias He 
353246c8347SAsias He 	offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
354c229370aSIngo Molnar 	if (ioctl(ndev.tap_fd, TUNSETOFFLOAD, offload) < 0) {
3554542f276SCyrill Gorcunov 		pr_warning("Config tap device TUNSETOFFLOAD error");
356246c8347SAsias He 		goto fail;
357246c8347SAsias He 	}
3584f56d42cSAsias He 
35973b7d038SAmos Kong 	if (strcmp(params->script, "none")) {
36073b7d038SAmos Kong 		pid = fork();
36173b7d038SAmos Kong 		if (pid == 0) {
362c229370aSIngo Molnar 			execl(params->script, params->script, ndev.tap_name, NULL);
36373b7d038SAmos Kong 			_exit(1);
36473b7d038SAmos Kong 		} else {
36573b7d038SAmos Kong 			waitpid(pid, &status, 0);
36673b7d038SAmos Kong 			if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
3674542f276SCyrill Gorcunov 				pr_warning("Fail to setup tap by %s", params->script);
36873b7d038SAmos Kong 				goto fail;
36973b7d038SAmos Kong 			}
37073b7d038SAmos Kong 		}
37173b7d038SAmos Kong 	} else {
372cb7202c1SSasha Levin 		memset(&ifr, 0, sizeof(ifr));
373c229370aSIngo Molnar 		strncpy(ifr.ifr_name, ndev.tap_name, sizeof(ndev.tap_name));
374bdfcfca6SSasha Levin 		sin.sin_addr.s_addr = inet_addr(params->host_ip);
375cb7202c1SSasha Levin 		memcpy(&(ifr.ifr_addr), &sin, sizeof(ifr.ifr_addr));
376cb7202c1SSasha Levin 		ifr.ifr_addr.sa_family = AF_INET;
3773b02f580SSasha Levin 		if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
3784542f276SCyrill Gorcunov 			pr_warning("Could not set ip address on tap device");
3793b02f580SSasha Levin 			goto fail;
3803b02f580SSasha Levin 		}
38173b7d038SAmos Kong 	}
382cb7202c1SSasha Levin 
383cb7202c1SSasha Levin 	memset(&ifr, 0, sizeof(ifr));
384c229370aSIngo Molnar 	strncpy(ifr.ifr_name, ndev.tap_name, sizeof(ndev.tap_name));
385cb7202c1SSasha Levin 	ioctl(sock, SIOCGIFFLAGS, &ifr);
386cb7202c1SSasha Levin 	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
387cb7202c1SSasha Levin 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0)
3884542f276SCyrill Gorcunov 		pr_warning("Could not bring tap device up");
389cb7202c1SSasha Levin 
390cb7202c1SSasha Levin 	close(sock);
3913b02f580SSasha Levin 
3923b02f580SSasha Levin 	return 1;
3933b02f580SSasha Levin 
3943b02f580SSasha Levin fail:
3953b02f580SSasha Levin 	if (sock >= 0)
3963b02f580SSasha Levin 		close(sock);
397c229370aSIngo Molnar 	if (ndev.tap_fd >= 0)
398c229370aSIngo Molnar 		close(ndev.tap_fd);
3993b02f580SSasha Levin 
4003b02f580SSasha Levin 	return 0;
4014f56d42cSAsias He }
4024f56d42cSAsias He 
40343835ac9SSasha Levin static void virtio_net__io_thread_init(struct kvm *kvm)
404c4aa7c02SPekka Enberg {
405c229370aSIngo Molnar 	pthread_mutex_init(&ndev.io_rx_lock, NULL);
406c229370aSIngo Molnar 	pthread_cond_init(&ndev.io_tx_cond, NULL);
407c4aa7c02SPekka Enberg 
408c229370aSIngo Molnar 	pthread_mutex_init(&ndev.io_rx_lock, NULL);
409c229370aSIngo Molnar 	pthread_cond_init(&ndev.io_tx_cond, NULL);
410c4aa7c02SPekka Enberg 
411c229370aSIngo Molnar 	pthread_create(&ndev.io_rx_thread, NULL, virtio_net_rx_thread, (void *)kvm);
412c229370aSIngo Molnar 	pthread_create(&ndev.io_tx_thread, NULL, virtio_net_tx_thread, (void *)kvm);
413c4aa7c02SPekka Enberg }
414c4aa7c02SPekka Enberg 
415bdfcfca6SSasha Levin void virtio_net__init(const struct virtio_net_parameters *params)
4164f56d42cSAsias He {
417*b5ee1ea7SAsias He 	struct ioevent ioevent;
4182449f6e3SSasha Levin 	u8 dev, line, pin;
41907f90696SSasha Levin 	u16 net_base_addr;
420*b5ee1ea7SAsias He 	int i;
4212449f6e3SSasha Levin 
4220a7ab0c6SSasha Levin 	if (irq__register_device(VIRTIO_ID_NET, &dev, &pin, &line) < 0)
4232449f6e3SSasha Levin 		return;
4242449f6e3SSasha Levin 
425c229370aSIngo Molnar 	pci_header.irq_pin  = pin;
426c229370aSIngo Molnar 	pci_header.irq_line = line;
42707f90696SSasha Levin 	net_base_addr	    = ioport__register(IOPORT_EMPTY, &virtio_net_io_ops, IOPORT_SIZE, NULL);
42807f90696SSasha Levin 	pci_header.bar[0]   = net_base_addr | PCI_BASE_ADDRESS_SPACE_IO;
42907f90696SSasha Levin 	ndev.base_addr	    = net_base_addr;
430c229370aSIngo Molnar 	pci__register(&pci_header, dev);
431c4aa7c02SPekka Enberg 
432*b5ee1ea7SAsias He 	ndev.mode = params->mode;
433*b5ee1ea7SAsias He 	if (ndev.mode == NET_MODE_TAP)
434*b5ee1ea7SAsias He 		virtio_net__tap_init(params);
435*b5ee1ea7SAsias He 	else
436*b5ee1ea7SAsias He 		uip_init(&ndev.info);
437*b5ee1ea7SAsias He 
43843835ac9SSasha Levin 	virtio_net__io_thread_init(params->kvm);
43927ab67f5SSasha Levin 
44027ab67f5SSasha Levin 	for (i = 0; i < VIRTIO_NET_NUM_QUEUES; i++) {
44127ab67f5SSasha Levin 		ioevent = (struct ioevent) {
44227ab67f5SSasha Levin 			.io_addr	= net_base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
44327ab67f5SSasha Levin 			.io_len		= sizeof(u16),
44427ab67f5SSasha Levin 			.fn		= ioevent_callback,
44527ab67f5SSasha Levin 			.datamatch	= i,
446926e0e2fSIngo Molnar 			.fn_ptr		= (void *)(long)i,
44727ab67f5SSasha Levin 			.fn_kvm		= params->kvm,
44827ab67f5SSasha Levin 			.fd		= eventfd(0, 0),
44927ab67f5SSasha Levin 		};
45027ab67f5SSasha Levin 
45127ab67f5SSasha Levin 		ioeventfd__add_event(&ioevent);
45227ab67f5SSasha Levin 	}
4534f56d42cSAsias He }
454