ctrans.c (48348B)
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 * File: ctecho.c 8 * Purpose: CPU transport setup and echo routines 9 * Requires: 10 */ 11 12 13 #include <sal/types.h> 14 #include <sal/core/libc.h> 15 #include <sal/core/thread.h> 16 #include <sal/core/dpc.h> 17 #include <sal/appl/sal.h> 18 #include <sal/appl/io.h> 19 #include <shared/bsl.h> 20 #include <bcm/stack.h> 21 22 #include <appl/diag/shell.h> 23 #include <appl/diag/system.h> 24 #include <appl/diag/parse.h> 25 #include <appl/diag/ctrans.h> 26 27 #include <appl/cpudb/cpudb.h> 28 #include <appl/cputrans/cputrans.h> 29 #include <appl/cputrans/atp.h> 30 #include <appl/cputrans/next_hop.h> 31 #include <appl/cputrans/cpu2cpu.h> 32 #include <appl/cputrans/atptrans_socket.h> 33 #if defined(BCM_RPC_SUPPORT) 34 #include <bcm/pkt.h> 35 #include <appl/cputrans/ct_tun.h> 36 #endif 37 38 #if defined(BROADCOM_DEBUG) 39 extern void atp_dump(int); 40 extern void c2c_dump(void); 41 #endif /* BROADCOM_DEBUG */ 42 43 44 #if defined(INCLUDE_LIB_CPUDB) && defined(INCLUDE_LIB_CPUTRANS) && \ 45 defined(INCLUDE_LIB_DISCOVER) && defined(INCLUDE_LIB_STKTASK) 46 47 48 /* 49 * The following routine is used to register with BCM RX in 50 * order to initiate BCM RX packet processing. 51 */ 52 #define RX_PKT_CLEAR_USEC 250000 /* Time to wait for RX discard */ 53 #define RX_PROCESS_START_PRIO 1 /* Callback routine prio */ 54 55 STATIC bcm_rx_t 56 rx_process_start(int unit, bcm_pkt_t *pkt, void *cookie) 57 { 58 COMPILER_REFERENCE(unit); 59 COMPILER_REFERENCE(pkt); 60 COMPILER_REFERENCE(cookie); 61 62 return BCM_RX_NOT_HANDLED; 63 } 64 65 /* 66 * Start BCM RX and initiate packet processing 67 * 68 * Note: 69 * BCM RX does not start packet processing until a callback 70 * routine is registered (other than the internal discard routine). 71 */ 72 STATIC int 73 rx_start(void) 74 { 75 int i; 76 int rv = BCM_E_NONE; 77 int rx_started = 0; 78 /* 79 * Start BCM RX 80 */ 81 for (i = 0; i < soc_ndev; i++) { 82 if (bcm_rx_active(SOC_NDEV_IDX2DEV(i))) { 83 rx_started++; 84 continue; 85 } 86 rv = bcm_rx_init(SOC_NDEV_IDX2DEV(i)); 87 if (rv == BCM_E_UNAVAIL) { 88 cli_out("WARNING: BCM RX init failed, unit %d: %s\n", 89 SOC_NDEV_IDX2DEV(i), bcm_errmsg(rv)); 90 continue; 91 } else if (BCM_FAILURE(rv)) { 92 cli_out("ERROR: BCM RX init failed, unit %d: %s\n", 93 SOC_NDEV_IDX2DEV(i), bcm_errmsg(rv)); 94 return rv; 95 } 96 97 rv = bcm_rx_start(SOC_NDEV_IDX2DEV(i), NULL); 98 if (BCM_FAILURE(rv)) { 99 cli_out("ERROR: BCM RX start failed, unit %d: %s\n", 100 SOC_NDEV_IDX2DEV(i), bcm_errmsg(rv)); 101 return rv; 102 } 103 rx_started++; 104 } 105 106 /* Error if RX did not get started on any unit */ 107 if (rx_started == 0) { 108 return BCM_E_UNAVAIL; 109 } 110 111 /* 112 * Start BCM RX packet processing 113 */ 114 115 /* RX packet processing has already started if NH is running */ 116 if (next_hop_running()) { 117 return BCM_E_NONE; 118 } 119 120 /* Register dummy callback to trigger BCM RX packet processing */ 121 for (i = 0; i < soc_ndev; i++) { 122 123 /* Skip units that did not get started */ 124 if (!bcm_rx_active(SOC_NDEV_IDX2DEV(i))) { 125 cli_out("WARNING: skipping callback registration on unit %d\n", SOC_NDEV_IDX2DEV(i)); 126 continue; 127 } 128 129 rv = bcm_rx_register(SOC_NDEV_IDX2DEV(i), "process_start", 130 rx_process_start, RX_PROCESS_START_PRIO, 131 NULL, BCM_RCO_F_ALL_COS); 132 if (BCM_FAILURE(rv)) { 133 cli_out("ERROR: Cannot register RX callback to initiate packet " 134 "processing, unit %d: %s\n", 135 SOC_NDEV_IDX2DEV(i), bcm_errmsg(rv)); 136 /* Clean-up */ 137 for (; i > 0; i--) { 138 bcm_rx_unregister(SOC_NDEV_IDX2DEV(i), rx_process_start, 139 RX_PROCESS_START_PRIO); 140 } 141 return rv; 142 } 143 } 144 145 /* Give time for RX handler to process and discard queued packets */ 146 sal_usleep(RX_PKT_CLEAR_USEC); 147 148 /* Routine no longer needed after RX packet processing has started */ 149 for (i = 0; i < soc_ndev; i++) { 150 bcm_rx_unregister(SOC_NDEV_IDX2DEV(i), rx_process_start, RX_PROCESS_START_PRIO); 151 } 152 153 return rv; 154 } 155 156 STATIC int 157 pkt_preinit(void) 158 { 159 int rv; 160 161 /* Start BCM RX and packet processing */ 162 if ((rv = rx_start()) < 0) { 163 return -1; 164 } 165 166 if (!cputrans_tx_setup_done()) { 167 168 rv = cputrans_tx_pkt_setup(100, &bcm_trans_ptr); 169 if (rv < 0) { 170 cli_out("ERROR: cputrans TX setup failed: %s\n", 171 bcm_errmsg(rv)); 172 return -1; 173 } 174 } 175 176 if (!cputrans_rx_setup_done()) { 177 rv = cputrans_rx_pkt_setup(-1, NULL); /* Use defaults */ 178 if (rv < 0) { 179 cli_out("ERROR: cputrans RX setup failed: %s\n", 180 bcm_errmsg(rv)); 181 return -1; 182 } 183 } 184 185 return 0; 186 } 187 188 189 /**************************************************************** 190 * 191 * CPUTRANS setup 192 */ 193 194 char ct_setup_usage[] = 195 "CTSetup <subcmd> [options]\n" 196 " Modify the CPUTRANS subsystem\n" 197 #ifndef COMPILER_STRING_CONST_LIMIT 198 " Subcommands:\n" 199 " <none> Report if running\n" 200 " BCMREG Register BCM transport pointers\n" 201 " TXLIMIT [COS=<n> Limit=<n>]\n" 202 " Set TX packet alloc limit for the given cos\n" 203 " RX START\n" 204 " Start packet RX\n" 205 " NEXTHOP [DBidx=<n>] [THRDpri=<n>] [RXpri=<n>]\n" 206 " [COS=<n>] [VLAN=<n>]\n" 207 " Start next hop with the given DB index\n" 208 " ATP [TXPri=<n>] [RXPri=<n>] [COS=<n>] [VLAN=<n>]\n" 209 " Start ATP with given thread priorities\n" 210 #if defined(BROADCOM_DEBUG) 211 " ATP SHOW\n" 212 " Display internal ATP information\n" 213 #endif /* BROADCOM_DEBUG */ 214 #ifdef INCLUDE_ATPTRANS_SOCKET 215 " ATP TRANSport SOCKet INStall DestKey=<key> DestIP=<ip-addr>\n" 216 " Install socket interface for ATP transport\n" 217 " ATP TRANSport SOCKet UNINStall DestKey=<key>\n" 218 " Uninstall socket interface for ATP transport\n" 219 " ATP TRANSport SOCKet SERVer {START | STOP}\n" 220 " Start/stop ATP-over-Sockets Server\n" 221 " ATP TRANSport SOCKet CONFIG PRIority=<pri> \ 222 ListenPORT=<port-num> ConnectionPORT=<port-num>\n" 223 " Configure socket interface for ATP transport\n" 224 #ifdef BROADCOM_DEBUG 225 " ATP TRANSport SOCKet SHOW\n" 226 " Display internal ATP-over-Sockets subsystem information\n" 227 #endif /* BROADCOM_DEBUG */ 228 #endif /* INCLUDE_ATPTRANS_SOCKET */ 229 #if defined(BROADCOM_DEBUG) 230 " C2C SHOW\n" 231 " Display internal C2C information\n" 232 #endif /* BROADCOM_DEBUG */ 233 " STOP Stop ATP\n" 234 " TIMEOUT [RetryTO=<n>] [RETRIES=<n>]\n" 235 " Set/get the timeout (in usecs) and number of retries\n" 236 " SEGLEN [<n>] Set/get the segment length\n" 237 " POOLSIZE [TX=<n>] [RX=<n>] " 238 " Set/get the TX/RX pool size\n" 239 #endif 240 #if defined(BCM_RPC_SUPPORT) 241 " TUNNEL mode [{RELIABLE | BESTEFFORT}]\n" 242 " Set/get the default rx tunnel mode\n" 243 " TUNNEL set\n" 244 " Create tx tunnel\n" 245 " TUNNEL destroy\n" 246 " Tear down tx tunnel\n" 247 #endif 248 ; 249 250 251 #ifdef INCLUDE_ATPTRANS_SOCKET 252 253 STATIC cmd_result_t 254 atptrans_socket_subcmd(int unit, args_t *args, cpudb_ref_t db_ref) 255 { 256 char *subcmd; 257 parse_table_t pt; 258 cpudb_key_t local_key; 259 cpudb_key_t dest_key; 260 bcm_ip_t dest_ip; 261 int rv = BCM_E_NONE; 262 263 if ((subcmd = ARG_GET(args)) == NULL) { 264 cli_out("Need option\n"); 265 return CMD_USAGE; 266 } 267 268 if (parse_cmp("INStall", subcmd, '\0')) { 269 270 /* Get destination CPU key and IP address */ 271 parse_table_init(unit, &pt); 272 parse_table_add(&pt, "DestKey", PQ_DFL|PQ_KEY, 0, 273 dest_key.key, 0); 274 parse_table_add(&pt, "DestIP", PQ_DFL|PQ_IP, 0, 275 (void *)&dest_ip, 0); 276 if (parse_arg_eq(args, &pt) < 2) { 277 parse_arg_eq_done(&pt); 278 return CMD_USAGE; 279 } 280 281 /* Make sure local CPU is set */ 282 CPUDB_KEY_COPY(local_key, db_refs[cur_db]->local_entry->base.key); 283 atptrans_socket_local_cpu_key_set(local_key); 284 285 /* Install socket for given dest CPU */ 286 rv = atptrans_socket_install(dest_key, dest_ip, 0x0); 287 if (BCM_FAILURE(rv)) { 288 cli_out("Cannot install socket interface in ATP transport " 289 "for CPU key " CPUDB_KEY_FMT_EOLN, 290 CPUDB_KEY_DISP(dest_key)); 291 } 292 parse_arg_eq_done(&pt); 293 294 } else if (parse_cmp("UNINStall", subcmd, '\0')) { 295 parse_table_init(unit, &pt); 296 parse_table_add(&pt, "DestKey", PQ_DFL|PQ_KEY, 0, 297 dest_key.key, 0); 298 if (parse_arg_eq(args, &pt) <= 0) { 299 parse_arg_eq_done(&pt); 300 return CMD_USAGE; 301 } 302 rv = atptrans_socket_uninstall(dest_key); 303 parse_arg_eq_done(&pt); 304 305 } else if (parse_cmp("SERVer", subcmd, '\0')) { 306 if ((subcmd = ARG_GET(args)) == NULL) { 307 cli_out("Need option\n"); 308 return CMD_USAGE; 309 } 310 if (sal_strcasecmp(subcmd, "START") == 0) { 311 rv = atptrans_socket_server_start(); 312 313 } else if (sal_strcasecmp(subcmd, "STOP") == 0) { 314 rv = atptrans_socket_server_stop(); 315 316 } else { 317 cli_out("Invalid argument: %s\n", subcmd); 318 return CMD_USAGE; 319 } 320 } else if (parse_cmp("CONFIG", subcmd, '\0')) { 321 /* Should be called after atptrans_socket_server_start() */ 322 /* Get destination priority and port numbers */ 323 int priority; 324 int listen_port; 325 int connect_port; 326 327 parse_table_init(unit, &pt); 328 parse_table_add(&pt, "PRIority", PQ_DFL | PQ_INT, 0, &priority, 0); 329 parse_table_add(&pt, "ListenPORT", PQ_DFL | PQ_INT, 0, 330 (void *) &listen_port, 0); 331 parse_table_add(&pt, "ConnectionPORT", PQ_DFL | PQ_INT, 0, 332 (void *) &connect_port, 0); 333 if (parse_arg_eq(args, &pt) <= 0) { 334 parse_arg_eq_done(&pt); 335 return CMD_USAGE; 336 } 337 rv = atptrans_socket_config_set(priority, listen_port, connect_port); 338 #ifdef BROADCOM_DEBUG 339 } else if (parse_cmp("SHOW", subcmd, '\0')) { 340 atptrans_socket_show(); 341 #endif /* BROADCOM_DEBUG */ 342 } else { 343 cli_out("Invalid option: %s\n", subcmd); 344 return CMD_USAGE; 345 } 346 if (BCM_FAILURE(rv)) { 347 if (rv == BCM_E_UNAVAIL) { 348 cli_out("Socket interface not available for current system\n"); 349 } 350 else { 351 cli_out("Command failed\n"); 352 } 353 } 354 355 return rv; 356 } 357 #endif /* INCLUDE_ATPTRANS_SOCKET */ 358 359 360 cmd_result_t 361 ct_setup(int unit, args_t *args) 362 { 363 parse_table_t pt; 364 char *subcmd; 365 int rv; 366 int db_idx = cur_db; 367 368 COMPILER_REFERENCE(unit); 369 370 if ((subcmd = ARG_GET(args)) == NULL) { 371 cli_out("Next Hop is%s running\n", 372 next_hop_running() ? "" : " not"); 373 cli_out("ATP is%s running\n", 374 atp_running() ? "" : " not"); 375 return CMD_OK; 376 } 377 378 if (sal_strcasecmp(subcmd, "RX") == 0) { 379 char *next_arg; 380 381 if ((next_arg = ARG_GET(args)) == NULL) { 382 return CMD_USAGE; 383 } 384 if (sal_strcasecmp(next_arg, "START")) { 385 return CMD_USAGE; 386 } 387 if (pkt_preinit() < 0) { 388 cli_out("Failed to start BCM RX\n"); 389 return CMD_FAIL; 390 } 391 392 } else if (sal_strcasecmp(subcmd, "NEXTHOP") == 0) { 393 int idx; 394 const cpudb_key_t *key; 395 int s_unit = 0, s_port = 0, duplex = 0; 396 int did_print = FALSE; 397 398 if (cputrans_trans_count() == 0) { 399 cputrans_trans_add(&bcm_trans_ptr); 400 } 401 402 if (ARG_CUR(args) == NULL) { 403 for (idx = 0; idx < next_hop_num_ports_get(); idx++) { 404 if (next_hop_port_get(idx, &s_unit, &s_port, &duplex) 405 == BCM_E_NONE) { 406 cli_out("NH idx %d: Unit %d, Port %d: %sarked duplex.\n", 407 idx, s_unit, s_port, duplex ? "M" : "Not m"); 408 } else { 409 cli_out("NH idx %d: INVALID?\n", idx); 410 } 411 did_print = TRUE; 412 } 413 for (idx = 0; idx < next_hop_max_entries_get(); idx++) { 414 key = next_hop_key_get(idx); 415 if (key != NULL) { 416 cli_out("KEY %x:%x:%x:%x:%x:%x is in NH DB\n", 417 (*key).key[0], (*key).key[1], (*key).key[2], 418 (*key).key[3], (*key).key[4], (*key).key[5]); 419 did_print = TRUE; 420 } 421 } 422 if (!did_print) { 423 cli_out("Next Hop database and ports empty\n"); 424 } 425 } else { 426 int thrd_pri = -1; 427 int rx_pri = -1; 428 int nhvlan = -1, nhcos = -1, src_mod = -1; 429 int add_ports = 0; 430 const cpudb_base_t *base; 431 432 parse_table_init(unit, &pt); 433 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 434 parse_table_add(&pt, "THRDpri", PQ_DFL|PQ_INT, 0, &thrd_pri, 0); 435 parse_table_add(&pt, "RXpri", PQ_DFL|PQ_INT, 0, &rx_pri, 0); 436 parse_table_add(&pt, "COS", PQ_DFL|PQ_INT, 0, &nhcos, 0); 437 parse_table_add(&pt, "VLAN", PQ_DFL|PQ_INT, 0, &nhvlan, 0); 438 parse_table_add(&pt, "SrcMOD", PQ_DFL|PQ_INT, 0, &src_mod, 0); 439 parse_table_add(&pt, "Add", PQ_DFL|PQ_INT, 0, &add_ports, 0); 440 if (parse_arg_eq(args, &pt) < 0) { 441 parse_arg_eq_done(&pt); 442 return CMD_USAGE; 443 } 444 parse_arg_eq_done(&pt); 445 if (db_idx < 0 || db_idx >= MAX_DBS || 446 db_refs[db_idx] == CPUDB_REF_NULL) { 447 cli_out("Bad db index: %d\n", db_idx); 448 return CMD_FAIL; 449 } 450 if (db_refs[db_idx]->local_entry == NULL) { 451 cli_out("No local DB entry in cpudb %d\n", db_idx); 452 return CMD_FAIL; 453 } 454 455 if (nhcos >= 0) { 456 next_hop_cos_set(nhcos); 457 } 458 if (nhvlan >= 0) { 459 next_hop_vlan_set(nhvlan); 460 /* Load the next hop mac addr into L2 tables */ 461 rv = nh_tx_dest_install(TRUE, nhvlan); 462 if (rv < 0) { 463 cli_out("NH TX dest install failed: %s\n", bcm_errmsg(rv)); 464 return CMD_FAIL; 465 } 466 } 467 if (src_mod >= 0) { 468 int mod, port; 469 470 nh_tx_src_get(&mod, &port); 471 mod = src_mod; 472 nh_tx_src_set(mod, port); 473 nh_tx_unknown_modid_set(src_mod); 474 } 475 476 if (pkt_preinit() < 0) { 477 cli_out("NH: Pre-init failed\n"); 478 return CMD_FAIL; 479 } 480 481 if (next_hop_running()) { 482 cli_out("Next hop is running; stopping: %d\n", 483 next_hop_stop()); 484 } 485 486 if (thrd_pri >= 0 || rx_pri >= 0) { 487 if (next_hop_config_set(NULL, thrd_pri, rx_pri) < 0) { 488 cli_out("Warning: config set failed\n"); 489 } 490 } 491 492 base = &db_refs[db_idx]->local_entry->base; 493 if (add_ports > 0) { 494 int i, u, p; 495 for (i = 0; i < base->num_stk_ports; i++) { 496 bcm_port_encap_config_t mode; 497 u = base->stk_ports[i].unit; 498 p = base->stk_ports[i].port; 499 500 rv = bcm_port_encap_config_get(u, p, &mode); 501 if (BCM_FAILURE(rv)) { 502 continue; 503 } 504 if (mode.encap == BCM_PORT_ENCAP_IEEE) { 505 continue; 506 } 507 rv = next_hop_port_add(u, p, 1); 508 if (rv < 0) { 509 cli_out("nexthop add (%d.%d) failed: %s\n", 510 u, p, bcm_errmsg(rv)); 511 } 512 } 513 } 514 rv = next_hop_start(base); 515 if (rv < 0) { 516 cli_out("ERROR: next_hop_start failed: %s\n", bcm_errmsg(rv)); 517 } 518 } 519 return CMD_OK; 520 #if defined(BROADCOM_DEBUG) 521 } else if (sal_strcasecmp(subcmd, "NHSHOW") == 0) { 522 next_hop_dump(); 523 return CMD_OK; 524 #endif /* BROADCOM_DEBUG */ 525 } else if (sal_strcasecmp(subcmd, "TXLIMIT") == 0) { 526 int cos = -1; 527 int limit = 0; 528 int rv; 529 530 parse_table_init(unit, &pt); 531 parse_table_add(&pt, "COS", PQ_DFL|PQ_INT, 0, &cos, 0); 532 parse_table_add(&pt, "Limit", PQ_DFL|PQ_INT, 0, &limit, 0); 533 534 if (parse_arg_eq(args, &pt) < 0) { 535 parse_arg_eq_done(&pt); 536 return CMD_USAGE; 537 } 538 539 if (cos == -1) { 540 for (cos = 0; cos <= BCM_COS_MAX; cos++) { 541 cputrans_tx_alloc_limit_get(cos, &limit); 542 cli_out("Limit for COS %d currently %d\n", cos, limit); 543 } 544 parse_arg_eq_done(&pt); 545 return CMD_OK; 546 } 547 548 rv = cputrans_tx_alloc_limit_set(cos, limit); 549 if (rv < 0) { 550 cli_out("WARNING: limit set returned %d: %s\n", rv, bcm_errmsg(rv)); 551 } 552 553 parse_arg_eq_done(&pt); 554 return CMD_OK; 555 556 } else if (sal_strcasecmp(subcmd, "ATP") == 0) { 557 int tx_pri = -1; 558 int rx_pri = -1; 559 int atp_cos = -1, atp_vlan = -1; 560 561 #if defined(BROADCOM_DEBUG) 562 if ((subcmd = ARG_CUR(args)) != NULL) { 563 if (sal_strcasecmp(subcmd, "SHOW") == 0) { 564 ARG_NEXT(args); 565 atp_dump(1); 566 return CMD_OK; 567 } 568 } 569 #endif /* BROADCOM_DEBUG */ 570 571 #ifdef INCLUDE_ATPTRANS_SOCKET 572 if ((subcmd = ARG_CUR(args)) != NULL) { 573 if (parse_cmp("TRANSport", subcmd, '\0')) { 574 ARG_NEXT(args); 575 if ((subcmd = ARG_GET(args)) == NULL) { 576 return CMD_USAGE; 577 } 578 if (db_idx < 0 || db_idx >= MAX_DBS || 579 db_refs[db_idx] == CPUDB_REF_NULL) { 580 cli_out("Bad or empty DB index: %d\n", db_idx); 581 return CMD_FAIL; 582 } 583 if (db_refs[db_idx]->local_entry == NULL) { 584 cli_out("No local DB entry in cpudb %d\n", db_idx); 585 return CMD_FAIL; 586 } 587 if (parse_cmp("SOCKet", subcmd, '\0')) { 588 return atptrans_socket_subcmd(unit, args, db_refs[db_idx]); 589 } 590 return CMD_USAGE; 591 } 592 } 593 #endif /* INCLUDE_ATPTRANS_SOCKET */ 594 595 if (cputrans_trans_count() == 0) { 596 cputrans_trans_add(&bcm_trans_ptr); 597 } 598 599 if (pkt_preinit() < 0) { 600 #ifdef INCLUDE_ATPTRANS_SOCKET 601 /* If ATP over sockets is running, then device RX is not 602 required for ATP */ 603 if (!atptrans_socket_server_running()) { 604 cli_out("ATP: Pre-init failed\n"); 605 return CMD_FAIL; 606 } 607 #else 608 cli_out("ATP: Pre-init failed\n"); 609 return CMD_FAIL; 610 #endif 611 } 612 613 parse_table_init(unit, &pt); 614 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 615 parse_table_add(&pt, "TXPrio", PQ_DFL|PQ_INT, 0, &tx_pri, 0); 616 parse_table_add(&pt, "RXPrio", PQ_DFL|PQ_INT, 0, &rx_pri, 0); 617 parse_table_add(&pt, "COS", PQ_DFL|PQ_INT, 0, &atp_cos, 0); 618 parse_table_add(&pt, "VLAN", PQ_DFL|PQ_INT, 0, &atp_vlan, 0); 619 if (parse_arg_eq(args, &pt) < 0) { 620 parse_arg_eq_done(&pt); 621 return CMD_USAGE; 622 } 623 if (db_idx < 0 || db_idx >= MAX_DBS || 624 db_refs[db_idx] == CPUDB_REF_NULL) { 625 cli_out("Bad db index: %d\n", db_idx); 626 parse_arg_eq_done(&pt); 627 return CMD_FAIL; 628 } 629 if (db_refs[db_idx]->local_entry == NULL) { 630 cli_out("No local DB entry in cpudb %d\n", db_idx); 631 parse_arg_eq_done(&pt); 632 return CMD_FAIL; 633 } 634 635 atp_cos_vlan_set(atp_cos, atp_vlan); 636 rv = atp_config_set(tx_pri, rx_pri, NULL); 637 if (rv < 0) { 638 cli_out("ERROR: ATP config set failed: %s\n", bcm_errmsg(rv)); 639 } 640 atp_db_update(db_refs[db_idx]); 641 rv = atp_start(ATP_F_LEARN_SLF, 642 ATP_UNITS_ALL, 643 BCM_RCO_F_ALL_COS); 644 if (rv < 0) { 645 cli_out("ERROR: ATP start failed: %s\n", bcm_errmsg(rv)); 646 } 647 parse_arg_eq_done(&pt); 648 #if defined(BROADCOM_DEBUG) 649 } else if (sal_strcasecmp(subcmd, "C2C") == 0) { 650 if ((subcmd = ARG_GET(args)) != NULL) { 651 if (sal_strcasecmp(subcmd, "SHOW") == 0) { 652 c2c_dump(); 653 return CMD_OK; 654 } 655 } 656 #endif /* BROADCOM_DEBUG */ 657 } else if (sal_strcasecmp(subcmd, "STOP") == 0) { 658 rv = atp_stop(); 659 if (rv < 0) { 660 cli_out("ERROR: ATP stop failed: %s\n", bcm_errmsg(rv)); 661 } 662 } else if (sal_strcasecmp(subcmd, "TIMEOUT") == 0) { 663 int retry_us = -1, retries = -1; 664 665 if (ARG_CUR(args) == NULL) { 666 atp_timeout_get(&retry_us, &retries); 667 cli_out("Retries occur after %d usecs and will be made %d times\n", 668 retry_us, retries); 669 } else { 670 parse_table_init(unit, &pt); 671 parse_table_add(&pt, "RetryTO", PQ_DFL|PQ_INT, 0, &retry_us, 0); 672 parse_table_add(&pt, "RETRIES", PQ_DFL|PQ_INT, 0, &retries, 0); 673 if (parse_arg_eq(args, &pt) < 0) { 674 parse_arg_eq_done(&pt); 675 return CMD_USAGE; 676 } 677 cli_out("Retry set(%d, %d) returns %d\n", retry_us, retries, 678 atp_timeout_set(retry_us, retries)); 679 parse_arg_eq_done(&pt); 680 } 681 } else if (sal_strcasecmp(subcmd, "SEGLEN") == 0) { 682 int seg_len = -1; 683 char *next_arg; 684 685 if ((next_arg = ARG_GET(args)) == NULL) { 686 seg_len = atp_segment_len_get(); 687 cli_out("Current segmentation length is %d\n", seg_len); 688 } else { 689 seg_len = strtoul(next_arg, NULL, 0); 690 cli_out("Seg_len set(%d) returns %d\n", seg_len, 691 atp_segment_len_set(seg_len)); 692 } 693 } else if (sal_strcasecmp(subcmd, "POOLSIZE") == 0) { 694 int tx_pool, rx_pool; 695 /* Get current pool sizes in case one is not specified */ 696 atp_pool_size_get(&tx_pool, &rx_pool); 697 if (ARG_CUR(args) == NULL) { 698 cli_out("Current TX pool: %d. RX pool %d.\n", tx_pool, rx_pool); 699 } else { 700 parse_table_init(unit, &pt); 701 parse_table_add(&pt, "TX", PQ_DFL|PQ_INT, 0, &tx_pool, 0); 702 parse_table_add(&pt, "RX", PQ_DFL|PQ_INT, 0, &rx_pool, 0); 703 if (parse_arg_eq(args, &pt) < 0) { 704 parse_arg_eq_done(&pt); 705 return CMD_USAGE; 706 } 707 cli_out("Pool size set returns %d\n", 708 atp_pool_size_set(tx_pool, rx_pool)); 709 parse_arg_eq_done(&pt); 710 } 711 #if defined(BCM_RPC_SUPPORT) 712 } else if (sal_strcasecmp(subcmd, "TUNNEL") == 0) { 713 if ((subcmd = ARG_GET(args)) == NULL) { 714 return CMD_USAGE; 715 } 716 717 if (sal_strcasecmp(subcmd, "mode") == 0) { 718 int mode = -1; 719 char *mode_str = NULL; 720 721 if ((mode_str = ARG_GET(args)) == NULL) { 722 723 /* Display the current rx tunnel mode */ 724 mode = ct_rx_tunnel_mode_default_get(); 725 if (BCM_CPU_TUNNEL_PACKET_RELIABLE == mode) { 726 mode_str = "RELIABLE"; 727 } else if (BCM_CPU_TUNNEL_PACKET_BEST_EFFORT == mode) { 728 mode_str = "BESTEFFORT"; 729 } 730 731 if (NULL != mode_str) { 732 cli_out("Default rx tunnel mode is %s.\n", mode_str); 733 } 734 } else { 735 if (sal_strcasecmp(mode_str, "BESTEFFORT") == 0) { 736 mode = BCM_CPU_TUNNEL_PACKET_BEST_EFFORT; 737 } else if (sal_strcasecmp(mode_str, "RELIABLE") == 0) { 738 mode = BCM_CPU_TUNNEL_PACKET_RELIABLE; 739 } else { 740 return CMD_USAGE; 741 } 742 743 rv = ct_rx_tunnel_mode_default_set(mode); 744 if (BCM_FAILURE(rv)) { 745 return CMD_FAIL; 746 } 747 } 748 } else if (sal_strcasecmp(subcmd, "set") == 0) { 749 rv = ct_tx_tunnel_setup(); 750 cli_out("BCM TX Tunnel Setup returns %s\n", bcm_errmsg(rv)); 751 } else if (sal_strcasecmp(subcmd, "destroy") == 0) { 752 rv = ct_tx_tunnel_stop(); 753 cli_out("BCM TX Tunnel Stop returns %s\n", bcm_errmsg(rv)); 754 } else { 755 return CMD_USAGE; 756 } 757 #endif /* BCM_RPC_SUPPORT */ 758 } else { 759 cli_out("Subcommand not found: %s\n", subcmd); 760 return CMD_USAGE; 761 } 762 763 return CMD_OK; 764 } 765 766 767 static char *cti_driver_list[] = { 768 "BCM", 769 "KERNEL", 770 "KREMOTE", 771 "OOB", 772 "NONE", 773 NULL}; 774 775 #define CTI_DRIVER_BCM 0 776 #define CTI_DRIVER_KERNEL 1 777 #define CTI_DRIVER_KREMOTE 2 778 #define CTI_DRIVER_OOB 3 779 #define CTI_DRIVER_NONE 4 780 781 static bcm_trans_ptr_t * cti_driver_ptrs[] = { 782 &bcm_trans_ptr, /* Usual BCM */ 783 NULL, /* Local via kernel driver */ 784 NULL, /* Remote via kernel driver */ 785 NULL, /* Out of band driver */ 786 NULL /* Install NULL driver */ 787 }; 788 789 static char *cti_transport_list[] = {"NH", "DBENTRY", "ALL", "DEF", NULL}; 790 791 #define CTI_TRANS_NH 0 792 #define CTI_TRANS_DBENTRY 1 793 #define CTI_TRANS_ALL 2 794 #define CTI_TRANS_DEF 3 795 796 char ct_install_usage[] = 797 "Usage: CTInstall [Key=<key> Driver=<mode> Unit=<unit> Port=<port>\n" 798 " Transport=<mode> DBidx=<n>]\n" 799 " Install per CPU transport driver for the given CPU key\n" 800 #ifndef COMPILER_STRING_CONST_LIMIT 801 " Current drivers supported include:\n" 802 " BCM - The usual BCM transport pointers\n" 803 " KERNEL - Local devices via a user to kernel interface\n" 804 " KREMOTE - Remote devices via a user to kernel interface\n" 805 " OOB - Out of band driver\n" 806 " NONE - Install NULL driver (disable per-CPU driver)\n" 807 " Current transports include:\n" 808 " NH - Install for next hop transmit\n" 809 " DBENTRY - Install in DB entry which affects CPU2CPU\n" 810 " ALL - Install in all transports above\n" 811 " DEF - Install as the default transport for C2C and NH\n" 812 #endif 813 ; 814 815 cmd_result_t 816 ct_install(int unit, args_t *args) 817 { 818 parse_table_t pt; 819 int rv; 820 int drv_mode = CTI_DRIVER_NONE; 821 int trans_mode = CTI_TRANS_ALL; 822 cpudb_key_t key; 823 int stk_unit; 824 bcm_port_t stk_port; 825 int db_idx = -1; 826 827 parse_table_init(unit, &pt); 828 parse_table_add(&pt, "Driver", PQ_DFL|PQ_MULTI, 0, &drv_mode, 829 cti_driver_list); 830 parse_table_add(&pt, "Transport", PQ_DFL|PQ_MULTI, 0, &trans_mode, 831 cti_transport_list); 832 parse_table_add(&pt, "Key", PQ_DFL|PQ_KEY, 0, key.key, 0); 833 parse_table_add(&pt, "Unit", PQ_DFL|PQ_INT, 0, &stk_unit, 0); 834 parse_table_add(&pt, "Port", PQ_DFL|PQ_PORT, 0, &stk_port, 0); 835 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 836 837 if (parse_arg_eq(args, &pt) < 0) { 838 parse_arg_eq_done(&pt); 839 return CMD_USAGE; 840 } 841 842 #ifdef INCLUDE_USER_KERNEL_TRANSPORTS 843 { 844 static int init = 1; 845 if(init == 1) { 846 { 847 static bcm_trans_ptr_t* bcm_uk_trans = NULL; 848 extern int bcm_uk_trans_create(char* service, int port, 849 bcm_trans_ptr_t** p); 850 assert(bcm_uk_trans_create(NULL, stk_port, 851 &bcm_uk_trans) >= 0); 852 cti_driver_ptrs[CTI_DRIVER_KERNEL] = bcm_uk_trans; 853 cputrans_trans_add(bcm_uk_trans); 854 } 855 { 856 static bcm_trans_ptr_t* bcm_uk_rtrans = NULL; 857 extern int bcm_uk_rtrans_create(char* service, 858 bcm_trans_ptr_t** p); 859 assert(bcm_uk_rtrans_create(NULL, &bcm_uk_rtrans) >= 0); 860 if(bcm_uk_rtrans) { 861 cti_driver_ptrs[CTI_DRIVER_KREMOTE] = bcm_uk_rtrans; 862 cputrans_trans_add(bcm_uk_rtrans); 863 } 864 } 865 } 866 init = 0; 867 } 868 #endif /* INCLUDE_KERNEL_USER_TRANSPORTS */ 869 870 if (drv_mode == CTI_DRIVER_NONE) { 871 cli_out("Note: Clearing per CPU transport with NULL driver\n"); 872 } else if (cti_driver_ptrs[drv_mode] == NULL) { 873 cli_out("Sorry, driver for %s is not yet implemented\n", 874 cti_driver_list[drv_mode]); 875 return CMD_FAIL; 876 } 877 878 879 /* Handle default transport request */ 880 if(trans_mode == CTI_TRANS_DEF) { 881 /* Install this transport as the default for both C2C and NH */ 882 bcm_trans_ptr_t* tp; 883 bcm_mac_t l; 884 uint32 flags; 885 886 c2c_config_get(&tp, l, &flags); 887 tp = cti_driver_ptrs[drv_mode]; 888 /* Enable checking for destination MAC in C2C packets */ 889 flags |= C2C_F_DEST_MAC_CHECK_ENABLE; 890 c2c_config_set(tp, l, flags); 891 nh_tx_setup(tp); 892 } 893 894 /* Handle next hop transport request */ 895 if (trans_mode == CTI_TRANS_ALL || trans_mode == CTI_TRANS_NH) { 896 rv = nh_tx_trans_ptr_set(stk_unit, stk_port, 897 cti_driver_ptrs[drv_mode]); 898 899 if (rv < 0) { 900 cli_out("WARNING: nh_tx pointer set returned %d: %s\nContinuing\n", 901 rv, bcm_errmsg(rv)); 902 } 903 } 904 905 /* Handle C2C transport request */ 906 if (trans_mode == CTI_TRANS_ALL || trans_mode == CTI_TRANS_DBENTRY) { 907 cpudb_entry_t *entry; 908 909 if (db_idx == -1) { 910 db_idx = cur_db; 911 } 912 if (db_refs[db_idx] == CPUDB_REF_NULL) { 913 cli_out("DB %d is not setup. Try 'CPUDB create'.\n", db_idx); 914 return CMD_FAIL; 915 } 916 CPUDB_KEY_SEARCH(db_refs[db_idx], key, entry); 917 if (entry == NULL) { 918 cli_out("ERROR: DB entry not found\n"); 919 return CMD_FAIL; 920 } 921 entry->trans_ptr = cti_driver_ptrs[drv_mode]; 922 } 923 924 return CMD_OK; 925 } 926 927 928 bcm_rx_t ab_echo_cb(cpudb_key_t src_key, 929 int client_id, 930 bcm_pkt_t *pkt, 931 uint8 *payload, 932 int payload_len, 933 void *cookie); 934 935 char echo_setup_usage[] = 936 "CTEchoSetup <subcmd>\n" 937 ; 938 939 char ct_echo_usage[] = 940 "CTEcho <subcmd> [opts]\n" 941 " REG [Mode=<mode>] [DBidx=<n>] [Reassem=<T|F>]\n" 942 " Register for the given mode, with the given CPUDB\n" 943 " UNREG [Mode=<mode>]" 944 " Unregister for the given mode\n" 945 " ECHO String=<string> [Mode=<ATP|BET|ATPNH|BETNH|BETBcast>] \n" 946 " [DEPTH=<n>] [DestKey=<key>] [ALLOChdr=<T|F>] [ASYNC=<T|F>]\n" 947 " [MinLen=<n>] [Regen=<T|F>]\n" 948 " Echo a string, with recursive calls to the given depth.\n"; 949 950 951 #define PACK_SHORT(buf, val) \ 952 do { \ 953 uint16 v2; \ 954 v2 = bcm_htons(val); \ 955 sal_memcpy(buf, &v2, sizeof(uint16)); \ 956 } while (0) 957 958 #define UNPACK_SHORT(buf, val) \ 959 do { \ 960 sal_memcpy(&(val), buf, sizeof(uint16)); \ 961 val = bcm_ntohs(val); \ 962 } while (0) 963 964 #define PACK_LONG(buf, val) \ 965 do { \ 966 uint32 v2; \ 967 v2 = bcm_htonl(val); \ 968 sal_memcpy(buf, &v2, sizeof(uint32)); \ 969 } while (0) 970 971 #define UNPACK_LONG(buf, val) \ 972 do { \ 973 sal_memcpy(&(val), buf, sizeof(uint32)); \ 974 val = bcm_ntohl(val); \ 975 } while (0) 976 977 978 /* First, a handler for echo packets */ 979 980 typedef struct { 981 int verbose; 982 } CallbackOptions; 983 984 985 /* Cookie data for echo async callback */ 986 typedef struct { 987 int unit; 988 } _echo_cb_async_t; 989 990 #define ECHO_BASE_CLI_ID 1000 991 #define CTE_MODE_ATP 0 992 #define CTE_MODE_BET 1 993 #define CTE_MODE_ATP_NH 2 994 #define CTE_MODE_BET_NH 3 995 #define CTE_MODE_BET_BCAST 4 996 #define CTE_MODE_COUNT 5 997 998 #define CTE_MODE_MASK 0xf 999 #define CTE_FLAGS_ASYNC_FREE 0x100 1000 #define CTE_FLAGS_ALLOC_HDR_HERE 0x200 1001 #define CTE_FLAGS_IS_BCAST 0x400 1002 #define CTE_FLAGS_VERBOSE 0x800 1003 #define CTE_FLAGS_CRC_REGEN 0x1000 1004 1005 static char *cte_mode_list[] = {"ATP", "BET", "ATPNH", "BETNH", "BETBcast", 1006 NULL}; 1007 1008 static CallbackOptions cb_options[CTE_MODE_COUNT]; 1009 1010 STATIC void echo_free_buf(void *payload_ptr, void *pkt_ptr, void *p3, 1011 void *p4, void *p5) 1012 { 1013 atp_rx_free(payload_ptr, pkt_ptr); 1014 } 1015 1016 STATIC void 1017 _send_echo_pkt_cb(uint8 *pkt, void *cookie, int rv) 1018 { 1019 _echo_cb_async_t *async_data; 1020 1021 if (cookie == NULL) { 1022 cli_out("Error in async callback routine; missing data\n"); 1023 return; 1024 } 1025 1026 async_data = (_echo_cb_async_t *)cookie; 1027 cli_out("Async callback routine, unit %d\n", async_data->unit); 1028 1029 /* Free buffer allocated earlier in _ct_echo() */ 1030 sal_dma_free(pkt); 1031 sal_free(async_data); 1032 } 1033 1034 STATIC int 1035 _send_echo_pkt(int client_id, 1036 uint8 *payload, 1037 int payload_len, 1038 int depth, 1039 uint32 pkt_flags, 1040 int mode, 1041 int verbose, 1042 cpudb_key_t dest_key, 1043 void *cookie) 1044 { 1045 int payload_offset = 0; 1046 uint32 ct_flags = 0; 1047 atp_tx_cb_f cb = NULL; 1048 int crc_payload_len; 1049 int rv; 1050 1051 if (verbose) { 1052 cli_out("echo pkt: %d bytes to " CPUDB_KEY_FMT_EOLN, payload_len, 1053 CPUDB_KEY_DISP(dest_key)); 1054 } 1055 PACK_SHORT(payload, depth); 1056 PACK_LONG(&payload[sizeof(uint16)], pkt_flags); 1057 1058 /* There are potentially two CRCs involved here: one is the CRC 1059 that protects the ECHO protocol payload, which is always 1060 present. The other is the Ethernet FCS, which is calculated by 1061 the Ethernet transmitter, space for which is only allocated if 1062 CTE_FLAGS_CRC_REGEN is set. */ 1063 crc_payload_len = payload_len - sizeof(uint32); 1064 if (pkt_flags & CTE_FLAGS_CRC_REGEN) { 1065 crc_payload_len -= sizeof(uint32); 1066 } 1067 1068 PACK_LONG(payload+crc_payload_len, 1069 ~_shr_crc32(~0, payload, crc_payload_len)); 1070 1071 if (mode == CTE_MODE_BET_BCAST) { 1072 ct_flags = CPUTRANS_BCAST; 1073 } 1074 1075 if (pkt_flags & CTE_FLAGS_ALLOC_HDR_HERE) { 1076 payload_offset = CPUTRANS_HEADER_BYTES; 1077 ct_flags |= CPUTRANS_NO_HEADER_ALLOC; 1078 } 1079 1080 if (pkt_flags & CTE_FLAGS_CRC_REGEN) { 1081 ct_flags |= CPUTRANS_CRC_REGEN; 1082 } 1083 1084 if (pkt_flags & CTE_FLAGS_ASYNC_FREE) { 1085 cb = _send_echo_pkt_cb; 1086 } 1087 1088 rv = atp_tx(dest_key, 1089 client_id, 1090 payload - payload_offset, 1091 payload_len + payload_offset, 1092 ct_flags, 1093 cb, 1094 cookie); 1095 1096 return rv; 1097 } 1098 1099 1100 bcm_rx_t 1101 ab_echo_cb(cpudb_key_t src_key, 1102 int client_id, 1103 bcm_pkt_t *pkt, 1104 uint8 *payload, 1105 int payload_len, 1106 void *cookie) 1107 { 1108 uint16 depth; 1109 int async_free; 1110 uint32 pkt_flags; 1111 bcm_rx_t rv = BCM_RX_HANDLED; 1112 int offset = 0; 1113 int mode; 1114 int len; 1115 CallbackOptions *options = (CallbackOptions *)cookie; 1116 1117 if (payload == NULL) { /* Just use first segment for string */ 1118 if (pkt == NULL) { 1119 cli_out("CT echo error: payload and pkt both NULL, cli %d\n", 1120 client_id); 1121 return BCM_RX_NOT_HANDLED; 1122 } 1123 payload = pkt->pkt_data[1].data; 1124 len = pkt->pkt_data[1].len; 1125 cli_out("CT echo warning: \n"); 1126 cli_out(" Segmented packet; segmentation not maintained on echo\n"); 1127 } else { 1128 len = payload_len; 1129 } 1130 1131 UNPACK_SHORT(payload, depth); 1132 offset += sizeof(uint16); 1133 UNPACK_LONG(payload + offset, pkt_flags); 1134 offset += sizeof(uint32); 1135 async_free = pkt_flags & CTE_FLAGS_ASYNC_FREE; 1136 mode = client_id - ECHO_BASE_CLI_ID; 1137 1138 if (mode < 0 || mode > 4) { 1139 cli_out("CT echo error: Bad client id: %d\n", client_id); 1140 return BCM_RX_NOT_HANDLED; 1141 } 1142 1143 if (sal_strlen((char *)&payload[offset]) > len) { 1144 cli_out("CT echo error: Unterminated string in first segment\n"); 1145 return BCM_RX_HANDLED; 1146 } 1147 1148 if (_shr_crc32(~0, payload, len) != _SHR_CRC32_CORRECT) { 1149 cli_out("CT echo error: Echo payload CRC failure.\n"); 1150 } 1151 1152 if (options->verbose) { 1153 cli_out("%s echo request from " CPUDB_KEY_FMT ": %s\n", 1154 cte_mode_list[mode], 1155 CPUDB_KEY_DISP(src_key), 1156 &payload[offset]); 1157 cli_out(" Depth %d, flags 0x%x, len %d. (total %d)\n", 1158 depth, pkt_flags, len - offset, payload_len); 1159 } 1160 1161 if (depth > 0) { 1162 /* Return echo: one less depth, clear async flag */ 1163 pkt_flags &= ~CTE_FLAGS_ASYNC_FREE; 1164 pkt_flags &= ~CTE_FLAGS_CRC_REGEN; 1165 _send_echo_pkt(client_id, payload, len, depth - 1, 1166 pkt_flags, mode, options->verbose, src_key, NULL); 1167 } 1168 1169 if (async_free) { 1170 rv = BCM_RX_HANDLED_OWNED; 1171 sal_dpc(echo_free_buf, payload, pkt, NULL, NULL, NULL); 1172 } else { 1173 rv = BCM_RX_HANDLED; 1174 } 1175 1176 return rv; 1177 } 1178 1179 #define ECHO_STR_OFFSET (sizeof(uint16) + sizeof(uint32)) 1180 1181 typedef struct { 1182 uint8 *pkt_buf; 1183 uint32 pkt_flags; 1184 uint8 *payload_buf; 1185 int payload_len; 1186 } _echo_payload_t; 1187 1188 int 1189 _ct_echo_pkt_create(_echo_payload_t *ep, 1190 char *str, int mode, int cte_flags, int minlen) 1191 { 1192 int payload_len, len, len_str; 1193 uint32 pkt_flags = 0; 1194 uint8 *pkt_buf, *payload_buf; 1195 int alloc_hdr_here = cte_flags & CTE_FLAGS_ALLOC_HDR_HERE; 1196 1197 sal_memset(ep, 0, sizeof(*ep)); 1198 1199 if (str == NULL) { 1200 cli_out("Null string\n"); 1201 return 0; 1202 } 1203 1204 pkt_flags = mode; 1205 len_str = sal_strlen(str); 1206 len = len_str + 1; 1207 len += ECHO_STR_OFFSET; /* To store depth, flags */ 1208 len += sizeof(uint32); /* CRC at end of payload */ 1209 1210 if (cte_flags & CTE_FLAGS_CRC_REGEN) { 1211 pkt_flags |= CTE_FLAGS_CRC_REGEN; 1212 len += sizeof(uint32); /* CRC at end of Ethernet frame */ 1213 } 1214 1215 len = minlen > len ? minlen : len; /* Take min length if set */ 1216 payload_len = len; 1217 if (alloc_hdr_here) { 1218 len += CPUTRANS_HEADER_BYTES; 1219 pkt_flags |= CTE_FLAGS_ALLOC_HDR_HERE; 1220 } 1221 1222 /* Create packet */ 1223 pkt_buf = sal_dma_alloc(len, "ct_echo"); 1224 if (pkt_buf == NULL) { 1225 cli_out("Could not alloc packet buffer\n"); 1226 return 0; 1227 } 1228 1229 /* Pack the string into the payload past depth, flags */ 1230 payload_buf = pkt_buf; 1231 if (alloc_hdr_here) { 1232 payload_buf += CPUTRANS_HEADER_BYTES; 1233 } 1234 1235 sal_strncpy((char *)&payload_buf[ECHO_STR_OFFSET], str, len_str); 1236 if (len_str) 1237 *(char*)&payload_buf[ECHO_STR_OFFSET+len_str] = '\0'; 1238 1239 ep->pkt_buf = pkt_buf; 1240 ep->pkt_flags = pkt_flags; 1241 ep->payload_buf = payload_buf; 1242 ep->payload_len = payload_len; 1243 1244 return 1; 1245 } 1246 1247 1248 void 1249 _ct_echo_async(int unit, cpudb_key_t dest_key, 1250 char *str, int depth, int mode, 1251 int cte_flags, int minlen) 1252 { 1253 void *cookie = NULL; 1254 _echo_cb_async_t *async_data = NULL; 1255 _echo_payload_t payload; 1256 int rv = BCM_E_NONE; 1257 int verbose = cte_flags & CTE_FLAGS_VERBOSE; 1258 1259 if (!_ct_echo_pkt_create(&payload, str, mode, cte_flags, minlen)) { 1260 return; 1261 } 1262 payload.pkt_flags |= CTE_FLAGS_ASYNC_FREE; 1263 1264 if ((async_data = sal_alloc(sizeof(*async_data), "ct-echo")) == NULL) { 1265 cli_out("Could not alloc memory for async data\n"); 1266 return; 1267 } 1268 async_data->unit = unit; 1269 cookie = (void *)async_data; 1270 1271 if (verbose) { 1272 cli_out("CT echo: Sending out %s echo request to CPU key " 1273 CPUDB_KEY_FMT ", depth %d, flags 0x%x\n", 1274 cte_mode_list[mode], CPUDB_KEY_DISP(dest_key), 1275 depth, payload.pkt_flags); 1276 } 1277 1278 rv = _send_echo_pkt(ECHO_BASE_CLI_ID + mode, 1279 payload.payload_buf, payload.payload_len, 1280 depth, payload.pkt_flags, mode, verbose, dest_key, 1281 cookie); 1282 1283 /* 1284 * Free buffers if atp tx was not successful. When atp tx is 1285 * successful , buffers are freed by the callback routine. 1286 */ 1287 if (BCM_FAILURE(rv)) { 1288 cli_out("%s tx returns %d (%s)\n", cte_mode_list[mode], 1289 rv, bcm_errmsg(rv)); 1290 sal_dma_free(payload.pkt_buf); 1291 sal_free(async_data); 1292 } else { 1293 cli_out("Echo sent successfully\n"); 1294 } 1295 } 1296 1297 void 1298 _ct_echo_sync(int unit, cpudb_key_t dest_key, 1299 char *str, int depth, int mode, 1300 int cte_flags, int minlen, int count) 1301 { 1302 void *cookie = NULL; 1303 _echo_payload_t payload; 1304 int rv = BCM_E_NONE; 1305 int actual = 0; 1306 int verbose = cte_flags & CTE_FLAGS_VERBOSE; 1307 1308 if (count == 0) { 1309 cli_out("Nothing to send\n"); 1310 return; 1311 } 1312 1313 if (!_ct_echo_pkt_create(&payload, str, mode, cte_flags, minlen)) { 1314 return; 1315 } 1316 1317 if (verbose) { 1318 cli_out("CT echo: Sending out %s echo request to CPU key " 1319 CPUDB_KEY_FMT ", depth %d, flags 0x%x\n", 1320 cte_mode_list[mode], CPUDB_KEY_DISP(dest_key), 1321 depth, payload.pkt_flags); 1322 } 1323 1324 while (count-- > 0) { 1325 rv = _send_echo_pkt(ECHO_BASE_CLI_ID + mode, 1326 payload.payload_buf, payload.payload_len, 1327 depth, payload.pkt_flags, mode, verbose, dest_key, 1328 cookie); 1329 1330 if (BCM_FAILURE(rv)) { 1331 cli_out("%s tx returns %d (%s)\n", cte_mode_list[mode], 1332 rv, bcm_errmsg(rv)); 1333 break; 1334 } else { 1335 actual++; 1336 } 1337 } 1338 1339 if (actual > 0) { 1340 cli_out("Echo sent successfully\n"); 1341 } 1342 1343 /* 1344 * Free buffers. 1345 */ 1346 1347 sal_dma_free(payload.pkt_buf); 1348 1349 } 1350 1351 cmd_result_t 1352 ct_echo(int unit, args_t *args) 1353 { 1354 parse_table_t pt; 1355 int depth = 1; 1356 char *str = NULL; 1357 static cpudb_key_t dest_key; 1358 int alloc_hdr = FALSE; 1359 int async = FALSE; 1360 int mode = 0; 1361 char *subcmd; 1362 static int db_idx = -1; 1363 int rv; 1364 int flags = 0; 1365 int minlen = 0; 1366 int reassem = TRUE; 1367 int verbose = TRUE; 1368 int count = 1; 1369 int crc_regen = FALSE; 1370 int cte_flags = 0; 1371 1372 if ((subcmd = ARG_GET(args)) == NULL) { 1373 cli_out("Requires string argument\n"); 1374 return CMD_USAGE; 1375 } 1376 if (sal_strcasecmp(subcmd, "REG") == 0) { 1377 parse_table_init(unit, &pt); 1378 parse_table_add(&pt, "Mode", PQ_DFL|PQ_MULTI,0, &mode, cte_mode_list); 1379 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 1380 parse_table_add(&pt, "Reassem", PQ_DFL|PQ_BOOL, 0, &reassem, 0); 1381 parse_table_add(&pt, "Verbose", PQ_DFL|PQ_BOOL, 0, &verbose, 0); 1382 if (parse_arg_eq(args, &pt) < 0) { 1383 parse_arg_eq_done(&pt); 1384 return CMD_USAGE; 1385 } 1386 if (db_idx == -1) { 1387 db_idx = cur_db; 1388 } 1389 if (db_refs[db_idx] == CPUDB_REF_NULL) { 1390 cli_out("DB %d is not setup. Try 'CPUDB create'.\n", db_idx); 1391 return CMD_FAIL; 1392 } 1393 1394 if (reassem) { 1395 flags |= ATP_F_REASSEM_BUF; 1396 } 1397 /* Set next-hop and BET flags appropriately */ 1398 if (mode == CTE_MODE_ATP_NH || 1399 mode == CTE_MODE_BET_NH || 1400 mode == CTE_MODE_BET_BCAST) { 1401 flags |= ATP_F_NEXT_HOP; 1402 } 1403 if (mode == CTE_MODE_BET_NH || 1404 mode == CTE_MODE_BET || 1405 mode == CTE_MODE_BET_BCAST) { 1406 flags |= ATP_F_NO_ACK; 1407 } 1408 1409 cb_options[mode].verbose = verbose; 1410 rv = atp_register(ECHO_BASE_CLI_ID + mode, flags, ab_echo_cb, 1411 (void *)(cb_options + mode), -1, -1); 1412 parse_arg_eq_done(&pt); 1413 if (rv < 0) { 1414 cli_out("Could not register echo as %s (%d) client (%d): %s\n", 1415 cte_mode_list[mode], mode, rv, bcm_errmsg(rv)); 1416 return CMD_FAIL; 1417 } 1418 } else if (sal_strcasecmp(subcmd, "UNREG") == 0) { 1419 parse_table_init(unit, &pt); 1420 parse_table_add(&pt, "Mode", PQ_DFL|PQ_MULTI,0, &mode, cte_mode_list); 1421 if (parse_arg_eq(args, &pt) < 0) { 1422 parse_arg_eq_done(&pt); 1423 return CMD_USAGE; 1424 } 1425 atp_unregister(ECHO_BASE_CLI_ID + mode); 1426 parse_arg_eq_done(&pt); 1427 } else if (sal_strcasecmp(subcmd, "ECHO") == 0) { 1428 parse_table_init(unit, &pt); 1429 parse_table_add(&pt, "String", PQ_DFL|PQ_STRING, 0, &str, 0); 1430 parse_table_add(&pt, "MinLen", PQ_DFL|PQ_INT, 0, &minlen, 0); 1431 parse_table_add(&pt, "DEPTH", PQ_DFL|PQ_INT, 0, &depth, 0); 1432 parse_table_add(&pt, "Mode", PQ_DFL|PQ_MULTI,0, &mode, cte_mode_list); 1433 parse_table_add(&pt, "DestKey", PQ_DFL|PQ_KEY, 0, dest_key.key, 0); 1434 parse_table_add(&pt, "ALLOChdr", PQ_DFL|PQ_BOOL, 0, &alloc_hdr, 0); 1435 parse_table_add(&pt, "ASYNC", PQ_DFL|PQ_BOOL, 0, &async, 0); 1436 parse_table_add(&pt, "Verbose", PQ_DFL|PQ_BOOL, 0, &verbose, 0); 1437 parse_table_add(&pt, "Regen", PQ_DFL|PQ_BOOL, 0, &crc_regen, 0); 1438 parse_table_add(&pt, "Count", PQ_DFL|PQ_INT, 0, &count, 0); 1439 if (parse_arg_eq(args, &pt) < 0) { 1440 parse_arg_eq_done(&pt); 1441 return CMD_USAGE; 1442 } 1443 1444 if (alloc_hdr) { 1445 cte_flags |= CTE_FLAGS_ALLOC_HDR_HERE; 1446 } 1447 1448 if (verbose) { 1449 cte_flags |= CTE_FLAGS_VERBOSE; 1450 } 1451 1452 if (crc_regen) { 1453 cte_flags |= CTE_FLAGS_CRC_REGEN; 1454 } 1455 1456 if (async) { 1457 _ct_echo_async(unit, dest_key, str, depth, 1458 mode, cte_flags, minlen); 1459 } else { 1460 _ct_echo_sync(unit, dest_key, str, depth, 1461 mode, cte_flags, minlen, count); 1462 } 1463 parse_arg_eq_done(&pt); 1464 } else if (sal_strcasecmp(subcmd, "SPIN") == 0) { 1465 parse_table_init(unit, &pt); 1466 parse_table_add(&pt, "Count", PQ_DFL|PQ_INT, 0, &count, 0); 1467 if (parse_arg_eq(args, &pt) < 0) { 1468 parse_arg_eq_done(&pt); 1469 return CMD_USAGE; 1470 } 1471 while(count-->0); 1472 parse_arg_eq_done(&pt); 1473 } else { 1474 cli_out("Subcommand not found: %s\n", subcmd); 1475 return CMD_USAGE; 1476 } 1477 1478 1479 1480 return CMD_OK; 1481 } 1482 1483 #endif /* TKS libs included */