xref: /dpdk/drivers/net/virtio/virtio_user/vhost_user.c (revision 47e2ad074867daf9dbf663b34c8e49b64c6a29f3)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4 
5 #include <sys/socket.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/un.h>
11 #include <string.h>
12 #include <errno.h>
13 
14 #include <rte_string_fns.h>
15 #include <rte_fbarray.h>
16 
17 #include "vhost.h"
18 #include "virtio_user_dev.h"
19 
20 /* The version of the protocol we support */
21 #define VHOST_USER_VERSION    0x1
22 
23 #define VHOST_MEMORY_MAX_NREGIONS 8
24 struct vhost_memory {
25 	uint32_t nregions;
26 	uint32_t padding;
27 	struct vhost_memory_region regions[VHOST_MEMORY_MAX_NREGIONS];
28 };
29 
30 enum vhost_user_request {
31 	VHOST_USER_NONE = 0,
32 	VHOST_USER_GET_FEATURES = 1,
33 	VHOST_USER_SET_FEATURES = 2,
34 	VHOST_USER_SET_OWNER = 3,
35 	VHOST_USER_RESET_OWNER = 4,
36 	VHOST_USER_SET_MEM_TABLE = 5,
37 	VHOST_USER_SET_LOG_BASE = 6,
38 	VHOST_USER_SET_LOG_FD = 7,
39 	VHOST_USER_SET_VRING_NUM = 8,
40 	VHOST_USER_SET_VRING_ADDR = 9,
41 	VHOST_USER_SET_VRING_BASE = 10,
42 	VHOST_USER_GET_VRING_BASE = 11,
43 	VHOST_USER_SET_VRING_KICK = 12,
44 	VHOST_USER_SET_VRING_CALL = 13,
45 	VHOST_USER_SET_VRING_ERR = 14,
46 	VHOST_USER_GET_PROTOCOL_FEATURES = 15,
47 	VHOST_USER_SET_PROTOCOL_FEATURES = 16,
48 	VHOST_USER_GET_QUEUE_NUM = 17,
49 	VHOST_USER_SET_VRING_ENABLE = 18,
50 	VHOST_USER_SET_STATUS = 39,
51 	VHOST_USER_GET_STATUS = 40,
52 	VHOST_USER_MAX
53 };
54 
55 struct vhost_user_msg {
56 	enum vhost_user_request request;
57 
58 #define VHOST_USER_VERSION_MASK     0x3
59 #define VHOST_USER_REPLY_MASK       (0x1 << 2)
60 #define VHOST_USER_NEED_REPLY_MASK  (0x1 << 3)
61 	uint32_t flags;
62 	uint32_t size; /* the following payload size */
63 	union {
64 #define VHOST_USER_VRING_IDX_MASK   0xff
65 #define VHOST_USER_VRING_NOFD_MASK  (0x1 << 8)
66 		uint64_t u64;
67 		struct vhost_vring_state state;
68 		struct vhost_vring_addr addr;
69 		struct vhost_memory memory;
70 	} payload;
71 	int fds[VHOST_MEMORY_MAX_NREGIONS];
72 } __rte_packed;
73 
74 #define VHOST_USER_HDR_SIZE offsetof(struct vhost_user_msg, payload.u64)
75 #define VHOST_USER_PAYLOAD_SIZE \
76 	(sizeof(struct vhost_user_msg) - VHOST_USER_HDR_SIZE)
77 
78 static int
79 vhost_user_write(int fd, struct vhost_user_msg *msg, int *fds, int fd_num)
80 {
81 	int r;
82 	struct msghdr msgh;
83 	struct iovec iov;
84 	size_t fd_size = fd_num * sizeof(int);
85 	char control[CMSG_SPACE(fd_size)];
86 	struct cmsghdr *cmsg;
87 
88 	memset(&msgh, 0, sizeof(msgh));
89 	memset(control, 0, sizeof(control));
90 
91 	iov.iov_base = (uint8_t *)msg;
92 	iov.iov_len = VHOST_USER_HDR_SIZE + msg->size;
93 
94 	msgh.msg_iov = &iov;
95 	msgh.msg_iovlen = 1;
96 	msgh.msg_control = control;
97 	msgh.msg_controllen = sizeof(control);
98 
99 	cmsg = CMSG_FIRSTHDR(&msgh);
100 	cmsg->cmsg_len = CMSG_LEN(fd_size);
101 	cmsg->cmsg_level = SOL_SOCKET;
102 	cmsg->cmsg_type = SCM_RIGHTS;
103 	memcpy(CMSG_DATA(cmsg), fds, fd_size);
104 
105 	do {
106 		r = sendmsg(fd, &msgh, 0);
107 	} while (r < 0 && errno == EINTR);
108 
109 	if (r < 0)
110 		PMD_DRV_LOG(ERR, "Failed to send msg: %s", strerror(errno));
111 
112 	return r;
113 }
114 
115 static int
116 vhost_user_read(int fd, struct vhost_user_msg *msg)
117 {
118 	uint32_t valid_flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION;
119 	int ret, sz_hdr = VHOST_USER_HDR_SIZE, sz_payload;
120 
121 	ret = recv(fd, (void *)msg, sz_hdr, 0);
122 	if (ret < sz_hdr) {
123 		PMD_DRV_LOG(ERR, "Failed to recv msg hdr: %d instead of %d.",
124 			    ret, sz_hdr);
125 		goto fail;
126 	}
127 
128 	/* validate msg flags */
129 	if (msg->flags != (valid_flags)) {
130 		PMD_DRV_LOG(ERR, "Failed to recv msg: flags %x instead of %x.",
131 			    msg->flags, valid_flags);
132 		goto fail;
133 	}
134 
135 	sz_payload = msg->size;
136 
137 	if ((size_t)sz_payload > sizeof(msg->payload))
138 		goto fail;
139 
140 	if (sz_payload) {
141 		ret = recv(fd, (void *)((char *)msg + sz_hdr), sz_payload, 0);
142 		if (ret < sz_payload) {
143 			PMD_DRV_LOG(ERR,
144 				"Failed to recv msg payload: %d instead of %d.",
145 				ret, msg->size);
146 			goto fail;
147 		}
148 	}
149 
150 	return 0;
151 
152 fail:
153 	return -1;
154 }
155 
156 static int
157 vhost_user_check_reply_ack(struct virtio_user_dev *dev, struct vhost_user_msg *msg)
158 {
159 	enum vhost_user_request req = msg->request;
160 	int ret;
161 
162 	if (!(msg->flags & VHOST_USER_NEED_REPLY_MASK))
163 		return 0;
164 
165 	ret = vhost_user_read(dev->vhostfd, msg);
166 	if (ret < 0) {
167 		PMD_DRV_LOG(ERR, "Failed to read reply-ack");
168 		return -1;
169 	}
170 
171 	if (req != msg->request) {
172 		PMD_DRV_LOG(ERR, "Unexpected reply-ack request type (%d)", msg->request);
173 		return -1;
174 	}
175 
176 	if (msg->size != sizeof(msg->payload.u64)) {
177 		PMD_DRV_LOG(ERR, "Unexpected reply-ack payload size (%u)", msg->size);
178 		return -1;
179 	}
180 
181 	if (msg->payload.u64) {
182 		PMD_DRV_LOG(ERR, "Slave replied NACK to request type (%d)", msg->request);
183 		return -1;
184 	}
185 
186 	return 0;
187 }
188 
189 static int
190 vhost_user_set_owner(struct virtio_user_dev *dev)
191 {
192 	int ret;
193 	struct vhost_user_msg msg = {
194 		.request = VHOST_USER_SET_OWNER,
195 		.flags = VHOST_USER_VERSION,
196 	};
197 
198 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
199 	if (ret < 0) {
200 		PMD_DRV_LOG(ERR, "Failed to set owner");
201 		return -1;
202 	}
203 
204 	return 0;
205 }
206 
207 static int
208 vhost_user_get_features(struct virtio_user_dev *dev, uint64_t *features)
209 {
210 	int ret;
211 	struct vhost_user_msg msg = {
212 		.request = VHOST_USER_GET_FEATURES,
213 		.flags = VHOST_USER_VERSION,
214 	};
215 
216 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
217 	if (ret < 0)
218 		goto err;
219 
220 	ret = vhost_user_read(dev->vhostfd, &msg);
221 	if (ret < 0)
222 		goto err;
223 
224 	if (msg.request != VHOST_USER_GET_FEATURES) {
225 		PMD_DRV_LOG(ERR, "Unexpected request type (%d)", msg.request);
226 		goto err;
227 	}
228 
229 	if (msg.size != sizeof(*features)) {
230 		PMD_DRV_LOG(ERR, "Unexpected payload size (%u)", msg.size);
231 		goto err;
232 	}
233 
234 	*features = msg.payload.u64;
235 
236 	return 0;
237 err:
238 	PMD_DRV_LOG(ERR, "Failed to get backend features");
239 
240 	return -1;
241 }
242 
243 static int
244 vhost_user_set_features(struct virtio_user_dev *dev, uint64_t features)
245 {
246 	int ret;
247 	struct vhost_user_msg msg = {
248 		.request = VHOST_USER_SET_FEATURES,
249 		.flags = VHOST_USER_VERSION,
250 		.size = sizeof(features),
251 		.payload.u64 = features,
252 	};
253 
254 	msg.payload.u64 |= dev->device_features & (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
255 
256 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
257 	if (ret < 0) {
258 		PMD_DRV_LOG(ERR, "Failed to set features");
259 		return -1;
260 	}
261 
262 	return 0;
263 }
264 
265 static int
266 vhost_user_get_protocol_features(struct virtio_user_dev *dev, uint64_t *features)
267 {
268 	int ret;
269 	struct vhost_user_msg msg = {
270 		.request = VHOST_USER_GET_PROTOCOL_FEATURES,
271 		.flags = VHOST_USER_VERSION,
272 	};
273 
274 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
275 	if (ret < 0)
276 		goto err;
277 
278 	ret = vhost_user_read(dev->vhostfd, &msg);
279 	if (ret < 0)
280 		goto err;
281 
282 	if (msg.request != VHOST_USER_GET_PROTOCOL_FEATURES) {
283 		PMD_DRV_LOG(ERR, "Unexpected request type (%d)", msg.request);
284 		goto err;
285 	}
286 
287 	if (msg.size != sizeof(*features)) {
288 		PMD_DRV_LOG(ERR, "Unexpected payload size (%u)", msg.size);
289 		goto err;
290 	}
291 
292 	*features = msg.payload.u64;
293 
294 	return 0;
295 err:
296 	PMD_DRV_LOG(ERR, "Failed to get backend protocol features");
297 
298 	return -1;
299 }
300 
301 static int
302 vhost_user_set_protocol_features(struct virtio_user_dev *dev, uint64_t features)
303 {
304 	int ret;
305 	struct vhost_user_msg msg = {
306 		.request = VHOST_USER_SET_PROTOCOL_FEATURES,
307 		.flags = VHOST_USER_VERSION,
308 		.size = sizeof(features),
309 		.payload.u64 = features,
310 	};
311 
312 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
313 	if (ret < 0) {
314 		PMD_DRV_LOG(ERR, "Failed to set protocol features");
315 		return -1;
316 	}
317 
318 	return 0;
319 }
320 
321 struct walk_arg {
322 	struct vhost_memory *vm;
323 	int *fds;
324 	int region_nr;
325 };
326 
327 static int
328 update_memory_region(const struct rte_memseg_list *msl __rte_unused,
329 		const struct rte_memseg *ms, void *arg)
330 {
331 	struct walk_arg *wa = arg;
332 	struct vhost_memory_region *mr;
333 	uint64_t start_addr, end_addr;
334 	size_t offset;
335 	int i, fd;
336 
337 	fd = rte_memseg_get_fd_thread_unsafe(ms);
338 	if (fd < 0) {
339 		PMD_DRV_LOG(ERR, "Failed to get fd, ms=%p rte_errno=%d",
340 			ms, rte_errno);
341 		return -1;
342 	}
343 
344 	if (rte_memseg_get_fd_offset_thread_unsafe(ms, &offset) < 0) {
345 		PMD_DRV_LOG(ERR, "Failed to get offset, ms=%p rte_errno=%d",
346 			ms, rte_errno);
347 		return -1;
348 	}
349 
350 	start_addr = (uint64_t)(uintptr_t)ms->addr;
351 	end_addr = start_addr + ms->len;
352 
353 	for (i = 0; i < wa->region_nr; i++) {
354 		if (wa->fds[i] != fd)
355 			continue;
356 
357 		mr = &wa->vm->regions[i];
358 
359 		if (mr->userspace_addr + mr->memory_size < end_addr)
360 			mr->memory_size = end_addr - mr->userspace_addr;
361 
362 		if (mr->userspace_addr > start_addr) {
363 			mr->userspace_addr = start_addr;
364 			mr->guest_phys_addr = start_addr;
365 		}
366 
367 		if (mr->mmap_offset > offset)
368 			mr->mmap_offset = offset;
369 
370 		PMD_DRV_LOG(DEBUG, "index=%d fd=%d offset=0x%" PRIx64
371 			" addr=0x%" PRIx64 " len=%" PRIu64, i, fd,
372 			mr->mmap_offset, mr->userspace_addr,
373 			mr->memory_size);
374 
375 		return 0;
376 	}
377 
378 	if (i >= VHOST_MEMORY_MAX_NREGIONS) {
379 		PMD_DRV_LOG(ERR, "Too many memory regions");
380 		return -1;
381 	}
382 
383 	mr = &wa->vm->regions[i];
384 	wa->fds[i] = fd;
385 
386 	mr->guest_phys_addr = start_addr;
387 	mr->userspace_addr = start_addr;
388 	mr->memory_size = ms->len;
389 	mr->mmap_offset = offset;
390 
391 	PMD_DRV_LOG(DEBUG, "index=%d fd=%d offset=0x%" PRIx64
392 		" addr=0x%" PRIx64 " len=%" PRIu64, i, fd,
393 		mr->mmap_offset, mr->userspace_addr,
394 		mr->memory_size);
395 
396 	wa->region_nr++;
397 
398 	return 0;
399 }
400 
401 static int
402 vhost_user_set_memory_table(struct virtio_user_dev *dev)
403 {
404 	struct walk_arg wa;
405 	int fds[VHOST_MEMORY_MAX_NREGIONS];
406 	int ret, fd_num;
407 	struct vhost_user_msg msg = {
408 		.request = VHOST_USER_SET_MEM_TABLE,
409 		.flags = VHOST_USER_VERSION,
410 	};
411 
412 	if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK))
413 		msg.flags |= VHOST_USER_NEED_REPLY_MASK;
414 
415 	wa.region_nr = 0;
416 	wa.vm = &msg.payload.memory;
417 	wa.fds = fds;
418 
419 	/*
420 	 * The memory lock has already been taken by memory subsystem
421 	 * or virtio_user_start_device().
422 	 */
423 	ret = rte_memseg_walk_thread_unsafe(update_memory_region, &wa);
424 	if (ret < 0)
425 		goto err;
426 
427 	fd_num = wa.region_nr;
428 	msg.payload.memory.nregions = wa.region_nr;
429 	msg.payload.memory.padding = 0;
430 
431 	msg.size = sizeof(msg.payload.memory.nregions);
432 	msg.size += sizeof(msg.payload.memory.padding);
433 	msg.size += fd_num * sizeof(struct vhost_memory_region);
434 
435 	ret = vhost_user_write(dev->vhostfd, &msg, fds, fd_num);
436 	if (ret < 0)
437 		goto err;
438 
439 	return vhost_user_check_reply_ack(dev, &msg);
440 err:
441 	PMD_DRV_LOG(ERR, "Failed to set memory table");
442 	return -1;
443 }
444 
445 static int
446 vhost_user_set_vring(struct virtio_user_dev *dev, enum vhost_user_request req,
447 		struct vhost_vring_state *state)
448 {
449 	int ret;
450 	struct vhost_user_msg msg = {
451 		.request = req,
452 		.flags = VHOST_USER_VERSION,
453 		.size = sizeof(*state),
454 		.payload.state = *state,
455 	};
456 
457 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
458 	if (ret < 0) {
459 		PMD_DRV_LOG(ERR, "Failed to set vring state (request %d)", req);
460 		return -1;
461 	}
462 
463 	return 0;
464 }
465 
466 static int
467 vhost_user_set_vring_enable(struct virtio_user_dev *dev, struct vhost_vring_state *state)
468 {
469 	return vhost_user_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, state);
470 }
471 
472 static int
473 vhost_user_set_vring_num(struct virtio_user_dev *dev, struct vhost_vring_state *state)
474 {
475 	return vhost_user_set_vring(dev, VHOST_USER_SET_VRING_NUM, state);
476 }
477 
478 static int
479 vhost_user_set_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
480 {
481 	return vhost_user_set_vring(dev, VHOST_USER_SET_VRING_BASE, state);
482 }
483 
484 static int
485 vhost_user_get_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
486 {
487 	int ret;
488 	struct vhost_user_msg msg;
489 	unsigned int index = state->index;
490 
491 	ret = vhost_user_set_vring(dev, VHOST_USER_GET_VRING_BASE, state);
492 	if (ret < 0) {
493 		PMD_DRV_LOG(ERR, "Failed to send request");
494 		goto err;
495 	}
496 
497 	ret = vhost_user_read(dev->vhostfd, &msg);
498 	if (ret < 0) {
499 		PMD_DRV_LOG(ERR, "Failed to read reply");
500 		goto err;
501 	}
502 
503 	if (msg.request != VHOST_USER_GET_VRING_BASE) {
504 		PMD_DRV_LOG(ERR, "Unexpected request type (%d)", msg.request);
505 		goto err;
506 	}
507 
508 	if (msg.size != sizeof(*state)) {
509 		PMD_DRV_LOG(ERR, "Unexpected payload size (%u)", msg.size);
510 		goto err;
511 	}
512 
513 	if (msg.payload.state.index != index) {
514 		PMD_DRV_LOG(ERR, "Unexpected ring index (%u)", state->index);
515 		goto err;
516 	}
517 
518 	*state = msg.payload.state;
519 
520 	return 0;
521 err:
522 	PMD_DRV_LOG(ERR, "Failed to get vring base");
523 	return -1;
524 }
525 
526 static int
527 vhost_user_set_vring_file(struct virtio_user_dev *dev, enum vhost_user_request req,
528 		struct vhost_vring_file *file)
529 {
530 	int ret;
531 	int fd = file->fd;
532 	int num_fd = 0;
533 	struct vhost_user_msg msg = {
534 		.request = req,
535 		.flags = VHOST_USER_VERSION,
536 		.size = sizeof(msg.payload.u64),
537 		.payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
538 	};
539 
540 	if (fd >= 0)
541 		num_fd++;
542 	else
543 		msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
544 
545 	ret = vhost_user_write(dev->vhostfd, &msg, &fd, num_fd);
546 	if (ret < 0) {
547 		PMD_DRV_LOG(ERR, "Failed to set vring file (request %d)", req);
548 		return -1;
549 	}
550 
551 	return 0;
552 }
553 
554 static int
555 vhost_user_set_vring_call(struct virtio_user_dev *dev, struct vhost_vring_file *file)
556 {
557 	return vhost_user_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
558 }
559 
560 static int
561 vhost_user_set_vring_kick(struct virtio_user_dev *dev, struct vhost_vring_file *file)
562 {
563 	return vhost_user_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file);
564 }
565 
566 
567 static int
568 vhost_user_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr *addr)
569 {
570 	int ret;
571 	struct vhost_user_msg msg = {
572 		.request = VHOST_USER_SET_VRING_ADDR,
573 		.flags = VHOST_USER_VERSION,
574 		.size = sizeof(*addr),
575 		.payload.addr = *addr,
576 	};
577 
578 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
579 	if (ret < 0) {
580 		PMD_DRV_LOG(ERR, "Failed to send vring addresses");
581 		return -1;
582 	}
583 
584 	return 0;
585 }
586 
587 static int
588 vhost_user_get_status(struct virtio_user_dev *dev, uint8_t *status)
589 {
590 	int ret;
591 	struct vhost_user_msg msg = {
592 		.request = VHOST_USER_GET_STATUS,
593 		.flags = VHOST_USER_VERSION,
594 	};
595 
596 	/*
597 	 * If features have not been negotiated, we don't know if the backend
598 	 * supports protocol features
599 	 */
600 	if (!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
601 		return -ENOTSUP;
602 
603 	/* Status protocol feature requires protocol features support */
604 	if (!(dev->device_features & (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)))
605 		return -ENOTSUP;
606 
607 	if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_STATUS)))
608 		return -ENOTSUP;
609 
610 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
611 	if (ret < 0) {
612 		PMD_DRV_LOG(ERR, "Failed to send request");
613 		goto err;
614 	}
615 
616 	ret = vhost_user_read(dev->vhostfd, &msg);
617 	if (ret < 0) {
618 		PMD_DRV_LOG(ERR, "Failed to recv request");
619 		goto err;
620 	}
621 
622 	if (msg.request != VHOST_USER_GET_STATUS) {
623 		PMD_DRV_LOG(ERR, "Unexpected request type (%d)", msg.request);
624 		goto err;
625 	}
626 
627 	if (msg.size != sizeof(msg.payload.u64)) {
628 		PMD_DRV_LOG(ERR, "Unexpected payload size (%u)", msg.size);
629 		goto err;
630 	}
631 
632 	*status = (uint8_t)msg.payload.u64;
633 
634 	return 0;
635 err:
636 	PMD_DRV_LOG(ERR, "Failed to get device status");
637 	return -1;
638 }
639 
640 static int
641 vhost_user_set_status(struct virtio_user_dev *dev, uint8_t status)
642 {
643 	int ret;
644 	struct vhost_user_msg msg = {
645 		.request = VHOST_USER_SET_STATUS,
646 		.flags = VHOST_USER_VERSION,
647 		.size = sizeof(msg.payload.u64),
648 		.payload.u64 = status,
649 	};
650 
651 	/*
652 	 * If features have not been negotiated, we don't know if the backend
653 	 * supports protocol features
654 	 */
655 	if (!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
656 		return -ENOTSUP;
657 
658 	/* Status protocol feature requires protocol features support */
659 	if (!(dev->device_features & (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)))
660 		return -ENOTSUP;
661 
662 	if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_STATUS)))
663 		return -ENOTSUP;
664 
665 	if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK))
666 		msg.flags |= VHOST_USER_NEED_REPLY_MASK;
667 
668 	ret = vhost_user_write(dev->vhostfd, &msg, NULL, 0);
669 	if (ret < 0) {
670 		PMD_DRV_LOG(ERR, "Failed to send get status request");
671 		return -1;
672 	}
673 
674 	return vhost_user_check_reply_ack(dev, &msg);
675 }
676 
677 #define MAX_VIRTIO_USER_BACKLOG 1
678 static int
679 virtio_user_start_server(struct virtio_user_dev *dev, struct sockaddr_un *un)
680 {
681 	int ret;
682 	int flag;
683 	int fd = dev->listenfd;
684 
685 	ret = bind(fd, (struct sockaddr *)un, sizeof(*un));
686 	if (ret < 0) {
687 		PMD_DRV_LOG(ERR, "failed to bind to %s: %s; remove it and try again\n",
688 			    dev->path, strerror(errno));
689 		return -1;
690 	}
691 	ret = listen(fd, MAX_VIRTIO_USER_BACKLOG);
692 	if (ret < 0)
693 		return -1;
694 
695 	flag = fcntl(fd, F_GETFL);
696 	if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
697 		PMD_DRV_LOG(ERR, "fcntl failed, %s", strerror(errno));
698 		return -1;
699 	}
700 
701 	return 0;
702 }
703 
704 /**
705  * Set up environment to talk with a vhost user backend.
706  *
707  * @return
708  *   - (-1) if fail;
709  *   - (0) if succeed.
710  */
711 static int
712 vhost_user_setup(struct virtio_user_dev *dev)
713 {
714 	int fd;
715 	int flag;
716 	struct sockaddr_un un;
717 
718 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
719 	if (fd < 0) {
720 		PMD_DRV_LOG(ERR, "socket() error, %s", strerror(errno));
721 		return -1;
722 	}
723 
724 	flag = fcntl(fd, F_GETFD);
725 	if (fcntl(fd, F_SETFD, flag | FD_CLOEXEC) < 0)
726 		PMD_DRV_LOG(WARNING, "fcntl failed, %s", strerror(errno));
727 
728 	memset(&un, 0, sizeof(un));
729 	un.sun_family = AF_UNIX;
730 	strlcpy(un.sun_path, dev->path, sizeof(un.sun_path));
731 
732 	if (dev->is_server) {
733 		dev->listenfd = fd;
734 		if (virtio_user_start_server(dev, &un) < 0) {
735 			PMD_DRV_LOG(ERR, "virtio-user startup fails in server mode");
736 			close(fd);
737 			return -1;
738 		}
739 		dev->vhostfd = -1;
740 	} else {
741 		if (connect(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
742 			PMD_DRV_LOG(ERR, "connect error, %s", strerror(errno));
743 			close(fd);
744 			return -1;
745 		}
746 		dev->vhostfd = fd;
747 	}
748 
749 	return 0;
750 }
751 
752 static int
753 vhost_user_enable_queue_pair(struct virtio_user_dev *dev,
754 			     uint16_t pair_idx,
755 			     int enable)
756 {
757 	int i;
758 
759 	if (dev->qp_enabled[pair_idx] == enable)
760 		return 0;
761 
762 	for (i = 0; i < 2; ++i) {
763 		struct vhost_vring_state state = {
764 			.index = pair_idx * 2 + i,
765 			.num = enable,
766 		};
767 
768 		if (vhost_user_set_vring_enable(dev, &state))
769 			return -1;
770 	}
771 
772 	dev->qp_enabled[pair_idx] = enable;
773 	return 0;
774 }
775 
776 struct virtio_user_backend_ops virtio_ops_user = {
777 	.setup = vhost_user_setup,
778 	.set_owner = vhost_user_set_owner,
779 	.get_features = vhost_user_get_features,
780 	.set_features = vhost_user_set_features,
781 	.get_protocol_features = vhost_user_get_protocol_features,
782 	.set_protocol_features = vhost_user_set_protocol_features,
783 	.set_memory_table = vhost_user_set_memory_table,
784 	.set_vring_num = vhost_user_set_vring_num,
785 	.set_vring_base = vhost_user_set_vring_base,
786 	.get_vring_base = vhost_user_get_vring_base,
787 	.set_vring_call = vhost_user_set_vring_call,
788 	.set_vring_kick = vhost_user_set_vring_kick,
789 	.set_vring_addr = vhost_user_set_vring_addr,
790 	.get_status = vhost_user_get_status,
791 	.set_status = vhost_user_set_status,
792 	.enable_qp = vhost_user_enable_queue_pair
793 };
794