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 : ®ion->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 : }
|