LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_uvhost_msg.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 358 638 56.1 %
Date: 2026-11-09 02:10:49 Functions: 21 29 72.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_uvhost_msg.c - handlers for messages received by the user space
       3             :  * vhost thread.
       4             :  *
       5             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       6             :  * Copyright Contributors to the OpenSDN project
       7             :  */
       8             : 
       9             : #include <sys/poll.h>
      10             : 
      11             : #include "vr_dpdk.h"
      12             : #include "vr_dpdk_virtio.h"
      13             : #include "vr_dpdk_usocket.h"
      14             : #include "vr_uvhost_client.h"
      15             : #include "vr_uvhost_msg.h"
      16             : #include "vr_uvhost_util.h"
      17             : #include "vr_dpdk_filestore.h"
      18             : 
      19             : #include <fcntl.h>
      20             : #include <linux/virtio_net.h>
      21             : #include <sys/mman.h>
      22             : #include <sys/stat.h>
      23             : #include <sys/un.h>
      24             : #include <sys/timerfd.h>
      25             : #include <linux/netlink.h>
      26             : #include <linux/rtnetlink.h>
      27             : #include <net/if.h>
      28             : 
      29             : #include <rte_errno.h>
      30             : #include <rte_hexdump.h>
      31             : 
      32             : typedef int (*vr_uvh_msg_handler_fn)(vr_uvh_client_t *vru_cl);
      33             : #define uvhm_client_name(vru_cl) (vru_cl->vruc_path + strlen(vr_socket_dir) \
      34             :     + sizeof(VR_UVH_VIF_PFX) - 1)
      35             : 
      36             : /*
      37             :  * Prototypes for user space vhost message handlers
      38             :  */
      39             : static int vr_uvmh_get_features(vr_uvh_client_t *vru_cl);
      40             : static int vr_uvmh_set_features(vr_uvh_client_t *vru_cl);
      41             : static int vr_uvmh_get_protocol_features(vr_uvh_client_t *vru_cl);
      42             : static int vr_uvmh_set_protocol_features(vr_uvh_client_t *vru_cl);
      43             : static int vr_uvhm_set_mem_table(vr_uvh_client_t *vru_cl);
      44             : static int vr_uvhm_set_log_base(vr_uvh_client_t *vru_cl);
      45             : static int vr_uvhm_set_vring_num(vr_uvh_client_t *vru_cl);
      46             : static int vr_uvhm_set_vring_addr(vr_uvh_client_t *vru_cl);
      47             : static int vr_uvhm_set_vring_base(vr_uvh_client_t *vru_cl);
      48             : static int vr_uvhm_get_vring_base(vr_uvh_client_t *vru_cl);
      49             : static int vr_uvhm_set_vring_call(vr_uvh_client_t *vru_cl);
      50             : static int vr_uvhm_get_queue_num(vr_uvh_client_t *vru_cl);
      51             : static int vr_uvhm_set_vring_enable(vr_uvh_client_t *vru_cl);
      52             : static int vr_uvh_cl_timer_setup(vr_uvh_client_t *vru_cl);
      53             : 
      54             : static vr_uvh_msg_handler_fn vr_uvhost_cl_msg_handlers[] = {
      55             :     NULL,
      56             :     vr_uvmh_get_features,
      57             :     vr_uvmh_set_features,
      58             :     NULL,
      59             :     NULL,
      60             :     vr_uvhm_set_mem_table,
      61             :     vr_uvhm_set_log_base,
      62             :     NULL,
      63             :     vr_uvhm_set_vring_num,
      64             :     vr_uvhm_set_vring_addr,
      65             :     vr_uvhm_set_vring_base,
      66             :     vr_uvhm_get_vring_base,
      67             :     NULL,
      68             :     vr_uvhm_set_vring_call,
      69             :     NULL,
      70             :     vr_uvmh_get_protocol_features,
      71             :     vr_uvmh_set_protocol_features,
      72             :     vr_uvhm_get_queue_num,
      73             :     vr_uvhm_set_vring_enable,
      74             :     NULL,
      75             : };
      76             : 
      77             : /*
      78             :  * Return the basename given a full path
      79             :  * Note: Dont use posix library function
      80             :  * as it could change the original string
      81             :  */
      82         623 : static char *basename(char *string)
      83             : {
      84         623 :     char *tmp = &string[strlen(string)-1];
      85             :     /* find basename */
      86        9571 :     while (tmp > string && *(tmp-1) != '/')
      87        8948 :         tmp--;
      88         623 :     if (tmp == string)
      89           0 :         return NULL;
      90         623 :     return tmp+8; /* remove the uvh_vif_ */
      91             : }
      92             : 
      93             : /*
      94             :  * Function to send interface state to Agent
      95             :  * state 0 - down
      96             :  * state 1 - up
      97             :  * Called when the VM goes down or comes up
      98             :  */
      99             : void
     100         623 : vr_uvh_nl_send_intf_state(int state, int intf_index, char *intf_name)
     101             : {
     102             :     int nl_fd;
     103             :     char buf[1024];
     104             :     struct nlmsghdr *nlh;
     105             :     struct ifinfomsg *ifinfo;
     106             :     struct nlattr *nla;
     107             :     int len, n;
     108             :     char *if_name_buf;
     109             :     struct sockaddr_nl sa;
     110             : 
     111         623 :     if (intf_name == NULL)
     112           0 :         return;
     113             : 
     114         623 :     memset(&sa, 0, sizeof(sa));
     115         623 :     sa.nl_family = AF_NETLINK;
     116         623 :     sa.nl_pid = 0;
     117         623 :     sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
     118             : 
     119             : 
     120             : 
     121         623 :     nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     122         623 :     if (nl_fd < 0) {
     123           0 :         vr_uvhost_log("Error creating netlink socket\n");
     124           0 :         goto error;
     125             :     }
     126         623 :     bind(nl_fd, (struct sockaddr *)&sa, sizeof(sa));
     127         623 :     nlh = (struct nlmsghdr *)buf;
     128             : 
     129         623 :     nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(struct ifinfomsg);
     130         623 :     nlh->nlmsg_type = RTM_NEWLINK;
     131         623 :     nlh->nlmsg_flags = NLM_F_REQUEST;
     132         623 :     nlh->nlmsg_seq = 1;
     133         623 :     nlh->nlmsg_pid = 0;
     134         623 :     ifinfo = (struct ifinfomsg *)(buf + NLMSG_HDRLEN);
     135             : 
     136         623 :     ifinfo->ifi_family = 0;
     137         623 :     ifinfo->ifi_type = 0;
     138         623 :     ifinfo->ifi_type = 0;
     139             :     /* Set index to -1 as agent needs only the interface name */
     140         623 :     ifinfo->ifi_index = -1;
     141         623 :     if (state)
     142         194 :         ifinfo->ifi_flags = IFF_MULTICAST|IFF_RUNNING|IFF_BROADCAST|IFF_UP;
     143             :     else
     144         429 :         ifinfo->ifi_flags = IFF_BROADCAST|IFF_UP;
     145             :     /* ifi_change needs to be set to 0xFFFFFFFF by default
     146             :      * as its a reserved field
     147             :      */
     148         623 :     ifinfo->ifi_change = 0xFFFFFFFF;
     149             : 
     150         623 :     nla = (struct nlattr *)(buf + NLMSG_HDRLEN + sizeof(struct ifinfomsg));
     151             : 
     152         623 :     len = NLA_HDRLEN + NLA_ALIGN(strlen(intf_name) + 1);
     153             : 
     154         623 :     nla->nla_len = len;
     155         623 :     nla->nla_type = IFLA_IFNAME;
     156             : 
     157         623 :     if_name_buf = (char *)nla + NLA_HDRLEN;
     158         623 :     strcpy(if_name_buf, intf_name);
     159             : 
     160         623 :     len += (NLMSG_HDRLEN + sizeof(struct ifinfomsg));
     161             : 
     162         623 :     nlh->nlmsg_len = len;
     163             : 
     164         623 :     n = sendto(nl_fd, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa));
     165         623 :     if (n != len) {
     166           0 :         vr_uvhost_log("Error sending netlink interface message\n");
     167             :     }
     168             : 
     169         623 :     close(nl_fd);
     170         623 : error:
     171         623 :     return;
     172             : }
     173             : 
     174             : /*
     175             :  * uvhm_mem_table_mmap - mmaps guest memory regions.
     176             :  *
     177             :  * Returns 0 on success, -1 otherwise.
     178             :  */
     179             : static int
     180         194 : uvhm_client_mmap(vr_uvh_client_t *vru_cl)
     181             : {
     182             :     int i;
     183             :     int ret;
     184             :     vr_uvh_client_mem_region_t *region;
     185             :     VhostUserMemory *vum_msg;
     186             :     uint64_t size;
     187             : 
     188         194 :     vum_msg = &vru_cl->vruc_msg.memory;
     189         194 :     vr_uvhost_log("Client %s: mapping %u memory regions:\n",
     190         194 :             uvhm_client_name(vru_cl), vum_msg->nregions);
     191             : 
     192         194 :     if (vum_msg->nregions > VHOST_MEMORY_MAX_NREGIONS) {
     193           0 :         vr_uvhost_log("Client %s: error mapping guest memory: too many regions"
     194             :                 "(%"PRIu32" > %d)\n",
     195           0 :                 uvhm_client_name(vru_cl), vum_msg->nregions,
     196             :                 VHOST_MEMORY_MAX_NREGIONS);
     197           0 :       return -1;
     198             :     }
     199         582 :     for (i = 0; i < vum_msg->nregions; i++) {
     200         388 :         vr_uvhost_log("    %d: FD %d addr 0x%" PRIx64 " size 0x%"
     201             :                 PRIx64 " off 0x%" PRIx64 "\n",
     202             :                 i, vru_cl->vruc_fds_sent[i],
     203             :                 vum_msg->regions[i].guest_phys_addr,
     204             :                 vum_msg->regions[i].memory_size,
     205             :                 vum_msg->regions[i].mmap_offset);
     206             : 
     207         388 :         if (vru_cl->vruc_fds_sent[i]) {
     208         388 :             region = &vru_cl->vruc_mem_regions[i];
     209             : 
     210         388 :             region->vrucmr_phys_addr = vum_msg->regions[i].guest_phys_addr;
     211         388 :             region->vrucmr_size = vum_msg->regions[i].memory_size;
     212         388 :             region->vrucmr_user_space_addr = vum_msg->regions[i].userspace_addr;
     213             : 
     214         388 :             size = vum_msg->regions[i].mmap_offset +
     215         388 :                        vum_msg->regions[i].memory_size;
     216         388 :             region->vrucmr_mmap_addr = (uint64_t)
     217         388 :                     mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
     218             :                             vru_cl->vruc_fds_sent[i], 0);
     219             : 
     220         388 :             if (region->vrucmr_mmap_addr == ((uint64_t)MAP_FAILED)) {
     221           0 :                 vr_uvhost_log("Client %s: error mmaping FD %d size 0x%" PRIx64
     222             :                         ": %s (%d)\n",
     223           0 :                         uvhm_client_name(vru_cl),
     224             :                         vru_cl->vruc_fds_sent[i], size,
     225           0 :                         rte_strerror(errno), errno);
     226             :                 /*
     227             :                  * The file descriptors will be closed in vr_uvh_cl_msg_handler()
     228             :                  */
     229           0 :                 return -1;
     230             :             }
     231             :             /* Get block size for the munmap(2). */
     232         388 :             ret = vr_dpdk_virtio_uvh_get_blk_size(vru_cl->vruc_fds_sent[i],
     233             :                     &region->vrucmr_blksize);
     234         388 :             if (ret) {
     235           0 :                 vr_uvhost_log("Client %s: error getting block size for FD %d\n",
     236           0 :                         uvhm_client_name(vru_cl),
     237             :                         vru_cl->vruc_fds_sent[i]);
     238           0 :                 return -1;
     239             :             }
     240         388 :             region->vrucmr_mmap_addr_aligned = (void *)(uintptr_t)
     241         388 :                 RTE_ALIGN_FLOOR(region->vrucmr_mmap_addr,
     242             :                         region->vrucmr_blksize);
     243         388 :             region->vrucmr_size_aligned = RTE_ALIGN_CEIL(size,
     244             :                     region->vrucmr_blksize);
     245             : 
     246             :             /*
     247             :              * Prevent guest memory from being dumped in vrouter-dpdk core.
     248             :              */
     249         388 :             if (madvise(region->vrucmr_mmap_addr_aligned,
     250             :                     region->vrucmr_size_aligned, MADV_DONTDUMP)) {
     251           0 :                 vr_uvhost_log("Client %s: error in madvise at addr 0x%" PRIx64 ", size 0x%"
     252             :                               PRIx64 "for FD %d: %s (%d)\n",
     253           0 :                               uvhm_client_name(vru_cl),
     254             :                               region->vrucmr_mmap_addr,
     255             :                               size, vru_cl->vruc_fds_sent[i],
     256           0 :                               rte_strerror(errno), errno);
     257             :                 /*
     258             :                  * Failure is not catastrophic, so continue below.
     259             :                  */
     260             :             }
     261             : 
     262             :             /* The file descriptor is no longer needed. */
     263         388 :             close(vru_cl->vruc_fds_sent[i]);
     264         388 :             vru_cl->vruc_fds_sent[i] = -1;
     265         388 :             region->vrucmr_mmap_addr += vum_msg->regions[i].mmap_offset;
     266             :         }
     267             :     }
     268             : 
     269             :     /* Save the number of regions. */
     270         194 :     vru_cl->vruc_num_mem_regions = vum_msg->nregions;
     271             : 
     272         194 :     return 0;
     273             : }
     274             : 
     275             : /*
     276             :  * uvhm_mem_table_munmap - munmaps guest memory regions.
     277             :  */
     278             : static void
     279         554 : uvhm_client_munmap(vr_uvh_client_t *vru_cl)
     280             : {
     281             :     int i, ret;
     282             :     vr_uvh_client_mem_region_t *region;
     283             : 
     284             :     /* Make sure the device has stopped before the munmap. */
     285         554 :     vr_dpdk_virtio_stop(vru_cl->vruc_idx);
     286             : 
     287         554 :     vr_uvhost_log("Client %s: unmapping %u memory regions:\n",
     288         554 :             uvhm_client_name(vru_cl), vru_cl->vruc_num_mem_regions);
     289         942 :     for (i = 0; i < vru_cl->vruc_num_mem_regions; i++) {
     290         388 :         region = &vru_cl->vruc_mem_regions[i];
     291         388 :         if (region->vrucmr_mmap_addr_aligned) {
     292         388 :             vr_uvhost_log("    %d: unmapping addr 0x%"PRIx64" size 0x%"PRIx64
     293             :                     "\n", i, region->vrucmr_phys_addr, region->vrucmr_size);
     294             : 
     295         388 :             ret = munmap(region->vrucmr_mmap_addr_aligned,
     296             :                     region->vrucmr_size_aligned);
     297         388 :             if (ret) {
     298           0 :                 vr_uvhost_log(
     299             :                         "Client %s: error unmapping memory region %d: %s (%d)\n",
     300           0 :                         uvhm_client_name(vru_cl), i, strerror(errno), errno);
     301             :             }
     302             : 
     303             :         }
     304             :     }
     305             :     /*
     306             :      * Possible memory leak when munmap fails. At this moment there is no
     307             :      * solution for that.
     308             :      */
     309         554 :     memset(vru_cl->vruc_mem_regions, 0, sizeof(vru_cl->vruc_mem_regions));
     310         554 :     vru_cl->vruc_num_mem_regions = 0;
     311             : 
     312         554 :     return;
     313             : }
     314             : 
     315             : /*
     316             :  * vr_uvmh_get_features - handle VHOST_USER_GET_FEATURES message from user space
     317             :  * vhost client.
     318             :  *
     319             :  * Returns 0 on success, -1 otherwise.
     320             :  */
     321             : static int
     322         194 : vr_uvmh_get_features(vr_uvh_client_t *vru_cl)
     323             : {
     324             :     /* TODO: Implement VHOST_F_LOG_ALL handler */
     325             :     /* VIRTIO_NET_F_CTRL_VQ is enough for vMX and FreeBSD */
     326         194 :     vru_cl->vruc_msg.u64 = (1ULL << VIRTIO_NET_F_CTRL_VQ) |
     327             :                            (1ULL << VIRTIO_NET_F_CSUM) |
     328             :                            (1ULL << VIRTIO_NET_F_GUEST_CSUM) |
     329             :                            (1ULL << VIRTIO_NET_F_MQ) |
     330             :                            (1ULL << VHOST_USER_F_PROTOCOL_FEATURES) |
     331             :                            (1ULL << VHOST_F_LOG_ALL);
     332             : 
     333         194 :     if (dpdk_check_rx_mrgbuf_disable() == 0)
     334         194 :         vru_cl->vruc_msg.u64 |= (1ULL << VIRTIO_NET_F_MRG_RXBUF);
     335             : 
     336         194 :     if (vr_perfs)
     337         194 :         vru_cl->vruc_msg.u64 |= (1ULL << VIRTIO_NET_F_GUEST_TSO4)|
     338             :                                 (1ULL << VIRTIO_NET_F_HOST_TSO4) |
     339             :                                 (1ULL << VIRTIO_NET_F_GUEST_TSO6)|
     340             :                                 (1ULL << VIRTIO_NET_F_HOST_TSO6);
     341             : 
     342         194 :     vr_uvhost_log("    GET FEATURES: returns 0x%"PRIx64"\n",
     343             :                                             vru_cl->vruc_msg.u64);
     344             : 
     345         194 :     vru_cl->vruc_msg.size = sizeof(vru_cl->vruc_msg.u64);
     346             : 
     347         194 :     return 0;
     348             : }
     349             : 
     350             : /*
     351             :  * vr_uvmh_set_features - handle VHOST_USER_SET_FEATURES message from user space
     352             :  * vhost client.
     353             :  *
     354             :  * Returns 0 on success, -1 otherwise.
     355             :  */
     356             : static int
     357           0 : vr_uvmh_set_features(vr_uvh_client_t *vru_cl)
     358             : {
     359             :     struct vr_interface *vif;
     360           0 :     uint8_t is_gso_vm = 1;
     361           0 :     unsigned long stored_features = 0;
     362             : 
     363           0 :     vr_uvhost_log("    SET FEATURES(original): 0x%"PRIx64"\n",
     364             :                                             vru_cl->vruc_msg.u64);
     365             : 
     366             :     /* Load from cache only if mrgbuf is enabled */
     367           0 :     if ((dpdk_check_rx_mrgbuf_disable() == 0) &&
     368           0 :         !(vru_cl->vruc_flags & VRUC_FLAG_SET_FEATURE_DONE))
     369           0 :         if (!vr_dpdk_load_persist_feature(uvhm_client_name(vru_cl),
     370             :                                           &stored_features)) {
     371           0 :             vru_cl->vruc_msg.u64 |= stored_features;
     372             :         }
     373             : 
     374           0 :     vr_uvhost_log("    SET FEATURES( updated): 0x%"PRIx64"\n",
     375             :                                             vru_cl->vruc_msg.u64);
     376             : 
     377           0 :     vif = __vrouter_get_interface(vrouter_get(0), vru_cl->vruc_idx);
     378           0 :     is_gso_vm =  (vru_cl->vruc_msg.u64 & (1ULL << VIRTIO_NET_F_GUEST_TSO4)) |
     379             :                  (vru_cl->vruc_msg.u64 & (1ULL << VIRTIO_NET_F_HOST_TSO4))  |
     380           0 :                  (vru_cl->vruc_msg.u64 & (1ULL << VIRTIO_NET_F_GUEST_TSO6)) |
     381             :                  (vru_cl->vruc_msg.u64 & (1ULL << VIRTIO_NET_F_HOST_TSO6));
     382             : 
     383             :     /* TODO: For now, assume if a VM can't do GSO, it can't do GRO either
     384             :      * as there is no virtio feature bit for GRO
     385             :      */
     386           0 :     if (vif) {
     387           0 :         if (!!is_gso_vm) {
     388           0 :             vif->vif_flags |= VIF_FLAG_GRO_NEEDED;
     389             :         } else {
     390           0 :             vif->vif_flags &= ~VIF_FLAG_GRO_NEEDED;
     391             :         }
     392             :     }
     393             : 
     394           0 :     if (vru_cl->vruc_msg.u64 & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) {
     395           0 :         vif->vif_flags |= VIF_FLAG_MRG_RXBUF;
     396           0 :         vr_dpdk_set_vhost_send_func(vru_cl->vruc_idx, 1);
     397             :     } else {
     398           0 :         vif->vif_flags &= ~VIF_FLAG_MRG_RXBUF;
     399           0 :         vr_dpdk_set_vhost_send_func(vru_cl->vruc_idx, 0);
     400             :     }
     401             :     /* Save to cache only if mrgbuf is enabled */
     402           0 :     if (dpdk_check_rx_mrgbuf_disable() == 0)
     403           0 :         vr_dpdk_store_persist_feature(uvhm_client_name(vru_cl),
     404             :                                       vru_cl->vruc_msg.u64);
     405           0 :     vru_cl->vruc_flags |= VRUC_FLAG_SET_FEATURE_DONE;
     406           0 :     return 0;
     407             : }
     408             : 
     409             : static int
     410           0 : vr_uvmh_get_protocol_features(vr_uvh_client_t *vru_cl)
     411             : {
     412           0 :     vru_cl->vruc_msg.u64 = ((1ULL << VHOST_USER_PROTOCOL_F_MQ) |
     413             :                             (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD));
     414           0 :     vr_uvhost_log("    GET PROTOCOL FEATURES: returns 0x%"PRIx64"\n",
     415             :                   vru_cl->vruc_msg.u64);
     416             : 
     417           0 :     vru_cl->vruc_msg.size = sizeof(vru_cl->vruc_msg.u64);
     418             : 
     419           0 :     return 0;
     420             : }
     421             : 
     422             : static int
     423           0 : vr_uvmh_set_protocol_features(vr_uvh_client_t *vru_cl)
     424             : {
     425           0 :     vr_uvhost_log("    SET PROTOCOL FEATURES: 0x%"PRIx64"\n",
     426             :                   vru_cl->vruc_msg.u64);
     427             : 
     428           0 :     return 0;
     429             : }
     430             : 
     431             : /*
     432             :  * vr_uvhm_set_mem_table - handles VHOST_USER_SET_MEM_TABLE message from
     433             :  * user space vhost client to learn the memory map of the guest.
     434             :  *
     435             :  * Returns 0 on success, -1 otherwise.
     436             :  */
     437             : static int
     438         194 : vr_uvhm_set_mem_table(vr_uvh_client_t *vru_cl)
     439             : {
     440         194 :     vr_uvhost_log("    SET MEM TABLE:\n");
     441             : 
     442             :     /* Unmap previously mmaped guest memory. */
     443         194 :     uvhm_client_munmap(vru_cl);
     444         194 :     return uvhm_client_mmap(vru_cl);
     445             : }
     446             : 
     447             : /*
     448             :  * vr_uvhm_set_log_base - handles VHOST_USER_SET_LOG_BASE message from
     449             :  * user space vhost client to learn the memory map of the guest.
     450             :  *
     451             :  * Returns 0 on success, -1 otherwise.
     452             :  */
     453             : static int
     454           0 : vr_uvhm_set_log_base(vr_uvh_client_t *vru_cl)
     455             : {
     456           0 :     vr_uvhost_log("    SET LOG BASE: 0x%"PRIx64"\n",
     457             :                   vru_cl->vruc_msg.u64);
     458             : 
     459           0 :     return 0;
     460             : }
     461             : 
     462             : /*
     463             :  * vr_uvhm_set_vring_num - handles VHOST_USER_SET_VRING_NUM message from
     464             :  * the user space vhost client to set the number of descriptors in the virtio
     465             :  * ring.
     466             :  *
     467             :  * Returns 0 on success, -1 otherwise.
     468             :  */
     469             : static int
     470         388 : vr_uvhm_set_vring_num(vr_uvh_client_t *vru_cl)
     471             : {
     472             :     VhostUserMsg *vum_msg;
     473             :     unsigned int vring_idx;
     474             : 
     475         388 :     vum_msg = &vru_cl->vruc_msg;
     476         388 :     vring_idx = vum_msg->state.index;
     477         388 :     vr_uvhost_log("    SET VRING NUM: vring %u num %u\n", vring_idx,
     478             :                                  vum_msg->state.num);
     479             : 
     480         388 :     if (vring_idx >= VHOST_CLIENT_MAX_VRINGS) {
     481           0 :         vr_uvhost_log("Client %s: error setting vring %u num: invalid vring index\n",
     482           0 :                         uvhm_client_name(vru_cl), vring_idx);
     483           0 :         return -1;
     484             :     }
     485         388 :     if (vr_dpdk_set_ring_num_desc(vru_cl->vruc_idx, vring_idx,
     486             :                                   vum_msg->state.num)) {
     487           0 :         vr_uvhost_log("Client %s: error setting vring %u size %u\n",
     488           0 :                     uvhm_client_name(vru_cl), vring_idx, vum_msg->state.num);
     489           0 :         return -1;
     490             :     }
     491             : 
     492         388 :     return 0;
     493             : }
     494             : 
     495             : /*
     496             :  * vr_uvhm_map_addr - map a virtual address sent by the vhost client into
     497             :  * a server virtual address.
     498             :  *
     499             :  * Returns a pointer to the corresponding location on success, NULL otherwise.
     500             :  */
     501             : static void *
     502        1164 : vr_uvhm_map_addr(vr_uvh_client_t *vru_cl, uint64_t addr)
     503             : {
     504             :     int i;
     505             :     uint64_t vmr_addr, vmr_size, ret_addr;
     506             : 
     507        1746 :     for (i = 0; i < vru_cl->vruc_num_mem_regions; i++) {
     508        1746 :         vmr_addr = vru_cl->vruc_mem_regions[i].vrucmr_user_space_addr;
     509        1746 :         vmr_size = vru_cl->vruc_mem_regions[i].vrucmr_size;
     510             : 
     511        1746 :         if ((vmr_addr <= addr) && (addr < (vmr_addr + vmr_size))) {
     512        1164 :              ret_addr = vru_cl->vruc_mem_regions[i].vrucmr_mmap_addr +
     513        1164 :                         (addr - vmr_addr);
     514        1164 :              return (void *) ret_addr;
     515             :         }
     516             :     }
     517             : 
     518           0 :     return NULL;
     519             : }
     520             : 
     521             : /*
     522             :  * uvhm_check_vring_ready - check if virtual queue is ready to use and
     523             :  * set the ready status.
     524             :  *
     525             :  * Returns 1 if vring ready, 0 otherwise.
     526             :  */
     527             : static int
     528         776 : uvhm_check_vring_ready(vr_uvh_client_t *vru_cl, unsigned int vring_idx)
     529             : {
     530         776 :     unsigned int vif_idx = vru_cl->vruc_idx;
     531             :     vr_dpdk_virtioq_t *vq;
     532             : 
     533         776 :     if (vif_idx >= VR_MAX_INTERFACES) {
     534           0 :         return 0;
     535             :     }
     536             : 
     537         776 :     if (vring_idx & 1) {
     538         388 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
     539             :     } else {
     540         388 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
     541             :     }
     542             : 
     543             :     /* vring is ready when addresses are set. */
     544         776 :     if (vq->vdv_desc && vq->vdv_ready_state != VQ_READY) {
     545             :         /*
     546             :          * Now the virtio queue is ready for forwarding.
     547             :          * TODO - need a memory barrier here for non-x86 CPU?
     548             :          */
     549         388 :         if (vr_dpdk_set_virtq_ready(vru_cl->vruc_idx, vring_idx, VQ_READY)) {
     550           0 :             vr_uvhost_log("Client %s: error setting vring %u ready state\n",
     551           0 :                     uvhm_client_name(vru_cl), vring_idx);
     552           0 :             return -1;
     553             :         }
     554             : 
     555         388 :         vr_uvhost_log("Client %s: vring %d is ready\n",
     556         388 :                 uvhm_client_name(vru_cl), vring_idx);
     557             : 
     558         388 :         return 1;
     559             :     }
     560             : 
     561         388 :     return 0;
     562             : }
     563             : 
     564             : /*
     565             :  * vr_uvhm_set_vring_addr - handles a VHOST_USER_SET_VRING_ADDR message from
     566             :  * the user space vhost client to set the address of the virtio rings.
     567             :  *
     568             :  * Returns 0 on success, -1 otherwise.
     569             :  */
     570             : static int
     571         388 : vr_uvhm_set_vring_addr(vr_uvh_client_t *vru_cl)
     572             : {
     573             :     struct vhost_vring_addr *vaddr;
     574             :     unsigned int vring_idx;
     575             :     struct vring_desc *vrucv_desc;
     576             :     struct vring_avail *vrucv_avail;
     577             :     struct vring_used *vrucv_used;
     578             : 
     579         388 :     vaddr = &vru_cl->vruc_msg.addr;
     580         388 :     vring_idx = vaddr->index;
     581         388 :     vr_uvhost_log("    SET VRING ADDR: vring %u flags 0x%x desc 0x%llx"
     582             :                      " used 0x%llx avail 0x%llx\n",
     583             :                      vring_idx, vaddr->flags, vaddr->desc_user_addr,
     584             :                      vaddr->used_user_addr, vaddr->avail_user_addr);
     585             : 
     586         388 :     if (vring_idx >= VHOST_CLIENT_MAX_VRINGS) {
     587           0 :         vr_uvhost_log("Client %s: error setting vring %u addr: invalid vring index\n",
     588           0 :                         uvhm_client_name(vru_cl), vring_idx);
     589           0 :         return -1;
     590             :     }
     591             : 
     592             :     vrucv_desc = (struct vring_desc *)
     593         388 :         vr_uvhm_map_addr(vru_cl, vaddr->desc_user_addr);
     594             :     vrucv_avail = (struct vring_avail *)
     595         388 :         vr_uvhm_map_addr(vru_cl, vaddr->avail_user_addr);
     596             :     vrucv_used = (struct vring_used *)
     597         388 :         vr_uvhm_map_addr(vru_cl, vaddr->used_user_addr);
     598             : 
     599         388 :     if (!vrucv_desc || !vrucv_avail || !vrucv_used)
     600           0 :         return -1;
     601             : 
     602         388 :     if (vr_dpdk_set_vring_addr(vru_cl->vruc_idx, vring_idx, vrucv_desc,
     603             :                                vrucv_avail, vrucv_used)) {
     604           0 :         vr_uvhost_log("Client %s: error setting vring %u addresses\n",
     605           0 :                 uvhm_client_name(vru_cl), vring_idx);
     606           0 :         return -1;
     607             :     }
     608             : 
     609             :     /* Try to recover from the vRouter crash. */
     610         388 :     vr_dpdk_virtio_recover_vring_base(vru_cl->vruc_idx, vring_idx);
     611             : 
     612         388 :     uvhm_check_vring_ready(vru_cl, vring_idx);
     613             : 
     614         388 :     return 0;
     615             : }
     616             : 
     617             : /*
     618             :  * vr_uvhm_set_vring_base - handles a VHOST_USER_SET_VRING_BASE messsage
     619             :  * from the vhost user client to set the based index of a vring.
     620             :  *
     621             :  * Returns 0 on success, -1 otherwise.
     622             :  */
     623             : static int
     624         388 : vr_uvhm_set_vring_base(vr_uvh_client_t *vru_cl)
     625             : {
     626             :     VhostUserMsg *vum_msg;
     627             :     unsigned int vring_idx;
     628             : 
     629         388 :     vum_msg = &vru_cl->vruc_msg;
     630         388 :     vring_idx = vum_msg->state.index;
     631         388 :     vr_uvhost_log("    SET VRING BASE: vring %u base %u\n",
     632             :                      vring_idx, vum_msg->state.num);
     633             : 
     634         388 :     if (vring_idx >= VHOST_CLIENT_MAX_VRINGS) {
     635           0 :         vr_uvhost_log("Client %s: error setting vring %u base: invalid vring index\n",
     636           0 :                         uvhm_client_name(vru_cl), vring_idx);
     637           0 :         return -1;
     638             :     }
     639             : 
     640         388 :     if (vr_dpdk_virtio_set_vring_base(vru_cl->vruc_idx, vring_idx,
     641             :                                       vum_msg->state.num)) {
     642           0 :         vr_uvhost_log("Client %s: error setting vring %u base %u\n",
     643           0 :                 uvhm_client_name(vru_cl), vring_idx, vum_msg->state.num);
     644           0 :         return -1;
     645             :     }
     646             : 
     647         388 :     return 0;
     648             : }
     649             : 
     650             : /*
     651             :  * vr_uvhm_get_vring_base - handles a VHOST_USER_GET_VRING_BASE messsage
     652             :  * from the vhost user client to get the base index of a vring.
     653             :  *
     654             :  * Returns 0 on success, -1 otherwise.
     655             :  */
     656             : static int
     657           0 : vr_uvhm_get_vring_base(vr_uvh_client_t *vru_cl)
     658             : {
     659             :     VhostUserMsg *vum_msg;
     660             :     unsigned int vring_idx;
     661             : 
     662           0 :     vum_msg = &vru_cl->vruc_msg;
     663           0 :     vring_idx = vum_msg->state.index;
     664           0 :     vr_uvhost_log("    GET VRING BASE: vring %u\n", vring_idx);
     665             : 
     666           0 :     if (vring_idx >= VHOST_CLIENT_MAX_VRINGS) {
     667           0 :         vr_uvhost_log("Client %s: error getting vring %u base: invalid vring index\n",
     668           0 :                         uvhm_client_name(vru_cl), vring_idx);
     669           0 :         return -1;
     670             :     }
     671             : 
     672           0 :     if (vr_dpdk_virtio_get_vring_base(vru_cl->vruc_idx, vring_idx,
     673             :                                      &vum_msg->state.num)) {
     674           0 :         vr_uvhost_log("Client %s: error getting vring %u base index\n",
     675           0 :                 uvhm_client_name(vru_cl), vring_idx);
     676           0 :         return -1;
     677             :     }
     678             : 
     679           0 :     vum_msg->size = sizeof(struct vhost_vring_state);
     680           0 :     vr_uvhost_log("    GET VRING BASE: returns %u\n", vum_msg->state.num);
     681             : 
     682           0 :     return 0;
     683             : }
     684             : 
     685             : /*
     686             :  * vr_uvhm_set_vring_call - handles a VHOST_USER_SET_VRING_CALL message
     687             :  * from the vhost user client to set the eventfd to be used to interrupt the
     688             :  * guest, if required.
     689             :  *
     690             :  * Returns 0 on success, -1 otherwise.
     691             :  */
     692             : static int
     693         388 : vr_uvhm_set_vring_call(vr_uvh_client_t *vru_cl)
     694             : {
     695             :     VhostUserMsg *vum_msg;
     696             :     unsigned int vring_idx;
     697             : 
     698         388 :     vum_msg = &vru_cl->vruc_msg;
     699         388 :     vring_idx = vum_msg->state.index;
     700         388 :     vr_uvhost_log("    SET VRING CALL: vring %u FD %d\n", vring_idx,
     701             :                                                 vru_cl->vruc_fds_sent[0]);
     702             : 
     703         388 :     if (!(vring_idx & VHOST_USER_VRING_NOFD_MASK)) {
     704         388 :         if (vring_idx >= VHOST_CLIENT_MAX_VRINGS) {
     705           0 :             vr_uvhost_log(
     706             :                 "Client %s: error setting vring %u call: invalid vring index\n",
     707           0 :                 uvhm_client_name(vru_cl), vring_idx);
     708           0 :             return -1;
     709             :         }
     710             : 
     711         388 :         if (vr_dpdk_set_ring_callfd(vru_cl->vruc_idx, vring_idx,
     712             :                                     vru_cl->vruc_fds_sent[0])) {
     713           0 :             vr_uvhost_log("Client %s: error setting vring %u call FD %d\n",
     714           0 :                     uvhm_client_name(vru_cl), vring_idx, vru_cl->vruc_fds_sent[0]);
     715           0 :             return -1;
     716             :         }
     717             :     } else {
     718           0 :         vr_uvhost_log("Client %s: not setting call fd due to mask 0x%x\n",
     719           0 :                         uvhm_client_name(vru_cl), vring_idx);
     720             : 
     721           0 :         vring_idx &= (~VHOST_USER_VRING_NOFD_MASK);
     722             :     }
     723             : 
     724             :     /* set FD to -1, so we do not close it in vr_uvh_cl_msg_handler() */
     725         388 :     vru_cl->vruc_fds_sent[0] = -1;
     726             : 
     727         388 :     uvhm_check_vring_ready(vru_cl, vring_idx);
     728             : 
     729         388 :     return 0;
     730             : }
     731             : 
     732             : /*
     733             :  * Handle the VHOST_USER_SET_VRING_ENABLE vhost-user protocol message.
     734             :  */
     735             : static int
     736           0 : vr_uvhm_set_vring_enable(vr_uvh_client_t *vru_cl)
     737             : {
     738             :     VhostUserMsg *vum_msg;
     739             :     unsigned int vring_idx;
     740             :     unsigned int queue_num;
     741             :     bool enable;
     742             : 
     743           0 :     vum_msg = &vru_cl->vruc_msg;
     744           0 :     vring_idx = vum_msg->state.index;
     745           0 :     enable = (bool)vum_msg->state.num;
     746             : 
     747             :     /* QEMU should NEVER send the disable command for queue 0 */
     748           0 :     if ((vring_idx == 0 || vring_idx == 1) && !enable) {
     749           0 :         RTE_LOG(ERR, UVHOST, "%s: Can not disable RX/TX queue 0\n", __func__);
     750           0 :         return -1;
     751             :     }
     752             : 
     753             :     /*
     754             :      * If the queue is higher than the number supported by vrouter, silently
     755             :      * fail here (as there is no error message returned to qemu).
     756             :      */
     757           0 :     if ((vring_idx / 2) >= vr_dpdk.nb_fwd_lcores) {
     758           0 :         RTE_LOG(ERR, UVHOST, "%s: Can not %s %s queue %d (only %d queues)\n",
     759             :             __func__, enable ? "enable" : "disable",
     760             :             (vring_idx & 1) ? "RX" : "TX", vring_idx / 2,
     761             :             vr_dpdk.nb_fwd_lcores);
     762           0 :         return 0;
     763             :     }
     764             : 
     765           0 :     vr_uvhost_log("Client %s: setting vring %u ready state %d\n",
     766           0 :                   uvhm_client_name(vru_cl), vring_idx, enable);
     767             : 
     768           0 :     uvhm_check_vring_ready(vru_cl, vring_idx);
     769             : 
     770           0 :     queue_num = vring_idx / 2;
     771             : 
     772           0 :     if (vring_idx & 1) {
     773             :         /* RX queues */
     774           0 :         vr_dpdk_virtio_rx_queue_enable_disable(vru_cl->vruc_idx,
     775             :                                                vru_cl->vruc_vif_gen, queue_num,
     776             :                                                enable);
     777             :     } else {
     778             :         /* TX queues */
     779           0 :         vr_dpdk_virtio_tx_queue_enable_disable(vru_cl->vruc_idx,
     780             :                                                vru_cl->vruc_vif_gen, queue_num,
     781             :                                                enable);
     782             :     }
     783             : 
     784           0 :     return 0;
     785             : }
     786             : 
     787             : /*
     788             :  * vr_uvh_cl_call_handler - calls message specific handler for messages
     789             :  * from user space vhost client.
     790             :  *
     791             :  * Returns 0 on success, -1 otherwise.
     792             :  */
     793             : static int
     794        2522 : vr_uvh_cl_call_handler(vr_uvh_client_t *vru_cl)
     795             : {
     796        2522 :     VhostUserMsg *msg = &vru_cl->vruc_msg;
     797             : 
     798        2522 :     if ((msg->request <= VHOST_USER_NONE) ||
     799        2522 :             (msg->request >= VHOST_USER_MAX)) {
     800           0 :         return -1;
     801             :     }
     802             : 
     803        2522 :     if (vr_uvhost_cl_msg_handlers[msg->request]) {
     804        1940 :         vr_uvhost_log("Client %s: handling message %d\n",
     805        1940 :                 uvhm_client_name(vru_cl), msg->request);
     806        1940 :         return vr_uvhost_cl_msg_handlers[msg->request](vru_cl);
     807             :     } else {
     808         582 :         vr_uvhost_log("Client %s: no handler defined for message %d\n",
     809         582 :                 uvhm_client_name(vru_cl), msg->request);
     810             :     }
     811             : 
     812         582 :     return 0;
     813             : }
     814             : 
     815             : static int
     816           0 : vr_uvhm_get_queue_num(vr_uvh_client_t *vru_cl)
     817             : {
     818             :     /* We support up to number of forwarding lcores queues as they are the only
     819             :      * lcores that handle rx queues. However, this causes a failure when spawning
     820             :      * the VM if the number of VCPUs in the VM is higher than the number of
     821             :      * forwarding cores in vrouter. So, return VR_DPDK_VIRTIO_MAX_QUEUES here,
     822             :      * but siliently fail the enable/disable of queues higher than the number
     823             :      * of forwarding cores when the message is received from qemu later. The
     824             :      * expectation is that the VM should not enable more queues that that.
     825             :      */
     826           0 :     vru_cl->vruc_msg.u64 = VR_DPDK_VIRTIO_MAX_QUEUES;
     827           0 :     vr_uvhost_log("    GET QUEUE NUM: returns 0x%"PRIx64"\n",
     828             :                   vru_cl->vruc_msg.u64);
     829             : 
     830           0 :     vru_cl->vruc_msg.size = sizeof(vru_cl->vruc_msg.u64);
     831             : 
     832           0 :     return 0;
     833             : }
     834             : 
     835             : /*
     836             :  * vr_uvh_cl_send_reply - send a reply to the vhost user client if
     837             :  * required.
     838             :  *
     839             :  * Returns 0 on success, -1 otherwise.
     840             :  */
     841             : static int
     842        2522 : vr_uvh_cl_send_reply(int fd, vr_uvh_client_t *vru_cl)
     843             : {
     844             :     int ret;
     845        2522 :     VhostUserMsg *msg = &vru_cl->vruc_msg;
     846             : 
     847        2522 :     switch(msg->request) {
     848         194 :         case VHOST_USER_GET_FEATURES:
     849             :         case VHOST_USER_GET_VRING_BASE:
     850             :         case VHOST_USER_GET_PROTOCOL_FEATURES:
     851             :         case VHOST_USER_GET_QUEUE_NUM:
     852             :         case VHOST_USER_SET_LOG_BASE:
     853             :             /*
     854             :              * Send reply for these messages only.
     855             :              */
     856         194 :             msg->flags &= (~VHOST_USER_VERSION_MASK);
     857         194 :             msg->flags |= VHOST_USER_VERSION;
     858         194 :             msg->flags |= VHOST_USER_REPLY_MASK;
     859             : 
     860         194 :             if (vru_cl->vruc_owner != pthread_self()) {
     861          95 :                 if (vru_cl->vruc_owner)
     862           0 :                     RTE_LOG(WARNING, UVHOST, "WARNING: thread %lx is trying to write"
     863             :                         " to uvhost client FD %d owned by thread %lx\n",
     864             :                         pthread_self(), fd, vru_cl->vruc_owner);
     865          95 :                 vru_cl->vruc_owner = pthread_self();
     866             :             }
     867         388 :             ret = send(fd, (void *) msg,
     868         194 :                        VHOST_USER_HSIZE + msg->size, MSG_DONTWAIT);
     869         194 :             if ((ret < 0) || (ret != (VHOST_USER_HSIZE + msg->size))) {
     870             :                 /*
     871             :                  * Socket to qemu should never be full as it sleeps waiting
     872             :                  * for a reply to the previous request.
     873             :                  */
     874           0 :                 vr_uvhost_log("Client %s: error sending vhost user reply\n",
     875           0 :                         uvhm_client_name(vru_cl));
     876           0 :                 return -1;
     877             :              }
     878             : 
     879         194 :             break;
     880             : 
     881        2328 :         default:
     882             :             /*
     883             :              * No reply needed.
     884             :              */
     885        2328 :             break;
     886             :     }
     887             : 
     888        2522 :     return 0;
     889             : }
     890             : 
     891             : /*
     892             :  * vr_uvh_cl_msg_handler - handler for messages from user space vhost
     893             :  * clients. Calls the appropriate handler based on the message type.
     894             :  *
     895             :  * Returns 0 on success, -1 on error.
     896             :  *
     897             :  * TODO: upon error, this function currently makes the process exit.
     898             :  * Instead, it should close the socket and continue serving other clients.
     899             :  */
     900             : static int
     901        2716 : vr_uvh_cl_msg_handler(int fd, void *arg)
     902             : {
     903        2716 :     vr_uvh_client_t *vru_cl = (vr_uvh_client_t *) arg;
     904             :     struct msghdr mhdr;
     905             :     struct iovec iov;
     906        2716 :     int i, err, ret = 0, read_len = 0;
     907             :     struct cmsghdr *cmsg;
     908             : 
     909        2716 :     memset(&mhdr, 0, sizeof(mhdr));
     910             : 
     911        2716 :     if (vru_cl->vruc_msg_bytes_read == 0) {
     912        2716 :         mhdr.msg_control = &vru_cl->vruc_cmsg;
     913        2716 :         mhdr.msg_controllen = sizeof(vru_cl->vruc_cmsg);
     914             : 
     915        2716 :         iov.iov_base = (void *) &vru_cl->vruc_msg;
     916        2716 :         iov.iov_len = VHOST_USER_HSIZE;
     917             : 
     918        2716 :         mhdr.msg_iov = &iov;
     919        2716 :         mhdr.msg_iovlen = 1;
     920             : 
     921        2716 :         ret = recvmsg(fd, &mhdr, MSG_DONTWAIT);
     922        2716 :         if (ret < 0) {
     923         194 :             if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
     924           0 :                 ret = 0;
     925           0 :                 goto cleanup;
     926             :             }
     927             : 
     928         388 :             vr_uvhost_log("Client %s: error receiving message: %s (%d)\n",
     929         194 :                     uvhm_client_name(vru_cl), strerror(errno), errno);
     930         194 :             ret = -1;
     931         194 :             goto cleanup;
     932        2522 :         } else if (ret > 0) {
     933        2522 :             if (mhdr.msg_flags & MSG_CTRUNC) {
     934           0 :                 vr_uvhost_log("Client %s: error receiving message: truncated\n",
     935           0 :                         uvhm_client_name(vru_cl));
     936           0 :                 ret = -1;
     937           0 :                 goto cleanup;
     938             :             }
     939             : 
     940        2522 :             cmsg = CMSG_FIRSTHDR(&mhdr);
     941        2522 :             if (cmsg && (cmsg->cmsg_len > 0) &&
     942         970 :                    (cmsg->cmsg_level == SOL_SOCKET) &&
     943         970 :                    (cmsg->cmsg_type == SCM_RIGHTS)) {
     944         970 :                    vru_cl->vruc_num_fds_sent = (cmsg->cmsg_len - CMSG_LEN(0))/
     945             :                                                    sizeof(int);
     946         970 :                    if (vru_cl->vruc_num_fds_sent > VHOST_MEMORY_MAX_NREGIONS) {
     947           0 :                         vr_uvhost_log("Client %s: error handling FDs: too many FDs (%d > %d)\n",
     948           0 :                                 uvhm_client_name(vru_cl),
     949             :                                 vru_cl->vruc_num_fds_sent,
     950             :                                 VHOST_MEMORY_MAX_NREGIONS);
     951           0 :                        vru_cl->vruc_num_fds_sent = VHOST_MEMORY_MAX_NREGIONS;
     952             :                    }
     953             : 
     954         970 :                    memcpy(vru_cl->vruc_fds_sent, CMSG_DATA(cmsg),
     955         970 :                           vru_cl->vruc_num_fds_sent*sizeof(int));
     956             :             }
     957             : 
     958        2522 :             vru_cl->vruc_msg_bytes_read = ret;
     959        2522 :             if (ret < VHOST_USER_HSIZE) {
     960           0 :                 ret = 0;
     961           0 :                 goto cleanup;
     962             :             }
     963             : 
     964        2522 :             read_len = vru_cl->vruc_msg.size;
     965             :         } else {
     966             :             /*
     967             :              * recvmsg returned 0, so return error.
     968             :              */
     969           0 :             vr_uvhost_log("Client %s: shutdown at message receiving\n",
     970           0 :                     uvhm_client_name(vru_cl));
     971           0 :             ret = -1;
     972           0 :             vr_dpdk_del_persist_feature(uvhm_client_name(vru_cl));
     973           0 :             goto cleanup;
     974             :         }
     975           0 :     } else if (vru_cl->vruc_msg_bytes_read < VHOST_USER_HSIZE) {
     976           0 :         read_len = VHOST_USER_HSIZE - vru_cl->vruc_msg_bytes_read;
     977             :     } else {
     978           0 :         read_len = vru_cl->vruc_msg.size -
     979           0 :                        (vru_cl->vruc_msg_bytes_read - VHOST_USER_HSIZE);
     980             :     }
     981             : 
     982        2522 :     if (read_len) {
     983        2134 :         if (vru_cl->vruc_owner != pthread_self()) {
     984           0 :             if (vru_cl->vruc_owner)
     985           0 :                 RTE_LOG(WARNING, UVHOST, "WARNING: thread %lx is trying to read"
     986             :                     " uvhost client FD %d owned by thread %lx\n",
     987             :                     pthread_self(), fd, vru_cl->vruc_owner);
     988           0 :             vru_cl->vruc_owner = pthread_self();
     989             :         }
     990        2134 :         ret = read(fd, (((char *)&vru_cl->vruc_msg) + vru_cl->vruc_msg_bytes_read),
     991             :                    read_len);
     992             : #ifdef VR_DPDK_RX_PKT_DUMP
     993             :         if (ret > 0) {
     994             :             RTE_LOG_DP(DEBUG, UVHOST, "%s[%lx]: FD %d read %d bytes\n", __func__,
     995             :                 pthread_self(), fd, ret);
     996             :             rte_hexdump(stdout, "uvhost full message dump:",
     997             :                 (((char *)&vru_cl->vruc_msg)),
     998             :                     ret + vru_cl->vruc_msg_bytes_read);
     999             :         } else if (ret < 0) {
    1000             :             RTE_LOG_DP(DEBUG, UVHOST, "%s[%lx]: FD %d read returned error %d: %s (%d)\n", __func__,
    1001             :                 pthread_self(), fd, ret, rte_strerror(errno), errno);
    1002             :         }
    1003             : #endif
    1004        2134 :         if (ret < 0) {
    1005           0 :             if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
    1006           0 :                 ret = 0;
    1007           0 :                 goto cleanup;
    1008             :             }
    1009             : 
    1010           0 :             vr_uvhost_log(
    1011             :                 "Client %s: error reading message: %s (%d)\n",
    1012           0 :                 uvhm_client_name(vru_cl), strerror(errno), errno);
    1013           0 :             ret = -1;
    1014           0 :             goto cleanup;
    1015        2134 :         } else if (ret == 0) {
    1016           0 :             vr_uvhost_log("Client %s: shutdown at message reading\n",
    1017           0 :                      uvhm_client_name(vru_cl));
    1018           0 :             ret = -1;
    1019           0 :             goto cleanup;
    1020             :         }
    1021             : 
    1022        2134 :         vru_cl->vruc_msg_bytes_read += ret;
    1023        2134 :         if (vru_cl->vruc_msg_bytes_read < VHOST_USER_HSIZE) {
    1024           0 :             ret = 0;
    1025           0 :             goto cleanup;
    1026             :         }
    1027             : 
    1028        2134 :         if (vru_cl->vruc_msg_bytes_read <
    1029        2134 :                 (vru_cl->vruc_msg.size + VHOST_USER_HSIZE)) {
    1030           0 :             ret = 0;
    1031           0 :             goto cleanup;
    1032             :         }
    1033             :     }
    1034             : 
    1035        2522 :     ret = vr_uvh_cl_call_handler(vru_cl);
    1036        2522 :     if (ret < 0) {
    1037           0 :         vr_uvhost_log("Client %s: error handling message %d\n",
    1038           0 :                 uvhm_client_name(vru_cl), vru_cl->vruc_msg.request);
    1039           0 :         ret = -1;
    1040           0 :         goto cleanup;
    1041             :     }
    1042             : 
    1043        2522 :     ret = vr_uvh_cl_send_reply(fd, vru_cl);
    1044        2522 :     if (ret < 0) {
    1045           0 :         vr_uvhost_log("Client %s: error sending reply for message %d\n",
    1046           0 :                 uvhm_client_name(vru_cl), vru_cl->vruc_msg.request);
    1047           0 :         ret = -1;
    1048           0 :         goto cleanup;
    1049             :     }
    1050             : 
    1051        2522 : cleanup:
    1052        2716 :     err = errno;
    1053             :     /* close all the FDs received */
    1054        3880 :     for (i = 0; i < vru_cl->vruc_num_fds_sent; i++) {
    1055        1164 :         if (vru_cl->vruc_fds_sent[i] > 0)
    1056         388 :             close(vru_cl->vruc_fds_sent[i]);
    1057             :     }
    1058        2716 :     if (ret == -1) {
    1059             :         /* Send netlink interface down message to agent */
    1060         194 :         vr_uvh_nl_send_intf_state(0, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1061             :         /* We set VQ_NOT_READY state and reset the queues in uvhm_client_munmap() */
    1062         194 :         uvhm_client_munmap(vru_cl);
    1063         194 :         if (vru_cl->vruc_vhostuser_mode == VRNU_VIF_MODE_SERVER) {
    1064             :             /* existing FD (stored in local variable in caller to
    1065             :              * this funcition) will be closed after return from this function
    1066             :              * reset the value to -1, so that new fd will be created
    1067             :              */
    1068         194 :             vru_cl->vruc_fd = -1;
    1069         194 :             if (vr_uvh_cl_timer_setup(vru_cl)) {
    1070           0 :                 vr_uvhost_log("Client %s: timer creation failed\n",
    1071           0 :                         uvhm_client_name(vru_cl));
    1072             :             }
    1073             :         }
    1074             :     }
    1075             :     /* clear state for next message from this client. */
    1076        2716 :     vru_cl->vruc_msg_bytes_read = 0;
    1077        2716 :     memset(&vru_cl->vruc_msg, 0, sizeof(vru_cl->vruc_msg));
    1078        2716 :     memset(vru_cl->vruc_cmsg, 0, sizeof(vru_cl->vruc_cmsg));
    1079        2716 :     memset(vru_cl->vruc_fds_sent, 0, sizeof(vru_cl->vruc_fds_sent));
    1080        2716 :     vru_cl->vruc_num_fds_sent = 0;
    1081        2716 :     errno = err;
    1082        2716 :     return ret;
    1083             : }
    1084             : 
    1085             : /*
    1086             :  * vr_uvh_cl_listen_handler - handler for connections from user space vhost
    1087             :  * clients. Accepts the connections and sets up a message handler for the
    1088             :  * client in the server.
    1089             :  *
    1090             :  * Returns 0 on success, -1 otherwise.
    1091             :  */
    1092             : static int
    1093           0 : vr_uvh_cl_listen_handler(int fd, void *arg)
    1094             : {
    1095           0 :     int s = 0, err;
    1096             :     struct sockaddr_un sun;
    1097           0 :     socklen_t len = sizeof(sun);
    1098           0 :     vr_uvh_client_t *vru_cl = (vr_uvh_client_t *) arg;
    1099             : 
    1100           0 :     vr_uvhost_log("Handling client connection FD %d\n", fd);
    1101           0 :     s = accept(fd, (struct sockaddr *) &sun, &len);
    1102           0 :     if (s < 0) {
    1103           0 :         if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
    1104           0 :             return 0;
    1105             :         }
    1106             : 
    1107           0 :         vr_uvhost_log("    error accepting client connection FD %d\n", fd);
    1108           0 :         return -1;
    1109             :     }
    1110           0 :     vr_uvhost_log("    FD %d accepted new client connection FD %d\n", fd, s);
    1111             : 
    1112             :     /* Send netlink interface up message to agent */
    1113           0 :     vr_uvh_nl_send_intf_state(1, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1114             : 
    1115             :     /* We still need to listen for the original socket to support VM
    1116             :      * shut off/restart, since we create the socket at vif --add
    1117             :      * and we get vif --add at the VM spawning, not VM (re)starting
    1118             :      */
    1119             : 
    1120             :     /* Do not set new client FD, since we still need to close parent FD
    1121             :      * on vif delete.
    1122             :      * We will get the client FD in our handler as an argument.
    1123             :      */
    1124             : 
    1125           0 :     if (vr_uvhost_add_fd(s, UVH_FD_READ, vru_cl, vr_uvh_cl_msg_handler)) {
    1126           0 :         vr_uvhost_log("    error adding client %s FD %d read handler\n",
    1127             :                       sun.sun_path, fd);
    1128           0 :         goto error;
    1129             :     }
    1130             : 
    1131           0 :     return 0;
    1132             : 
    1133           0 : error:
    1134             : 
    1135           0 :     err = errno;
    1136           0 :     if (s) {
    1137           0 :         close(s);
    1138             :     }
    1139             : 
    1140           0 :     if (vru_cl) {
    1141           0 :         vr_uvhost_del_client(vru_cl);
    1142             :     }
    1143           0 :     errno = err;
    1144             : 
    1145           0 :     return -1;
    1146             : }
    1147             : 
    1148             : /*
    1149             :  * vr_uvh_cl_timer_handler - handler for timer events for
    1150             :  * clients when Qemu in server mode
    1151             :  *
    1152             :  * Returns 0 on success, -1 on error.
    1153             :  *
    1154             :  */
    1155             : static int
    1156         717 : vr_uvh_cl_timer_handler(int fd, void *arg)
    1157             : {
    1158         717 :     vr_uvh_client_t *vru_cl = (vr_uvh_client_t *) arg;
    1159             :     struct sockaddr_un sun;
    1160         717 :     int ret = 0;
    1161             : 
    1162         717 :     memset(&sun, 0, sizeof(sun));
    1163         717 :     sun.sun_family = AF_UNIX;
    1164         717 :     memcpy(sun.sun_path, vru_cl->vruc_path, sizeof(sun.sun_path) - 1);
    1165             : 
    1166         717 :     ret = connect(vru_cl->vruc_fd, (struct sockaddr *) &sun, sizeof(sun));
    1167         717 :     if (ret == -1) {
    1168             :         RTE_LOG_DP(DEBUG, UVHOST, "Error connecting uvhost socket FD %d to %s:"
    1169             :                 " %s (%d)\n", vru_cl->vruc_fd, sun.sun_path, rte_strerror(errno), errno);
    1170             :         /* Check the interface is connected or not.
    1171             :          * Avoiding race condition where tap interface already connected */
    1172         523 :         if(errno != EISCONN)
    1173         496 :             ret = vr_uvh_cl_timer_setup(vru_cl);
    1174             : 
    1175             :     } else {
    1176             : 
    1177         194 :         vr_uvhost_log("    connected to %s for uvhost socket FD %d\n",
    1178             :                   sun.sun_path, vru_cl->vruc_fd);
    1179             :         /*
    1180             :          * Remove the timer fd
    1181             :          */
    1182         194 :         vr_uvhost_del_fd(vru_cl->vruc_timer_fd, UVH_FD_READ);
    1183         194 :         vru_cl->vruc_timer_fd = -1;
    1184             : 
    1185             :         /*
    1186             :          * socket connected
    1187             :          * add to msg handler
    1188             :          */
    1189         194 :         ret = vr_uvhost_add_fd(vru_cl->vruc_fd, UVH_FD_READ, vru_cl,
    1190             :                                 vr_uvh_cl_msg_handler);
    1191         194 :         if (ret == -1) {
    1192           0 :             vr_uvhost_log("    error adding vif %u socket FD %d\n",
    1193             :                             vru_cl->vruc_idx, vru_cl->vruc_fd);
    1194             :         }
    1195             :         /* Send netlink interface up message to agent */
    1196         194 :         vr_uvh_nl_send_intf_state(1, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1197             :     }
    1198             : 
    1199         717 :     return ret;
    1200             : }
    1201             : 
    1202             : /*
    1203             :  * vr_uvh_cl_timer_setup - Setup timer to reconnect to the
    1204             :  * Qemu server.
    1205             :  *
    1206             :  * Returns 0 on success, -1 on error.
    1207             :  *
    1208             :  */
    1209             : static int
    1210         925 : vr_uvh_cl_timer_setup(vr_uvh_client_t *vru_cl)
    1211             : {
    1212         925 :     int ret = 0;
    1213             :     struct itimerspec cl_timer;
    1214             : 
    1215         925 :     cl_timer.it_interval.tv_sec  = 0;
    1216         925 :     cl_timer.it_interval.tv_nsec = 0;
    1217         925 :     cl_timer.it_value.tv_sec  = 5;
    1218         925 :     cl_timer.it_value.tv_nsec = 0;
    1219             : 
    1220         925 :     if (vru_cl->vruc_fd == -1) {
    1221         194 :         vru_cl->vruc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    1222         194 :         if (vru_cl->vruc_fd == -1) {
    1223           0 :             vr_uvhost_log("    error creating vif %u socket: %s (%d)\n",
    1224           0 :                             vru_cl->vruc_idx, rte_strerror(errno), errno);
    1225           0 :             ret = -1;
    1226           0 :             goto error;
    1227             :         }
    1228             :     }
    1229             : 
    1230         925 :     if (vru_cl->vruc_timer_fd == -1)
    1231         429 :         vru_cl->vruc_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    1232             : 
    1233         925 :     if (vru_cl->vruc_timer_fd == -1) {
    1234           0 :         vr_uvhost_log("    timer create failed for uvhost socket FD %d:"
    1235           0 :                 " %s (%d)\n", vru_cl->vruc_fd, rte_strerror(errno), errno);
    1236           0 :         ret = -1;
    1237             :     } else {
    1238         925 :         ret = timerfd_settime(vru_cl->vruc_timer_fd, 0, &cl_timer, NULL);
    1239         925 :         if (ret == -1) {
    1240           0 :             vr_uvhost_log("    timer setup failed for uvhost socket FD %d:"
    1241           0 :                 " %s (%d)\n", vru_cl->vruc_fd, rte_strerror(errno), errno);
    1242           0 :             close(vru_cl->vruc_timer_fd);
    1243           0 :             vru_cl->vruc_timer_fd = -1;
    1244             :         } else {
    1245         925 :             if (vr_uvhost_add_fd(vru_cl->vruc_timer_fd, UVH_FD_READ, vru_cl,
    1246             :                         vr_uvh_cl_timer_handler)) {
    1247           0 :                 ret = -1;
    1248           0 :                 vr_uvhost_log("    error adding timer FD %d read handler\n",
    1249             :                       vru_cl->vruc_timer_fd);
    1250           0 :                 close(vru_cl->vruc_timer_fd);
    1251           0 :                 vru_cl->vruc_timer_fd = -1;
    1252             :             }
    1253             :         }
    1254             :     }
    1255             : 
    1256         925 : error:
    1257         925 :     return ret;
    1258             : }
    1259             : 
    1260             : /*
    1261             :  * vr_uvh_nl_vif_del_handler - handle a message from the netlink thread
    1262             :  * to delete a vif.
    1263             :  *
    1264             :  * Returns 0 on success, -1 otherwise.
    1265             :  */
    1266             : int
    1267         166 : vr_uvh_nl_vif_del_handler(vrnu_vif_del_t *msg)
    1268             : {
    1269         166 :     unsigned int cidx = msg->vrnu_vif_idx;
    1270             :     vr_uvh_client_t *vru_cl;
    1271             : 
    1272         166 :     vr_uvhost_log("Deleting vif %d virtual device\n", cidx);
    1273             : 
    1274         166 :     if (cidx >= VR_UVH_MAX_CLIENTS) {
    1275           0 :         vr_uvhost_log("    error deleting vif %u: invalid vif index\n", cidx);
    1276           0 :         return -1;
    1277             :     }
    1278             : 
    1279         166 :     vr_dpdk_virtio_set_vif_client(cidx, NULL);
    1280             : 
    1281         166 :     vru_cl = vr_uvhost_get_client(cidx);
    1282         166 :     if (vru_cl == NULL) {
    1283           0 :         vr_uvhost_log("    error deleting vif %d: no client found\n",
    1284             :                       cidx);
    1285           0 :         return -1;
    1286             :     }
    1287             :     /* Unmmap guest memory. */
    1288         166 :     uvhm_client_munmap(vru_cl);
    1289         166 :     vr_uvhost_del_client(vru_cl);
    1290             : 
    1291         166 :     return 0;
    1292             : }
    1293             : 
    1294             : 
    1295             : /*
    1296             :  * vr_uvh_nl_vif_add_handler - handle a vif add message from the netlink
    1297             :  * thread. In response, the vhost server thread starts listening on the
    1298             :  * UNIX domain socket corresponding to this vif.
    1299             :  *
    1300             :  * Returns 0 on success, -1 otherwise.
    1301             :  */
    1302             : static int
    1303         332 : vr_uvh_nl_vif_add_handler(vrnu_vif_add_t *msg)
    1304             : {
    1305         332 :     int s = 0, ret = -1, err, sock_connected = 0;
    1306             :     struct sockaddr_un sun;
    1307             :     int flags;
    1308         332 :     vr_uvh_client_t *vru_cl = NULL;
    1309             :     mode_t umask_mode;
    1310             : 
    1311         332 :     if (msg == NULL) {
    1312           0 :         vr_uvhost_log("    error adding vif %u: message is NULL\n",
    1313             :                         msg->vrnu_vif_idx);
    1314           0 :         return -1;
    1315             :     }
    1316             : 
    1317         332 :     vr_uvhost_log("Adding vif %d virtual device %s\n", msg->vrnu_vif_idx,
    1318         332 :                         msg->vrnu_vif_name);
    1319         332 :     s = socket(AF_UNIX, SOCK_STREAM, 0);
    1320         332 :     if (s == -1) {
    1321           0 :         vr_uvhost_log("    error creating vif %u socket: %s (%d)\n",
    1322           0 :                         msg->vrnu_vif_idx, rte_strerror(errno), errno);
    1323           0 :         goto error;
    1324             :     }
    1325             : 
    1326             :     /* FIXME: workaround for agent issue #1796091
    1327             :      * Agent sends vhostuser mode as client eventhough
    1328             :      * its hardcoded in the api-server as server and
    1329             :      * the port configuration from neutron shows as server.
    1330             :      * Hardcode it to server mode as we dont use client
    1331             :      * mode in > 5.x, until agent code is fixed.
    1332             :      */
    1333         332 :     if (msg->vrnu_vif_vhostuser_mode == VRNU_VIF_MODE_CLIENT)
    1334         332 :         msg->vrnu_vif_vhostuser_mode = VRNU_VIF_MODE_SERVER;
    1335             : 
    1336         332 :     if (msg->vrnu_vif_vhostuser_mode == VRNU_VIF_MODE_CLIENT)
    1337           0 :         vr_uvhost_log("    vif (client) %u socket %s FD is %d\n",
    1338           0 :                             msg->vrnu_vif_idx, msg->vrnu_vif_name, s);
    1339             :     else
    1340         332 :         vr_uvhost_log("    vif (server) %u socket %s FD is %d\n",
    1341         332 :                             msg->vrnu_vif_idx, msg->vrnu_vif_name, s);
    1342             : 
    1343         332 :     memset(&sun, 0, sizeof(sun));
    1344         332 :     sun.sun_family = AF_UNIX;
    1345         332 :     strncpy(sun.sun_path, vr_socket_dir, sizeof(sun.sun_path) - 1);
    1346         332 :     strncat(sun.sun_path, "/"VR_UVH_VIF_PFX, sizeof(sun.sun_path)
    1347         332 :         - strlen(sun.sun_path) - 1);
    1348         332 :     strncat(sun.sun_path, msg->vrnu_vif_name,
    1349         332 :         sizeof(sun.sun_path) - strlen(sun.sun_path) - 1);
    1350             : 
    1351         332 :     mkdir(vr_socket_dir, VR_DEF_SOCKET_DIR_MODE);
    1352             :     /* qemu in server mode needs rw access */
    1353         332 :     chmod(vr_socket_dir, 0777);
    1354             : 
    1355             :     /*
    1356             :      * Client mode Qemu
    1357             :      * vrouter-dpdk listens on the socket path
    1358             :      */
    1359         332 :     if (msg->vrnu_vif_vhostuser_mode == VRNU_VIF_MODE_CLIENT) {
    1360             : 
    1361           0 :         unlink(sun.sun_path);
    1362             : 
    1363             :         /*
    1364             :          * Ensure RW permissions for the socket files such that QEMU process is
    1365             :          * able to connect.
    1366             :          */
    1367           0 :         umask_mode = umask(~(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
    1368             :                 S_IWOTH));
    1369             : 
    1370           0 :         ret = bind(s, (struct sockaddr *) &sun, sizeof(sun));
    1371           0 :         if (ret == -1) {
    1372           0 :             vr_uvhost_log("    error binding vif %u FD %d to %s: %s (%d)\n",
    1373           0 :                 msg->vrnu_vif_idx, s, sun.sun_path, rte_strerror(errno), errno);
    1374           0 :             goto error;
    1375             :         }
    1376             : 
    1377           0 :         umask(umask_mode);
    1378             : 
    1379             :         /*
    1380             :          * Set the socket to non-blocking
    1381             :          */
    1382           0 :         flags = fcntl(s, F_GETFL, 0);
    1383           0 :         fcntl(s, flags | O_NONBLOCK);
    1384             : 
    1385           0 :         ret = listen(s, 1);
    1386           0 :         if (ret == -1) {
    1387           0 :             vr_uvhost_log("    error listening vif %u socket FD %d: %s (%d)\n",
    1388           0 :                             msg->vrnu_vif_idx, s, rte_strerror(errno), errno);
    1389           0 :             goto error;
    1390             :         }
    1391             : 
    1392             :     } else {
    1393             :         /*
    1394             :          * Server mode Qemu
    1395             :          * Connect to the socket
    1396             :          */
    1397         332 :         ret = connect(s, (struct sockaddr *) &sun, sizeof(sun));
    1398         332 :         if (ret == -1) {
    1399         332 :             vr_uvhost_log("    error connecting uvhost socket FD %d to %s:"
    1400         332 :                 " %s (%d)\n", s, sun.sun_path, rte_strerror(errno), errno);
    1401             :         } else {
    1402           0 :             vr_uvhost_log("connected to sock    vif %u socket %s FD is %d\n",
    1403           0 :                             msg->vrnu_vif_idx, msg->vrnu_vif_name, s);
    1404           0 :             sock_connected = 1;
    1405             :         }
    1406             :     }
    1407             : 
    1408         332 :     vru_cl = vr_uvhost_new_client(s, sun.sun_path, msg->vrnu_vif_idx);
    1409         332 :     if (vru_cl == NULL) {
    1410          97 :         vr_uvhost_log("    error creating vif %u socket %s new vhost client\n",
    1411             :                       msg->vrnu_vif_idx, sun.sun_path);
    1412          97 :         goto error;
    1413             :     }
    1414             : 
    1415         235 :     vru_cl->vruc_idx = msg->vrnu_vif_idx;
    1416         235 :     vru_cl->vruc_nrxqs = msg->vrnu_vif_nrxqs;
    1417         235 :     vru_cl->vruc_ntxqs = msg->vrnu_vif_ntxqs;
    1418         235 :     vru_cl->vruc_vif_gen = msg->vrnu_vif_gen;
    1419         235 :     vru_cl->vruc_vhostuser_mode = msg->vrnu_vif_vhostuser_mode;
    1420         235 :     vru_cl->vruc_timer_fd = -1;
    1421             : 
    1422         235 :     if (msg->vrnu_vif_vhostuser_mode == VRNU_VIF_MODE_CLIENT) {
    1423             :         /* Send netlink interface down message to agent */
    1424           0 :         vr_uvh_nl_send_intf_state(0, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1425             : 
    1426             :         /*
    1427             :          * Client mode Qemu
    1428             :          * add to listen handler
    1429             :          */
    1430           0 :         ret = vr_uvhost_add_fd(s, UVH_FD_READ, vru_cl, vr_uvh_cl_listen_handler);
    1431           0 :         if (ret == -1) {
    1432           0 :             vr_uvhost_log("    error adding vif %u socket FD %d\n",
    1433             :                             msg->vrnu_vif_idx, s);
    1434           0 :             goto error;
    1435             :         }
    1436             :     } else {
    1437         235 :         if (sock_connected) {
    1438             :             /*
    1439             :              * Server mode Qemu
    1440             :              * add to client handler
    1441             :              */
    1442           0 :             vr_uvhost_log("adding to msg handler    vif %u socket %s FD is %d\n",
    1443           0 :                                 msg->vrnu_vif_idx, msg->vrnu_vif_name, s);
    1444           0 :             if (vr_uvhost_add_fd(s, UVH_FD_READ, vru_cl, vr_uvh_cl_msg_handler)) {
    1445           0 :                 vr_uvhost_log("    error adding client %s FD %d read handler\n",
    1446             :                               sun.sun_path, s);
    1447           0 :                 goto error;
    1448             :             }
    1449             :             /* Send netlink interface up message to agent */
    1450           0 :             vr_uvh_nl_send_intf_state(1, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1451             :         } else {
    1452             :             /* Send netlink interface down message to agent */
    1453         235 :             vr_uvh_nl_send_intf_state(0, vru_cl->vruc_idx, basename(vru_cl->vruc_path));
    1454         235 :             if (vr_uvh_cl_timer_setup(vru_cl)) {
    1455           0 :                 vr_uvhost_log("    error adding vif %u socket %s to timer\n",
    1456             :                             msg->vrnu_vif_idx, sun.sun_path);
    1457           0 :                 goto error;
    1458             :             }
    1459             :         }
    1460             :     }
    1461             : 
    1462         235 :     vr_dpdk_virtio_set_vif_client(msg->vrnu_vif_idx, vru_cl);
    1463             : 
    1464         235 :     return 0;
    1465             : 
    1466          97 : error:
    1467             : 
    1468          97 :     err = errno;
    1469          97 :     if (s) {
    1470          97 :         close(s);
    1471             :     }
    1472             : 
    1473          97 :     if (vru_cl) {
    1474           0 :         vr_uvhost_del_client(vru_cl);
    1475             :     }
    1476          97 :     errno = err;
    1477             : 
    1478          97 :     return ret;
    1479             : }
    1480             : 
    1481             : 
    1482             : /*
    1483             :  * vr_uvh_nl_msg_handler - handles messages received form the netlink
    1484             :  * thread. This is usually to convey the name of the UNIX domain socket
    1485             :  * that the user space vhost server should listen on for connections from
    1486             :  * qemu.
    1487             :  *
    1488             :  * Returns 0, but logs a message if an error occurs. Returning error would
    1489             :  * result in connection to netlink being removed from poll().
    1490             :  */
    1491             : static int
    1492         498 : vr_uvh_nl_msg_handler(int fd, void *arg)
    1493             : {
    1494             :     vrnu_msg_t msg;
    1495             :     int ret;
    1496             : 
    1497         498 :     ret = recv(fd, (void *) &msg, sizeof(msg), MSG_DONTWAIT);
    1498         498 :     if (ret < 0) {
    1499           0 :         if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
    1500           0 :             vr_uvhost_log("Error %d in netlink msg receive in vhost server\n",
    1501           0 :                           errno);
    1502           0 :             return 0;
    1503             :         } else {
    1504           0 :             return 0;
    1505             :         }
    1506             :     }
    1507             : 
    1508         498 :     if (ret != sizeof(msg)) {
    1509           0 :         vr_uvhost_log("Received msg of length %d, expected %zu in vhost server",
    1510             :                       ret, sizeof(msg));
    1511           0 :         return 0;
    1512             :     }
    1513             : 
    1514         498 :     switch (msg.vrnum_type) {
    1515         332 :         case VRNU_MSG_VIF_ADD:
    1516         332 :             ret = vr_uvh_nl_vif_add_handler(&msg.vrnum_vif_add);
    1517         332 :             break;
    1518             : 
    1519         166 :         case VRNU_MSG_VIF_DEL:
    1520         166 :             ret = vr_uvh_nl_vif_del_handler(&msg.vrnum_vif_del);
    1521         166 :             break;
    1522             : 
    1523           0 :         default:
    1524           0 :             vr_uvhost_log("Unknown netlink msg %d received in vhost server\n",
    1525           0 :                           msg.vrnum_type);
    1526           0 :             ret = -1;
    1527           0 :             break;
    1528             :     }
    1529             : 
    1530         498 :     return 0;
    1531             : }
    1532             : 
    1533             : /*
    1534             :  * vr_uvh_nl_listen_handler - handles conenctions from the netlink
    1535             :  * thread.
    1536             :  *
    1537             :  * Returns 0 on success, -1 otherwise.
    1538             :  */
    1539             : int
    1540          53 : vr_uvh_nl_listen_handler(int fd, void *arg)
    1541             : {
    1542             :     int s;
    1543             :     struct sockaddr_un sun;
    1544          53 :     socklen_t len = sizeof(sun);
    1545             : 
    1546          53 :     vr_uvhost_log("Handling connection FD %d...\n", fd);
    1547          53 :     s = accept(fd, (struct sockaddr *) &sun, &len);
    1548          53 :     if (s < 0) {
    1549           0 :         vr_uvhost_log("    error accepting NetLink connection FD %d\n", fd);
    1550           0 :         return -1;
    1551             :     }
    1552          53 :     vr_uvhost_log("    FD %d accepted new NetLink connection FD %d\n", fd, s);
    1553             : 
    1554          53 :     if (vr_uvhost_add_fd(s, UVH_FD_READ, NULL, vr_uvh_nl_msg_handler)) {
    1555           0 :         vr_uvhost_log("    error adding socket %s FD %d read handler\n",
    1556             :                       sun.sun_path, fd);
    1557           0 :         return -1;
    1558             :     }
    1559             : 
    1560          53 :     return 0;
    1561             : }

Generated by: LCOV version 1.14