1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #ifndef RTE_EXEC_ENV_WINDOWS 6 #include <unistd.h> 7 #include <sys/socket.h> 8 #include <sys/un.h> 9 #include <pthread.h> 10 #endif /* !RTE_EXEC_ENV_WINDOWS */ 11 12 /* we won't link against libbsd, so just always use DPDKs-specific strlcpy */ 13 #undef RTE_USE_LIBBSD 14 #include <rte_string_fns.h> 15 #include <rte_common.h> 16 #include <rte_spinlock.h> 17 18 #include "telemetry_internal.h" 19 20 #define MAX_LEN 128 21 #define BUF_SIZE 1024 22 #define CLIENTS_UNREG_ACTION "\"action\":2" 23 #define CLIENTS_CMD "\"command\":\"clients\"" 24 #define CLIENTS_DATA "\"data\":{\"client_path\":\"" 25 #define STATS_ACTION "\"action\":0" 26 #define DATA_REQ_LABEL "\"data\":" 27 #define TELEMETRY_LEGACY_MAX_CALLBACKS 4 28 29 30 static int 31 register_client(const char *cmd __rte_unused, 32 const char *params __rte_unused, 33 char *buffer, int buf_len); 34 35 struct json_command { 36 char action[MAX_LEN]; 37 char cmd[MAX_LEN]; 38 char data[MAX_LEN]; 39 telemetry_legacy_cb fn; 40 41 }; 42 43 struct json_command callbacks[TELEMETRY_LEGACY_MAX_CALLBACKS] = { 44 { 45 .action = "\"action\":1", 46 .cmd = CLIENTS_CMD, 47 .data = CLIENTS_DATA, 48 .fn = register_client 49 } 50 }; 51 int num_legacy_callbacks = 1; 52 static rte_spinlock_t callback_sl = RTE_SPINLOCK_INITIALIZER; 53 54 int 55 rte_telemetry_legacy_register(const char *cmd, 56 enum rte_telemetry_legacy_data_req data_req, 57 telemetry_legacy_cb fn) 58 { 59 if (fn == NULL) 60 return -EINVAL; 61 if (num_legacy_callbacks >= (int) RTE_DIM(callbacks)) 62 return -ENOENT; 63 64 rte_spinlock_lock(&callback_sl); 65 strlcpy(callbacks[num_legacy_callbacks].action, STATS_ACTION, MAX_LEN); 66 snprintf(callbacks[num_legacy_callbacks].cmd, MAX_LEN, 67 "\"command\":\"%s\"", cmd); 68 snprintf(callbacks[num_legacy_callbacks].data, MAX_LEN, 69 data_req ? "%s{\"" : "%snull", 70 DATA_REQ_LABEL); 71 callbacks[num_legacy_callbacks].fn = fn; 72 num_legacy_callbacks++; 73 rte_spinlock_unlock(&callback_sl); 74 75 return 0; 76 } 77 78 static int 79 register_client(const char *cmd __rte_unused, const char *params, 80 char *buffer __rte_unused, int buf_len __rte_unused) 81 { 82 #ifndef RTE_EXEC_ENV_WINDOWS 83 pthread_t th; 84 char data[BUF_SIZE]; 85 int fd; 86 int rc; 87 struct sockaddr_un addrs; 88 #endif /* !RTE_EXEC_ENV_WINDOWS */ 89 90 if (!strchr(params, ':')) { 91 fprintf(stderr, "Invalid data\n"); 92 return -1; 93 } 94 #ifndef RTE_EXEC_ENV_WINDOWS 95 strlcpy(data, strchr(params, ':'), sizeof(data)); 96 memcpy(data, &data[strlen(":\"")], strlen(data)); 97 if (!strchr(data, '\"')) { 98 fprintf(stderr, "Invalid client data\n"); 99 return -1; 100 } 101 *strchr(data, '\"') = 0; 102 103 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 104 if (fd < 0) { 105 perror("Failed to open socket"); 106 return -1; 107 } 108 addrs.sun_family = AF_UNIX; 109 strlcpy(addrs.sun_path, data, sizeof(addrs.sun_path)); 110 111 if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) { 112 perror("\nClient connection error\n"); 113 close(fd); 114 return -1; 115 } 116 rc = pthread_create(&th, NULL, &legacy_client_handler, 117 (void *)(uintptr_t)fd); 118 if (rc != 0) { 119 fprintf(stderr, "Failed to create legacy client thread: %s\n", 120 strerror(rc)); 121 close(fd); 122 return -1; 123 } 124 pthread_detach(th); 125 #endif /* !RTE_EXEC_ENV_WINDOWS */ 126 return 0; 127 } 128 129 #ifndef RTE_EXEC_ENV_WINDOWS 130 131 static int 132 send_error_response(int s, int err) 133 { 134 const char *desc; 135 char out_buf[100000]; 136 137 switch (err) { 138 case -ENOMEM: 139 desc = "Memory Allocation Error"; 140 break; 141 case -EINVAL: 142 desc = "Invalid Argument 404"; 143 break; 144 case -EPERM: 145 desc = "Unknown"; 146 break; 147 default: 148 /* Default case keeps behaviour of Telemetry library */ 149 printf("\nInvalid error type: %d\n", err); 150 return -EINVAL; 151 } 152 int used = snprintf(out_buf, sizeof(out_buf), "{\"status_code\": " 153 "\"Status Error: %s\", \"data\": null}", desc); 154 if (write(s, out_buf, used) < 0) { 155 perror("Error writing to socket"); 156 return -1; 157 } 158 return 0; 159 } 160 161 static void 162 perform_command(telemetry_legacy_cb fn, const char *param, int s) 163 { 164 char out_buf[100000]; 165 int ret, used = 0; 166 167 ret = fn("", param, out_buf, sizeof(out_buf)); 168 if (ret < 0) { 169 ret = send_error_response(s, ret); 170 if (ret < 0) 171 printf("\nCould not send error response\n"); 172 return; 173 } 174 used += ret; 175 if (write(s, out_buf, used) < 0) 176 perror("Error writing to socket"); 177 } 178 179 static int 180 parse_client_request(char *buffer, int buf_len, int s) 181 { 182 int i; 183 char *data = buffer + buf_len; 184 telemetry_legacy_cb fn = NULL; 185 const char *valid_sep = ",}"; 186 if (buffer[0] != '{' || buffer[buf_len - 1] != '}') 187 return -EPERM; 188 189 if (strstr(buffer, CLIENTS_UNREG_ACTION) && strstr(buffer, CLIENTS_CMD) 190 && strstr(buffer, CLIENTS_DATA)) 191 return 0; 192 193 for (i = 0; i < num_legacy_callbacks; i++) { 194 char *action_ptr = strstr(buffer, callbacks[i].action); 195 char *cmd_ptr = strstr(buffer, callbacks[i].cmd); 196 char *data_ptr = strstr(buffer, callbacks[i].data); 197 if (!action_ptr || !cmd_ptr || !data_ptr) 198 continue; 199 200 char action_sep = action_ptr[strlen(callbacks[i].action)]; 201 char cmd_sep = cmd_ptr[strlen(callbacks[i].cmd)]; 202 if (!(strchr(valid_sep, action_sep) && strchr(valid_sep, 203 cmd_sep))) 204 return -EPERM; 205 char data_sep; 206 207 if (!strchr(data_ptr, '{')) 208 data_sep = data_ptr[strlen(callbacks[i].data)]; 209 else { 210 if (!strchr(data_ptr, '}')) 211 return -EINVAL; 212 char *data_end = strchr(data_ptr, '}'); 213 data = data_ptr + strlen(DATA_REQ_LABEL); 214 data_sep = data_end[1]; 215 data_end[1] = 0; 216 } 217 if (!strchr(valid_sep, data_sep)) 218 return -EPERM; 219 fn = callbacks[i].fn; 220 break; 221 } 222 223 if (!fn) 224 return -EINVAL; 225 perform_command(fn, data, s); 226 return 0; 227 } 228 229 void * 230 legacy_client_handler(void *sock_id) 231 { 232 int s = (int)(uintptr_t)sock_id; 233 int ret; 234 char buffer_recv[BUF_SIZE]; 235 /* receive data is not null terminated */ 236 int bytes = read(s, buffer_recv, sizeof(buffer_recv) - 1); 237 238 while (bytes > 0) { 239 buffer_recv[bytes] = 0; 240 int i, j; 241 char buffer[BUF_SIZE]; 242 for (i = 0, j = 0; buffer_recv[i] != '\0'; i++) { 243 buffer[j] = buffer_recv[i]; 244 j += !isspace(buffer_recv[i]); 245 } 246 buffer[j] = 0; 247 ret = parse_client_request(buffer, j, s); 248 if (ret < 0) { 249 ret = send_error_response(s, ret); 250 if (ret < 0) 251 printf("\nCould not send error response\n"); 252 } 253 bytes = read(s, buffer_recv, sizeof(buffer_recv) - 1); 254 } 255 close(s); 256 return NULL; 257 } 258 259 #endif /* !RTE_EXEC_ENV_WINDOWS */ 260