1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2020 Intel Corporation 3 */ 4 5 #include <string.h> 6 #include <sys/socket.h> 7 #include <sys/un.h> 8 #include <unistd.h> 9 #include <limits.h> 10 11 #include <rte_eal.h> 12 #include <rte_common.h> 13 #include <rte_telemetry.h> 14 #include <rte_string_fns.h> 15 16 #include "test.h" 17 #include "telemetry_data.h" 18 19 #define TELEMETRY_VERSION "v2" 20 #define REQUEST_CMD "/test" 21 #define BUF_SIZE 1024 22 #define TEST_OUTPUT(exp) test_output(__func__, exp) 23 24 static struct rte_tel_data response_data; 25 static int sock; 26 27 /* 28 * This function is the callback registered with Telemetry to be used when 29 * the /test command is requested. This callback returns the global data built 30 * up by the individual test cases. 31 */ 32 static int 33 test_cb(const char *cmd __rte_unused, const char *params __rte_unused, 34 struct rte_tel_data *d) 35 { 36 *d = response_data; 37 return 0; 38 } 39 40 /* 41 * This function is called by each test case function. It communicates with 42 * the telemetry socket by requesting the /test command, and reading the 43 * response. The expected response is passed in by the test case function, 44 * and is compared to the actual response received from Telemetry. 45 */ 46 static int 47 test_output(const char *func_name, const char *expected) 48 { 49 int bytes; 50 char buf[BUF_SIZE * 16]; 51 if (write(sock, REQUEST_CMD, strlen(REQUEST_CMD)) < 0) { 52 printf("%s: Error with socket write - %s\n", __func__, 53 strerror(errno)); 54 return -1; 55 } 56 bytes = read(sock, buf, sizeof(buf) - 1); 57 if (bytes < 0) { 58 printf("%s: Error with socket read - %s\n", __func__, 59 strerror(errno)); 60 return -1; 61 } 62 buf[bytes] = '\0'; 63 printf("%s: buf = '%s', expected = '%s'\n", func_name, buf, expected); 64 return strncmp(expected, buf, sizeof(buf)); 65 } 66 67 static int 68 test_dict_with_array_int_values(void) 69 { 70 int i; 71 72 struct rte_tel_data *child_data = rte_tel_data_alloc(); 73 rte_tel_data_start_array(child_data, RTE_TEL_INT_VAL); 74 75 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 76 rte_tel_data_start_array(child_data2, RTE_TEL_INT_VAL); 77 78 memset(&response_data, 0, sizeof(response_data)); 79 rte_tel_data_start_dict(&response_data); 80 81 for (i = 0; i < 5; i++) { 82 rte_tel_data_add_array_int(child_data, i); 83 rte_tel_data_add_array_int(child_data2, i); 84 } 85 86 rte_tel_data_add_dict_container(&response_data, "dict_0", 87 child_data, 0); 88 rte_tel_data_add_dict_container(&response_data, "dict_1", 89 child_data2, 0); 90 91 return TEST_OUTPUT("{\"/test\":{\"dict_0\":[0,1,2,3,4]," 92 "\"dict_1\":[0,1,2,3,4]}}"); 93 } 94 95 static int 96 test_array_with_array_int_values(void) 97 { 98 int i; 99 100 struct rte_tel_data *child_data = rte_tel_data_alloc(); 101 rte_tel_data_start_array(child_data, RTE_TEL_INT_VAL); 102 103 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 104 rte_tel_data_start_array(child_data2, RTE_TEL_INT_VAL); 105 106 memset(&response_data, 0, sizeof(response_data)); 107 rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); 108 109 for (i = 0; i < 5; i++) { 110 rte_tel_data_add_array_int(child_data, i); 111 rte_tel_data_add_array_int(child_data2, i); 112 } 113 rte_tel_data_add_array_container(&response_data, child_data, 0); 114 rte_tel_data_add_array_container(&response_data, child_data2, 0); 115 116 return TEST_OUTPUT("{\"/test\":[[0,1,2,3,4],[0,1,2,3,4]]}"); 117 } 118 119 static int 120 test_case_array_int(void) 121 { 122 int i; 123 memset(&response_data, 0, sizeof(response_data)); 124 rte_tel_data_start_array(&response_data, RTE_TEL_INT_VAL); 125 for (i = 0; i < 5; i++) 126 rte_tel_data_add_array_int(&response_data, i); 127 return TEST_OUTPUT("{\"/test\":[0,1,2,3,4]}"); 128 } 129 130 static int 131 test_case_add_dict_int(void) 132 { 133 int i = 0; 134 char name_of_value[8]; 135 136 memset(&response_data, 0, sizeof(response_data)); 137 rte_tel_data_start_dict(&response_data); 138 139 for (i = 0; i < 5; i++) { 140 sprintf(name_of_value, "dict_%d", i); 141 rte_tel_data_add_dict_int(&response_data, name_of_value, i); 142 } 143 144 return TEST_OUTPUT("{\"/test\":{\"dict_0\":0,\"dict_1\":1,\"dict_2\":2," 145 "\"dict_3\":3,\"dict_4\":4}}"); 146 } 147 148 static int 149 test_case_array_string(void) 150 { 151 memset(&response_data, 0, sizeof(response_data)); 152 rte_tel_data_start_array(&response_data, RTE_TEL_STRING_VAL); 153 rte_tel_data_add_array_string(&response_data, "aaaa"); 154 rte_tel_data_add_array_string(&response_data, "bbbb"); 155 rte_tel_data_add_array_string(&response_data, "cccc"); 156 rte_tel_data_add_array_string(&response_data, "dddd"); 157 rte_tel_data_add_array_string(&response_data, "eeee"); 158 159 return TEST_OUTPUT("{\"/test\":[\"aaaa\",\"bbbb\",\"cccc\",\"dddd\"," 160 "\"eeee\"]}"); 161 } 162 163 static int 164 test_case_add_dict_string(void) 165 { 166 memset(&response_data, 0, sizeof(response_data)); 167 rte_tel_data_start_dict(&response_data); 168 169 rte_tel_data_add_dict_string(&response_data, "dict_0", "aaaa"); 170 rte_tel_data_add_dict_string(&response_data, "dict_1", "bbbb"); 171 rte_tel_data_add_dict_string(&response_data, "dict_2", "cccc"); 172 rte_tel_data_add_dict_string(&response_data, "dict_3", "dddd"); 173 174 return TEST_OUTPUT("{\"/test\":{\"dict_0\":\"aaaa\",\"dict_1\":" 175 "\"bbbb\",\"dict_2\":\"cccc\",\"dict_3\":\"dddd\"}}"); 176 } 177 178 179 static int 180 test_dict_with_array_string_values(void) 181 { 182 struct rte_tel_data *child_data = rte_tel_data_alloc(); 183 rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); 184 185 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 186 rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); 187 188 memset(&response_data, 0, sizeof(response_data)); 189 rte_tel_data_start_dict(&response_data); 190 191 rte_tel_data_add_array_string(child_data, "aaaa"); 192 rte_tel_data_add_array_string(child_data2, "bbbb"); 193 194 rte_tel_data_add_dict_container(&response_data, "dict_0", 195 child_data, 0); 196 rte_tel_data_add_dict_container(&response_data, "dict_1", 197 child_data2, 0); 198 199 return TEST_OUTPUT("{\"/test\":{\"dict_0\":[\"aaaa\"],\"dict_1\":" 200 "[\"bbbb\"]}}"); 201 } 202 203 static int 204 test_array_with_array_string_values(void) 205 { 206 struct rte_tel_data *child_data = rte_tel_data_alloc(); 207 rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); 208 209 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 210 rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); 211 212 memset(&response_data, 0, sizeof(response_data)); 213 rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); 214 215 rte_tel_data_add_array_string(child_data, "aaaa"); 216 rte_tel_data_add_array_string(child_data2, "bbbb"); 217 218 rte_tel_data_add_array_container(&response_data, child_data, 0); 219 rte_tel_data_add_array_container(&response_data, child_data2, 0); 220 221 return TEST_OUTPUT("{\"/test\":[[\"aaaa\"],[\"bbbb\"]]}"); 222 } 223 224 static int 225 test_case_array_u64(void) 226 { 227 int i; 228 memset(&response_data, 0, sizeof(response_data)); 229 rte_tel_data_start_array(&response_data, RTE_TEL_U64_VAL); 230 for (i = 0; i < 5; i++) 231 rte_tel_data_add_array_u64(&response_data, i); 232 return TEST_OUTPUT("{\"/test\":[0,1,2,3,4]}"); 233 } 234 235 static int 236 test_case_add_dict_u64(void) 237 { 238 int i = 0; 239 char name_of_value[8]; 240 241 memset(&response_data, 0, sizeof(response_data)); 242 rte_tel_data_start_dict(&response_data); 243 244 for (i = 0; i < 5; i++) { 245 sprintf(name_of_value, "dict_%d", i); 246 rte_tel_data_add_dict_u64(&response_data, name_of_value, i); 247 } 248 return TEST_OUTPUT("{\"/test\":{\"dict_0\":0,\"dict_1\":1,\"dict_2\":2," 249 "\"dict_3\":3,\"dict_4\":4}}"); 250 } 251 252 static int 253 test_dict_with_array_u64_values(void) 254 { 255 int i; 256 257 struct rte_tel_data *child_data = rte_tel_data_alloc(); 258 rte_tel_data_start_array(child_data, RTE_TEL_U64_VAL); 259 260 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 261 rte_tel_data_start_array(child_data2, RTE_TEL_U64_VAL); 262 263 memset(&response_data, 0, sizeof(response_data)); 264 rte_tel_data_start_dict(&response_data); 265 266 for (i = 0; i < 10; i++) { 267 rte_tel_data_add_array_u64(child_data, i); 268 rte_tel_data_add_array_u64(child_data2, i); 269 } 270 271 rte_tel_data_add_dict_container(&response_data, "dict_0", 272 child_data, 0); 273 rte_tel_data_add_dict_container(&response_data, "dict_1", 274 child_data2, 0); 275 276 return TEST_OUTPUT("{\"/test\":{\"dict_0\":[0,1,2,3,4,5,6,7,8,9]," 277 "\"dict_1\":[0,1,2,3,4,5,6,7,8,9]}}"); 278 } 279 280 static int 281 test_array_with_array_u64_values(void) 282 { 283 int i; 284 285 struct rte_tel_data *child_data = rte_tel_data_alloc(); 286 rte_tel_data_start_array(child_data, RTE_TEL_U64_VAL); 287 288 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 289 rte_tel_data_start_array(child_data2, RTE_TEL_U64_VAL); 290 291 memset(&response_data, 0, sizeof(response_data)); 292 rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); 293 294 for (i = 0; i < 5; i++) { 295 rte_tel_data_add_array_u64(child_data, i); 296 rte_tel_data_add_array_u64(child_data2, i); 297 } 298 rte_tel_data_add_array_container(&response_data, child_data, 0); 299 rte_tel_data_add_array_container(&response_data, child_data2, 0); 300 301 return TEST_OUTPUT("{\"/test\":[[0,1,2,3,4],[0,1,2,3,4]]}"); 302 } 303 304 static int 305 connect_to_socket(void) 306 { 307 char buf[BUF_SIZE]; 308 int sock, bytes; 309 struct sockaddr_un telem_addr; 310 311 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 312 if (sock < 0) { 313 printf("\n%s: Error creating socket: %s\n", __func__, 314 strerror(errno)); 315 return -1; 316 } 317 telem_addr.sun_family = AF_UNIX; 318 snprintf(telem_addr.sun_path, sizeof(telem_addr.sun_path), 319 "%s/dpdk_telemetry.%s", rte_eal_get_runtime_dir(), 320 TELEMETRY_VERSION); 321 if (connect(sock, (struct sockaddr *) &telem_addr, 322 sizeof(telem_addr)) < 0) { 323 printf("\n%s: Error connecting to socket: %s\n", __func__, 324 strerror(errno)); 325 close(sock); 326 return -1; 327 } 328 329 bytes = read(sock, buf, sizeof(buf) - 1); 330 if (bytes < 0) { 331 printf("%s: Error with socket read - %s\n", __func__, 332 strerror(errno)); 333 close(sock); 334 return -1; 335 } 336 buf[bytes] = '\0'; 337 printf("\n%s: %s\n", __func__, buf); 338 return sock; 339 } 340 341 static int 342 test_telemetry_data(void) 343 { 344 typedef int (*test_case)(void); 345 unsigned int i = 0; 346 347 sock = connect_to_socket(); 348 if (sock <= 0) 349 return -1; 350 351 test_case test_cases[] = {test_case_array_string, 352 test_case_array_int, test_case_array_u64, 353 test_case_add_dict_int, test_case_add_dict_u64, 354 test_case_add_dict_string, 355 test_dict_with_array_int_values, 356 test_dict_with_array_u64_values, 357 test_dict_with_array_string_values, 358 test_array_with_array_int_values, 359 test_array_with_array_u64_values, 360 test_array_with_array_string_values }; 361 362 rte_telemetry_register_cmd(REQUEST_CMD, test_cb, "Test"); 363 for (i = 0; i < RTE_DIM(test_cases); i++) { 364 if (test_cases[i]() != 0) { 365 close(sock); 366 return -1; 367 } 368 } 369 close(sock); 370 return 0; 371 } 372 373 REGISTER_TEST_COMMAND(telemetry_data_autotest, test_telemetry_data); 374