net/virtio: move vhost-user requests to vhost-user backend
[dpdk.git] / drivers / net / virtio / virtio_user / vhost_user.c
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 };