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

Generated by: LCOV version 1.14