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