Line data Source code
1 : /*
2 : * vr_uvhost_util.c - utils for user-space vhost server that peers with
3 : * the vhost client inside qemu (version 2.1 and later).
4 : *
5 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
6 : * Copyright Contributors to the OpenSDN project
7 : */
8 :
9 : #include "vr_dpdk.h"
10 : #include "vr_uvhost_util.h"
11 :
12 : typedef struct uvh_fd_s {
13 : int uvh_fd;
14 : void *uvh_fd_arg;
15 : uvh_fd_handler_t uvh_fd_fn;
16 : } uvh_fd_t;
17 :
18 : /* Global variables */
19 : static uvh_fd_t uvh_rfds[MAX_UVHOST_FDS];
20 : static uvh_fd_t uvh_wfds[MAX_UVHOST_FDS];
21 :
22 : /*
23 : * vr_uvhost_log - logs user space vhost messages to a file.
24 : */
25 : void
26 8452 : vr_uvhost_log(const char *format, ...)
27 : {
28 : va_list args;
29 :
30 8452 : if (RTE_LOGTYPE_UVHOST & rte_logs.type) {
31 8452 : char buf[VR_DPDK_STR_BUF_SZ] = "UVHOST: ";
32 :
33 8452 : strncat(buf, format, sizeof(buf) - strlen(buf) - 1);
34 8452 : buf[sizeof(buf) - 1] = '\0';
35 :
36 8452 : va_start(args, format);
37 8452 : rte_vlog(RTE_LOG_INFO, RTE_LOGTYPE_UVHOST, buf, args);
38 8452 : va_end(args);
39 : }
40 8452 : }
41 :
42 : /*
43 : * vr_uvhost_del_fd - deletes a FD from the read/write list that the
44 : * user space vhost server is listening on. fd_type indicates if it
45 : * is a read/write socket. The FD passed in will be closed.
46 : *
47 : * Returns 0 on success, -1 otherwise.
48 : */
49 : int
50 596 : vr_uvhost_del_fd(int fd, uvh_fd_type_t fd_type)
51 : {
52 : int i;
53 : uvh_fd_t *fds;
54 :
55 : RTE_LOG_DP(DEBUG, UVHOST, "Deleting FD %d...\n", fd);
56 596 : if (fd_type == UVH_FD_READ) {
57 596 : fds = uvh_rfds;
58 0 : } else if (fd_type == UVH_FD_WRITE) {
59 0 : fds = uvh_wfds;
60 : } else {
61 0 : return -1;
62 : }
63 :
64 3578 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
65 3578 : if (fds[i].uvh_fd == fd) {
66 596 : break;
67 : }
68 : }
69 :
70 596 : if (i == MAX_UVHOST_FDS) {
71 : /* The descriptor could be deleted on read error, so no need to
72 : * print the error message.
73 : */
74 0 : return -1;
75 : }
76 :
77 596 : fds[i].uvh_fd = -1;
78 596 : fds[i].uvh_fd_arg = NULL;
79 :
80 596 : close(fd);
81 :
82 596 : return 0;
83 : }
84 :
85 : /*
86 : * vr_uvhost_del_fds_by_arg - deletes all FDs from the read/write lists matching
87 : * the given argument (pointer to a client). All the FDs found will be closed.
88 : *
89 : * Returns 0 on success, -1 otherwise.
90 : */
91 : int
92 166 : vr_uvhost_del_fds_by_arg(void *arg)
93 : {
94 : int i;
95 :
96 723096 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
97 722930 : if (uvh_rfds[i].uvh_fd > 0 && uvh_rfds[i].uvh_fd_arg == arg)
98 181 : vr_uvhost_del_fd(uvh_rfds[i].uvh_fd, UVH_FD_READ);
99 722930 : if (uvh_wfds[i].uvh_fd > 0 && uvh_wfds[i].uvh_fd_arg == arg)
100 0 : vr_uvhost_del_fd(uvh_wfds[i].uvh_fd, UVH_FD_WRITE);
101 : }
102 :
103 166 : return 0;
104 : }
105 :
106 : /*
107 : * vr_uvhost_add_fd - adds the specified FD into the read/write list that
108 : * the user space vhost server is waiting on. The type indicates if it
109 : * is a read/write socket and the handler is the function that is called when
110 : * there is an event on the socket.
111 : *
112 : * Returns 0 on success, -1 otherwise.
113 : */
114 : int
115 1278 : vr_uvhost_add_fd(int fd, uvh_fd_type_t fd_type, void *fd_handler_arg,
116 : uvh_fd_handler_t fd_handler)
117 : {
118 : int i;
119 : uvh_fd_t *fds;
120 :
121 : RTE_LOG_DP(DEBUG, UVHOST, "Adding FD %d...\n", fd);
122 1278 : if (fd_type == UVH_FD_READ) {
123 1278 : fds = uvh_rfds;
124 0 : } else if (fd_type == UVH_FD_WRITE) {
125 0 : fds = uvh_wfds;
126 : } else {
127 0 : return -1;
128 : }
129 :
130 6932 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
131 6932 : if (fds[i].uvh_fd == fd || fds[i].uvh_fd == -1) {
132 1278 : fds[i].uvh_fd = fd;
133 1278 : fds[i].uvh_fd_arg = fd_handler_arg;
134 1278 : fds[i].uvh_fd_fn = fd_handler;
135 :
136 1278 : return 0;
137 : }
138 : }
139 :
140 0 : vr_uvhost_log("Error adding FD %d: no room for a new FD\n", fd);
141 :
142 0 : return -1;
143 : }
144 :
145 : /*
146 : * vr_uvhost_fds_init - initializes the read and write fds before
147 : * we enter the poll loop.
148 : */
149 : void
150 53 : vr_uvhost_fds_init(void)
151 : {
152 : int i;
153 :
154 230868 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
155 230815 : uvh_rfds[i].uvh_fd = -1;
156 230815 : uvh_wfds[i].uvh_fd = -1;
157 : }
158 :
159 53 : return;
160 : }
161 :
162 : /*
163 : * vr_uvh_call_fd_handlers_internal - call the handler associated with the
164 : * given fd.
165 : *
166 : * Returns 0 on success, -1 otherwise.
167 : */
168 : static int
169 3984 : vr_uvh_call_fd_handlers_internal(uvh_fd_t *fd_arr, int fd)
170 : {
171 3984 : int i, ret = 0;
172 :
173 21257 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
174 21257 : if (fd_arr[i].uvh_fd != fd) {
175 17273 : continue;
176 : }
177 :
178 3984 : ret = fd_arr[i].uvh_fd_fn(fd_arr[i].uvh_fd, fd_arr[i].uvh_fd_arg);
179 3984 : if (ret) {
180 221 : return -1;
181 : } else {
182 3763 : return 0;
183 : }
184 : }
185 :
186 0 : return -1;
187 : }
188 :
189 : /*
190 : * vr_uvh_call_fd_handlers - call the handler for each FD that is set upon
191 : * return from poll().
192 : *
193 : * Returns nothing.
194 : */
195 : void
196 3871 : vr_uvh_call_fd_handlers(struct pollfd *fds, nfds_t nfds)
197 : {
198 : unsigned int i;
199 : int ret;
200 :
201 30922 : for (i = 0; i < nfds; i++) {
202 27051 : if (fds[i].fd >= 0) {
203 27051 : if (fds[i].revents & POLLIN) {
204 3984 : ret = vr_uvh_call_fd_handlers_internal(uvh_rfds, fds[i].fd);
205 3984 : if (ret) {
206 221 : vr_uvhost_del_fd(fds[i].fd, UVH_FD_READ);
207 : }
208 : }
209 : }
210 : }
211 :
212 3871 : return;
213 : }
214 :
215 : /*
216 : * vr_uvh_init_pollfds - initializes the array to pass to poll based on the
217 : * state of the fds.
218 : *
219 : * Returns nothing.
220 : */
221 : void
222 3924 : vr_uvh_init_pollfds(struct pollfd *fds, nfds_t *nfds)
223 : {
224 3924 : unsigned int i, count = 0;
225 :
226 17092944 : for (i = 0; i < MAX_UVHOST_FDS; i++) {
227 17089020 : if (uvh_rfds[i].uvh_fd != -1) {
228 27289 : fds[count].fd = uvh_rfds[i].uvh_fd;
229 27289 : fds[count].events = POLLIN;
230 27289 : count++;
231 : }
232 : }
233 :
234 3924 : *nfds = count;
235 :
236 3924 : return;
237 : }
|