1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <glob.h> 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <limits.h> 9 #include <fcntl.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <poll.h> 13 14 15 #include <rte_log.h> 16 #include <rte_power_guest_channel.h> 17 18 #include "guest_channel.h" 19 20 RTE_LOG_REGISTER_SUFFIX(guest_channel_logtype, guest_channel, INFO); 21 #define RTE_LOGTYPE_GUEST_CHANNEL guest_channel_logtype 22 #define GUEST_CHANNEL_LOG(level, ...) \ 23 RTE_LOG_LINE(level, GUEST_CHANNEL, "" __VA_ARGS__) 24 25 /* Timeout for incoming message in milliseconds. */ 26 #define TIMEOUT 10 27 28 static int global_fds[RTE_MAX_LCORE] = { [0 ... RTE_MAX_LCORE-1] = -1 }; 29 30 int 31 guest_channel_host_check_exists(const char *path) 32 { 33 char glob_path[PATH_MAX]; 34 glob_t g; 35 int ret; 36 37 /* we cannot know in advance which cores have VM channels, so glob */ 38 snprintf(glob_path, PATH_MAX, "%s.*", path); 39 40 ret = glob(glob_path, GLOB_NOSORT, NULL, &g); 41 if (ret != 0) { 42 /* couldn't read anything */ 43 ret = 0; 44 goto out; 45 } 46 47 /* do we have at least one match? */ 48 ret = g.gl_pathc > 0; 49 50 out: 51 globfree(&g); 52 return ret; 53 } 54 55 int 56 guest_channel_host_connect(const char *path, unsigned int lcore_id) 57 { 58 int flags, ret; 59 struct rte_power_channel_packet pkt; 60 char fd_path[PATH_MAX]; 61 int fd = -1; 62 63 if (lcore_id >= RTE_MAX_LCORE) { 64 GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d", 65 lcore_id, RTE_MAX_LCORE-1); 66 return -1; 67 } 68 /* check if path is already open */ 69 if (global_fds[lcore_id] != -1) { 70 GUEST_CHANNEL_LOG(ERR, "Channel(%u) is already open with fd %d", 71 lcore_id, global_fds[lcore_id]); 72 return -1; 73 } 74 75 snprintf(fd_path, PATH_MAX, "%s.%u", path, lcore_id); 76 GUEST_CHANNEL_LOG(INFO, "Opening channel '%s' for lcore %u", 77 fd_path, lcore_id); 78 fd = open(fd_path, O_RDWR); 79 if (fd < 0) { 80 GUEST_CHANNEL_LOG(ERR, "Unable to connect to '%s' with error " 81 "%s", fd_path, strerror(errno)); 82 return -1; 83 } 84 85 flags = fcntl(fd, F_GETFL, 0); 86 if (flags < 0) { 87 GUEST_CHANNEL_LOG(ERR, "Failed on fcntl get flags for file %s", 88 fd_path); 89 goto error; 90 } 91 92 flags |= O_NONBLOCK; 93 if (fcntl(fd, F_SETFL, flags) < 0) { 94 GUEST_CHANNEL_LOG(ERR, "Failed on setting non-blocking mode for " 95 "file %s", fd_path); 96 goto error; 97 } 98 /* QEMU needs a delay after connection */ 99 sleep(1); 100 101 /* Send a test packet, this command is ignored by the host, but a successful 102 * send indicates that the host endpoint is monitoring. 103 */ 104 pkt.command = RTE_POWER_CPU_POWER_CONNECT; 105 global_fds[lcore_id] = fd; 106 ret = guest_channel_send_msg(&pkt, lcore_id); 107 if (ret != 0) { 108 GUEST_CHANNEL_LOG(ERR, 109 "Error on channel '%s' communications test: %s", 110 fd_path, ret > 0 ? strerror(ret) : 111 "channel not connected"); 112 goto error; 113 } 114 GUEST_CHANNEL_LOG(INFO, "Channel '%s' is now connected", fd_path); 115 return 0; 116 error: 117 close(fd); 118 global_fds[lcore_id] = -1; 119 return -1; 120 } 121 122 int 123 guest_channel_send_msg(struct rte_power_channel_packet *pkt, 124 unsigned int lcore_id) 125 { 126 int ret, buffer_len = sizeof(*pkt); 127 void *buffer = pkt; 128 129 if (lcore_id >= RTE_MAX_LCORE) { 130 GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d", 131 lcore_id, RTE_MAX_LCORE-1); 132 return -1; 133 } 134 135 if (global_fds[lcore_id] < 0) { 136 GUEST_CHANNEL_LOG(ERR, "Channel is not connected"); 137 return -1; 138 } 139 while (buffer_len > 0) { 140 ret = write(global_fds[lcore_id], buffer, buffer_len); 141 if (ret == buffer_len) 142 return 0; 143 if (ret == -1) { 144 if (errno == EINTR) 145 continue; 146 return errno; 147 } 148 buffer = (char *)buffer + ret; 149 buffer_len -= ret; 150 } 151 return 0; 152 } 153 154 int rte_power_guest_channel_send_msg(struct rte_power_channel_packet *pkt, 155 unsigned int lcore_id) 156 { 157 return guest_channel_send_msg(pkt, lcore_id); 158 } 159 160 int power_guest_channel_read_msg(void *pkt, 161 size_t pkt_len, 162 unsigned int lcore_id) 163 { 164 int ret; 165 struct pollfd fds; 166 167 if (pkt_len == 0 || pkt == NULL) 168 return -1; 169 170 if (lcore_id >= RTE_MAX_LCORE) { 171 GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d", 172 lcore_id, RTE_MAX_LCORE-1); 173 return -1; 174 } 175 176 if (global_fds[lcore_id] < 0) { 177 GUEST_CHANNEL_LOG(ERR, "Channel is not connected"); 178 return -1; 179 } 180 181 fds.fd = global_fds[lcore_id]; 182 fds.events = POLLIN; 183 184 ret = poll(&fds, 1, TIMEOUT); 185 if (ret == 0) { 186 GUEST_CHANNEL_LOG(DEBUG, "Timeout occurred during poll function."); 187 return -1; 188 } else if (ret < 0) { 189 GUEST_CHANNEL_LOG(ERR, "Error occurred during poll function: %s", 190 strerror(errno)); 191 return -1; 192 } 193 194 while (pkt_len > 0) { 195 ret = read(global_fds[lcore_id], 196 pkt, pkt_len); 197 198 if (ret < 0) { 199 if (errno == EINTR) 200 continue; 201 return -1; 202 } 203 204 if (ret == 0) { 205 GUEST_CHANNEL_LOG(ERR, "Expected more data, but connection has been closed."); 206 return -1; 207 } 208 pkt = (char *)pkt + ret; 209 pkt_len -= ret; 210 } 211 212 return 0; 213 } 214 215 int rte_power_guest_channel_receive_msg(void *pkt, 216 size_t pkt_len, 217 unsigned int lcore_id) 218 { 219 return power_guest_channel_read_msg(pkt, pkt_len, lcore_id); 220 } 221 222 void 223 guest_channel_host_disconnect(unsigned int lcore_id) 224 { 225 if (lcore_id >= RTE_MAX_LCORE) { 226 GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d", 227 lcore_id, RTE_MAX_LCORE-1); 228 return; 229 } 230 if (global_fds[lcore_id] < 0) 231 return; 232 close(global_fds[lcore_id]); 233 global_fds[lcore_id] = -1; 234 } 235