ftmon.c (16357B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Diag CLI IPFIX command 8 */ 9 10 #include <appl/diag/system.h> 11 #include <appl/diag/parse.h> 12 #include <shared/bsl.h> 13 #include <soc/format.h> 14 15 #include <bcm/error.h> 16 #include <bcm/flowtracker.h> 17 #include <bcm_int/esw/flowtracker.h> 18 #include <bcm_int/esw/flowtracker/ft_export.h> 19 20 char cmd_ftmon_usage[] = 21 "Parameters: [report +/-<values>] [set <values>] [stop|start]\n" 22 #ifndef COMPILER_STRING_CONST_LIMIT 23 "\t start - Start the FT export fifo deamon\n" 24 "\t stop - Stop the FT export fifo deamon\n" 25 "\t report - Configure reporting to the console\n" 26 "\t count - print export entry # only\n" 27 "\t decode - dump decoded export entry\n" 28 "\t Prepend + to set, - to clear\n" 29 #endif 30 ; 31 32 static int ftmon_report_count[BCM_MAX_NUM_UNITS] = { 0 }; 33 static int ftmon_is_running[BCM_MAX_NUM_UNITS] = { 0 }; 34 static uint32 ftmon_report[BCM_MAX_NUM_UNITS] = { 0 }; 35 36 #ifdef BCM_FLOWTRACKER_SUPPORT 37 extern int bcma_ft_ipfix_print_record(int unit, 38 int set_c, 39 int payload_length, 40 uint8 *payload_data); 41 #endif /* BCM_FLOWTRACKER_SUPPORT */ 42 43 typedef struct ft_cache_s { 44 int record_count; 45 bcm_collector_export_record_t record; 46 } ft_cache_t; 47 48 /* FT record reasons. */ 49 #define FT_RECORD_REASON_ALU16 0x1 50 #define FT_RECORD_REASON_ALU32 0x2 51 #define FT_RECORD_REASON_STATE_TRANS 0x4 52 #define FT_RECORD_REASON_LEARN 0x8 53 #define FT_RECORD_REASON_AGED 0x10 54 #define FT_RECORD_REASON_FLUSH 0x20 55 #define FT_RECORD_REASON_PERIODIC 0x40 56 57 58 typedef struct ft_record_info_s { 59 int ft_group; 60 int ft_index; 61 int key_len; 62 int data_len; 63 uint32 ft_reason; 64 uint8 ft_key[64]; 65 uint8 ft_data[64]; 66 } ft_record_info_t; 67 68 ft_cache_t *ft_record_cache[BCM_MAX_NUM_UNITS]; 69 70 #define REPORT_COUNT 0x01 /* Report export count */ 71 #define REPORT_DECODE 0x02 /* Report Decoded export data */ 72 #define REPORT_CACHE 0x04 /* Report Start Caching export data */ 73 #define REPORT_DUMP 0x08 /* Report Dump cached record data */ 74 75 #define REPORT_CACHE_ENABLED 0x10 76 77 static const parse_pm_t ftmon_report_table[] = { 78 {"Count", REPORT_COUNT}, 79 {"Decode", REPORT_DECODE}, 80 {"Cache", REPORT_CACHE}, 81 {"Dump", REPORT_DUMP}, 82 {"@ALL", ~0}, 83 {"@*", ~0}, 84 {NULL, 0} 85 }; 86 87 88 #ifdef BCM_FLOWTRACKER_SUPPORT 89 uint8 record_data_record[] = { 90 0xe1, 91 0xfe, 92 0x00, 93 0x80, 94 0x01, 95 0x94, 96 0x00, 97 0x19, 98 0x00, 99 0x08, 100 0x00, 101 0x00, 102 0x00, 103 0x00, 104 0x00, 105 0x00, 106 0x00, 107 0x00, 108 0x00, 109 0x00, 110 0x00, 111 0x00, 112 0x00, 113 0x00, 114 0x00, 115 0x00, 116 0x00, 117 0x00, 118 0x00, 119 0x00, 120 0x00, 121 0x00, 122 0x00, 123 0x00, 124 0x00, 125 0x00, 126 0x00, 127 0x00, 128 0x00, 129 0x00, 130 0x00, 131 0x00, 132 0x00, 133 0x00, 134 0x00, 135 0x00, 136 0x00, 137 0x00, 138 0x00, 139 0x00, 140 0x06, 141 0x42, 142 0x72, 143 0x6f, 144 0x61, 145 0x19, 146 0x32, 147 0x00, 148 0x00, 149 0x1a, 150 0x32, 151 0x00, 152 0x00, 153 0x02, 154 155 0x00, 156 0xc9, 157 0xff, 158 0xff, 159 0xde, 160 0x00, 161 0x00, 162 0x00, 163 0x00, 164 0x44, 165 0x00, 166 0x00, 167 0x00, 168 0x01, 169 0x00, 170 0x2a, 171 0x00, 172 0x00, 173 0x00, 174 0x2a, 175 0xff, 176 0xff, 177 0x00, 178 0x00, 179 0x00, 180 0x00, 181 0x06, 182 0x00, 183 0x01, 184 0x00, 185 0x00, 186 0x00, 187 0x00, 188 0x00, 189 0x00, 190 0x00, 191 0x00, 192 0x00, 193 0x00, 194 0x00, 195 0x00, 196 0x00, 197 0x00, 198 0x00, 199 0x00, 200 0x00, 201 0x00, 202 0x00, 203 0x00, 204 0x00, 205 0x00, 206 0x00, 207 0x00, 208 0x00, 209 0x00, 210 0x00, 211 0x00, 212 0x00, 213 0x00, 214 0x00, 215 0x00, 216 0x00, 217 0x00, 218 0x00, 219 }; 220 221 222 223 224 STATIC void 225 bcm_ftmon_export_entry_parse(int unit, 226 bcm_collector_export_record_t *record, 227 ft_record_info_t *record_info) 228 { 229 int ix, rec_words, fld_len; 230 soc_field_t fld; 231 soc_format_t fmt; 232 uint32 fldbuf[32] = {0}, entbuf[32] = {0}, *record_p; 233 234 235 rec_words = 128 / 4; 236 237 record_p = (uint32 *)(&(record->data_record[0])); 238 for (ix = 0; ix < (rec_words); ix++) { 239 240 entbuf[rec_words - ix - 1] = record_p[ix]; 241 } 242 243 fmt = BSC_EX_EXPORT_RECORDfmt; 244 245 sal_memset(fldbuf, 0, 128); 246 fld = GROUP_IDf; 247 record_info->ft_group = soc_format_field32_get(unit, fmt, entbuf, fld); 248 249 sal_memset(fldbuf, 0, 128); 250 fld = FLOW_INDEXf; 251 record_info->ft_index = soc_format_field32_get(unit, fmt, entbuf, fld); 252 253 sal_memset(fldbuf, 0, 128); 254 fld = EXPORT_REASONf; 255 record_info->ft_reason = soc_format_field32_get(unit, fmt, entbuf, fld); 256 257 sal_memset(fldbuf, 0, 128); 258 fld = FLOW_KEYf; 259 fld_len = soc_format_field_length(unit, fmt, fld); 260 soc_format_field_get(unit, fmt, entbuf, fld, fldbuf); 261 record_info->key_len = (fld_len / 8); 262 sal_memcpy((record_info->ft_key), fldbuf, (fld_len / 8)); 263 264 sal_memset(fldbuf, 0, 128); 265 fld = FLOW_DATAf; 266 fld_len = soc_format_field_length(unit, fmt, fld); 267 soc_format_field_get(unit, fmt, entbuf, fld, fldbuf); 268 record_info->data_len = (fld_len / 8); 269 sal_memcpy((record_info->ft_data), fldbuf, (fld_len / 8)); 270 271 return; 272 } 273 274 #define LINE_DEMARC cli_out("**************************************************\n") 275 276 277 STATIC void 278 bcm_ftmon_export_entry_dump(int unit, 279 int count, 280 bcm_collector_export_record_t *record, 281 ft_record_info_t *record_info) 282 { 283 int ix; 284 uint8 *d, n; 285 286 LINE_DEMARC; 287 288 cli_out("FT Export Record: Flow Index:%d", record_info->ft_index); 289 if (count > 0) { 290 cli_out(" Num Exports:%d", count); 291 } 292 cli_out("\n"); 293 294 cli_out("Group Id:%d Flow Reasons:%d", record_info->ft_group, record_info->ft_reason); 295 cli_out("\n"); 296 297 cli_out("Key:\n"); 298 n = record_info->key_len; 299 d = &(record_info->ft_key[0]); 300 301 for (ix = 0; ix < n; ix++) { 302 303 if (ix == 0) 304 cli_out("0x"); 305 306 cli_out("%02x", d[ix]); 307 308 if (ix == (n - 1)) 309 cli_out("\n"); 310 } 311 312 313 cli_out("Data:\n"); 314 n = record_info->data_len; 315 d = &(record_info->ft_data[0]); 316 317 for (ix = 0; ix < n; ix++) { 318 319 if (ix == 0) 320 cli_out("0x"); 321 322 cli_out("%02x", d[ix]); 323 324 if (ix == (n - 1)) 325 cli_out("\n"); 326 } 327 328 329 LINE_DEMARC; 330 331 return; 332 } 333 334 int 335 bcm_ftmon_record_parse_test(int unit) 336 { 337 bcm_collector_export_record_t record; 338 ft_record_info_t record_info; 339 340 sal_memcpy(record.data_record,record_data_record, 128); 341 bcm_ftmon_export_entry_parse(unit, &record, &record_info); 342 343 return 0; 344 } 345 346 347 348 bcm_collector_export_record_handle_t 349 ftmon_callback(int unit, 350 bcm_collector_t collector_id, 351 bcm_collector_export_record_t *record, 352 void *userdata) 353 { 354 int handled = 0; 355 ft_record_info_t record_info; 356 357 358 /* Increment the global record count. */ 359 ftmon_report_count[unit]++; 360 361 /* If Caching is disabled, print count for each record.*/ 362 if ((ftmon_report[unit] & REPORT_COUNT) && 363 !(ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 364 cli_out("Export entry #%d.\n", ftmon_report_count[unit]); 365 handled = 1; 366 } 367 368 /* If Caching is enabled, dump each record.*/ 369 if ((ftmon_report[unit] & REPORT_DUMP) && 370 !(ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 371 372 sal_memset(&(record_info), 0, sizeof(record_info)); 373 bcm_ftmon_export_entry_parse(unit, record, &record_info); 374 375 bcm_ftmon_export_entry_dump(unit, 0, record, &record_info); 376 handled = 1; 377 } 378 379 /* Decode record.*/ 380 if ((ftmon_report[unit] & REPORT_DECODE) && 381 !(ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 382 383 if (bcma_ft_ipfix_print_record(unit, 0, record->size, record->data_record)) { 384 cli_out("ipfix parsing failed\n"); 385 } 386 handled = 1; 387 } 388 389 390 391 /* If cache is enabled, cache the record.*/ 392 if(ftmon_report[unit] & REPORT_CACHE_ENABLED) { 393 sal_memset(&(record_info), 0, sizeof(record_info)); 394 bcm_ftmon_export_entry_parse(unit, record, &record_info); 395 396 ft_record_cache[unit][record_info.ft_index].record_count += 1; 397 sal_memcpy(&(ft_record_cache[unit][record_info.ft_index].record), 398 record, sizeof(bcm_collector_export_record_t)); 399 400 handled = 1; 401 } 402 403 if (handled == 0) { 404 return BCM_FLOWTRACKER_EXPORT_RECORD_NOT_HANDLED; 405 } else { 406 return BCM_FLOWTRACKER_EXPORT_RECORD_HANDLED_OWNED; 407 } 408 } 409 410 411 STATIC int 412 ftmon_cache_alloc(int unit, int enable) 413 { 414 int max_flows; 415 416 /* Max flows is size of single wide key table. */ 417 max_flows = soc_mem_index_count(unit, FT_KEY_SINGLEm); 418 419 if (enable) { 420 ft_record_cache[unit] = sal_alloc((sizeof(ft_cache_t) * max_flows), 421 "FT records Cache"); 422 sal_memset(ft_record_cache[unit], 0, (sizeof(ft_cache_t) * max_flows)); 423 if (ft_record_cache[unit] == NULL) { 424 return -1; 425 } 426 } else { 427 sal_free(ft_record_cache[unit]); 428 ft_record_cache[unit] = NULL; 429 } 430 431 return 0; 432 } 433 #endif /* BCM_FLOWTRACKER_SUPPORT */ 434 435 436 cmd_result_t 437 cmd_ftmon(int unit, args_t *arg) 438 { 439 int rv; 440 char *subcmd; 441 #ifdef BCM_FLOWTRACKER_SUPPORT 442 bcm_collector_t collector_id; 443 bcm_collector_callback_options_t callback_options; 444 #endif /* BCM_FLOWTRACKER_SUPPORT */ 445 446 if (!soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) { 447 return (CMD_NFND); 448 } 449 450 if (!ARG_CNT(arg)) { /* Nothing passed */ 451 cli_out("IPFIX Deamon Status: %s.\n", 452 (ftmon_is_running[unit]) ? "Running" : "Not Running"); 453 454 cli_out("Reporting is enabled for: "); 455 parse_mask_format(80, ftmon_report_table, ftmon_report[unit]); 456 cli_out("Reporting is disabled for: "); 457 parse_mask_format(80, ftmon_report_table, ftmon_report[unit] ^ ~0); 458 459 cli_out("Number of records received: %d\n", ftmon_report_count[unit]); 460 return(CMD_OK); 461 } 462 463 subcmd = ARG_GET(arg); 464 if (subcmd == NULL) { 465 return CMD_USAGE; 466 } 467 468 rv = BCM_E_NONE; 469 470 #ifdef BCM_FLOWTRACKER_SUPPORT 471 callback_options.callback_prio = 0; 472 if (!sal_strcasecmp(subcmd, "start")) { 473 if (ftmon_is_running[unit]) { 474 cli_out("%s: FTMON thread already running.\n", ARG_CMD(arg)); 475 return CMD_OK; 476 } 477 ftmon_report_count[unit] = 0; 478 ftmon_is_running[unit] = 1; 479 rv = bcma_ft_export_fifo_control(unit, 1000000); 480 if (rv < 0) { 481 cli_out("%s: ERROR: %s\n", ARG_CMD(arg), bcm_errmsg(rv)); 482 return CMD_FAIL; 483 } 484 485 rv = bcma_ft_export_dma_collector_get(unit, &collector_id); 486 if (BCM_FAILURE(rv)) { 487 return CMD_FAIL; 488 } 489 490 rv = bcm_collector_export_record_register(unit, collector_id, 491 callback_options, 492 ftmon_callback, NULL); 493 } else if (!sal_strcasecmp(subcmd, "stop")) { 494 if (!ftmon_is_running[unit]) { 495 cli_out("%s: ERROR: FTMON thread already stopped.\n", ARG_CMD(arg)); 496 return CMD_FAIL; 497 } 498 rv = bcma_ft_export_fifo_control(unit, 0); 499 if (rv < 0) { 500 cli_out("%s: ERROR: %s\n", ARG_CMD(arg), bcm_errmsg(rv)); 501 return CMD_FAIL; 502 } 503 ftmon_is_running[unit] = 0; 504 505 rv = bcma_ft_export_dma_collector_get(unit, &collector_id); 506 if (BCM_FAILURE(rv)) { 507 return CMD_FAIL; 508 } 509 510 rv = bcm_collector_export_record_unregister(unit, collector_id, 511 callback_options, 512 ftmon_callback); 513 514 } else if (!sal_strcasecmp(subcmd, "report")) { 515 if (ARG_CNT(arg)) { 516 while ((subcmd = ARG_CUR(arg)) != NULL && 517 !parse_mask(subcmd, ftmon_report_table, &ftmon_report[unit])) { 518 ARG_NEXT(arg); /* Bump arg if matched report */ 519 } 520 521 /* Enable caching. */ 522 if ((ftmon_report[unit] & REPORT_CACHE) && 523 !(ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 524 if (ftmon_cache_alloc(unit, TRUE) != 0) { 525 return CMD_FAIL; 526 } 527 ftmon_report[unit] |= REPORT_CACHE_ENABLED; 528 } 529 530 /* Disable caching. */ 531 if (!(ftmon_report[unit] & REPORT_CACHE) && 532 (ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 533 if (ftmon_cache_alloc(unit, FALSE) != 0) { 534 return CMD_FAIL; 535 } 536 ftmon_report[unit] &= ~REPORT_CACHE_ENABLED; 537 } 538 539 /* Dump cached entries. */ 540 if ((ftmon_report[unit] & REPORT_DUMP) && 541 (ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 542 int ix; 543 int max_flows; 544 ft_record_info_t record_info; 545 546 /* Max flows is size of single wide key table. */ 547 max_flows = soc_mem_index_count(unit, FT_KEY_SINGLEm); 548 549 for (ix = 0; ix < max_flows; ix++) { 550 if ((ft_record_cache[unit][ix].record_count) > 0) { 551 bcm_ftmon_export_entry_parse(unit, &(ft_record_cache[unit][ix].record), &record_info); 552 bcm_ftmon_export_entry_dump(unit, ft_record_cache[unit][ix].record_count, &(ft_record_cache[unit][ix].record), &record_info); 553 } 554 } 555 } 556 557 } else { /* Print values */ 558 cli_out("FTMON Reporting on for: "); 559 parse_mask_format(50, ftmon_report_table, ftmon_report[unit]); 560 cli_out("FTMON Reporting off for: "); 561 parse_mask_format(50, ftmon_report_table, ~ftmon_report[unit]); 562 } 563 } else if (!sal_strcasecmp(subcmd, "dump")) { 564 /* Dump cached entries. */ 565 if ((ftmon_report[unit] & REPORT_CACHE_ENABLED)) { 566 int ix; 567 int max_flows; 568 ft_record_info_t record_info; 569 570 /* Max flows is size of single wide key table. */ 571 max_flows = soc_mem_index_count(unit, FT_KEY_SINGLEm); 572 573 for (ix = 0; ix < max_flows; ix++) { 574 if ((ft_record_cache[unit][ix].record_count) > 0) { 575 bcm_ftmon_export_entry_parse(unit, &(ft_record_cache[unit][ix].record), &record_info); 576 bcm_ftmon_export_entry_dump(unit, ft_record_cache[unit][ix].record_count, &(ft_record_cache[unit][ix].record), &record_info); 577 } 578 } 579 } 580 581 582 } else { 583 return CMD_USAGE; 584 } 585 #endif /* BCM_FLOWTRACKER_SUPPORT */ 586 587 if (rv < 0) { 588 cli_out("%s: ERROR: %s\n", ARG_CMD(arg), bcm_errmsg(rv)); 589 return CMD_FAIL; 590 } 591 592 return CMD_OK; 593 }