xref: /kvmtool/virtio/net.c (revision 4f56d42c789fd598de8cc5820598332594eb8592)
1 #include "kvm/virtio-net.h"
2 #include "kvm/virtio-pci.h"
3 #include "kvm/virtio.h"
4 #include "kvm/ioport.h"
5 #include "kvm/types.h"
6 #include "kvm/mutex.h"
7 #include "kvm/util.h"
8 #include "kvm/kvm.h"
9 #include "kvm/pci.h"
10 
11 #include <linux/virtio_net.h>
12 #include <linux/if_tun.h>
13 #include <net/if.h>
14 #include <sys/ioctl.h>
15 #include <assert.h>
16 #include <fcntl.h>
17 
18 #define VIRTIO_NET_IRQ		14
19 #define VIRTIO_NET_QUEUE_SIZE	128
20 #define VIRTIO_NET_NUM_QUEUES	2
21 #define VIRTIO_NET_RX_QUEUE	0
22 #define VIRTIO_NET_TX_QUEUE	1
23 #define PCI_VIRTIO_NET_DEVNUM	3
24 
25 struct net_device {
26 	pthread_mutex_t			mutex;
27 
28 	struct virt_queue		vqs[VIRTIO_NET_NUM_QUEUES];
29 	struct virtio_net_config	net_config;
30 	uint32_t			host_features;
31 	uint32_t			guest_features;
32 	uint16_t			config_vector;
33 	uint8_t				status;
34 	uint16_t			queue_selector;
35 
36 	pthread_t			io_rx_thread;
37 	pthread_mutex_t			io_rx_mutex;
38 	pthread_cond_t			io_rx_cond;
39 
40 	pthread_t			io_tx_thread;
41 	pthread_mutex_t			io_tx_mutex;
42 	pthread_cond_t			io_tx_cond;
43 
44 	int				tap_fd;
45 	char				tap_name[IFNAMSIZ];
46 };
47 
48 static struct net_device net_device = {
49 	.mutex			= PTHREAD_MUTEX_INITIALIZER,
50 
51 	.net_config = {
52 		.mac		= {0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
53 		.status		= VIRTIO_NET_S_LINK_UP,
54 	},
55 
56 	.host_features		= 1UL << VIRTIO_NET_F_MAC,
57 };
58 
59 static void *virtio_net_rx_thread(void *p)
60 {
61 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
62 	struct virt_queue *vq;
63 	struct kvm *self;
64 	uint16_t out, in;
65 	uint16_t head;
66 	int len;
67 
68 	self = p;
69 	vq = &net_device.vqs[VIRTIO_NET_RX_QUEUE];
70 
71 	while (1) {
72 		mutex_lock(&net_device.io_rx_mutex);
73 		if (!virt_queue__available(vq))
74 			pthread_cond_wait(&net_device.io_rx_cond, &net_device.io_rx_mutex);
75 		mutex_unlock(&net_device.io_rx_mutex);
76 
77 		while (virt_queue__available(vq)) {
78 			head = virt_queue__get_iov(vq, iov, &out, &in, self);
79 
80 			/* We do not specify GSO or CSUM features, So we can ignore virtio_net_hdr */
81 			len = readv(net_device.tap_fd, iov + 1, in - 1);
82 
83 			/* However, We have to tell guest we have write the virtio_net_hdr */
84 			virt_queue__set_used_elem(vq, head, sizeof(struct virtio_net_hdr) + len);
85 
86 			/* We should interrupt guest right now, otherwise latency is huge. */
87 			kvm__irq_line(self, VIRTIO_NET_IRQ, 1);
88 		}
89 
90 	}
91 
92 	pthread_exit(NULL);
93 	return NULL;
94 
95 }
96 
97 static void *virtio_net_tx_thread(void *p)
98 {
99 	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
100 	struct virt_queue *vq;
101 	struct kvm *self;
102 	uint16_t out, in;
103 	uint16_t head;
104 	int len;
105 
106 	self = p;
107 	vq = &net_device.vqs[VIRTIO_NET_TX_QUEUE];
108 
109 	while (1) {
110 		mutex_lock(&net_device.io_tx_mutex);
111 		if (!virt_queue__available(vq))
112 			pthread_cond_wait(&net_device.io_tx_cond, &net_device.io_tx_mutex);
113 		mutex_unlock(&net_device.io_tx_mutex);
114 
115 		while (virt_queue__available(vq)) {
116 			head = virt_queue__get_iov(vq, iov, &out, &in, self);
117 			len = writev(net_device.tap_fd, iov + 1, out - 1);
118 			virt_queue__set_used_elem(vq, head, len);
119 		}
120 
121 		kvm__irq_line(self, VIRTIO_NET_IRQ, 1);
122 	}
123 
124 	pthread_exit(NULL);
125 	return NULL;
126 
127 }
128 static bool virtio_net_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
129 {
130 	uint8_t *config_space = (uint8_t *) &net_device.net_config;
131 
132 	if (size != 1 || count != 1)
133 		return false;
134 
135 	if ((offset - VIRTIO_PCI_CONFIG_NOMSI) > sizeof(struct virtio_net_config))
136 		error("config offset is too big: %li", offset - VIRTIO_PCI_CONFIG_NOMSI);
137 
138 	ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
139 
140 	return true;
141 }
142 
143 static bool virtio_net_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
144 {
145 	unsigned long offset = port - IOPORT_VIRTIO_NET;
146 	bool ret = true;
147 
148 	mutex_lock(&net_device.mutex);
149 
150 	switch (offset) {
151 	case VIRTIO_PCI_HOST_FEATURES:
152 		ioport__write32(data, net_device.host_features);
153 		break;
154 	case VIRTIO_PCI_GUEST_FEATURES:
155 		ret = false;
156 		break;
157 	case VIRTIO_PCI_QUEUE_PFN:
158 		ioport__write32(data, net_device.vqs[net_device.queue_selector].pfn);
159 		break;
160 	case VIRTIO_PCI_QUEUE_NUM:
161 		ioport__write16(data, VIRTIO_NET_QUEUE_SIZE);
162 		break;
163 	case VIRTIO_PCI_QUEUE_SEL:
164 	case VIRTIO_PCI_QUEUE_NOTIFY:
165 		ret = false;
166 		break;
167 	case VIRTIO_PCI_STATUS:
168 		ioport__write8(data, net_device.status);
169 		break;
170 	case VIRTIO_PCI_ISR:
171 		ioport__write8(data, 0x1);
172 		kvm__irq_line(self, VIRTIO_NET_IRQ, 0);
173 		break;
174 	case VIRTIO_MSI_CONFIG_VECTOR:
175 		ioport__write16(data, net_device.config_vector);
176 		break;
177 	default:
178 		ret = virtio_net_pci_io_device_specific_in(data, offset, size, count);
179 	};
180 
181 	mutex_unlock(&net_device.mutex);
182 
183 	return ret;
184 }
185 
186 static void virtio_net_handle_callback(struct kvm *self, uint16_t queue_index)
187 {
188 	if (queue_index == VIRTIO_NET_TX_QUEUE) {
189 
190 		mutex_lock(&net_device.io_tx_mutex);
191 		pthread_cond_signal(&net_device.io_tx_cond);
192 		mutex_unlock(&net_device.io_tx_mutex);
193 
194 	} else if (queue_index == VIRTIO_NET_RX_QUEUE) {
195 
196 		mutex_lock(&net_device.io_rx_mutex);
197 		pthread_cond_signal(&net_device.io_rx_cond);
198 		mutex_unlock(&net_device.io_rx_mutex);
199 
200 	}
201 }
202 
203 static bool virtio_net_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
204 {
205 	unsigned long offset = port - IOPORT_VIRTIO_NET;
206 	bool ret = true;
207 
208 	mutex_lock(&net_device.mutex);
209 
210 	switch (offset) {
211 	case VIRTIO_PCI_GUEST_FEATURES:
212 		net_device.guest_features	= ioport__read32(data);
213 		break;
214 	case VIRTIO_PCI_QUEUE_PFN: {
215 		struct virt_queue *queue;
216 		void *p;
217 
218 		assert(net_device.queue_selector < VIRTIO_NET_NUM_QUEUES);
219 
220 		queue		= &net_device.vqs[net_device.queue_selector];
221 		queue->pfn	= ioport__read32(data);
222 		p		= guest_flat_to_host(self, queue->pfn << 12);
223 
224 		vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, 4096);
225 
226 		break;
227 	}
228 	case VIRTIO_PCI_QUEUE_SEL:
229 		net_device.queue_selector	= ioport__read16(data);
230 		break;
231 	case VIRTIO_PCI_QUEUE_NOTIFY: {
232 		uint16_t queue_index;
233 		queue_index	= ioport__read16(data);
234 		virtio_net_handle_callback(self, queue_index);
235 		break;
236 	}
237 	case VIRTIO_PCI_STATUS:
238 		net_device.status		= ioport__read8(data);
239 		break;
240 	case VIRTIO_MSI_CONFIG_VECTOR:
241 		net_device.config_vector	= VIRTIO_MSI_NO_VECTOR;
242 		break;
243 	case VIRTIO_MSI_QUEUE_VECTOR:
244 		break;
245 	default:
246 		ret = false;
247 	};
248 
249 	mutex_unlock(&net_device.mutex);
250 	return ret;
251 }
252 
253 static struct ioport_operations virtio_net_io_ops = {
254 	.io_in	= virtio_net_pci_io_in,
255 	.io_out	= virtio_net_pci_io_out,
256 };
257 
258 #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
259 #define PCI_DEVICE_ID_VIRTIO_NET		0x1000
260 #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
261 #define PCI_SUBSYSTEM_ID_VIRTIO_NET		0x0001
262 
263 static struct pci_device_header virtio_net_pci_device = {
264 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
265 	.device_id		= PCI_DEVICE_ID_VIRTIO_NET,
266 	.header_type		= PCI_HEADER_TYPE_NORMAL,
267 	.revision_id		= 0,
268 	.class			= 0x020000,
269 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
270 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_NET,
271 	.bar[0]			= IOPORT_VIRTIO_NET | PCI_BASE_ADDRESS_SPACE_IO,
272 	.irq_pin		= 3,
273 	.irq_line		= VIRTIO_NET_IRQ,
274 };
275 
276 static void virtio_net__tap_init(void)
277 {
278 	struct ifreq ifr;
279 
280 	net_device.tap_fd = open("/dev/net/tun", O_RDWR);
281 	if (net_device.tap_fd < 0)
282 		die("Unable to open /dev/net/tun\n");
283 
284 	memset(&ifr, 0, sizeof(ifr));
285 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
286 
287 	if (ioctl(net_device.tap_fd, TUNSETIFF, &ifr) < 0)
288 		die("Config tap device error. Are you root?");
289 
290 	strncpy(net_device.tap_name, ifr.ifr_name, sizeof(net_device.tap_name));
291 
292 	ioctl(net_device.tap_fd, TUNSETNOCSUM, 1);
293 
294 	/*FIXME: Remove this after user can specify ip address and netmask*/
295 	if (system("ifconfig tap0 192.168.33.2") < 0)
296 		warning("Can not set ip address on tap0");
297 }
298 
299 static void virtio_net__io_thread_init(struct kvm *self)
300 {
301 	pthread_mutex_init(&net_device.io_rx_mutex, NULL);
302 	pthread_cond_init(&net_device.io_tx_cond, NULL);
303 
304 	pthread_mutex_init(&net_device.io_rx_mutex, NULL);
305 	pthread_cond_init(&net_device.io_tx_cond, NULL);
306 
307 	pthread_create(&net_device.io_rx_thread, NULL, virtio_net_rx_thread, (void *)self);
308 	pthread_create(&net_device.io_tx_thread, NULL, virtio_net_tx_thread, (void *)self);
309 }
310 
311 void virtio_net__init(struct kvm *self)
312 {
313 	pci__register(&virtio_net_pci_device, PCI_VIRTIO_NET_DEVNUM);
314 	ioport__register(IOPORT_VIRTIO_NET, &virtio_net_io_ops, IOPORT_VIRTIO_NET_SIZE);
315 
316 	virtio_net__tap_init();
317 	virtio_net__io_thread_init(self);
318 }
319