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_dict_with_dict_values(void) 205 { 206 struct rte_tel_data *dict_of_dicts = rte_tel_data_alloc(); 207 rte_tel_data_start_dict(dict_of_dicts); 208 209 struct rte_tel_data *child_data = rte_tel_data_alloc(); 210 rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); 211 212 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 213 rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); 214 215 memset(&response_data, 0, sizeof(response_data)); 216 rte_tel_data_start_dict(&response_data); 217 218 rte_tel_data_add_array_string(child_data, "aaaa"); 219 rte_tel_data_add_array_string(child_data2, "bbbb"); 220 rte_tel_data_add_dict_container(dict_of_dicts, "dict_0", 221 child_data, 0); 222 rte_tel_data_add_dict_container(dict_of_dicts, "dict_1", 223 child_data2, 0); 224 rte_tel_data_add_dict_container(&response_data, "dict_of_dicts", 225 dict_of_dicts, 0); 226 227 return TEST_OUTPUT("{\"/test\":{\"dict_of_dicts\":{\"dict_0\":" 228 "[\"aaaa\"],\"dict_1\":[\"bbbb\"]}}}"); 229 } 230 231 static int 232 test_array_with_array_string_values(void) 233 { 234 struct rte_tel_data *child_data = rte_tel_data_alloc(); 235 rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); 236 237 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 238 rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); 239 240 memset(&response_data, 0, sizeof(response_data)); 241 rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); 242 243 rte_tel_data_add_array_string(child_data, "aaaa"); 244 rte_tel_data_add_array_string(child_data2, "bbbb"); 245 246 rte_tel_data_add_array_container(&response_data, child_data, 0); 247 rte_tel_data_add_array_container(&response_data, child_data2, 0); 248 249 return TEST_OUTPUT("{\"/test\":[[\"aaaa\"],[\"bbbb\"]]}"); 250 } 251 252 static int 253 test_case_array_u64(void) 254 { 255 int i; 256 memset(&response_data, 0, sizeof(response_data)); 257 rte_tel_data_start_array(&response_data, RTE_TEL_U64_VAL); 258 for (i = 0; i < 5; i++) 259 rte_tel_data_add_array_u64(&response_data, i); 260 return TEST_OUTPUT("{\"/test\":[0,1,2,3,4]}"); 261 } 262 263 static int 264 test_case_add_dict_u64(void) 265 { 266 int i = 0; 267 char name_of_value[8]; 268 269 memset(&response_data, 0, sizeof(response_data)); 270 rte_tel_data_start_dict(&response_data); 271 272 for (i = 0; i < 5; i++) { 273 sprintf(name_of_value, "dict_%d", i); 274 rte_tel_data_add_dict_u64(&response_data, name_of_value, i); 275 } 276 return TEST_OUTPUT("{\"/test\":{\"dict_0\":0,\"dict_1\":1,\"dict_2\":2," 277 "\"dict_3\":3,\"dict_4\":4}}"); 278 } 279 280 static int 281 test_dict_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_dict(&response_data); 293 294 for (i = 0; i < 10; i++) { 295 rte_tel_data_add_array_u64(child_data, i); 296 rte_tel_data_add_array_u64(child_data2, i); 297 } 298 299 rte_tel_data_add_dict_container(&response_data, "dict_0", 300 child_data, 0); 301 rte_tel_data_add_dict_container(&response_data, "dict_1", 302 child_data2, 0); 303 304 return TEST_OUTPUT("{\"/test\":{\"dict_0\":[0,1,2,3,4,5,6,7,8,9]," 305 "\"dict_1\":[0,1,2,3,4,5,6,7,8,9]}}"); 306 } 307 308 static int 309 test_array_with_array_u64_values(void) 310 { 311 int i; 312 313 struct rte_tel_data *child_data = rte_tel_data_alloc(); 314 rte_tel_data_start_array(child_data, RTE_TEL_U64_VAL); 315 316 struct rte_tel_data *child_data2 = rte_tel_data_alloc(); 317 rte_tel_data_start_array(child_data2, RTE_TEL_U64_VAL); 318 319 memset(&response_data, 0, sizeof(response_data)); 320 rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); 321 322 for (i = 0; i < 5; i++) { 323 rte_tel_data_add_array_u64(child_data, i); 324 rte_tel_data_add_array_u64(child_data2, i); 325 } 326 rte_tel_data_add_array_container(&response_data, child_data, 0); 327 rte_tel_data_add_array_container(&response_data, child_data2, 0); 328 329 return TEST_OUTPUT("{\"/test\":[[0,1,2,3,4],[0,1,2,3,4]]}"); 330 } 331 332 static int 333 connect_to_socket(void) 334 { 335 char buf[BUF_SIZE]; 336 int sock, bytes; 337 struct sockaddr_un telem_addr; 338 339 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 340 if (sock < 0) { 341 printf("\n%s: Error creating socket: %s\n", __func__, 342 strerror(errno)); 343 return -1; 344 } 345 telem_addr.sun_family = AF_UNIX; 346 snprintf(telem_addr.sun_path, sizeof(telem_addr.sun_path), 347 "%s/dpdk_telemetry.%s", rte_eal_get_runtime_dir(), 348 TELEMETRY_VERSION); 349 if (connect(sock, (struct sockaddr *) &telem_addr, 350 sizeof(telem_addr)) < 0) { 351 printf("\n%s: Error connecting to socket: %s\n", __func__, 352 strerror(errno)); 353 close(sock); 354 return -1; 355 } 356 357 bytes = read(sock, buf, sizeof(buf) - 1); 358 if (bytes < 0) { 359 printf("%s: Error with socket read - %s\n", __func__, 360 strerror(errno)); 361 close(sock); 362 return -1; 363 } 364 buf[bytes] = '\0'; 365 printf("\n%s: %s\n", __func__, buf); 366 return sock; 367 } 368 369 static int 370 test_telemetry_data(void) 371 { 372 typedef int (*test_case)(void); 373 unsigned int i = 0; 374 375 sock = connect_to_socket(); 376 if (sock <= 0) 377 return -1; 378 379 test_case test_cases[] = {test_case_array_string, 380 test_case_array_int, test_case_array_u64, 381 test_case_add_dict_int, test_case_add_dict_u64, 382 test_case_add_dict_string, 383 test_dict_with_array_int_values, 384 test_dict_with_array_u64_values, 385 test_dict_with_array_string_values, 386 test_dict_with_dict_values, 387 test_array_with_array_int_values, 388 test_array_with_array_u64_values, 389 test_array_with_array_string_values }; 390 391 rte_telemetry_register_cmd(REQUEST_CMD, test_cb, "Test"); 392 for (i = 0; i < RTE_DIM(test_cases); i++) { 393 if (test_cases[i]() != 0) { 394 close(sock); 395 return -1; 396 } 397 } 398 close(sock); 399 return 0; 400 } 401 402 REGISTER_TEST_COMMAND(telemetry_data_autotest, test_telemetry_data); 403