1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library.  If not, see
14  * <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include <config.h>
19 
20 #ifdef WITH_SYS_IOCTL_H
21 # include <sys/ioctl.h>
22 #endif
23 
24 #if WITH_DECL_VHOST_VSOCK_SET_GUEST_CID
25 # include <linux/vhost.h>
26 #endif
27 
28 #include "virvsock.h"
29 
30 #include "virerror.h"
31 #include "virlog.h"
32 
33 
34 #define VIR_FROM_THIS VIR_FROM_NONE
35 
36 VIR_LOG_INIT("util.vsock");
37 
38 #if WITH_DECL_VHOST_VSOCK_SET_GUEST_CID
39 static int
virVsockSetGuestCidQuiet(int fd,unsigned int guest_cid)40 virVsockSetGuestCidQuiet(int fd,
41                          unsigned int guest_cid)
42 {
43     uint64_t val = guest_cid;
44 
45     return ioctl(fd, VHOST_VSOCK_SET_GUEST_CID, &val);
46 }
47 
48 #else
49 static int
virVsockSetGuestCidQuiet(int fd G_GNUC_UNUSED,unsigned int guest_cid G_GNUC_UNUSED)50 virVsockSetGuestCidQuiet(int fd G_GNUC_UNUSED,
51                          unsigned int guest_cid G_GNUC_UNUSED)
52 {
53     errno = ENOSYS;
54     return -1;
55 }
56 #endif
57 
58 
59 /**
60  * virVsockSetGuestCid:
61  * @fd: file descriptor of a vsock interface
62  * @guest_cid: guest CID to be set
63  *
64  * Wrapper for VHOST_VSOCK_SET_GUEST_CID ioctl.
65  * Returns: 0 on success, -1 on error.
66  */
67 int
virVsockSetGuestCid(int fd,unsigned int guest_cid)68 virVsockSetGuestCid(int fd,
69                     unsigned int guest_cid)
70 {
71     if (virVsockSetGuestCidQuiet(fd, guest_cid) < 0) {
72         virReportSystemError(errno, "%s",
73                              _("failed to set guest cid"));
74         return -1;
75     }
76 
77     return 0;
78 }
79 
80 #define VIR_VSOCK_GUEST_CID_MIN 3
81 
82 /**
83  * virVsockAcquireGuestCid:
84  * @fd: file descriptor of a vsock interface
85  * @guest_cid: where to store the guest CID
86  *
87  * Iterates over usable CIDs until a free one is found.
88  * Returns: 0 on success, with the acquired CID stored in guest_cid
89  *         -1 on error.
90  */
91 int
virVsockAcquireGuestCid(int fd,unsigned int * guest_cid)92 virVsockAcquireGuestCid(int fd,
93                         unsigned int *guest_cid)
94 {
95     unsigned int cid = VIR_VSOCK_GUEST_CID_MIN;
96 
97     for (; virVsockSetGuestCidQuiet(fd, cid) < 0; cid++) {
98         if (errno != EADDRINUSE) {
99             virReportSystemError(errno, "%s",
100                                  _("failed to acquire guest cid"));
101             return -1;
102         }
103     }
104     *guest_cid = cid;
105 
106     return 0;
107 }
108