disc.c (127604B)
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: disc.c 8 * Purpose: Broadcom Discovery Algorithm 9 * Requires: 10 * 11 * The discovery procedure is run using next hop transmit only. 12 * It builds a local database with static variables, so it is 13 * not re-entrant. 14 * 15 * This version of discovery runs in the callers thread of 16 * execution. No async option is provided. 17 * 18 * We assume that a full probe packet can be sent in a packet 19 * that is returned by RX. Each probe entry takes less than 20 bytes, 20 * so a 1K buffer can hold 50 entries. 21 */ 22 23 #include <shared/bsl.h> 24 25 #include <sdk_config.h> 26 #include <assert.h> 27 28 #include <shared/alloc.h> 29 #include <sal/core/libc.h> 30 #include <sal/core/thread.h> 31 #include <sal/core/sync.h> 32 #include <sal/core/time.h> 33 34 #include <bcm/types.h> 35 #include <bcm/rx.h> 36 #include <bcm/error.h> 37 38 #include <appl/discover/disc.h> 39 #include <appl/cputrans/next_hop.h> 40 #include <appl/cputrans/cputrans.h> 41 #include <appl/cputrans/atp.h> 42 43 #include <appl/cpudb/cpudb.h> 44 45 #include "disc_int.h" 46 47 #ifndef DISC_COS_DEFAULT 48 #define DISC_COS_DEFAULT 0 49 #endif 50 51 #ifndef DISC_VLAN_DEFAULT 52 #define DISC_VLAN_DEFAULT 1 53 #endif 54 55 #ifndef DISC_THREAD_STACK 56 #define DISC_THREAD_STACK SAL_THREAD_STKSZ 57 #endif 58 59 #ifndef DISC_THREAD_PRIORITY 60 #define DISC_THREAD_PRIORITY 100 61 #endif 62 63 #define DISC_TASK (_disc_tid != SAL_THREAD_ERROR) 64 65 static volatile sal_thread_t _disc_tid = SAL_THREAD_ERROR; 66 67 typedef struct disc_callback_handler_s { 68 disc_cb_t callback; 69 void *user_data; 70 } disc_callback_handler_t; 71 72 typedef enum disc_task_cmd_e { 73 DISC_TASK_CMD_UNKNOWN, 74 DISC_TASK_CMD_RUN, 75 DISC_TASK_CMD_STOP 76 } disc_task_cmd_t; 77 78 typedef enum disc_status_e { 79 DISC_STATUS_INACTIVE, 80 DISC_STATUS_SYNC_RUNNING, 81 DISC_STATUS_TASK_RUNNING, 82 DISC_STATUS_TASK_IDLE 83 } disc_status_t; 84 85 #define DISC_TASK_SLEEP sal_sem_take(disc_task_sem, sal_sem_FOREVER) 86 #define DISC_TASK_WAKE sal_sem_give(disc_task_sem) 87 88 89 static int disc_cos = DISC_COS_DEFAULT; 90 static int disc_vlan = DISC_VLAN_DEFAULT; 91 92 /* Locks and synchronization, 93 * disc_lock Mutual exclusion for queues 94 * disc_sem Signal to main processing loop 95 * Macros: 96 * DISC_LOCK Take mutex 97 * DISC_UNLOCK Give mutex 98 * INIT_DONE See if discovery module init is complete 99 * DISC_INIT_CHECK if not initialized, attempt to init system. 100 */ 101 102 /* Thread and synchronization */ 103 static sal_mutex_t disc_lock; 104 static sal_sem_t disc_sem; 105 106 static int disc_version = DISCOVERY_VERSION_DEFAULT; 107 static int disc_fallback = TRUE; /* Indicates version auto-fallback */ 108 109 #define DISC_LOCK sal_mutex_take(disc_lock, sal_mutex_FOREVER) 110 #define DISC_UNLOCK sal_mutex_give(disc_lock) 111 #define DISC_SLEEP(_t) sal_sem_take(disc_sem, _t) 112 #define DISC_WAKE sal_sem_give(disc_sem) 113 114 #define INIT_DONE (disc_lock != NULL) 115 #define DISC_INIT_CHECK if (!INIT_DONE) BCM_IF_ERROR_RETURN(_disc_init()) 116 117 /**************************************************************** 118 * 119 * Local discovery configuration and active information 120 * disc_trans_ptr Low level transport driver 121 * disc_m_elect Master election function 122 * disc_timeout_us Overall timeout 123 * disc_cfg_to_us Set ports that have not received 124 * probe packets as inactive 125 * disc_retrx_us Retransmit timeout 126 * disc_retrx_min_us Min time between pkts out 127 * 128 * Macros 129 * LOCAL_KEY(db_ref) Local CPU entry's DB key 130 * LOCAL_MAC(db_ref) Local CPU entry's MAC address 131 * LOCAL_FLAGS(db_ref) Local CPU entry's flags 132 * STKP_UNIT(db_ref, i) Local CPU entry's unit for stack port [i] 133 * STKP_PORT(db_ref, i) Local CPU entry's port for stack port [i] 134 * STK_PORT(db_ref, i) Local CPU entry's stack port [i] (flags, etc) 135 * STK_FLAGS(db_ref, i) Flags for local stack port i 136 */ 137 138 STATIC int disc_m_elect_default(cpudb_ref_t db_ref, void *user_data); 139 140 /* The database reference to use */ 141 static bcm_trans_ptr_t *disc_trans_ptr = TRANS_PTR_DEFAULT; 142 143 static volatile int disc_timeout_us = DISC_TIMEOUT_DEFAULT; 144 static volatile int disc_cfg_to_us = DISC_CFG_TO_DEFAULT; 145 static volatile int disc_retrx_us = DISC_RETRX_DEFAULT; 146 int disc_retrx_min_us = DISC_RETRX_MIN_DEFAULT; 147 static disc_election_cb_t disc_m_elect = disc_m_elect_default; 148 static disc_start_election_cb_t disc_start_elect = NULL; 149 static void *disc_m_user_data; 150 151 #define LOCAL_KEY(db_ref) (db_ref->local_entry->base.key) 152 #define LOCAL_MAC(db_ref) (db_ref->local_entry->base.mac) 153 #define LOCAL_FLAGS(db_ref) (db_ref->local_entry->flags) 154 155 #define STKP_UNIT(db_ref, i) (db_ref->local_entry->base.stk_ports[i].unit) 156 #define STKP_PORT(db_ref, i) (db_ref->local_entry->base.stk_ports[i].port) 157 158 /* Stack port info other than unit/port */ 159 #define STK_PORT(db_ref, i) (db_ref->local_entry->sp_info[i]) 160 #define STK_FLAGS(db_ref, i) STK_PORT(db_ref, i).flags 161 162 #define DATA_SALLOC(size) atp_tx_data_alloc(size) 163 #define DATA_SFREE(ptr) atp_tx_data_free(ptr) 164 165 #define DISC_TTL_FULL_DUPLEX 2 /* full duplex TTL */ 166 167 /* 168 * If disc_ttl is enabled (> 0), then TTL is sent and examined in probe 169 * packets. 170 * 171 * The TTL increased each time "send init info" is called up to 172 * disc_ttl_max. 173 */ 174 175 uint8 disc_ttl_min = DISC_TTL_MIN_DEFAULT; 176 uint8 disc_ttl_max = DISC_TTL_MAX_DEFAULT; 177 uint8 disc_ttl; 178 179 /* Discovery packet rate limiting 180 181 Large numbers of stack ports can easily overwhelm the Next Hop 182 protocol, which has a limited capacity to detect stale packets. Rate 183 limiting the transmission of probe and route packets helps keep the 184 Next Hop protocol working correctly. 185 186 Define DISC_PPS <= 0 to disable discovery packet rate limiting. 187 188 */ 189 190 #ifndef DISC_PPS 191 #define DISC_PPS 100 192 #endif 193 194 #if DISC_PPS > 0 195 static int disc_tx_init; 196 static sal_usecs_t disc_tx_prev; 197 #endif 198 199 /**************************************************************** 200 * 201 * Discovery packet coordination 202 * 203 * Packet structure to maintain info about packet until serviced 204 * in discovery thread. 205 * 206 * Probe and routing packet queues. 207 */ 208 209 /* 210 * This is used for queuing probe and routing packets 211 * The queues are very simple. We either add one entry, or remove 212 * all entries in the queue at once; so it can be an array with 213 * a length. 214 */ 215 216 typedef struct disc_pkt_s disc_pkt_t; 217 struct disc_pkt_s { 218 cpudb_key_t src_key; 219 uint8* pkt_buf; 220 uint8* data; 221 int len; 222 int rx_unit, rx_port; 223 }; 224 225 #ifndef DISC_PKTS_MAX 226 #define DISC_PKTS_MAX 32 /* Max packets allowed queued at a time */ 227 #endif 228 229 230 static disc_pkt_t probe_pkt_queue[DISC_PKTS_MAX]; 231 static volatile int probe_pkt_count; 232 233 static disc_pkt_t routing_pkt_queue[DISC_PKTS_MAX]; 234 static volatile int routing_pkt_count; 235 236 /* Output packets */ 237 static uint8 *route_pkt_buf[ROUTE_PKTS_MAX]; 238 static int route_pkt_len[ROUTE_PKTS_MAX]; 239 240 /* 241 * To handle ports that have link, but on which there is no 242 * activity, a check is made of whether a probe packet has been 243 * seen on the port since the beginning of discovery. If none 244 * has been seen for a given amount of time, the port will be 245 * marked inactive and ignored for the rest of the processing. 246 * If discovery then completes successfully, those ports will be 247 * marked as "no-link". 248 * 249 * probe_pkt_seen is a bit-map indexed by local stack port index. 250 */ 251 static uint32 probe_pkt_seen[_SHR_BITDCLSIZE(CPUDB_STK_PORTS_MAX)]; 252 253 #define PP_SEEN_GET(n) SHR_BITGET(probe_pkt_seen, n) 254 #define PP_SEEN_SET(n) SHR_BITSET(probe_pkt_seen, n) 255 #define PP_SEEN_CLR(n) SHR_BITCLR(probe_pkt_seen, n) 256 #define PP_SEEN_ZERO sal_memset(probe_pkt_seen, 0, \ 257 SHR_BITALLOCSIZE(CPUDB_STK_PORTS_MAX)) 258 259 /**************************************************************** 260 * 261 * State 262 * disc_flags 263 * Divided into transient and non-transient flags. 264 * Transient flags are reset when starting. 265 * SETUP_DONE disc_setup has been called. 266 * DISC_RUNNING Discovery thread is running. 267 * DISC_ABORT Terminate discovery 268 * ABORT_ACK Respond that ACK seen 269 * DISC_ERROR An error occurred, terminating discovery 270 * DISC_TIMEOUT Discovery timed out (implies error) 271 * DB_UPDATED Local DB has been changed. 272 * INFO_IN Enough info is in to send routing pkts 273 * can be sent 274 * PROBE_SEND Force probe packets to be sent the 275 * next cycle; used by restart. 276 * RESTART Request controlling application 277 * restart discovery with same sequence 278 * number 279 * RESTART_DSEQ_NUM Request controlling application 280 * restart discovery with a new sequence 281 * number 282 * TX_KNOWN Some TX is known; this indicates 283 * we can send out routing pkts 284 * 285 * disc_start_time When did discovery start 286 * disc_tx_pkt_err Counter: TX errors 287 * disc_rx_pkt_err Counter: RX processing errors 288 * disc_alloc_fail Counter: Memory (external) resource error 289 * disc_resource_err Counter: Internal resource error 290 * disc_external_err Counter: External resource error 291 * disc_internal_err Counter: Internal error 292 */ 293 294 volatile uint32 disc_flags; 295 #define DF_SETUP_DONE 0x1 296 #define DF_DISC_RUNNING 0x2 297 #define DF_DISC_ABORT 0x4 298 #define DF_ABORT_ACK 0x8 /* ACK that abort occurred */ 299 #define DF_DISC_ERROR 0x10 300 #define DF_DISC_TIMEOUT 0x20 301 #define DF_DB_UPDATED 0x40 302 #define DF_INFO_IN 0x80 303 #define DF_DISC_SUCCESS 0x100 304 #define DF_TX_KNOWN 0x200 305 #define DF_IGNORE_PACKETS 0x400 306 #define DF_SEND_CFG_PKT 0x800 307 #define DF_CFG_PKT_SENT 0x1000 308 309 /* On abort, return value to use is saved here */ 310 static volatile int disc_abort_rv; 311 312 #define DISC_EXIT_FLAGS \ 313 (DF_DISC_ERROR | DF_DISC_ABORT | DF_DISC_TIMEOUT | DF_DISC_SUCCESS) 314 315 #define DISC_EXIT (disc_flags & DISC_EXIT_FLAGS) 316 317 /* When did discovery start; will restart if timeout_set is called */ 318 static volatile sal_usecs_t disc_start_time; 319 static volatile sal_usecs_t disc_last_probe_time; 320 static volatile sal_usecs_t disc_last_route_time; 321 322 #define CUR_DSEQ_NUM(db_ref) (db_ref->local_entry->base.dseq_num) 323 324 /* Some counters */ 325 int disc_tx_pkt_err = 0; 326 int disc_rx_pkt_err = 0; 327 int disc_alloc_fail = 0; 328 int disc_resource_err = 0; 329 int disc_external_err = 0; 330 int disc_internal_err = 0; 331 int disc_tot_err = 0; 332 333 /* Will fail if this many total errors occurs. */ 334 335 #ifndef DISC_MAX_ERRORS 336 #define DISC_MAX_ERRORS 20 337 #endif 338 339 static cpudb_ref_t disc_task_db = NULL; 340 static disc_callback_handler_t _disc_callback; 341 static disc_task_cmd_t disc_task_cmd; 342 static sal_sem_t disc_task_sem; 343 static disc_status_t disc_stat = DISC_STATUS_INACTIVE; 344 static sal_mutex_t disc_status_lock; 345 346 /**************************************************************** 347 * 348 * Forward declarations 349 */ 350 351 STATIC bcm_rx_t disc_rx_pkt(cpudb_key_t src_key, int port_num, 352 int unit, int port, uint8 *pkt_buf, 353 int len, void *cookie); 354 STATIC int _disc_init(void); 355 356 STATIC int disc_prep(cpudb_ref_t db_ref); 357 STATIC void queues_clear(void); 358 STATIC cpudb_entry_t *_disc_key_resolve(cpudb_ref_t db_ref, 359 cpudb_key_t key, 360 bcm_mac_t mac, 361 int dseq_num); 362 363 STATIC int disc_done_check(cpudb_ref_t db_ref, int *rv, int unreg); 364 STATIC void disc_status_update(cpudb_ref_t db_ref); 365 366 STATIC void routing_pkts_send(cpudb_ref_t db_ref); 367 STATIC void routing_pkt_process(cpudb_ref_t db_ref, disc_pkt_t *routing_pkt); 368 STATIC void probe_pkt_process(cpudb_ref_t db_ref, disc_pkt_t *probe_pkt); 369 STATIC void probe_pkts_generate(cpudb_ref_t db_ref); 370 STATIC int _disc_run(cpudb_ref_t db_ref); 371 STATIC int disc_callout(cpudb_ref_t db_ref, int status); 372 373 374 /**************************************************************** 375 * 376 * Configuration functions for timeout, transport pointer and 377 * done callback function 378 */ 379 380 /* 381 * Function: 382 * disc_timeout_set/get 383 * Purpose: 384 * Set/get the overall timeout and retransmit times in us 385 * Parameters: 386 * timeout_us - Overall timeout in us (OUT for get) 387 * retrx_us - Retransmit timeout in us (OUT for get) 388 * Returns: 389 * BCM_E_XXX 390 * Notes: 391 * If either parameter is < 0 on set, it is ignored. 392 * The timeout or cfg timeout may be changed while running; 393 * in this case, (if timeout_us > 0) the start time is 394 * recalculated to the present time. 395 */ 396 397 int 398 disc_timeout_set(int timeout_us, int cfg_to_us, int retrx_us) 399 { 400 DISC_INIT_CHECK; 401 402 if (timeout_us >= 0) { 403 disc_timeout_us = timeout_us; 404 if (disc_flags & DF_DISC_RUNNING) { 405 disc_start_time = sal_time_usecs(); 406 } 407 } 408 409 if (cfg_to_us >= 0) { 410 disc_cfg_to_us = cfg_to_us; 411 if (disc_flags & DF_DISC_RUNNING) { 412 disc_start_time = sal_time_usecs(); 413 } 414 } 415 416 if (retrx_us >= 0) { 417 disc_retrx_us = retrx_us; 418 } 419 420 return BCM_E_NONE; 421 } 422 423 int 424 disc_timeout_get(int *timeout_us, int *cfg_to_us, int *retrx_us) 425 { 426 DISC_INIT_CHECK; 427 428 *timeout_us = disc_timeout_us; 429 *cfg_to_us = disc_cfg_to_us; 430 *retrx_us = disc_retrx_us; 431 432 return BCM_E_NONE; 433 } 434 435 /* 436 * Function: 437 * disc_(cos,vlan)_(set,get) 438 * Purpose: 439 * Set/get the COS and VLAN settings used by discovery 440 * Notes: 441 * The RX subsystem and chip COS configurations must be 442 * set up consistently with the values used here; similarly 443 * for the VLAN settings. 444 */ 445 446 int 447 disc_cos_set(int cos) 448 { 449 disc_cos = cos; 450 451 return BCM_E_NONE; 452 } 453 454 int 455 disc_cos_get(int *cos) 456 { 457 *cos = disc_cos; 458 459 return BCM_E_NONE; 460 } 461 462 int 463 disc_vlan_set(int vlan) 464 { 465 disc_vlan = vlan; 466 467 return BCM_E_NONE; 468 } 469 470 int 471 disc_vlan_get(int *vlan) 472 { 473 *vlan = disc_vlan; 474 475 return BCM_E_NONE; 476 } 477 478 /* 479 * Sets/gets the current discovery version used when sending 480 * discovery packets. 481 */ 482 int 483 disc_version_set(int version) 484 { 485 int rv = BCM_E_NONE; 486 487 switch (version) { 488 case DISCOVERY_VERSION_0: 489 case DISCOVERY_VERSION_1: 490 case DISCOVERY_VERSION_2: 491 disc_version = version; 492 break; 493 default: 494 rv = BCM_E_PARAM; 495 break; 496 } 497 498 return rv; 499 } 500 501 int 502 disc_version_get(int *version) 503 { 504 if (version != NULL) { 505 *version = disc_version; 506 } 507 508 return BCM_E_NONE; 509 } 510 511 /* 512 * Enables/disables discovery version auto fallback. 513 * 514 * When set, the current discovery version is set back 515 * to the received discovery version (lower) in case of a discovery 516 * version mismatch. 517 */ 518 int 519 disc_fallback_set(int enable) 520 { 521 if (enable) { 522 disc_fallback = TRUE; 523 } else { 524 disc_fallback = FALSE; 525 } 526 return BCM_E_NONE; 527 } 528 529 int 530 disc_fallback_get(int *enable) 531 { 532 if (enable != NULL) { 533 *enable = disc_fallback; 534 } 535 536 return BCM_E_NONE; 537 } 538 539 540 541 /* 542 * Function: 543 * disc_trans_ptr_set/get 544 * Purpose: 545 * Set/get the transport pointer used by discovery 546 * Parameters: 547 * trans_ptr - (OUT for "get") Pointer to table of drivers 548 * Returns: 549 * BCM_E_XXX 550 * Notes: 551 * trans_ptr may be NULL on get. 552 */ 553 554 int 555 disc_trans_ptr_set(bcm_trans_ptr_t *trans_ptr) 556 { 557 if (trans_ptr == NULL) { 558 return BCM_E_PARAM; 559 } 560 561 disc_trans_ptr = trans_ptr; 562 return BCM_E_NONE; 563 } 564 565 int 566 disc_trans_ptr_get(bcm_trans_ptr_t **trans_ptr) 567 { 568 if (trans_ptr != NULL) { 569 *trans_ptr = disc_trans_ptr; 570 } 571 return BCM_E_NONE; 572 } 573 574 575 /* 576 * Function: 577 * disc_ttl_min/max_set/get 578 * Purpose: 579 * Set/get the probe minimum and maximum TTL 580 * Parameters: 581 * min_ttl - Minimum TTL (OUT for get) 582 * max_ttl - Maximum TTL (OUT for get) 583 * Returns: 584 * BCM_E_XXX 585 * Notes: 586 * If either parameter is less than DISC_TTL_MIN_DEFAULT, 587 * then the corresponding value will not be set, and return 588 * BCM_E_PARAM. 589 */ 590 591 int 592 disc_ttl_min_set(int ttl_min) 593 { 594 int rv = BCM_E_NONE; 595 596 if (ttl_min >= DISC_TTL_MIN_DEFAULT) { 597 disc_ttl_min = ttl_min; 598 } else { 599 rv = BCM_E_PARAM; 600 } 601 602 return rv; 603 } 604 605 int 606 disc_ttl_min_get(int *ttl_min) 607 { 608 if (ttl_min) { 609 *ttl_min = disc_ttl_min; 610 } 611 612 return BCM_E_NONE; 613 } 614 615 616 int 617 disc_ttl_max_set(int ttl_max) 618 { 619 int rv = BCM_E_NONE; 620 621 if (ttl_max >= DISC_TTL_MIN_DEFAULT) { 622 disc_ttl_max = ttl_max; 623 } else { 624 rv = BCM_E_PARAM; 625 } 626 627 return rv; 628 } 629 630 int 631 disc_ttl_max_get(int *ttl_max) 632 { 633 if (ttl_max) { 634 *ttl_max = disc_ttl_max; 635 } 636 637 return BCM_E_NONE; 638 } 639 640 641 #if defined(BROADCOM_DEBUG) 642 int _check_start_values(cpudb_ref_t db_ref) 643 { 644 645 if (!cpudb_valid(db_ref)) { 646 LOG_ERROR(BSL_LS_TKS_DISCOVER, 647 (BSL_META("disc ERR: Bad DB reference\n"))); 648 return BCM_E_PARAM; 649 } 650 651 if (db_ref->local_entry == NULL) { 652 LOG_ERROR(BSL_LS_TKS_DISCOVER, 653 (BSL_META("disc ERR: Can't find local DB entry\n"))); 654 return BCM_E_PARAM; 655 } 656 657 if (disc_retrx_min_us >= disc_retrx_us) { 658 LOG_ERROR(BSL_LS_TKS_DISCOVER, 659 (BSL_META("disc ERR: retrx mis-configuration. min %d max %d\n"), 660 disc_retrx_min_us, disc_retrx_us)); 661 return BCM_E_PARAM; 662 } 663 664 if (db_ref->local_entry->base.num_units < 0 || 665 db_ref->local_entry->base.dest_port < 0 || 666 db_ref->local_entry->base.dest_unit < 0) { 667 LOG_WARN(BSL_LS_TKS_DISCOVER, 668 (BSL_META("disc WARN: Bad local DB info\n"))); 669 } 670 671 if (disc_ttl_min == 1 && disc_ttl_max == 1) { 672 LOG_WARN(BSL_LS_TKS_DISCOVER, 673 (BSL_META("DISC WARN: TTL min == max == 1. Discovery will fail\n"))); 674 } 675 676 return BCM_E_NONE; 677 } 678 #endif /* BROADCOM_DEBUG */ 679 680 681 /**************************************************************** 682 * 683 * Setup, start and abort functions 684 */ 685 686 /* Get internal Discovery subsystem status */ 687 STATIC int 688 disc_status_get(disc_status_t *status) 689 { 690 int rv = BCM_E_PARAM; 691 692 if (status) { 693 sal_mutex_take(disc_status_lock, sal_mutex_FOREVER); 694 *status = disc_stat; 695 sal_mutex_give(disc_status_lock); 696 rv = BCM_E_NONE; 697 } 698 699 return rv; 700 } 701 702 #define STEAL_QUEUE(_q, _cnt, _dest_q, _dest_cnt) \ 703 do { \ 704 int _bytes; \ 705 DISC_LOCK; \ 706 _bytes = (_cnt) * sizeof(disc_pkt_t); \ 707 sal_memcpy(_dest_q, _q, _bytes); \ 708 sal_memset(_q, 0, _bytes); \ 709 _dest_cnt = _cnt; \ 710 _cnt = 0; \ 711 DISC_UNLOCK; \ 712 } while (0) 713 714 /* Temporary holding pen for handling a discovery queue. */ 715 static disc_pkt_t _proc_queue[DISC_PKTS_MAX]; 716 static volatile int _proc_count; 717 718 /* Handle incoming probe/routing pkts */ 719 720 static INLINE void 721 disc_incoming_pkts_process(cpudb_ref_t db_ref) 722 { 723 int i; 724 725 if (probe_pkt_count > 0) { /* Received probe pkts to forward */ 726 /* Steal then process the probe packets */ 727 STEAL_QUEUE(probe_pkt_queue, probe_pkt_count, 728 _proc_queue, _proc_count); 729 730 /* clear fowarded flag */ 731 for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) { 732 STK_FLAGS(db_ref, i) &= ~CPUDB_SPF_TX_FORWARDED; 733 } 734 735 for (i = 0; i < _proc_count; i++) { 736 probe_pkt_process(db_ref, &_proc_queue[i]); 737 if (DISC_EXIT) { 738 return; 739 } 740 } 741 } 742 743 if (routing_pkt_count > 0) { /* Received routing packet */ 744 /* Steal then process the probe packets */ 745 STEAL_QUEUE(routing_pkt_queue, routing_pkt_count, 746 _proc_queue, _proc_count); 747 748 for (i = 0; i < _proc_count; i++) { 749 routing_pkt_process(db_ref, &_proc_queue[i]); 750 if (DISC_EXIT) { 751 return; 752 } 753 } 754 } 755 } 756 757 #undef STEAL_QUEUE 758 759 /* 760 * Function: 761 * disc_pkts_process 762 * Purpose: 763 * Handle any pending packets queued from RX; check for timeout. 764 * Returns: 765 * Boolean, TRUE => done; FALSE => continue 766 * Notes: 767 * Results of discovery are stored in disc_flags 768 */ 769 770 static INLINE void 771 disc_pkts_process(cpudb_ref_t db_ref) 772 { 773 sal_usecs_t cur_time; 774 int dt; 775 776 cur_time = sal_time_usecs(); 777 /* See if probe packets should be resent. */ 778 dt = SAL_USECS_SUB(cur_time, disc_last_probe_time); 779 if (dt < 0 || dt > disc_retrx_us) { 780 if (!(LOCAL_FLAGS(db_ref) & CPUDB_F_LOCAL_COMPLETE)) { 781 probe_pkts_generate(db_ref); /* send probes */ 782 } 783 disc_last_probe_time = cur_time; 784 } 785 786 if (DISC_EXIT) { 787 return; 788 } 789 790 /* Check for queued probe and routing pkts */ 791 disc_incoming_pkts_process(db_ref); 792 793 if (DISC_EXIT) { 794 return; 795 } 796 797 cur_time = sal_time_usecs(); 798 if (disc_flags & DF_INFO_IN) { /* Have info for routing pkts too */ 799 /* 800 * IF (Never sent out rte pkt) OR 801 * (DB updated and min time elapsed) OR 802 * (retransmit timeout) 803 * THEN send route pkts 804 */ 805 dt = SAL_USECS_SUB(cur_time, disc_last_route_time); 806 if (disc_last_route_time == 0 || 807 ((disc_flags & DF_DB_UPDATED) && 808 (dt > disc_retrx_min_us)) || 809 (dt > disc_retrx_us) || 810 (dt < 0)) { /* Send out routing pkts */ 811 812 routing_pkts_send(db_ref); 813 disc_last_route_time = cur_time; 814 } 815 } 816 } 817 818 819 /* 820 * Function: 821 * disc_start 822 * Purpose: 823 * Start the discovery process 824 * Parameters: 825 * db_ref - The database reference to use; see notes 826 * m_elect - Master election callback (DEPRECATED) 827 * Returns: 828 * BCM_E_XXX 829 * Notes: 830 * If db_ref < 0, then a new DB is created and used. 831 * 832 * This routine is not re-entrant. 833 * 834 * The discovery sequence number will be extracted from the local 835 * CPU DB entry. 836 * 837 * Calling disc_election_register() to register an election function 838 * is preferred over passing the election function to disc_start(). 839 */ 840 int 841 disc_start(cpudb_ref_t db_ref, disc_start_election_cb_t m_elect) 842 { 843 disc_status_t status; 844 int rv; 845 846 BCM_IF_ERROR_RETURN(disc_status_get(&status)); 847 848 if (status != DISC_STATUS_INACTIVE) { 849 return BCM_E_BUSY; 850 } 851 852 if (m_elect != NULL) { 853 disc_start_elect = m_elect; 854 } 855 rv = _disc_run(db_ref); 856 857 return rv; 858 } 859 860 /* 861 * Low level init routine; set up sync objects 862 * Should only be called once. 863 */ 864 865 STATIC int 866 _disc_init(void) 867 { 868 int delay, retries; 869 int to; 870 871 /* Set up status lock */ 872 if (disc_status_lock != NULL) { 873 sal_mutex_destroy(disc_status_lock); 874 } 875 876 disc_status_lock = sal_mutex_create("discstatus"); 877 if (disc_status_lock == NULL) { 878 return BCM_E_MEMORY; 879 } 880 881 882 /* Set up mutex */ 883 if (disc_lock != NULL) { 884 sal_mutex_destroy(disc_lock); 885 disc_lock = NULL; 886 } 887 888 disc_lock = sal_mutex_create("discovery"); 889 if (disc_lock == NULL) { 890 sal_mutex_destroy(disc_status_lock); 891 return BCM_E_MEMORY; 892 } 893 894 /* Set up disc_sem */ 895 if (disc_sem != NULL) { 896 sal_sem_destroy(disc_sem); 897 } 898 899 disc_sem = sal_sem_create("disc_sem", sal_sem_BINARY, 0); 900 if (disc_sem == NULL) { 901 sal_mutex_destroy(disc_lock); 902 sal_mutex_destroy(disc_status_lock); 903 disc_lock = NULL; 904 return BCM_E_MEMORY; 905 } 906 907 /* Initialize time out based on ATP settings */ 908 atp_timeout_get(&delay, &retries); 909 to = delay * (retries + 1); 910 if (to > DISC_TIMEOUT_DEFAULT) { 911 disc_timeout_us = to; 912 } 913 914 return BCM_E_NONE; 915 } 916 917 918 919 /* 920 * Function: 921 * disc_abort 922 * Purpose: 923 * Request discovery exit with possible restart 924 * Parameters: 925 * disc_rv - Value discovery should return on exit 926 * timeout - if > 0, us to wait for "running" flag to clear 927 * before returning fail 928 * Returns: 929 * BCM_E_NONE if "running" flag clears before timeout 930 * BCM_E_FAIL if "running" flag still set after timeout 931 */ 932 933 int 934 disc_abort(int disc_rv, int timeout_us) 935 { 936 int i; 937 int retries; 938 int rv = BCM_E_NONE; 939 940 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 941 (BSL_META("DISC abort: RV %d, to %d\n"), 942 disc_rv, 943 timeout_us)); 944 945 DISC_LOCK; 946 disc_abort_rv = disc_rv; 947 disc_flags &= ~DF_ABORT_ACK; 948 disc_flags |= DF_DISC_ABORT; 949 950 if (!(disc_flags & DF_DISC_RUNNING)) { 951 DISC_UNLOCK; 952 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 953 (BSL_META("DISC abort: not running\n"))); 954 return BCM_E_NONE; 955 } 956 DISC_UNLOCK; 957 958 DISC_WAKE; 959 960 if (timeout_us > 0) { /* Block until restart noted */ 961 retries = timeout_us/10000 + 1; /* At least 1. */ 962 963 /* Wait for exit */ 964 for (i = 0; i < retries; i++) { 965 if (disc_flags & DF_ABORT_ACK) { 966 break; 967 } 968 sal_usleep(10000); 969 } 970 971 if (!(disc_flags & DF_ABORT_ACK)) { 972 LOG_WARN(BSL_LS_TKS_DISCOVER, 973 (BSL_META("DISC WARN: Discovery did not exit in " 974 "%d us\n"), timeout_us)); 975 rv = BCM_E_FAIL; 976 } 977 } 978 979 return rv; 980 } 981 982 983 /* Prepare local variables and send out initial pkts for discovery. 984 Assumes lock held. 985 */ 986 987 STATIC int 988 disc_prep(cpudb_ref_t db_ref) 989 { 990 int rv; 991 int i; 992 993 /* Make sure routing packets are allocated */ 994 for (i = 0; i < ROUTE_PKTS_MAX; i++) { 995 if (route_pkt_buf[i] == NULL) { 996 route_pkt_buf[i] = DATA_SALLOC(ROUTE_PKT_BYTES_MAX); 997 if (route_pkt_buf[i] == NULL) { 998 LOG_WARN(BSL_LS_TKS_DISCOVER, 999 (BSL_META("disc WARN: Route pkt alloc %d\n"), 1000 i)); 1001 return BCM_E_MEMORY; 1002 } 1003 } 1004 } 1005 1006 1007 1008 #if defined(BROADCOM_DEBUG) 1009 if (CPUDB_ENTRY_COUNT_GET(db_ref) > 1) { 1010 LOG_WARN(BSL_LS_TKS_DISCOVER, 1011 (BSL_META("disc WARN: Local DB has > 1 entry\n"))); 1012 } 1013 #endif /* BROADCOM_DEBUG */ 1014 1015 /* Init error counters */ 1016 disc_tx_pkt_err = disc_rx_pkt_err = 0; 1017 disc_resource_err = disc_internal_err = disc_tot_err = 0; 1018 1019 /* Ignore packets (and let them drain) for the first sleep interval */ 1020 disc_flags |= DF_IGNORE_PACKETS; 1021 1022 if (!next_hop_running()) { 1023 nh_tx_local_mac_set(LOCAL_MAC(db_ref)); 1024 rv = next_hop_start(&db_ref->local_entry->base); 1025 if (BCM_FAILURE(rv)) { 1026 LOG_WARN(BSL_LS_TKS_DISCOVER, 1027 (BSL_META("disc WARN: Error starting next hop\n"))); 1028 disc_flags |= DF_DISC_ERROR; 1029 return rv; 1030 } 1031 } 1032 1033 /* Set up initial state */ 1034 PP_SEEN_ZERO; /* Clear out stack port markings */ 1035 disc_ttl = disc_ttl_min; 1036 disc_last_probe_time = disc_start_time = sal_time_usecs(); 1037 disc_last_route_time = 0; /* Signal not yet sent */ 1038 #if DISC_PPS > 0 1039 disc_tx_init = 0; 1040 #endif 1041 1042 /* Initialize discovery flags, but preserve ABORT_ACK */ 1043 if (disc_flags & DF_ABORT_ACK) { 1044 disc_flags = DF_DISC_RUNNING | DF_SETUP_DONE | DF_ABORT_ACK; 1045 } else { 1046 disc_flags = DF_DISC_RUNNING | DF_SETUP_DONE; 1047 } 1048 1049 return BCM_E_NONE; 1050 } 1051 1052 /* Clean up discovery on exit; does not deallocate or do final cleanup */ 1053 1054 STATIC void 1055 queues_clear(void) 1056 { 1057 int i; 1058 disc_pkt_t *pkt; 1059 1060 /* Clean up any packets in receive queues */ 1061 for (i = 0; i < DISC_PKTS_MAX; i++) { 1062 pkt = &probe_pkt_queue[i]; 1063 if (pkt->pkt_buf != NULL) { 1064 bcm_rx_free(pkt->rx_unit, pkt->pkt_buf); 1065 pkt->pkt_buf = NULL; 1066 } 1067 } 1068 probe_pkt_count = 0; 1069 sal_memset(probe_pkt_queue, 0, sizeof(disc_pkt_t) * DISC_PKTS_MAX); 1070 1071 for (i = 0; i < DISC_PKTS_MAX; i++) { 1072 pkt = &routing_pkt_queue[i]; 1073 if (pkt->pkt_buf != NULL) { 1074 bcm_rx_free(pkt->rx_unit, pkt->pkt_buf); 1075 pkt->pkt_buf = NULL; 1076 } 1077 } 1078 routing_pkt_count = 0; 1079 sal_memset(routing_pkt_queue, 0, sizeof(disc_pkt_t) * DISC_PKTS_MAX); 1080 1081 for (i = 0; i < DISC_PKTS_MAX; i++) { 1082 pkt = &_proc_queue[i]; 1083 if (pkt->pkt_buf != NULL) { 1084 bcm_rx_free(pkt->rx_unit, pkt->pkt_buf); 1085 pkt->pkt_buf = NULL; 1086 } 1087 } 1088 _proc_count = 0; 1089 sal_memset(_proc_queue, 0, sizeof(disc_pkt_t) * DISC_PKTS_MAX); 1090 } 1091 1092 /**************************************************************** 1093 * 1094 * Discovery packet handling 1095 */ 1096 STATIC int stk_entry_bytes_get(int version); 1097 STATIC int route_entry_bytes_get(int num_sp, int num_units, int version); 1098 1099 STATIC int probe_pkt_local_cpu_key(cpudb_ref_t db_ref, 1100 uint8 *buf, int entry_count); 1101 STATIC void probe_pkt_with_local_key(cpudb_ref_t db_ref, 1102 disc_pkt_t *probe_pkt, 1103 int local_idx, 1104 int entry_count); 1105 STATIC int stk_port_find(cpudb_ref_t db_ref, int unit, int port); 1106 STATIC void probe_pkt_forward(cpudb_ref_t db_ref, 1107 disc_pkt_t *probe_pkt, 1108 int entry_count, int rx_sp_idx, int fdo); 1109 STATIC int disc_config_send(cpudb_ref_t db_ref); 1110 1111 STATIC bcm_rx_t disc_config_pkt_handler(cpudb_key_t src_key, 1112 int client_id, 1113 bcm_pkt_t *pkt, 1114 uint8 *payload, 1115 int payload_len, 1116 void *cookie); 1117 STATIC int route_entry_process(uint8 *buf, cpudb_entry_t *entry, int version); 1118 1119 /* 1120 * The following routines returns the buffer size for 1121 * routing packet entry, as follows: 1122 * 1123 * Route-entry = Route-base + Stk-entries 1124 * Stk-entries = Stk-entry * num-stk-ports 1125 */ 1126 1127 /* Stack Entry */ 1128 STATIC int 1129 stk_entry_bytes_get(int version) 1130 { 1131 int bytes = 0; 1132 1133 switch (version) { 1134 case DISCOVERY_VERSION_0: 1135 bytes = STK_ENTRY_RX_IDX_OFS + sizeof(uint32); 1136 break; 1137 case DISCOVERY_VERSION_1: 1138 bytes = STK_ENTRY_BFLAGS_OFS + sizeof(uint32); 1139 break; 1140 case DISCOVERY_VERSION_2: 1141 default: 1142 bytes = STK_ENTRY_PORT_OFS + sizeof(uint32); 1143 break; 1144 } 1145 1146 return bytes; 1147 } 1148 1149 /* Route Entry */ 1150 STATIC int 1151 route_entry_bytes_get(int num_sp, int num_units, int version) 1152 { 1153 return (ROUTE_BASE_BYTES(num_units) + 1154 (num_sp * stk_entry_bytes_get(version))); 1155 } 1156 1157 STATIC void 1158 routing_pkt_process(cpudb_ref_t db_ref, disc_pkt_t *routing_pkt) 1159 { 1160 int entry_count; 1161 uint8 *buf; 1162 uint8 *buf_upper_limit; 1163 int i; 1164 cpudb_entry_t *entry; 1165 cpudb_key_t key; 1166 int bytes; 1167 int stk_count; 1168 int num_units; 1169 int src_dseq_num; 1170 int dseq_num; 1171 int version; 1172 1173 if (routing_pkt->pkt_buf == NULL) { 1174 ++disc_rx_pkt_err; 1175 ++disc_tot_err; 1176 return; 1177 } 1178 if (routing_pkt->len == 0) { 1179 ++disc_rx_pkt_err; 1180 ++disc_tot_err; 1181 bcm_rx_free(routing_pkt->rx_unit, routing_pkt->pkt_buf); 1182 routing_pkt->pkt_buf = NULL; 1183 return; 1184 } 1185 1186 /* buf points to start of disc packet */ 1187 buf = routing_pkt->pkt_buf + CPUTRANS_HEADER_BYTES; 1188 buf_upper_limit = routing_pkt->pkt_buf + routing_pkt->len; 1189 entry_count = (int)(buf[ENTRY_COUNT_OFS]); 1190 UNPACK_LONG(&buf[SRC_DSEQ_NUM_OFS], src_dseq_num); 1191 version = buf[DISC_VER_OFS]; 1192 buf += DISC_HEADER_BYTES; 1193 1194 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1195 (BSL_META("disc: Processing rte pkt\n"))); 1196 1197 /* If src is not in DB or sequence numbers mismatch, discard pkt */ 1198 CPUDB_KEY_SEARCH(db_ref, routing_pkt->src_key, entry); 1199 if (entry == NULL) { 1200 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1201 (BSL_META("disc: Rte src key not found " CPUDB_KEY_FMT_EOLN), 1202 CPUDB_KEY_DISP(routing_pkt->src_key))); 1203 bcm_rx_free(routing_pkt->rx_unit, routing_pkt->pkt_buf); 1204 routing_pkt->pkt_buf = NULL; 1205 return; 1206 } 1207 if (entry->base.dseq_num != src_dseq_num) { 1208 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1209 (BSL_META("disc: Rte src dseq num mismatch; pkt %d, db %d.\n"), 1210 src_dseq_num, entry->base.dseq_num)); 1211 bcm_rx_free(routing_pkt->rx_unit, routing_pkt->pkt_buf); 1212 routing_pkt->pkt_buf = NULL; 1213 return; 1214 } 1215 1216 for (i = 0; i < entry_count; i++) { 1217 1218 if (buf > buf_upper_limit) { 1219 ++disc_rx_pkt_err; 1220 ++disc_tot_err; 1221 break; 1222 } 1223 1224 /* 1225 * Get entry CPU key and discovery sequence number 1226 * 1227 * It is possible for a routing packet to arrive sooner 1228 * than a probe packet for a given remote CPU. In this case, 1229 * the entry for the CPU will be created. 1230 * 1231 * The CPU entry must contain the correct discovery 1232 * sequence number to avoid sequence mismatch. 1233 */ 1234 CPUDB_KEY_UNPACK(buf, key); 1235 UNPACK_LONG(&buf[ROUTE_DSEQ_NUM_OFS], dseq_num); 1236 1237 /* Add entry to DB if not already present. */ 1238 entry = _disc_key_resolve(db_ref, key, &buf[ROUTE_MAC_OFS], dseq_num); 1239 1240 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1241 (BSL_META("disc: Rte entry %p key " CPUDB_KEY_FMT_EOLN), 1242 entry, CPUDB_KEY_DISP(key))); 1243 if (entry == NULL || entry == db_ref->local_entry) { 1244 UNPACK_LONG(&buf[ROUTE_NUM_UNITS_OFS], num_units); 1245 UNPACK_LONG(&buf[ROUTE_STK_COUNT_OFS], stk_count); 1246 buf += route_entry_bytes_get(stk_count, num_units, version); 1247 continue; 1248 } 1249 1250 bytes = route_entry_process(buf, entry, version); 1251 if (bytes < 0) { 1252 ++disc_rx_pkt_err; 1253 ++disc_tot_err; 1254 break; 1255 } 1256 buf += bytes; 1257 } 1258 1259 bcm_rx_free(routing_pkt->rx_unit, routing_pkt->pkt_buf); 1260 routing_pkt->pkt_buf = NULL; 1261 } 1262 1263 STATIC int 1264 disc_done_check(cpudb_ref_t db_ref, int *rv, int unreg) 1265 { 1266 sal_usecs_t cur_time; 1267 int done = TRUE; 1268 int dt; 1269 1270 cur_time = sal_time_usecs(); 1271 1272 dt = SAL_USECS_SUB(cur_time, disc_start_time); 1273 DISC_LOCK; 1274 if (disc_flags & DF_DISC_ERROR) { /* Error occurred */ 1275 *rv = BCM_E_FAIL; 1276 } else if (disc_flags & DF_DISC_SUCCESS) { /* Completed successfully */ 1277 *rv = BCM_E_NONE; 1278 } else if (disc_flags & DF_DISC_ABORT) { /* Exit forced */ 1279 *rv = disc_abort_rv; 1280 } else if (dt < 0 || dt > disc_timeout_us) { 1281 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1282 (BSL_META("disc ERR: Timeout occurred\n"))); 1283 disc_flags |= DF_DISC_TIMEOUT | DF_DISC_ERROR; 1284 *rv = BCM_E_TIMEOUT; 1285 } else if (disc_tot_err >= DISC_MAX_ERRORS) { 1286 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1287 (BSL_META("disc ERR: Error limit exceeded\n"))); 1288 *rv = BCM_E_FAIL; 1289 } else { 1290 done = FALSE; 1291 } 1292 1293 if (done) { 1294 /* Clear the running/abort flags for future calls */ 1295 disc_flags &= ~DF_DISC_RUNNING; 1296 queues_clear(); 1297 } 1298 1299 DISC_UNLOCK; 1300 1301 if (unreg && done) { 1302 /* Unregister callbacks */ 1303 next_hop_unregister(disc_rx_pkt, DISC_NH_PKT_TYPE); 1304 } 1305 1306 return done; 1307 } 1308 1309 1310 STATIC INLINE int 1311 all_stk_entries_resolved(cpudb_ref_t db_ref) 1312 { 1313 cpudb_entry_t *key_entry, *entry; 1314 int stk_idx; 1315 uint32 flags; 1316 1317 CPUDB_FOREACH_ENTRY(db_ref, entry) { 1318 if (entry->base.num_stk_ports <= 0 && entry != db_ref->local_entry) { 1319 /* Haven't gotten routing info on this non-local entry yet. */ 1320 return FALSE; 1321 } 1322 for (stk_idx = 0; stk_idx < entry->base.num_stk_ports; 1323 stk_idx++) { 1324 flags = entry->sp_info[stk_idx].flags; 1325 if (flags & CPUDB_SPF_NO_LINK || 1326 flags & CPUDB_SPF_INACTIVE || 1327 flags & CPUDB_SPF_ETHERNET) { 1328 continue; /* Ignore disabled ports */ 1329 } 1330 if (!(flags & CPUDB_SPF_TX_RESOLVED) || 1331 !(flags & CPUDB_SPF_RX_RESOLVED)) { 1332 /* Missing info on this stack port */ 1333 return FALSE; 1334 } 1335 1336 /* 1337 * CPU keys can only be added by probe packets. It's 1338 * possible they're referenced by a stack port, but 1339 * have not been added to the local DB yet. 1340 */ 1341 CPUDB_KEY_SEARCH(db_ref, 1342 entry->sp_info[stk_idx].tx_cpu_key, key_entry); 1343 if (key_entry == NULL) { 1344 return FALSE; 1345 } 1346 CPUDB_KEY_SEARCH(db_ref, 1347 entry->sp_info[stk_idx].rx_cpu_key, key_entry); 1348 if (key_entry == NULL) { 1349 return FALSE; 1350 } 1351 } 1352 } 1353 1354 return TRUE; 1355 } 1356 1357 /* Check for config timeout and if so, mark ports w/o PP_SEEN as inactive */ 1358 1359 static INLINE void 1360 inactive_ports_check(cpudb_ref_t db_ref) 1361 { 1362 cpudb_entry_t *lentry; 1363 sal_usecs_t cur_time; 1364 int stk_idx; 1365 int dt; 1366 1367 if (LOCAL_FLAGS(db_ref) & CPUDB_F_INACTIVE_MARKED) { 1368 return; 1369 } 1370 1371 cur_time = sal_time_usecs(); 1372 1373 dt = SAL_USECS_SUB(cur_time, disc_start_time); 1374 1375 /* 1376 * Run through local stack ports; if no probe packet seen on a 1377 * port w/i timeout, mark as inactive. 1378 */ 1379 if (dt < 0 || dt > disc_cfg_to_us) { 1380 lentry = db_ref->local_entry; 1381 for (stk_idx = 0; stk_idx < lentry->base.num_stk_ports; 1382 stk_idx++) { 1383 if (PP_SEEN_GET(stk_idx) == 0) { 1384 STK_FLAGS(db_ref, stk_idx) |= CPUDB_SPF_INACTIVE; 1385 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1386 (BSL_META("DISC: Marking SP %d inactive\n"), 1387 stk_idx)); 1388 } 1389 } 1390 LOCAL_FLAGS(db_ref) |= CPUDB_F_INACTIVE_MARKED; 1391 } 1392 } 1393 1394 1395 /* 1396 * Global flags for ATP config client; applications may make 1397 * this "no-ACK". This must be set before discovery (or stack 1398 * task) is started. 1399 */ 1400 uint32 disc_config_atp_flags = DISC_CONFIG_ATP_FLAGS_DEFAULT; 1401 1402 /* Set up ATP once local complete is known */ 1403 static INLINE void 1404 lc_atp_setup(cpudb_ref_t db_ref) 1405 { 1406 int rv; 1407 cpudb_entry_t *entry; 1408 1409 /* Register CONFIG client */ 1410 rv = atp_register(DISC_CONFIG_CLIENT_ID, disc_config_atp_flags, 1411 disc_config_pkt_handler, db_ref, disc_cos, disc_vlan); 1412 if (BCM_FAILURE(rv)) { 1413 LOG_WARN(BSL_LS_TKS_DISCOVER, 1414 (BSL_META("disc WARN: could not register cfg client\n"))); 1415 } 1416 1417 /* Make sure ATP knows about all keys in DB */ 1418 CPUDB_FOREACH_ENTRY(db_ref, entry) { 1419 if (entry != db_ref->local_entry) { 1420 atp_key_add(entry->base.key, 1421 entry->flags & CPUDB_F_IS_LOCAL); 1422 } 1423 } 1424 } 1425 1426 /* 1427 * The master entry in DB has been set (first time) 1428 * Do what needs to be done 1429 */ 1430 1431 static INLINE void 1432 master_is_set(cpudb_ref_t db_ref) 1433 { 1434 int rv; 1435 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1436 (BSL_META("Disc: Master is set to " CPUDB_KEY_FMT " w/ dseq num %d\n"), 1437 CPUDB_KEY_DISP(db_ref->master_entry->base.key), 1438 db_ref->master_entry->base.dseq_num)); 1439 if (db_ref->master_entry == db_ref->local_entry) { 1440 /* Send out config pkts */ 1441 rv = disc_config_send(db_ref); 1442 if (BCM_FAILURE(rv)) { 1443 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1444 (BSL_META("Disc ERR: cfg send returns %d: %s\n"), 1445 rv, bcm_errmsg(rv))); 1446 DISC_LOCK; 1447 disc_flags |= DF_DISC_ERROR; 1448 DISC_UNLOCK; 1449 } else { 1450 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1451 (BSL_META("Disc: master cfg pkts out sn %d\n"), 1452 db_ref->master_entry->base.dseq_num)); 1453 } 1454 } 1455 } 1456 1457 /* Local configuration is complete; continue */ 1458 static INLINE void 1459 local_complete_set(cpudb_ref_t db_ref) 1460 { 1461 /* If we get here, the local DB is complete; make callback */ 1462 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1463 (BSL_META("Disc: Local DB complete\n"))); 1464 LOCAL_FLAGS(db_ref) |= CPUDB_F_LOCAL_COMPLETE; 1465 1466 lc_atp_setup(db_ref); 1467 } 1468 1469 static INLINE void 1470 global_complete_set(cpudb_ref_t db_ref) 1471 { 1472 int rv; 1473 1474 LOCAL_FLAGS(db_ref) |= CPUDB_F_GLOBAL_COMPLETE; 1475 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1476 (BSL_META("Disc: All DB entries report complete\n"))); 1477 1478 if (db_ref->master_entry != NULL) { 1479 /* Assume this means that we're not the master. */ 1480 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1481 (BSL_META("DISC: Global done, but master known.\n"))); 1482 } 1483 1484 /* Attempt to elect master. If the old election callback interface 1485 is present, use the old one, otherwise use the new one. */ 1486 if (disc_start_elect) { 1487 rv = disc_start_elect(db_ref); 1488 } else { 1489 rv = disc_m_elect(db_ref, disc_m_user_data); 1490 } 1491 if (rv != BCM_E_NONE) { 1492 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1493 (BSL_META("Disc: Master elect returns %d causing abort: %s\n"), 1494 rv, rv == DISC_RESTART_NEW_SEQ ? "Restarting" : 1495 bcm_errmsg(rv))); 1496 DISC_LOCK; 1497 disc_flags |= DF_DISC_ABORT; 1498 disc_abort_rv = rv; 1499 DISC_UNLOCK; 1500 } else if (db_ref->master_entry == NULL) { 1501 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1502 (BSL_META("Disc WARN: Global done; no master\n"))); 1503 } else { 1504 master_is_set(db_ref); 1505 } 1506 } 1507 1508 /* 1509 * Check for completed discovery and set flags appropriately 1510 * Updates local CPU flags when all other CPUs indicate disc done 1511 */ 1512 1513 STATIC void 1514 disc_status_update(cpudb_ref_t db_ref) 1515 { 1516 cpudb_entry_t *entry; 1517 int rv, flags = 0; 1518 1519 /* First, see if cfg pkt should go out; if so, discovery done */ 1520 if ((disc_flags & DF_SEND_CFG_PKT) && 1521 !(disc_flags & DF_CFG_PKT_SENT)) { 1522 rv = disc_config_send(db_ref); 1523 if (BCM_FAILURE(rv)) { 1524 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1525 (BSL_META("DISC: Failed to respond with cfg pkt: %s\n"), 1526 bcm_errmsg(rv))); 1527 } else { 1528 flags |= DF_DISC_SUCCESS; 1529 } 1530 1531 flags |= DF_CFG_PKT_SENT; 1532 1533 if (flags & DF_DISC_SUCCESS) { 1534 DISC_LOCK; 1535 disc_flags |= flags; 1536 DISC_UNLOCK; 1537 return; 1538 } 1539 } 1540 1541 /* Look for configuration timeout; mark inactive ports */ 1542 inactive_ports_check(db_ref); 1543 1544 if (!(LOCAL_FLAGS(db_ref) & CPUDB_F_LOCAL_COMPLETE)) { 1545 /* Run through all stack ports in CPUDB and see if resolved */ 1546 if (!all_stk_entries_resolved(db_ref)) { 1547 return; /* Nope, continue processing */ 1548 } 1549 /* All info in DB is resolved. Set local complete */ 1550 local_complete_set(db_ref); 1551 } 1552 1553 if (!(LOCAL_FLAGS(db_ref) & CPUDB_F_GLOBAL_COMPLETE)) { 1554 /* Now check whether every CPU entry has local complete set */ 1555 CPUDB_FOREACH_ENTRY(db_ref, entry) { 1556 if (!(entry->flags & CPUDB_F_LOCAL_COMPLETE)) { 1557 return; 1558 } 1559 } 1560 global_complete_set(db_ref); 1561 } else if (db_ref->local_entry == db_ref->master_entry) { 1562 /* See if all (other) CPUs have responded with cfg pkt ACKs. */ 1563 CPUDB_FOREACH_ENTRY(db_ref, entry) { 1564 if (entry == db_ref->master_entry) { 1565 continue; 1566 } 1567 if (!(entry->flags & CPUDB_F_CONFIG_IN)) { 1568 return; 1569 } 1570 } 1571 1572 /* All CPU entries have indicated they accept the configuration */ 1573 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1574 (BSL_META("DISC: All DB entries accept config.\n"))); 1575 flags |= DF_DISC_SUCCESS; 1576 DISC_LOCK; 1577 disc_flags |= flags; 1578 DISC_UNLOCK; 1579 } 1580 } 1581 1582 /* Check if a local port is duplex; if so, tell next hop */ 1583 #define CHECK_IS_DUPLEX(db_ref, sp) \ 1584 if ((STK_FLAGS(db_ref, sp) & CPUDB_SPF_TX_RESOLVED) && \ 1585 (STK_FLAGS(db_ref, sp) & CPUDB_SPF_RX_RESOLVED) && \ 1586 (CPUDB_KEY_COMPARE(STK_PORT(db_ref, sp).rx_cpu_key, \ 1587 STK_PORT(db_ref, sp).tx_cpu_key) == 0)) do { \ 1588 STK_FLAGS(db_ref, sp) |= CPUDB_SPF_DUPLEX; \ 1589 next_hop_port_add(STKP_UNIT(db_ref, sp), \ 1590 STKP_PORT(db_ref, sp), TRUE); \ 1591 } while (0) 1592 1593 1594 /* 1595 * Set the RX/TX key if not already known; check for duplex 1596 * Also checks if "local config" already done; if this 1597 * occurred on a port that was assumed to be inactive, 1598 * discovery restart is required. 1599 */ 1600 1601 static INLINE int 1602 stk_port_rx_set(cpudb_ref_t db_ref, int sp, cpudb_key_t cpu_key, 1603 int remote_sp_idx, uint32 flags) 1604 { 1605 if (!(STK_FLAGS(db_ref, sp) & CPUDB_SPF_RX_RESOLVED)) { 1606 if (LOCAL_FLAGS(db_ref) & CPUDB_F_LOCAL_COMPLETE || 1607 STK_FLAGS(db_ref, sp) & CPUDB_SPF_INACTIVE) { 1608 /* Signal restart request to controlling application */ 1609 DISC_LOCK; 1610 disc_flags |= DF_DISC_ABORT; 1611 disc_abort_rv = DISC_RESTART_NEW_SEQ; 1612 DISC_UNLOCK; 1613 return -1; 1614 } 1615 CPUDB_KEY_COPY(STK_PORT(db_ref, sp).rx_cpu_key, (cpu_key)); 1616 STK_PORT(db_ref, sp).rx_stk_idx = (int)(remote_sp_idx); 1617 STK_FLAGS(db_ref, sp) |= CPUDB_SPF_RX_RESOLVED | (flags); 1618 DISC_LOCK; 1619 disc_flags |= DF_DB_UPDATED; 1620 DISC_UNLOCK; 1621 CHECK_IS_DUPLEX(db_ref, sp); 1622 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1623 (BSL_META("disc: Set RX for sp %d\n"), 1624 sp)); 1625 } 1626 1627 return 0; 1628 } 1629 1630 /* Set the TX key if not already known; check for duplex */ 1631 static INLINE int 1632 stk_port_tx_set(cpudb_ref_t db_ref, int sp, cpudb_key_t cpu_key, 1633 int remote_sp_idx, uint32 flags) 1634 { 1635 if (!(STK_FLAGS(db_ref, sp) & CPUDB_SPF_TX_RESOLVED)) { 1636 if (LOCAL_FLAGS(db_ref) & CPUDB_F_LOCAL_COMPLETE || 1637 STK_FLAGS(db_ref, sp) & CPUDB_SPF_INACTIVE) { 1638 /* Signal restart request to controlling application */ 1639 DISC_LOCK; 1640 disc_flags |= DF_DISC_ABORT; 1641 disc_abort_rv = DISC_RESTART_NEW_SEQ; 1642 DISC_UNLOCK; 1643 return -1; 1644 } 1645 CPUDB_KEY_COPY(STK_PORT(db_ref, sp).tx_cpu_key, (cpu_key)); 1646 STK_PORT(db_ref, sp).tx_stk_idx = (int)(remote_sp_idx); 1647 STK_FLAGS(db_ref, sp) |= CPUDB_SPF_TX_RESOLVED | (flags); 1648 DISC_LOCK; 1649 disc_flags |= DF_DB_UPDATED | DF_TX_KNOWN; 1650 DISC_UNLOCK; 1651 CHECK_IS_DUPLEX(db_ref, sp); 1652 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1653 (BSL_META("disc: Set TX for sp %d\n"), 1654 sp)); 1655 } 1656 1657 return 0; 1658 } 1659 1660 1661 /* 1662 * Get the type out of a discovery packet. Does not check if it's 1663 * a discovery packet 1664 */ 1665 1666 int 1667 disc_pkt_type_get(uint8 *pkt_buf) 1668 { 1669 uint8 *data_start; 1670 1671 data_start = pkt_buf + CPUTRANS_HEADER_BYTES; 1672 return (int)data_start[LOCAL_PKT_TYPE_OFS]; 1673 } 1674 1675 1676 /* 1677 * Function: 1678 * disc_probe_pkt_new 1679 * Purpose: 1680 * Determine if pkt_buf holds a discovery packet with new 1681 * probe information. 1682 * Returns: 1683 * FALSE if not a new probe packet 1684 * TRUE if it is a new probe packet 1685 * Notes: 1686 * Should not be called when discovery is running 1687 * This is used by stack task to see if new info has 1688 * appeared and discovery should be restarted. 1689 */ 1690 1691 int 1692 disc_probe_pkt_new(cpudb_ref_t db_ref, cpudb_key_t src_key, uint8 *pkt_buf) 1693 { 1694 int pkt_type; 1695 uint8 *data_start, *entry_buf; 1696 cpudb_entry_t *entry; 1697 int i; 1698 cpudb_key_t key; 1699 int entry_count; 1700 int dseq_num; 1701 1702 /* First, is it a discovery probe packet */ 1703 /* pkt_buf points to start of packet */ 1704 data_start = pkt_buf + CPUTRANS_HEADER_BYTES; 1705 pkt_type = (int)data_start[LOCAL_PKT_TYPE_OFS]; 1706 1707 if (pkt_type != DISC_PKT_TYPE_PROBE) { 1708 return FALSE; /* Not a probe packet */ 1709 } 1710 1711 /* If no db, definitely a new packet */ 1712 if (db_ref == CPUDB_REF_NULL) { 1713 return TRUE; 1714 } 1715 1716 /* If new source key, it's a new packet */ 1717 CPUDB_KEY_SEARCH(db_ref, src_key, entry); 1718 if (entry == NULL) { 1719 return TRUE; 1720 } 1721 1722 entry_count = (int)(data_start[ENTRY_COUNT_OFS]); 1723 entry_buf = data_start + PROBE_ENTRY_OFS(0); 1724 1725 /* 1726 * If sequence number different, this is harder. For now only return if 1727 * greater than old seq num 1728 */ 1729 for (i = 0; i < entry_count; i++) { 1730 CPUDB_KEY_UNPACK(entry_buf, key); 1731 CPUDB_KEY_SEARCH(db_ref, key, entry); 1732 UNPACK_LONG(&entry_buf[PROBE_DSEQ_NUM_OFS], dseq_num); 1733 if (entry == NULL) { 1734 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1735 (BSL_META("disc probe chk: New key " 1736 CPUDB_KEY_FMT_EOLN), 1737 CPUDB_KEY_DISP(src_key))); 1738 return TRUE; /* New CPU key */ 1739 } else { 1740 if (dseq_num - entry->base.dseq_num > 0) { 1741 /* pkt SN newer than DB */ 1742 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1743 (BSL_META("disc probe chk: New SN %d for key " 1744 CPUDB_KEY_FMT_EOLN), 1745 dseq_num, 1746 CPUDB_KEY_DISP(entry->base.key))); 1747 return TRUE; 1748 } 1749 } 1750 entry_buf += PROBE_ENTRY_BYTES; 1751 } 1752 1753 return FALSE; 1754 } 1755 1756 #define PROBE_PKT_OK 0 1757 #define PROBE_PKT_DROP -1 1758 #define PROBE_PKT_DB_CLEAR -2 1759 #define PROBE_PKT_MEMORY -3 1760 1761 1762 /* 1763 * If found, return index of entry in a probe pkt containing the local mac. 1764 * buf points to beginning of list of entries. 1765 */ 1766 STATIC INLINE int 1767 probe_pkt_local_cpu_key(cpudb_ref_t db_ref, uint8 *buf, int entry_count) 1768 { 1769 int i; 1770 cpudb_key_t key; 1771 1772 for (i = 0; i < entry_count; i++) { 1773 CPUDB_KEY_UNPACK(buf, key); 1774 if (!CPUDB_KEY_COMPARE(key, LOCAL_KEY(db_ref))) { 1775 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1776 (BSL_META("disc: Local key in probe pkt, %d\n"), 1777 i)); 1778 return i; 1779 } 1780 1781 buf += PROBE_ENTRY_BYTES; 1782 } 1783 1784 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1785 (BSL_META("disc: Local key not in probe pkt\n"))); 1786 return -1; 1787 } 1788 1789 STATIC int probe_pkt_dseq_num_check(cpudb_ref_t db_ref, 1790 uint8 *pkt_start, 1791 int entry_count); 1792 #define _DROP_PKT do { \ 1793 bcm_rx_free(probe_pkt->rx_unit, probe_pkt->pkt_buf); \ 1794 probe_pkt->pkt_buf = NULL; \ 1795 } while (0) 1796 1797 /* Process a probe packet */ 1798 1799 1800 1801 1802 STATIC void 1803 probe_pkt_process(cpudb_ref_t db_ref, disc_pkt_t *probe_pkt) 1804 { 1805 int entry_count, last_entry; 1806 uint8 *entry_buf; 1807 int remote_tx_idx; 1808 int local_idx; 1809 cpudb_key_t key; 1810 cpudb_entry_t *remote_ent; 1811 int rx_sp_idx; 1812 int dseq_num; 1813 int drop_pkt; 1814 int result; 1815 1816 1817 /* See disc_int.h for packet format description */ 1818 1819 /* Unpack the number of entries */ 1820 entry_count = (int)(probe_pkt->data[ENTRY_COUNT_OFS]); 1821 last_entry = entry_count - 1; 1822 1823 /* First, check RX for stk port on which pkt received */ 1824 entry_buf = probe_pkt->data + PROBE_ENTRY_OFS(last_entry); 1825 CPUDB_KEY_UNPACK(entry_buf, key); 1826 remote_tx_idx = (int)(entry_buf[PROBE_TX_IDX_OFS]); 1827 UNPACK_LONG(&entry_buf[PROBE_DSEQ_NUM_OFS], dseq_num); 1828 1829 /* Record local connection for RX of this stack port */ 1830 rx_sp_idx = stk_port_find(db_ref, probe_pkt->rx_unit, 1831 probe_pkt->rx_port); 1832 if (rx_sp_idx < 0) { 1833 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1834 (BSL_META("disc ERR: Could not find stk port for " 1835 "probe from unit %d port %d\n"), 1836 probe_pkt->rx_unit, probe_pkt->rx_port)); 1837 ++disc_rx_pkt_err; 1838 ++disc_tot_err; 1839 _DROP_PKT; 1840 return; 1841 } 1842 1843 if (!(STK_FLAGS(db_ref, rx_sp_idx) & CPUDB_SPF_RX_RESOLVED)) { 1844 remote_ent = _disc_key_resolve(db_ref, key, 1845 &entry_buf[PROBE_MAC_OFS], dseq_num); 1846 if (remote_ent == NULL) { 1847 LOG_ERROR(BSL_LS_TKS_DISCOVER, 1848 (BSL_META("disc ERR: Error adding KEY to DB\n"))); 1849 ++disc_rx_pkt_err; 1850 ++disc_tot_err; 1851 _DROP_PKT; 1852 return; 1853 } else if (stk_port_rx_set(db_ref, rx_sp_idx, key, 1854 remote_tx_idx, 0) < 0) { 1855 _DROP_PKT; 1856 return; 1857 } 1858 } 1859 1860 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1861 (BSL_META("disc: Prb pkt Rmt TX %d RX %d key " 1862 CPUDB_KEY_FMT " cnt %d\n"), remote_tx_idx, 1863 rx_sp_idx, CPUDB_KEY_DISP(key), entry_count)); 1864 1865 /* 1866 * Update the key entries in the DB and check for changed 1867 * sequence numbers 1868 */ 1869 entry_buf = probe_pkt->data + PROBE_ENTRY_OFS(0); 1870 drop_pkt = TRUE; 1871 1872 if (entry_count > disc_ttl) { 1873 /* A probe packet with a number of entries greater than the 1874 TTL means that this is a probe forwarded because of a 1875 it was found to have a sequence number greater than 1876 what was found in the receivers database. */ 1877 result = PROBE_PKT_DB_CLEAR; 1878 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1879 (BSL_META("disc: probe entry count %d > %d - forcing forwarding\n"), 1880 entry_count, disc_ttl)); 1881 } else { 1882 result = probe_pkt_dseq_num_check(db_ref, entry_buf, entry_count); 1883 } 1884 1885 switch (result) { 1886 case PROBE_PKT_OK: 1887 drop_pkt = FALSE; 1888 break; 1889 case PROBE_PKT_DROP: 1890 break; 1891 case PROBE_PKT_DB_CLEAR: /* Clear DB and process packet */ 1892 DISC_LOCK; 1893 disc_flags |= DF_DISC_ABORT; 1894 disc_abort_rv = DISC_RESTART_REQUEST; 1895 DISC_UNLOCK; 1896 break; 1897 case PROBE_PKT_MEMORY: 1898 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 1899 (BSL_META("disc: Could not add probe entry\n"))); 1900 break; 1901 default: 1902 assert(0 && "Bad rv dseq_num_check"); 1903 break; 1904 } 1905 1906 /* Look for local CPU key in packet; */ 1907 local_idx = probe_pkt_local_cpu_key(db_ref, 1908 &probe_pkt->data[ENTRY_START_OFS], 1909 entry_count); 1910 1911 if (!DISC_EXIT && !drop_pkt) { /* Default behavior */ 1912 if (local_idx < 0) { 1913 probe_pkt_forward(db_ref, probe_pkt, entry_count, 1914 rx_sp_idx, TRUE); 1915 } else { 1916 /* Local CPU key is in packet; analyze it */ 1917 probe_pkt_with_local_key(db_ref, probe_pkt, 1918 local_idx, entry_count); 1919 } 1920 1921 } else if ((result == PROBE_PKT_DB_CLEAR) && (local_idx < 0)) { 1922 /* 1923 * When discovery is restarted due to a probe packet with 1924 * a new sequence number, always forward the packet to 1925 * trigger discovery to restart in the rest of the systems. 1926 * 1927 * Increasing the TTL by 1 if the ttl is at one will ensure 1928 * such forwarding will occur for packets that are about to be 1929 * dropped. 1930 */ 1931 uint8 *ttl_ptr = &probe_pkt->data[DISC_PROBE_TTL_OFS]; 1932 1933 if (*ttl_ptr == 1) { 1934 (*ttl_ptr)++; 1935 } 1936 probe_pkt_forward(db_ref, probe_pkt, entry_count, 1937 rx_sp_idx, FALSE); 1938 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1939 (BSL_META("Restart discovery, forward probe from " 1940 CPUDB_KEY_FMT_EOLN), 1941 CPUDB_KEY_DISP(key))); 1942 } 1943 1944 /* Free the buffer */ 1945 bcm_rx_free(probe_pkt->rx_unit, probe_pkt->pkt_buf); 1946 probe_pkt->pkt_buf = NULL; 1947 1948 return; 1949 } 1950 1951 #undef _DROP_PKT 1952 1953 /* Check stack port data from the packet */ 1954 1955 static INLINE void 1956 stk_port_analyze(cpudb_entry_t *entry, int sp_idx, uint8 *buf, int new_entry, 1957 int version) 1958 { 1959 int new_flags, flags; 1960 cpudb_stk_port_t *sp_p; 1961 1962 sp_p = &entry->sp_info[sp_idx]; 1963 1964 UNPACK_U32_INCR(buf, new_flags); 1965 flags = sp_p->flags; 1966 1967 /* If new entry or new flags are set, copy data from pkt */ 1968 if (new_entry || ((flags | new_flags) != flags)) { /* Unpack */ 1969 sp_p->flags = new_flags; 1970 CPUDB_KEY_UNPACK(buf, sp_p->tx_cpu_key); 1971 buf += CPUDB_KEY_BYTES; 1972 UNPACK_U32_INCR(buf, sp_p->tx_stk_idx); 1973 CPUDB_KEY_UNPACK(buf, sp_p->rx_cpu_key); 1974 buf += CPUDB_KEY_BYTES; 1975 UNPACK_U32_INCR(buf, sp_p->rx_stk_idx); 1976 if (version >= DISCOVERY_VERSION_1) { 1977 UNPACK_U32_INCR(buf, entry->base.stk_ports[sp_idx].weight); 1978 UNPACK_U32_INCR(buf, entry->base.stk_ports[sp_idx].bflags); 1979 } 1980 if (version >= DISCOVERY_VERSION_2) { 1981 UNPACK_U32_INCR(buf, entry->base.stk_ports[sp_idx].unit); 1982 UNPACK_U32_INCR(buf, entry->base.stk_ports[sp_idx].port); 1983 } else { 1984 entry->base.stk_ports[sp_idx].unit = -1; 1985 entry->base.stk_ports[sp_idx].port = -1; 1986 } 1987 DISC_LOCK; 1988 disc_flags |= DF_DB_UPDATED; 1989 DISC_UNLOCK; 1990 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 1991 (BSL_META("disc: Stk update flags %x\n"), 1992 new_flags)); 1993 } 1994 } 1995 1996 #if defined(BROADCOM_DEBUG) 1997 STATIC int 1998 _check_route_pkt(uint8 *buf, cpudb_entry_t *entry) 1999 { 2000 int stk_port_count; 2001 2002 /* Could check all of entry, but just check num stk ports for now */ 2003 if (entry->base.num_stk_ports > 0) { /* Have seen before */ 2004 UNPACK_LONG(&buf[ROUTE_STK_COUNT_OFS], stk_port_count); 2005 if (entry->base.num_stk_ports != stk_port_count) { 2006 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2007 (BSL_META("disc ERR: stk port count mismatch for %x:%x\n"), 2008 entry->base.mac[4], entry->base.mac[5])); 2009 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2010 (BSL_META(" was %d. new %d\n"), 2011 entry->base.num_stk_ports, stk_port_count)); 2012 return BCM_E_FAIL; /* Do not analyze further */ 2013 } 2014 } 2015 2016 return BCM_E_NONE; 2017 } 2018 #endif /* BROADCOM_DEBUG */ 2019 2020 /* 2021 * Process a DB entry pointed to by buf; buf points to the beginning 2022 * of the routing entry (the key). 2023 * Returns number of bytes processed on success. < 0 if error 2024 */ 2025 2026 STATIC int 2027 route_entry_process(uint8 *buf, cpudb_entry_t *entry, int version) 2028 { 2029 uint32 combined_flags; 2030 int new_entry = FALSE; 2031 int sp_idx; 2032 int i; 2033 int num_units; 2034 int num_stk_ports; 2035 int dseq_num; 2036 bcm_mac_t mac; 2037 uint32 flags; 2038 int slot_id; 2039 int master_pri; 2040 uint8 app_data[CPUDB_APP_DATA_BYTES]; 2041 uint32 base_flags; 2042 CPUDB_BOARD_ID board_id; 2043 int dest_unit; 2044 int dest_port; 2045 2046 /* Extract the Seq Number from the packet entry */ 2047 UNPACK_LONG(&buf[ROUTE_DSEQ_NUM_OFS], dseq_num); 2048 2049 /* Do not update CPUDB with stale info from route, treat it as NOOP */ 2050 if (dseq_num < entry->base.dseq_num) { 2051 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2052 (BSL_META("disc: stale info for " 2053 CPUDB_KEY_FMT " seq %d->%d\n"), 2054 CPUDB_KEY_DISP(entry->base.key), 2055 entry->base.dseq_num, dseq_num)); 2056 UNPACK_LONG(&buf[ROUTE_NUM_UNITS_OFS], num_units); 2057 UNPACK_LONG(&buf[ROUTE_STK_COUNT_OFS], num_stk_ports); 2058 if (num_units > CPUDB_UNITS_MAX) { 2059 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2060 (BSL_META("disc ERR: Rte unit cnt %d > DB limit %d\n"), 2061 num_units, CPUDB_UNITS_MAX)); 2062 return BCM_E_FAIL; 2063 } 2064 if (num_stk_ports > CPUDB_STK_PORTS_MAX) { 2065 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2066 (BSL_META("disc ERR: Rte stk port cnt %d > DB limit %d\n"), 2067 num_stk_ports, CPUDB_STK_PORTS_MAX)); 2068 return BCM_E_FAIL; 2069 } 2070 return route_entry_bytes_get(num_stk_ports, num_units, version); 2071 } 2072 2073 /* Extract flags from packet entry data */ 2074 UNPACK_LONG(&buf[ROUTE_FLAGS_OFS], flags); 2075 2076 /* Treat the higher seq number as a new entry. Higher than expected seq 2077 * number would mean that the existng information is stale and should 2078 * be all overwritten by the information in the incoming route entry. 2079 */ 2080 if (!(entry->flags & CPUDB_F_BASE_INIT_DONE) || 2081 (dseq_num > entry->base.dseq_num)) { 2082 if (!(entry->flags & CPUDB_F_BASE_INIT_DONE)) { 2083 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2084 (BSL_META("disc: Base init key " CPUDB_KEY_FMT_EOLN), 2085 CPUDB_KEY_DISP(entry->base.key))); 2086 flags |= CPUDB_F_BASE_INIT_DONE; 2087 } else { 2088 /* If the entry was already base init'd then append 2089 * existing flags to the flags from incoming packet 2090 */ 2091 flags |= entry->flags; 2092 } 2093 2094 /* Init base info */ 2095 if (dseq_num > entry->base.dseq_num) { 2096 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2097 (BSL_META("disc: new info for " CPUDB_KEY_FMT " seq %d->%d\n"), 2098 CPUDB_KEY_DISP(entry->base.key), 2099 entry->base.dseq_num, dseq_num)); 2100 } 2101 2102 /* Extract the unretrieved data from the packet entry */ 2103 sal_memcpy(mac, &buf[ROUTE_MAC_OFS], sizeof(bcm_mac_t)); 2104 buf += ROUTE_SLOT_ID_OFS; 2105 UNPACK_U32_INCR(buf, slot_id); 2106 if (entry->db_ref->local_entry->base.flags & CPUDB_BASE_F_CHASSIS) { 2107 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2108 (BSL_META("Found slot %d\n"), 2109 slot_id)); 2110 } 2111 UNPACK_U32_INCR(buf, master_pri); 2112 2113 sal_memcpy(app_data, buf, CPUDB_APP_DATA_BYTES); 2114 buf += CPUDB_APP_DATA_BYTES; 2115 board_id = cpudb_board_id_unknown; 2116 base_flags = 0; 2117 /* Get application data: Board ID and Flag */ 2118 if (version >= DISCOVERY_VERSION_2) { 2119 #if defined(DISCOVER_APP_DATA_BOARDID) 2120 uint8 *app_buf = app_data; 2121 UNPACK_U32_INCR(app_buf, board_id); 2122 UNPACK_U32_INCR(app_buf, base_flags); 2123 #endif /* DISCOVER_APP_DATA_BOARDID */ 2124 } 2125 2126 /* Get unit count and check database limit */ 2127 UNPACK_U32_INCR(buf, num_units); 2128 if (num_units > CPUDB_UNITS_MAX) { 2129 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2130 (BSL_META("disc ERR: Rte unit count %d exceeds DB limit %d\n"), 2131 num_units, CPUDB_UNITS_MAX)); 2132 return BCM_E_FAIL; 2133 } 2134 UNPACK_U32_INCR(buf, dest_unit); 2135 UNPACK_U32_INCR(buf, dest_port); 2136 2137 /* Get stack port count and check database limit */ 2138 UNPACK_U32_INCR(buf, num_stk_ports); 2139 if (num_stk_ports > CPUDB_STK_PORTS_MAX) { 2140 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2141 (BSL_META("disc ERR: Rte stk port count %d exceeds DB limit %d\n"), 2142 num_stk_ports, CPUDB_STK_PORTS_MAX)); 2143 return BCM_E_FAIL; 2144 } 2145 2146 sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t)); 2147 entry->base.dseq_num = dseq_num; 2148 entry->flags = flags; 2149 entry->base.slot_id = slot_id; 2150 entry->base.master_pri = master_pri; 2151 sal_memcpy(entry->base.app_data, app_data, CPUDB_APP_DATA_BYTES); 2152 entry->base.board_id = board_id; 2153 entry->base.flags = base_flags; 2154 entry->base.num_units = num_units; 2155 entry->base.dest_unit = dest_unit; 2156 entry->base.dest_port = dest_port; 2157 entry->base.num_stk_ports = num_stk_ports; 2158 2159 /* Unpack per unit info */ 2160 for (i = 0; i < entry->base.num_units; i++) { 2161 UNPACK_U32_INCR(buf, entry->base.mod_ids_req[i]); 2162 UNPACK_U32_INCR(buf, entry->base.pref_mod_id[i]); 2163 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2164 (BSL_META("disc: Rte unit %d. mr %d. pref %d\n"), 2165 i, entry->base.mod_ids_req[i], 2166 entry->base.pref_mod_id[i])); 2167 } 2168 2169 2170 DISC_LOCK; 2171 disc_flags |= DF_DB_UPDATED; 2172 DISC_UNLOCK; 2173 new_entry = TRUE; 2174 } else { 2175 /* Check for new flags */ 2176 combined_flags = (flags | entry->flags); 2177 if (combined_flags != entry->flags) { 2178 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2179 (BSL_META("disc: Rte flag update %x->%x\n"), 2180 entry->flags, combined_flags)); 2181 entry->flags = combined_flags; 2182 DISC_LOCK; 2183 disc_flags |= DF_DB_UPDATED; 2184 DISC_UNLOCK; 2185 } 2186 #if defined(BROADCOM_DEBUG) 2187 BCM_IF_ERROR_RETURN(_check_route_pkt(buf, entry)); 2188 #endif /* BROADCOM_DEBUG */ 2189 buf += ROUTE_BASE_BYTES(entry->base.num_units); 2190 } 2191 2192 /* buf now points to the beginning of the stack ports. Analyze them */ 2193 for (sp_idx = 0; sp_idx < entry->base.num_stk_ports; sp_idx++) { 2194 stk_port_analyze(entry, sp_idx, buf, new_entry, version); 2195 buf += stk_entry_bytes_get(version); 2196 } 2197 2198 return route_entry_bytes_get(entry->base.num_stk_ports, 2199 entry->base.num_units, version); 2200 } 2201 2202 /**************************************************************** 2203 * RX next hop packet handler; At this point, we know it's a 2204 * discovery packet, but don't know what kind. 2205 */ 2206 2207 /* Assumes lock */ 2208 2209 static INLINE int 2210 enqueue_probe_pkt(cpudb_key_t src_key, int unit, int port, 2211 uint8 *pkt_buf, int len) 2212 { 2213 disc_pkt_t *pkt_info; 2214 2215 if (probe_pkt_count + 1 >= DISC_PKTS_MAX) { 2216 ++disc_resource_err; 2217 return BCM_E_RESOURCE; 2218 } 2219 2220 pkt_info = &probe_pkt_queue[probe_pkt_count++]; 2221 CPUDB_KEY_COPY(pkt_info->src_key, src_key); 2222 pkt_info->rx_unit = unit; 2223 pkt_info->rx_port = port; 2224 pkt_info->pkt_buf = pkt_buf; 2225 pkt_info->len = len; 2226 pkt_info->data = pkt_buf + CPUTRANS_HEADER_BYTES; 2227 2228 return BCM_E_NONE; 2229 } 2230 2231 /* Assumes lock */ 2232 2233 static INLINE int 2234 enqueue_routing_pkt(cpudb_key_t src_key, int unit, int port, 2235 uint8 *pkt_buf, int len) 2236 { 2237 disc_pkt_t *pkt_info; 2238 2239 if (routing_pkt_count + 1 >= DISC_PKTS_MAX) { 2240 ++disc_resource_err; 2241 return BCM_E_RESOURCE; 2242 } 2243 2244 pkt_info = &routing_pkt_queue[routing_pkt_count++]; 2245 CPUDB_KEY_COPY(pkt_info->src_key, src_key); 2246 pkt_info->rx_unit = unit; 2247 pkt_info->rx_port = port; 2248 pkt_info->pkt_buf = pkt_buf; 2249 pkt_info->len = len; 2250 2251 return BCM_E_NONE; 2252 } 2253 2254 /* Assumes lock held */ 2255 static INLINE int 2256 stack_port_active_mark(cpudb_ref_t db_ref, int unit, int port) 2257 { 2258 int idx; 2259 2260 idx = stk_port_find(db_ref, unit, port); 2261 if (idx >= 0) { 2262 if (STK_FLAGS(db_ref, idx) & CPUDB_SPF_INACTIVE) { 2263 /* 2264 * An inactive port has seen a discovery packet. This 2265 * counts as a stack event. Request restart 2266 */ 2267 disc_flags |= DF_DISC_ABORT; 2268 disc_abort_rv = DISC_RESTART_NEW_SEQ; 2269 return -1; 2270 } 2271 PP_SEEN_SET(idx); /* Probe packet seen on port */ 2272 } 2273 2274 return 0; 2275 } 2276 2277 /* Supports versions 0, 1, and 2 packets */ 2278 2279 STATIC bcm_rx_t 2280 disc_rx_pkt_ver(cpudb_key_t src_key, 2281 int unit, int port, uint8 *pkt_buf, 2282 int len, cpudb_ref_t db_ref) 2283 { 2284 int pkt_type; 2285 2286 /* Called with DISC_LOCK held */ 2287 pkt_type = disc_pkt_type_get(pkt_buf); 2288 2289 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2290 (BSL_META_U(unit, 2291 "disc: %s (%d) pkt in\n"), 2292 pkt_type == DISC_PKT_TYPE_PROBE ? "PROBE" : "ROUTING" , 2293 pkt_type)); 2294 switch (pkt_type) { 2295 case DISC_PKT_TYPE_PROBE: /* Probe packet */ 2296 2297 /* Mark the stack port active if found */ 2298 if (stack_port_active_mark(db_ref, unit, port) < 0) { 2299 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2300 (BSL_META_U(unit, 2301 "disc: Inactive Stack port %d %d now active.\n"), 2302 unit, port)); 2303 DISC_UNLOCK; 2304 DISC_WAKE; 2305 return BCM_RX_HANDLED; 2306 } 2307 if (enqueue_probe_pkt(src_key, unit, port, pkt_buf, len) < 0) { 2308 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2309 (BSL_META_U(unit, 2310 "disc: Discarding probe pkt\n"))); 2311 DISC_UNLOCK; 2312 return BCM_RX_HANDLED; 2313 } 2314 break; 2315 case DISC_PKT_TYPE_ROUTING: /* Routing packet */ 2316 if (enqueue_routing_pkt(src_key, unit, port, pkt_buf, len) < 0) { 2317 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2318 (BSL_META_U(unit, 2319 "disc: Discarding routing pkt\n"))); 2320 DISC_UNLOCK; 2321 return BCM_RX_HANDLED; 2322 } 2323 break; 2324 default: 2325 LOG_WARN(BSL_LS_TKS_DISCOVER, 2326 (BSL_META_U(unit, 2327 "disc WARN: Unsupported packet type %d"), 2328 pkt_type)); 2329 ++disc_tot_err; 2330 DISC_UNLOCK; 2331 return BCM_RX_NOT_HANDLED; 2332 2333 } 2334 2335 #if defined(BCM_RXP_DEBUG) 2336 bcm_rx_pool_own(pkt_buf, "disc_pkt"); 2337 #endif 2338 2339 /* Normal exit */ 2340 DISC_UNLOCK; 2341 DISC_WAKE; 2342 2343 return BCM_RX_HANDLED_OWNED; 2344 } 2345 2346 STATIC bcm_rx_t 2347 disc_rx_pkt(cpudb_key_t src_key, int port_num, 2348 int unit, int port, uint8 *pkt_buf, 2349 int len, void *cookie) 2350 { 2351 int d_ver; 2352 cpudb_ref_t db_ref; 2353 static int version_warn = TRUE; 2354 2355 COMPILER_REFERENCE(port_num); 2356 2357 if (!INIT_DONE) { 2358 return BCM_RX_NOT_HANDLED; 2359 } 2360 2361 DISC_LOCK; 2362 2363 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2364 (BSL_META_U(unit, 2365 "disc: disc_rx_pkt\n"))); 2366 if (!(disc_flags & DF_DISC_RUNNING)) { 2367 DISC_UNLOCK; 2368 /* If no task_db or discovery not running, then sink probe */ 2369 if (disc_pkt_type_get(pkt_buf) == DISC_PKT_TYPE_PROBE && 2370 disc_task_db) { 2371 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2372 (BSL_META_U(unit, 2373 "disc: rx while idle.\n"))); 2374 (void)disc_callout(disc_task_db, DISC_PROBE_RECEIVED); 2375 } 2376 return BCM_RX_NOT_HANDLED; 2377 } 2378 2379 if (disc_flags & DF_IGNORE_PACKETS) { 2380 DISC_UNLOCK; 2381 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2382 (BSL_META_U(unit, 2383 "disc: rx ignored.\n"))); 2384 return BCM_RX_NOT_HANDLED; 2385 } 2386 2387 db_ref = *(cpudb_ref_t *)cookie; 2388 if (!cpudb_valid(db_ref)) { 2389 DISC_UNLOCK; 2390 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2391 (BSL_META_U(unit, 2392 "disc: Config pkt in when db_ref is invalid.\n"))); 2393 return BCM_RX_NOT_HANDLED; 2394 } 2395 2396 d_ver = pkt_buf[CPUTRANS_HEADER_BYTES + DISC_VER_OFS]; 2397 2398 /* Fallback only if received discovery packet version is lower */ 2399 if (disc_fallback && (disc_version > d_ver)) { 2400 LOG_WARN(BSL_LS_TKS_DISCOVER, 2401 (BSL_META_U(unit, 2402 "DISC WARN: Protocol version changed from %d to %d\n"), 2403 disc_version, d_ver)); 2404 disc_version = d_ver; 2405 DISC_UNLOCK; 2406 return BCM_RX_HANDLED; 2407 } else if (d_ver != disc_version && version_warn) { 2408 LOG_WARN(BSL_LS_TKS_DISCOVER, 2409 (BSL_META_U(unit, 2410 "DISC WARN: Received discovery version %d, sending %d\n"), 2411 d_ver, disc_version)); 2412 version_warn = FALSE; 2413 } 2414 2415 switch (d_ver) { 2416 case DISCOVERY_VERSION_0: 2417 case DISCOVERY_VERSION_1: 2418 case DISCOVERY_VERSION_2: 2419 return disc_rx_pkt_ver(src_key, unit, port, pkt_buf, len, db_ref); 2420 } 2421 2422 /* Unknown version - throw packet away */ 2423 DISC_UNLOCK; 2424 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2425 (BSL_META_U(unit, 2426 "disc: Unknown discovery version %d in probe/route\n"), 2427 d_ver)); 2428 return BCM_RX_NOT_HANDLED; 2429 } 2430 2431 2432 /* 2433 * Set up the header of a discovery pkt. 2434 * 2435 * Note that "ttl" is put in the reserved field. If DISC TTL is not 2436 * enabled, then this value should be 0. 2437 */ 2438 2439 STATIC INLINE void 2440 disc_pkt_setup(uint8 *pkt_buf, uint8 pkt_type, uint8 entry_count, 2441 uint8 ttl_rsvd, int dseq_num, int version) 2442 { 2443 pkt_buf[DISC_VER_OFS] = (uint8)version; 2444 pkt_buf[DISC_RSVD_OFS] = (uint8)ttl_rsvd; 2445 pkt_buf[LOCAL_PKT_TYPE_OFS] = pkt_type; 2446 pkt_buf[ENTRY_COUNT_OFS] = entry_count; 2447 PACK_LONG(&pkt_buf[SRC_DSEQ_NUM_OFS], dseq_num); 2448 } 2449 2450 2451 /* 2452 * Function: 2453 * disc_header_setup 2454 * Purpose: 2455 * Set up the header for a discovery packet 2456 * Parameters: 2457 * pkt_buf - Buffer to setup 2458 * pkt_type - Type for discovery header 2459 * entry_count - How many entries (if applicable) 2460 * Returns: 2461 * BCM_E_XXX 2462 */ 2463 2464 void 2465 disc_header_setup(uint8 *pkt_buf, uint8 pkt_type, uint8 entry_count, 2466 uint8 ttl_rsvd, int dseq_num) 2467 { 2468 disc_pkt_setup(pkt_buf, pkt_type, entry_count, ttl_rsvd, dseq_num, 2469 disc_version); 2470 } 2471 2472 #if DISC_PPS > 0 2473 2474 #define DISC_TX_DELAY (1000000/DISC_PPS) /* usec between transmissions */ 2475 2476 STATIC void 2477 disc_rate_limit(void) 2478 { 2479 sal_usecs_t now = sal_time_usecs(); 2480 int delta = 0; 2481 2482 if (disc_tx_init) { 2483 delta = SAL_USECS_SUB(now, disc_tx_prev); 2484 if (delta > 0 && delta < DISC_TX_DELAY) { 2485 sal_usleep(DISC_TX_DELAY - delta); 2486 } 2487 } else { 2488 disc_tx_init = !disc_tx_init; 2489 } 2490 2491 disc_tx_prev = now; 2492 } 2493 #else 2494 /* rate limiting disabled */ 2495 #define disc_rate_limit() 2496 #endif /* DISC_PPS */ 2497 2498 /**************************************************************** 2499 * 2500 * Probe packet handling 2501 */ 2502 2503 /* Explicitly send probe pkt to each stk port so that idx can be updated */ 2504 2505 STATIC void 2506 probe_pkt_tx(cpudb_ref_t db_ref, uint8 *buf, int len, uint8 *cur_entry, 2507 disc_pkt_t *probe_pkt) 2508 { 2509 int i; 2510 int rv = BCM_E_NONE; 2511 int unit, port; 2512 2513 /* if probe_pkt is not NULL, detect full duplex optimization */ 2514 2515 for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) { 2516 if (STK_FLAGS(db_ref, i) & CPUDB_SPF_NO_LINK || 2517 STK_FLAGS(db_ref, i) & CPUDB_SPF_ETHERNET) { 2518 continue; 2519 } 2520 unit = STKP_UNIT(db_ref, i); 2521 port = STKP_PORT(db_ref, i); 2522 2523 if (probe_pkt && 2524 (unit != probe_pkt->rx_unit || port != probe_pkt->rx_port)) { 2525 /* full duplex optimization: only forward packets to original 2526 sender. */ 2527 continue; 2528 } 2529 if (STK_FLAGS(db_ref, i) & CPUDB_SPF_TX_RESOLVED && 2530 STK_FLAGS(db_ref, i) & CPUDB_SPF_RX_RESOLVED && 2531 STK_FLAGS(db_ref, i) & CPUDB_SPF_TX_FORWARDED) { 2532 /* this port already resolved locally, and a probe 2533 has been forwarded via this port. */ 2534 continue; 2535 } 2536 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2537 (BSL_META_U(unit, 2538 "DISC: Sending probe pkt cos %d to port %d (%d, %d)\n"), 2539 disc_cos, i, unit, port)); 2540 2541 next_hop_buffer_init(buf, DISC_NH_PKT_TYPE, cpudb_neighbor_key); 2542 cur_entry[PROBE_TX_IDX_OFS] = (uint8)i; 2543 2544 disc_rate_limit(); 2545 2546 rv = nh_tx(unit, 2547 port, 2548 buf, 2549 len, 2550 disc_cos, 2551 disc_vlan, 2552 NEXT_HOP_PKT_TYPE, 2553 CPUTRANS_NO_HEADER_ALLOC | CPUTRANS_CRC_REGEN, 2554 NULL, 2555 NULL); 2556 if (BCM_FAILURE(rv)) { 2557 ++disc_tx_pkt_err; 2558 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2559 (BSL_META_U(unit, 2560 "disc ERR %d: probe pkt tx to " 2561 "stkport %d: %s\n"), rv, i, bcm_errmsg(rv))); 2562 break; 2563 } else { 2564 if (probe_pkt) { 2565 STK_FLAGS(db_ref, i) |= CPUDB_SPF_TX_FORWARDED; 2566 } 2567 } 2568 } 2569 } 2570 2571 2572 /* Send out initial probe packets */ 2573 STATIC void 2574 probe_pkts_generate(cpudb_ref_t db_ref) 2575 { 2576 uint8 *buf, *start_buf; 2577 int len; 2578 2579 /* Just one entry in initial packets sent out */ 2580 len = CPUTRANS_HEADER_BYTES + PROBE_ENTRY_OFS(1) + sizeof(uint32); 2581 buf = start_buf = DATA_SALLOC(len); 2582 if (buf == NULL) { 2583 ++disc_alloc_fail; 2584 ++disc_tot_err; 2585 return; 2586 } 2587 2588 buf += CPUTRANS_HEADER_BYTES; 2589 disc_pkt_setup(buf, DISC_PKT_TYPE_PROBE, 1, disc_ttl, 2590 db_ref->local_entry->base.dseq_num, disc_version); 2591 buf += ENTRY_START_OFS; 2592 CPUDB_KEY_PACK(buf, LOCAL_KEY(db_ref)); 2593 sal_memcpy(&buf[PROBE_MAC_OFS], LOCAL_MAC(db_ref), sizeof(bcm_mac_t)); 2594 /* Set sequence number */ 2595 PACK_LONG(&buf[PROBE_DSEQ_NUM_OFS], CUR_DSEQ_NUM(db_ref)); 2596 probe_pkt_tx(db_ref, start_buf, len, buf, NULL); 2597 2598 /* Update TTL if enabled (disc_ttl > 0) */ 2599 if (disc_ttl > 0 && ++disc_ttl > disc_ttl_max) { 2600 disc_ttl = disc_ttl_max; 2601 } else { 2602 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2603 (BSL_META("DISC: TTL is %d\n"), 2604 disc_ttl)); 2605 } 2606 2607 DATA_SFREE(start_buf); 2608 } 2609 2610 2611 /* 2612 * Clear all mod ids 2613 */ 2614 STATIC INLINE void 2615 db_entry_clear_mod_ids(cpudb_entry_t *entry) 2616 { 2617 int unit; 2618 int max_units; 2619 2620 max_units = COUNTOF(entry->base.pref_mod_id); 2621 for (unit = 0; unit < max_units; unit++) { 2622 entry->base.pref_mod_id[unit] = -1; 2623 } 2624 2625 max_units = COUNTOF(entry->mod_ids); 2626 for (unit = 0; unit < max_units; unit++) { 2627 entry->mod_ids[unit] = -1; 2628 } 2629 2630 return; 2631 } 2632 2633 /* 2634 * Run through the entries in a probe packet. Add new entries to 2635 * the DB. For existing entries, check for changes in sequence number. 2636 * 2637 * In order of precedence, returns 2638 * PROBE_PKT_DROP if packet should be dropped due to old seq num. 2639 * PROBE_PKT_DB_CLEAR if newer sequence number found; 2640 * PROBE_PKT_MEMORY if unable to add an entry 2641 * PROBE_PKT_OK if all okay; 2642 * 2643 * pkt_buf points to the beginning of the first entry in the packet 2644 */ 2645 2646 STATIC int 2647 probe_pkt_dseq_num_check(cpudb_ref_t db_ref, uint8 *pkt_start, 2648 int entry_count) 2649 { 2650 cpudb_key_t key; 2651 cpudb_entry_t *entry; 2652 int i; 2653 int dseq_num; 2654 int new_entries = 0; 2655 int diff; 2656 uint8 *pkt_buf, *first_new; 2657 2658 first_new = NULL; 2659 pkt_buf = pkt_start; 2660 /* First, run thru entries looking for different seq nums (drop pkt) */ 2661 for (i = 0; i < entry_count; i++) { 2662 CPUDB_KEY_UNPACK(pkt_buf, key); 2663 CPUDB_KEY_SEARCH(db_ref, key, entry); 2664 UNPACK_LONG(&pkt_buf[PROBE_DSEQ_NUM_OFS], dseq_num); 2665 if (entry == NULL) { 2666 new_entries++; 2667 if (first_new == NULL) { 2668 first_new = pkt_buf; 2669 } 2670 } else { 2671 diff = dseq_num - entry->base.dseq_num; 2672 if (diff > 0) { /* pkt SN is newer than local DB */ 2673 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2674 (BSL_META("disc: New seq num %d for key " 2675 CPUDB_KEY_FMT_EOLN), 2676 dseq_num, 2677 CPUDB_KEY_DISP(entry->base.key))); 2678 return PROBE_PKT_DB_CLEAR; 2679 } else if (diff < 0) { /* pkt SN is older than DB */ 2680 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 2681 (BSL_META("disc: Old seq num. DB SN %d. Pkt SN %d. key " 2682 CPUDB_KEY_FMT_EOLN), 2683 entry->base.dseq_num, 2684 dseq_num, CPUDB_KEY_DISP(entry->base.key))); 2685 return PROBE_PKT_DROP; 2686 } 2687 } 2688 pkt_buf += PROBE_ENTRY_BYTES; 2689 } 2690 2691 /* Now update any missing entries */ 2692 pkt_buf = first_new; 2693 while (new_entries > 0) { 2694 CPUDB_KEY_UNPACK(pkt_buf, key); 2695 CPUDB_KEY_SEARCH(db_ref, key, entry); 2696 UNPACK_LONG(&pkt_buf[PROBE_DSEQ_NUM_OFS], dseq_num); 2697 if (entry == NULL) { 2698 new_entries--; 2699 DISC_LOCK; 2700 disc_flags |= DF_DB_UPDATED; 2701 DISC_UNLOCK; 2702 entry = cpudb_entry_create(db_ref, key, FALSE); 2703 if (entry == NULL) { 2704 return PROBE_PKT_MEMORY; 2705 } 2706 db_entry_clear_mod_ids(entry); 2707 entry->base.dseq_num = dseq_num; 2708 } 2709 2710 pkt_buf += PROBE_ENTRY_BYTES; 2711 } 2712 return PROBE_PKT_OK; 2713 } 2714 2715 /* 2716 * Local CPU key is not in this probe pkt; 2717 * Add local info to pkt and send off to all stack ports. 2718 * 2719 * ASSUMPTION: The RX packet we're manipulating is long enough 2720 * to hold a max length probe packet. 2721 * 2722 * Disable full duplex optimization if enable_fdo is false. 2723 */ 2724 2725 STATIC void 2726 probe_pkt_forward(cpudb_ref_t db_ref, disc_pkt_t *probe_pkt, 2727 int entry_count, int rx_sp_idx, int enable_fdo) 2728 { 2729 uint8 *local_entry; 2730 int tx_len; 2731 uint8 ttl_rsvd; 2732 disc_pkt_t *fd_opt = NULL; 2733 2734 ttl_rsvd = probe_pkt->data[DISC_PROBE_TTL_OFS]; 2735 switch (ttl_rsvd) { 2736 case 0: /* Ignore TTL */ 2737 break; 2738 case 1: /* TTL expired, do not forward */ 2739 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2740 (BSL_META("DISC: Not forwarding probe pkt due to TTL == 1\n"))); 2741 return; 2742 default: /* Decrement TTL and forward */ 2743 probe_pkt->data[DISC_PROBE_TTL_OFS] = ttl_rsvd - 1; 2744 2745 if (disc_ttl_min == DISC_TTL_FULL_DUPLEX && 2746 disc_ttl_max == DISC_TTL_FULL_DUPLEX && 2747 enable_fdo) { 2748 fd_opt = probe_pkt; 2749 } 2750 2751 break; 2752 } 2753 2754 local_entry = &probe_pkt->data[PROBE_ENTRY_OFS(entry_count++)]; 2755 CPUDB_KEY_PACK(local_entry, LOCAL_KEY(db_ref)); 2756 sal_memcpy(&local_entry[PROBE_MAC_OFS], LOCAL_MAC(db_ref), 2757 sizeof(bcm_mac_t)); 2758 local_entry[PROBE_RX_IDX_OFS] = (uint8)rx_sp_idx; 2759 PACK_LONG(&local_entry[PROBE_DSEQ_NUM_OFS], CUR_DSEQ_NUM(db_ref)); 2760 2761 /* Update the entry count in the packet */ 2762 probe_pkt->data[ENTRY_COUNT_OFS] = (uint8)entry_count; 2763 2764 /* TX UNIT and TX PORT are filled in by receiving CPU */ 2765 tx_len = CPUTRANS_HEADER_BYTES + DISC_HEADER_BYTES + 2766 entry_count * PROBE_ENTRY_BYTES + sizeof(uint32); 2767 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2768 (BSL_META("disc: Prb pkt out, ent %d len %d\n"), 2769 entry_count, tx_len)); 2770 probe_pkt_tx(db_ref, probe_pkt->pkt_buf, tx_len, local_entry, fd_opt); 2771 } 2772 2773 2774 /* 2775 * Handle a probe packet with the local CPU key which has traveled 2776 * off the board (it has some other CPU info as well.) 2777 * 2778 * The transmit portion of the original stack port is now resolved. 2779 * 2780 * Otherwise, we scan through the entries and add the CPU keys. 2781 * We could discern a lot of stack ports, but that will come to us 2782 * from routing packets. 2783 */ 2784 2785 static INLINE void 2786 off_board_pkt_handle(cpudb_ref_t db_ref, 2787 uint8 *buf, /* Points to first new entry */ 2788 int tx_sp_idx, /* index of orig TX stk port */ 2789 int new_entries) /* How many new entries in pkt -- 2790 that is, >= local entry */ 2791 { 2792 int i; 2793 cpudb_entry_t *entry; 2794 cpudb_key_t key; 2795 int remote_rx_idx; 2796 int dseq_num; 2797 2798 /* From the first entry after the local key, we can determine the 2799 * TX connection of the stack port. Note: new_entries >= 1. */ 2800 2801 remote_rx_idx = (int)buf[PROBE_RX_IDX_OFS]; 2802 CPUDB_KEY_UNPACK(buf, key); 2803 UNPACK_LONG(&buf[PROBE_DSEQ_NUM_OFS], dseq_num); 2804 entry = _disc_key_resolve(db_ref, key, &buf[PROBE_MAC_OFS], dseq_num); 2805 if (entry == NULL) { 2806 ++disc_rx_pkt_err; 2807 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2808 (BSL_META("disc ERR: bad key, off board 0\n"))); 2809 return; 2810 } 2811 2812 if (stk_port_tx_set(db_ref, tx_sp_idx, key, remote_rx_idx, 0) < 0) { 2813 return; 2814 } 2815 2816 /* Have seen an offboard packet now */ 2817 DISC_LOCK; 2818 disc_flags |= DF_INFO_IN; 2819 DISC_UNLOCK; 2820 2821 /* Put other MACs in the local DB */ 2822 buf += PROBE_ENTRY_BYTES; /* Next entry */ 2823 for (i = 1; i < new_entries; i++) { /* One done above */ 2824 CPUDB_KEY_UNPACK(buf, key); 2825 UNPACK_LONG(&buf[PROBE_DSEQ_NUM_OFS], dseq_num); 2826 entry = _disc_key_resolve(db_ref, key, &buf[PROBE_MAC_OFS], dseq_num); 2827 if (entry == NULL) { 2828 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2829 (BSL_META("disc ERR: bad key, off board %d\n"), 2830 i)); 2831 ++disc_rx_pkt_err; 2832 return; 2833 } 2834 buf += PROBE_ENTRY_BYTES; /* Next entry */ 2835 } 2836 } 2837 2838 2839 /* Handle a probe packet that has the local MAC address in an entry 2840 */ 2841 2842 STATIC void 2843 probe_pkt_with_local_key(cpudb_ref_t db_ref, 2844 disc_pkt_t *probe_pkt, /* The pkt */ 2845 int local_idx, /* Where is local MAC */ 2846 int entry_count) /* How many entries in pkt */ 2847 { 2848 uint8 *buf; 2849 int tx_sp_idx; 2850 int rx_sp_idx; 2851 2852 /* Local MAC found. Update local DB. Set buf to start of entries */ 2853 buf = &probe_pkt->data[PROBE_ENTRY_OFS(local_idx)]; 2854 2855 /* Grab the originating unit/port info for this pkt */ 2856 tx_sp_idx = (int)buf[PROBE_TX_IDX_OFS]; 2857 rx_sp_idx = stk_port_find(db_ref, probe_pkt->rx_unit, probe_pkt->rx_port); 2858 2859 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2860 (BSL_META("disc: Prb pkt local. RX %d. TX %d, ent cnt %d\n"), 2861 rx_sp_idx, tx_sp_idx, entry_count)); 2862 2863 #if defined(BROADCOM_DEBUG) 2864 if (tx_sp_idx < 0 || tx_sp_idx > db_ref->local_entry->base.num_stk_ports) { 2865 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2866 (BSL_META("disc ERR: Did not find stk port in probe pkt"))); 2867 return; 2868 } 2869 if (rx_sp_idx < 0) { 2870 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2871 (BSL_META("disc ERR: Did not find rx stk port of probe pkt"))); 2872 return; 2873 } 2874 #endif /* BROADCOM_DEBUG */ 2875 2876 if (entry_count == 1) { /* It's an on-board connection */ 2877 /* 2878 * (cpu, tx_sp_idx) --> (cpu, rx_sp_idx); 2879 * so TX of tx_sp_idx goes to local CPU, rx_sp_idx; 2880 * and pkts received on rx_sp_idx were sent by local cpu to tx_sp_idx. 2881 * Got that? The RX one was already set in probe_pkt_process. 2882 */ 2883 stk_port_tx_set(db_ref, tx_sp_idx, LOCAL_KEY(db_ref), 2884 rx_sp_idx, CPUDB_SPF_ON_BOARD); 2885 } else { 2886 off_board_pkt_handle(db_ref, buf + PROBE_ENTRY_BYTES, tx_sp_idx, 2887 entry_count - local_idx - 1); 2888 } 2889 } 2890 2891 2892 /**************************************************************** 2893 * 2894 * Routing packet handling 2895 */ 2896 STATIC INLINE int db_entry_pack(uint8 *buf, cpudb_entry_t *entry, 2897 int max_bytes, int version); 2898 2899 /* 2900 * Send a route packet specifically to each stack port using 2901 * next hop tx. 2902 */ 2903 static INLINE void 2904 route_pkt_tx(cpudb_ref_t db_ref, uint8 *buf, int len) 2905 { 2906 int i; 2907 int rv = BCM_E_NONE; 2908 cpudb_entry_t *dest_entry; 2909 2910 /* Keep track of TX keys to which we've sent info; up to 4 keys */ 2911 cpudb_key_t sent_keys[CPUDB_STK_PORTS_MAX]; 2912 int sk_count = 0, sk_idx; 2913 int cpu_done; 2914 2915 for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) { 2916 if (!(STK_FLAGS(db_ref, i) & CPUDB_SPF_TX_RESOLVED) || 2917 (STK_FLAGS(db_ref, i) & CPUDB_SPF_NO_LINK) || 2918 (STK_FLAGS(db_ref, i) & CPUDB_SPF_ETHERNET) ) { 2919 continue; 2920 } 2921 2922 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 2923 (BSL_META("disc rte pkt out len %d to %d @ " CPUDB_KEY_FMT_EOLN), 2924 len, i, CPUDB_KEY_DISP(STK_PORT(db_ref, i).tx_cpu_key))); 2925 CPUDB_KEY_SEARCH(db_ref, STK_PORT(db_ref, i).tx_cpu_key, dest_entry); 2926 if (dest_entry != NULL) { 2927 cpu_done = FALSE; /* See if info sent to this CPU already */ 2928 for (sk_idx = 0; sk_idx < sk_count; sk_idx++) { 2929 if (CPUDB_KEY_EQUAL(sent_keys[sk_idx], dest_entry->base.key)) { 2930 cpu_done = TRUE; 2931 break; 2932 } 2933 } 2934 if (cpu_done) { 2935 continue; 2936 } 2937 2938 if (sk_count < CPUDB_STK_PORTS_MAX) { /* Record destination key */ 2939 CPUDB_KEY_COPY(sent_keys[sk_count], dest_entry->base.key); 2940 sk_count++; 2941 } 2942 } 2943 2944 next_hop_buffer_init(buf, DISC_NH_PKT_TYPE, cpudb_neighbor_key); 2945 2946 disc_rate_limit(); 2947 2948 rv = nh_tx(STKP_UNIT(db_ref, i), 2949 STKP_PORT(db_ref, i), 2950 buf, 2951 len, 2952 disc_cos, 2953 disc_vlan, 2954 NEXT_HOP_PKT_TYPE, 2955 CPUTRANS_NO_HEADER_ALLOC, 2956 NULL, 2957 NULL); 2958 if (BCM_FAILURE(rv)) { 2959 ++disc_tx_pkt_err; 2960 LOG_ERROR(BSL_LS_TKS_DISCOVER, 2961 (BSL_META("disc ERR: sending rte to stkport %d\n"), 2962 i)); 2963 break; 2964 } 2965 if (DISC_EXIT) { 2966 break; 2967 } 2968 } 2969 } 2970 2971 2972 /* Pack the current database into routing packets */ 2973 static INLINE int 2974 routing_pkts_form(cpudb_ref_t db_ref) 2975 { 2976 uint8 *pkt_buf = NULL; 2977 cpudb_entry_t *entry; 2978 int cur_offset = 0; /* Byte offset into current packet */ 2979 int tot_entries; /* Total number of route entries to pack */ 2980 int tot_pkts; /* Total number of route packets */ 2981 int entry_bytes; /* Number of bytes in route entry */ 2982 int num_entries; /* Number of entries already packed in the packet */ 2983 int pkt_bytes_left; /* Remaining bytes in current route packet */ 2984 int cur_pkt_idx; /* Current route packet being packed */ 2985 int version = disc_version; 2986 2987 2988 /* 2989 * A routing packet has the following format 2990 * 2991 * +----------------+----------------+-------------------+ 2992 * | <cputrans-hdr> | <disc-pkt-hdr> | <route-entry> * n | 2993 * +----------------+----------------+-------------------+ 2994 * 2995 * Where, n is the number of route entries in the packet 2996 */ 2997 2998 /* Remaining bytes available in packet buffer */ 2999 pkt_bytes_left = ROUTE_PKT_BYTES_MAX - 3000 (CPUTRANS_HEADER_BYTES + ENTRY_START_OFS); 3001 3002 tot_pkts = 0; 3003 tot_entries = 0; 3004 num_entries = 0; 3005 cur_pkt_idx = -1; 3006 3007 CPUDB_FOREACH_ENTRY(db_ref, entry) { 3008 if (!(entry->flags & CPUDB_F_BASE_INIT_DONE)) { 3009 continue; 3010 } 3011 3012 /* Get size required by route entry */ 3013 entry_bytes = route_entry_bytes_get(entry->base.num_stk_ports, 3014 entry->base.num_units, 3015 version); 3016 /* 3017 * Route packet should fit at least one entry 3018 */ 3019 if ((entry_bytes > pkt_bytes_left) && (num_entries == 0)) { 3020 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3021 (BSL_META("disc ERR: route pkt entry too long, need %d, left %d\n"), 3022 entry_bytes, pkt_bytes_left)); 3023 ++disc_internal_err; 3024 ++disc_tot_err; 3025 return -1; 3026 } 3027 3028 /* 3029 * Start a new packet if: 3030 * - Current number of entries is 0, or 3031 * - There is no enough space left in packet, or 3032 * - Number of entries per packet has reached the limit 3033 */ 3034 if ((num_entries == 0) || (entry_bytes > pkt_bytes_left) || 3035 (num_entries >= ROUTE_ENTRIES_PER_PKT_MAX)) { 3036 3037 /* Complete setup for current packet, if any */ 3038 if (cur_pkt_idx >= 0) { 3039 /* Set header and record length */ 3040 disc_pkt_setup(pkt_buf + CPUTRANS_HEADER_BYTES, 3041 DISC_PKT_TYPE_ROUTING, num_entries, 0, 3042 db_ref->local_entry->base.dseq_num, version); 3043 route_pkt_len[cur_pkt_idx] = ROUTE_PKT_BYTES_MAX - 3044 pkt_bytes_left; 3045 } 3046 3047 /* Check route packets limit */ 3048 if ((++cur_pkt_idx) >= ROUTE_PKTS_MAX) { 3049 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3050 (BSL_META("disc ERR: number of route pkts exceeds limit %d\n"), 3051 ROUTE_PKTS_MAX)); 3052 ++disc_internal_err; 3053 ++disc_tot_err; 3054 return -1; 3055 } 3056 3057 num_entries = 0; 3058 pkt_buf = route_pkt_buf[cur_pkt_idx]; 3059 pkt_bytes_left = ROUTE_PKT_BYTES_MAX - 3060 (CPUTRANS_HEADER_BYTES + ENTRY_START_OFS); 3061 } 3062 3063 /* Pack the entry */ 3064 cur_offset = ROUTE_PKT_BYTES_MAX - pkt_bytes_left; 3065 entry_bytes = db_entry_pack(&pkt_buf[cur_offset], entry, 3066 pkt_bytes_left, version); 3067 if (entry_bytes < 0) { 3068 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3069 (BSL_META("disc ERR: cannot pack route entry %d in packet %d\n"), 3070 num_entries + 1, cur_pkt_idx)); 3071 ++disc_internal_err; 3072 ++disc_tot_err; 3073 return -1; 3074 } 3075 3076 pkt_bytes_left -= entry_bytes; 3077 num_entries++; 3078 tot_entries++; 3079 3080 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3081 (BSL_META("disc: Packing route entry %d in packet %d, " 3082 "buffer left %d\n"), 3083 num_entries, cur_pkt_idx, pkt_bytes_left)); 3084 } 3085 3086 /* Complete setup for last packet, if needed */ 3087 if (num_entries != 0) { 3088 disc_pkt_setup(pkt_buf + CPUTRANS_HEADER_BYTES, 3089 DISC_PKT_TYPE_ROUTING, num_entries, 0, 3090 db_ref->local_entry->base.dseq_num, version); 3091 route_pkt_len[cur_pkt_idx] = ROUTE_PKT_BYTES_MAX - pkt_bytes_left; 3092 } 3093 3094 tot_pkts = cur_pkt_idx + 1; 3095 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3096 (BSL_META("disc: Packed %d entries in %d pkts\n"), 3097 tot_entries, tot_pkts)); 3098 3099 return tot_pkts; 3100 } 3101 3102 3103 /* 3104 * Send out routing packets to each off board port; may need to send 3105 * more than one packet to cover all entries in the DB. 3106 */ 3107 STATIC void 3108 routing_pkts_send(cpudb_ref_t db_ref) 3109 { 3110 int num_pkts; 3111 int i; 3112 3113 if (!(disc_flags & DF_TX_KNOWN)) { 3114 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3115 (BSL_META("disc: No route out; no TX known\n"))); 3116 return; 3117 } 3118 3119 num_pkts = routing_pkts_form(db_ref); 3120 if (num_pkts <= 0) { 3121 return; 3122 } 3123 3124 DISC_LOCK; 3125 disc_flags &= ~DF_DB_UPDATED; /* Clear updated flag */ 3126 DISC_UNLOCK; 3127 3128 for (i = 0; i < num_pkts; i++) { 3129 route_pkt_tx(db_ref, route_pkt_buf[i], route_pkt_len[i]); 3130 if (DISC_EXIT) { 3131 break; 3132 } 3133 } 3134 } 3135 3136 3137 STATIC INLINE void 3138 db_stk_entry_pack(uint8 *buf, cpudb_entry_t *entry, int sp, int version) 3139 { 3140 cpudb_stk_port_t *sp_p; 3141 3142 sp_p = &entry->sp_info[sp]; 3143 PACK_U32_INCR(buf, sp_p->flags); 3144 CPUDB_KEY_PACK(buf, sp_p->tx_cpu_key); 3145 buf += CPUDB_KEY_BYTES; 3146 PACK_U32_INCR(buf, sp_p->tx_stk_idx); 3147 CPUDB_KEY_PACK(buf, sp_p->rx_cpu_key); 3148 buf += CPUDB_KEY_BYTES; 3149 PACK_U32_INCR(buf, sp_p->rx_stk_idx); 3150 if (version >= DISCOVERY_VERSION_1) { 3151 PACK_U32_INCR(buf, entry->base.stk_ports[sp].weight); 3152 PACK_U32_INCR(buf, entry->base.stk_ports[sp].bflags); 3153 } 3154 if (version >= DISCOVERY_VERSION_2) { 3155 PACK_U32_INCR(buf, entry->base.stk_ports[sp].unit); 3156 PACK_U32_INCR(buf, entry->base.stk_ports[sp].port); 3157 } 3158 } 3159 3160 3161 STATIC INLINE int 3162 db_entry_pack(uint8 *buf, cpudb_entry_t *entry, int max_bytes, int version) 3163 { 3164 int bytes = 0; 3165 int sp; 3166 int i; 3167 3168 bytes = route_entry_bytes_get(entry->base.num_stk_ports, 3169 entry->base.num_units, version); 3170 if (bytes > max_bytes) { 3171 return -1; 3172 } 3173 3174 CPUDB_KEY_PACK(buf, entry->base.key); 3175 buf += CPUDB_KEY_BYTES; 3176 sal_memcpy(buf, entry->base.mac, sizeof(bcm_mac_t)); 3177 buf += sizeof(bcm_mac_t); 3178 PACK_U32_INCR(buf, entry->base.dseq_num); 3179 /* coverity[result_independent_of_operands] */ 3180 PACK_U32_INCR(buf, entry->flags & CPUDB_F_FORWARD_MASK); 3181 PACK_U32_INCR(buf, entry->base.slot_id); 3182 PACK_U32_INCR(buf, entry->base.master_pri); 3183 3184 /* Set application data with Board ID and Flag information */ 3185 if (version >= DISCOVERY_VERSION_2) { 3186 #if defined(DISCOVER_APP_DATA_BOARDID) 3187 uint8 *app_buf = entry->base.app_data; 3188 PACK_U32_INCR(app_buf, entry->base.board_id); 3189 PACK_U32_INCR(app_buf, entry->base.flags); 3190 #endif /* DISCOVER_APP_DATA_BOARDID */ 3191 } 3192 sal_memcpy(buf, entry->base.app_data, CPUDB_APP_DATA_BYTES); 3193 buf += CPUDB_APP_DATA_BYTES; 3194 3195 PACK_U32_INCR(buf, entry->base.num_units); 3196 PACK_U32_INCR(buf, entry->base.dest_unit); 3197 PACK_U32_INCR(buf, entry->base.dest_port); 3198 PACK_U32_INCR(buf, entry->base.num_stk_ports); 3199 3200 for (i = 0; i < entry->base.num_units; i++) { 3201 PACK_U32_INCR(buf, entry->base.mod_ids_req[i]); 3202 PACK_U32_INCR(buf, entry->base.pref_mod_id[i]); 3203 } 3204 3205 for (sp = 0; sp < entry->base.num_stk_ports; sp++) { 3206 db_stk_entry_pack(buf, entry, sp, version); 3207 buf += stk_entry_bytes_get(version); 3208 } 3209 3210 return bytes; 3211 } 3212 3213 3214 /**************************************************************** 3215 * 3216 * Local DB access routines 3217 */ 3218 3219 /* 3220 * If key exists in CPUDB, return pointer to entry; otherwise add it 3221 * and return the new entry. If entry is added, update discovery 3222 * updated timer. 3223 */ 3224 STATIC cpudb_entry_t * 3225 _disc_key_resolve(cpudb_ref_t db_ref, cpudb_key_t key, bcm_mac_t mac, 3226 int dseq_num) 3227 { 3228 cpudb_entry_t *entry; 3229 3230 3231 CPUDB_KEY_SEARCH(db_ref, key, entry); 3232 3233 if (entry != NULL) { 3234 return entry; 3235 } 3236 3237 DISC_LOCK; 3238 disc_flags |= DF_DB_UPDATED; 3239 DISC_UNLOCK; 3240 entry = cpudb_entry_create(db_ref, key, FALSE); 3241 if (entry == NULL) { 3242 disc_external_err++; 3243 ++disc_tot_err; 3244 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3245 (BSL_META("disc ERR: Error adding key\n"))); 3246 return NULL; 3247 } 3248 sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t)); 3249 db_entry_clear_mod_ids(entry); 3250 entry->base.dseq_num = dseq_num; 3251 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3252 (BSL_META("disc: Added key " CPUDB_KEY_FMT 3253 "), mac %x:%x seq %d to DB\n"), CPUDB_KEY_DISP(key), 3254 mac[4], mac[5], dseq_num)); 3255 3256 return entry; 3257 } 3258 3259 /* Return index local stack port arrays if found */ 3260 STATIC int 3261 stk_port_find(cpudb_ref_t db_ref, int unit, int port) 3262 { 3263 int i; 3264 3265 for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) { 3266 if (unit == STKP_UNIT(db_ref, i) && port == STKP_PORT(db_ref, i)) { 3267 return i; 3268 } 3269 } 3270 3271 return -1; 3272 } 3273 3274 /* Handles versions 0, 1, and 2 config packets */ 3275 3276 STATIC bcm_rx_t 3277 disc_config_pkt_handler_ver(cpudb_key_t src_key, 3278 int client_id, 3279 bcm_pkt_t *pkt, 3280 uint8 *payload, 3281 int payload_len, 3282 cpudb_ref_t db_ref) 3283 { 3284 cpudb_entry_t *entry; 3285 uint32 src_dseq_num; 3286 uint32 master_dseq_num; 3287 int num_cpus; 3288 cpudb_key_t master_key; 3289 3290 /* Called with DISC_LOCK held */ 3291 /* See cfg_header_pack below */ 3292 num_cpus = payload[ENTRY_COUNT_OFS]; 3293 UNPACK_LONG(&payload[SRC_DSEQ_NUM_OFS], src_dseq_num); 3294 CPUDB_KEY_UNPACK(&payload[CFG_MASTER_KEY_OFS], master_key); 3295 UNPACK_LONG(&payload[CFG_MSEQ_NUM_OFS], master_dseq_num); 3296 3297 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3298 (BSL_META("disc: Config pkt in from " CPUDB_KEY_FMT " disc SN %d\n"), 3299 CPUDB_KEY_DISP(src_key), src_dseq_num)); 3300 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3301 (BSL_META("disc: Cfg pkt master key " CPUDB_KEY_FMT " disc SN %d\n"), 3302 CPUDB_KEY_DISP(master_key), master_dseq_num)); 3303 3304 /* 3305 * Search for the src key entry. 3306 * Check the discovery sequence numbers agree. 3307 */ 3308 CPUDB_KEY_SEARCH(db_ref, src_key, entry); 3309 if (entry == NULL) { 3310 ++disc_rx_pkt_err; 3311 ++disc_tot_err; 3312 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3313 (BSL_META("disc ERR: Config pkt, bad source key " 3314 CPUDB_KEY_FMT_EOLN), 3315 CPUDB_KEY_DISP(src_key))); 3316 DISC_UNLOCK; 3317 return BCM_RX_HANDLED; 3318 } 3319 if (entry->base.dseq_num != src_dseq_num) { 3320 ++disc_rx_pkt_err; 3321 ++disc_tot_err; 3322 LOG_WARN(BSL_LS_TKS_DISCOVER, 3323 (BSL_META("disc warn: Config pkt from " CPUDB_KEY_FMT 3324 "), seq num mismatch: pkt %d, db %d\n"), 3325 CPUDB_KEY_DISP(src_key), 3326 src_dseq_num, entry->base.dseq_num)); 3327 DISC_UNLOCK; 3328 return BCM_RX_HANDLED; 3329 } 3330 if (db_ref->num_cpus != num_cpus) { 3331 ++disc_rx_pkt_err; 3332 ++disc_tot_err; 3333 LOG_WARN(BSL_LS_TKS_DISCOVER, 3334 (BSL_META("disc warn: Config pkt from " CPUDB_KEY_FMT 3335 "), num CPU mismatch: pkt %d db %d\n"), 3336 CPUDB_KEY_DISP(src_key), 3337 num_cpus, db_ref->num_cpus)); 3338 DISC_UNLOCK; 3339 return BCM_RX_HANDLED; 3340 } 3341 3342 /* If local is master, this should be a confirmation packet */ 3343 if (db_ref->local_entry == db_ref->master_entry) { 3344 if (!CPUDB_KEY_EQUAL(master_key, db_ref->local_entry->base.key)) { 3345 DISC_UNLOCK; 3346 LOG_WARN(BSL_LS_TKS_DISCOVER, 3347 (BSL_META("disc ERR: Config pkt from " CPUDB_KEY_FMT 3348 "), master mismatch: pkt " CPUDB_KEY_FMT 3349 "), (local master)\n"), 3350 CPUDB_KEY_DISP(src_key), 3351 CPUDB_KEY_DISP(master_key))); 3352 return BCM_RX_HANDLED; 3353 } 3354 entry->flags |= CPUDB_F_CONFIG_IN; 3355 } else { /* I'm not the master. */ 3356 if (db_ref->master_entry != NULL && 3357 db_ref->master_entry != entry) { 3358 LOG_WARN(BSL_LS_TKS_DISCOVER, 3359 (BSL_META("disc WARN: Config pkt w/ different master; " 3360 "overwriting\n"))); 3361 } 3362 db_ref->master_entry = entry; 3363 entry->flags |= CPUDB_F_IS_MASTER; 3364 disc_flags |= DF_SEND_CFG_PKT; 3365 disc_flags &= ~DF_CFG_PKT_SENT; 3366 } 3367 3368 DISC_UNLOCK; 3369 DISC_WAKE; 3370 3371 return BCM_RX_HANDLED; 3372 } 3373 3374 STATIC bcm_rx_t 3375 disc_config_pkt_handler(cpudb_key_t src_key, 3376 int client_id, 3377 bcm_pkt_t *pkt, 3378 uint8 *payload, 3379 int payload_len, 3380 void *cookie) 3381 { 3382 uint8 d_ver; 3383 cpudb_ref_t db_ref; 3384 3385 if (!INIT_DONE) { 3386 return BCM_RX_NOT_HANDLED; 3387 } 3388 3389 DISC_LOCK; 3390 3391 if (!(disc_flags & DF_DISC_RUNNING) || 3392 (disc_flags & DF_DISC_SUCCESS)) { 3393 DISC_UNLOCK; 3394 LOG_WARN(BSL_LS_TKS_DISCOVER, 3395 (BSL_META("disc: Config pkt in when disc_flags are %x.\n"), 3396 disc_flags)); 3397 return BCM_RX_NOT_HANDLED; 3398 } 3399 3400 db_ref = (cpudb_ref_t)cookie; 3401 if (!cpudb_valid(db_ref) || (db_ref->local_entry == NULL)) { 3402 DISC_UNLOCK; 3403 LOG_WARN(BSL_LS_TKS_DISCOVER, 3404 (BSL_META("disc: Config pkt in when db_ref is invalid.\n"))); 3405 return BCM_RX_NOT_HANDLED; 3406 } 3407 3408 if (!(db_ref->local_entry->flags & CPUDB_F_LOCAL_COMPLETE)) { 3409 DISC_UNLOCK; 3410 LOG_WARN(BSL_LS_TKS_DISCOVER, 3411 (BSL_META("disc: Config pkt in when local DB not complete\n"))); 3412 return BCM_RX_NOT_HANDLED; 3413 } 3414 3415 d_ver = payload[DISC_VER_OFS]; 3416 3417 switch (d_ver) { 3418 case DISCOVERY_VERSION_0: 3419 case DISCOVERY_VERSION_1: 3420 case DISCOVERY_VERSION_2: 3421 return disc_config_pkt_handler_ver(src_key, client_id, pkt, 3422 payload, payload_len, db_ref); 3423 3424 } 3425 3426 /* Unknown version - throw packet away */ 3427 DISC_UNLOCK; 3428 LOG_WARN(BSL_LS_TKS_DISCOVER, 3429 (BSL_META("disc: Unknown discovery version %d in config\n"), 3430 d_ver)); 3431 return BCM_RX_HANDLED; 3432 } 3433 3434 STATIC void 3435 cfg_header_pack(cpudb_ref_t db_ref, uint8 *buf) 3436 { 3437 buf += CPUTRANS_HEADER_BYTES; 3438 disc_pkt_setup(buf, DISC_PKT_TYPE_CONFIG, db_ref->num_cpus, 3439 0, db_ref->local_entry->base.dseq_num, disc_version); 3440 buf += DISC_HEADER_BYTES; 3441 CPUDB_KEY_PACK(buf, db_ref->master_entry->base.key); 3442 buf += CPUDB_KEY_BYTES; 3443 PACK_LONG(buf, db_ref->master_entry->base.dseq_num); 3444 buf += sizeof(uint32); 3445 } 3446 3447 /* 3448 * Send out config pkts to each other CPUs in DB; if master, send to 3449 * all other CPUs. Otherwise, just direct to the master. 3450 * 3451 * Returns BCM_E_XXX 3452 */ 3453 STATIC int 3454 disc_config_send(cpudb_ref_t db_ref) 3455 { 3456 uint8 *buf, *start_buf; 3457 int len; 3458 int rv = BCM_E_NONE; 3459 cpudb_entry_t *entry; 3460 3461 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3462 (BSL_META("DISC: Generating config packet(s)\n"))); 3463 3464 if (!cpudb_valid(db_ref) || (db_ref->master_entry == NULL)) { 3465 LOG_WARN(BSL_LS_TKS_DISCOVER, 3466 (BSL_META("disc WARN: cfg send; master is NULL\n"))); 3467 return BCM_E_PARAM; 3468 } 3469 3470 if (!(LOCAL_FLAGS(db_ref) & CPUDB_F_LOCAL_COMPLETE)) { 3471 LOG_WARN(BSL_LS_TKS_DISCOVER, 3472 (BSL_META("disc WARN: cfg send, but not local complete\n"))); 3473 } 3474 3475 len = CPUTRANS_HEADER_BYTES + CFG_HEADER_BYTES; 3476 buf = start_buf = DATA_SALLOC(len); 3477 if (buf == NULL) { 3478 ++disc_alloc_fail; 3479 ++disc_tot_err; 3480 return BCM_E_MEMORY; 3481 } 3482 cfg_header_pack(db_ref, buf); 3483 3484 if (db_ref->local_entry != db_ref->master_entry) { 3485 /* Send only to master */ 3486 rv = atp_tx(db_ref->master_entry->base.key, 3487 DISC_CONFIG_CLIENT_ID, 3488 start_buf, 3489 len, 3490 CPUTRANS_NO_HEADER_ALLOC, 3491 NULL, 3492 NULL); 3493 if (BCM_FAILURE(rv)) { 3494 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3495 (BSL_META("disc ERR: %s (%d) Failed to tx cfg pkt to " 3496 CPUDB_KEY_FMT_EOLN), 3497 bcm_errmsg(rv), rv, 3498 CPUDB_KEY_DISP(db_ref->master_entry->base.key))); 3499 } 3500 } else { 3501 CPUDB_FOREACH_ENTRY(db_ref, entry) { 3502 if (entry == db_ref->local_entry) { 3503 continue; 3504 } 3505 3506 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3507 (BSL_META("disc: Cfg pkt out to " CPUDB_KEY_FMT_EOLN), 3508 CPUDB_KEY_DISP(entry->base.key))); 3509 rv = atp_tx(entry->base.key, 3510 DISC_CONFIG_CLIENT_ID, 3511 start_buf, 3512 len, 3513 CPUTRANS_NO_HEADER_ALLOC, 3514 NULL, 3515 NULL); 3516 if (BCM_FAILURE(rv)) { 3517 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3518 (BSL_META("disc ERR: %s (%d) Failed to tx pkt to " 3519 CPUDB_KEY_FMT_EOLN), 3520 bcm_errmsg(rv), rv, 3521 CPUDB_KEY_DISP(entry->base.key))); 3522 break; 3523 } 3524 } 3525 } 3526 3527 DATA_SFREE(start_buf); 3528 return BCM_E_NONE; 3529 } 3530 3531 3532 /* 3533 * Function: 3534 * disc_m_elect_default 3535 * Purpose: 3536 * Default master election function 3537 * Parameters: 3538 * db_ref - The DB to analyze 3539 * Returns: 3540 * DISC_RESTART_NEW_SEQ is supported 3541 * BCM_E_XXX 3542 * Notes: 3543 * Used if no other master elect is provided. 3544 * Only set the local master if "global complete" is set. This ensures 3545 * info is spread to other CPUs. 3546 * 3547 * If local is not master, set master_entry so that discovery will 3548 * register to receive configuration packets 3549 * 3550 * Uses highest master priority/lowest key as master; 3551 */ 3552 3553 STATIC int 3554 disc_m_elect_default(cpudb_ref_t db_ref, void *user_data) 3555 { 3556 cpudb_entry_t *entry, *best_entry; 3557 int high_priority; 3558 3559 COMPILER_REFERENCE(user_data); 3560 3561 if (db_ref == CPUDB_REF_NULL || db_ref->local_entry == NULL) { 3562 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3563 (BSL_META("disc m_elect ERR: Bad DB or local entry\n"))); 3564 return BCM_E_FAIL; 3565 } 3566 3567 /* 3568 * First, find the highest priority in the DB; 3569 * Then find the lowest key of those with that priority 3570 */ 3571 best_entry = db_ref->local_entry; 3572 high_priority = db_ref->local_entry->base.master_pri; 3573 CPUDB_FOREACH_ENTRY(db_ref, entry) { 3574 if (entry == db_ref->local_entry) { 3575 continue; 3576 } 3577 if (entry->base.master_pri > high_priority) { 3578 best_entry = entry; 3579 high_priority = entry->base.master_pri; 3580 } 3581 } 3582 3583 CPUDB_FOREACH_ENTRY(db_ref, entry) { 3584 if (entry == db_ref->local_entry || entry == best_entry) { 3585 continue; 3586 } 3587 if (entry->base.master_pri == high_priority) { 3588 if (CPUDB_KEY_COMPARE(entry->base.key, 3589 best_entry->base.key) < 0) { 3590 best_entry = entry; 3591 } 3592 } 3593 } 3594 3595 if (best_entry == db_ref->local_entry) { /* See notes */ 3596 if (!(LOCAL_FLAGS(db_ref) & CPUDB_F_GLOBAL_COMPLETE)) { 3597 LOG_DEBUG(BSL_LS_TKS_DISCOVER, 3598 (BSL_META("disc m_elect: " 3599 "Local is master; wait for global complete\n"))); 3600 return BCM_E_NONE; 3601 } 3602 } 3603 3604 if (db_ref->master_entry != NULL && db_ref->master_entry != best_entry) { 3605 LOG_WARN(BSL_LS_TKS_DISCOVER, 3606 (BSL_META("DISC m_elect: Master set, but changing\n"))); 3607 } 3608 3609 db_ref->master_entry = best_entry; 3610 best_entry->flags |= CPUDB_F_IS_MASTER; 3611 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3612 (BSL_META("disc m_elect: Master is " 3613 CPUDB_KEY_FMT ", %slocal\n"), 3614 CPUDB_KEY_DISP(best_entry->base.key), 3615 best_entry == db_ref->local_entry ? "" : "not ")); 3616 return BCM_E_NONE; 3617 } 3618 3619 #if defined(BROADCOM_DEBUG) 3620 void 3621 disc_counter_dump(void) 3622 { 3623 LOG_INFO(BSL_LS_TKS_DISCOVER, 3624 (BSL_META("disc_alloc_fail = %d\n"), 3625 disc_alloc_fail)); 3626 LOG_INFO(BSL_LS_TKS_DISCOVER, 3627 (BSL_META("disc_resource_err = %d\n"), 3628 disc_resource_err)); 3629 LOG_INFO(BSL_LS_TKS_DISCOVER, 3630 (BSL_META("disc_internal_err = %d\n"), 3631 disc_internal_err)); 3632 LOG_INFO(BSL_LS_TKS_DISCOVER, 3633 (BSL_META("disc_tx_pkt_err = %d\n"), 3634 disc_tx_pkt_err)); 3635 LOG_INFO(BSL_LS_TKS_DISCOVER, 3636 (BSL_META("disc_rx_pkt_err = %d\n"), 3637 disc_rx_pkt_err)); 3638 LOG_INFO(BSL_LS_TKS_DISCOVER, 3639 (BSL_META("disc_tot_err = %d\n"), 3640 disc_tot_err)); 3641 LOG_INFO(BSL_LS_TKS_DISCOVER, 3642 (BSL_META("disc_external_err = %d\n"), 3643 disc_external_err)); 3644 } 3645 #endif /* BROADCOM_DEBUG */ 3646 3647 static void 3648 disc_status_set(disc_status_t status) 3649 { 3650 sal_mutex_take(disc_status_lock, sal_mutex_FOREVER); 3651 disc_stat = status; 3652 sal_mutex_give(disc_status_lock); 3653 } 3654 3655 /* 3656 * Function: 3657 * int disc_election_register(*disc_election_cb_t m_elect, 3658 * void *user_data) 3659 * Purpose: 3660 * Register a master election function 3661 * Parameters: 3662 * m_elect - election function 3663 * user_data - currently ignored 3664 * Returns: 3665 * BCM_E_NONE - no errors 3666 * BCM_E_PARAM - m_elect is NULL 3667 * Notes: 3668 * Only one registration at a time, and each new registration 3669 * overwrites the previous one. 3670 */ 3671 3672 int 3673 disc_election_register(disc_election_cb_t m_elect, void *user_data) 3674 { 3675 int rv = BCM_E_PARAM; 3676 3677 if (m_elect != NULL) { 3678 disc_m_elect = m_elect; 3679 disc_m_user_data = user_data; 3680 3681 /* Don't use an old callback interface */ 3682 disc_start_elect = NULL; 3683 rv = BCM_E_NONE; 3684 } 3685 3686 return rv; 3687 } 3688 3689 /* 3690 * Function: 3691 * disc_election_unregister(*disc_election_cb_t m_elect, 3692 * void *user_data) 3693 * Purpose: 3694 * Deregister a master election function 3695 * Parameters: 3696 * m_elect - election function 3697 * user_data - currently ignored 3698 * Returns: 3699 * BCM_E_NONE - no errors 3700 * BCM_E_PARAM - m_elect and/or user_data was not initially registered 3701 * Notes: 3702 * Election reverts to default election function 3703 */ 3704 3705 int 3706 disc_election_unregister(disc_election_cb_t m_elect, void *user_data) 3707 { 3708 int rv = BCM_E_PARAM; 3709 3710 if (disc_m_elect == m_elect && disc_m_user_data == user_data) { 3711 disc_m_elect = disc_m_elect_default; 3712 disc_m_user_data = NULL; 3713 rv = BCM_E_NONE; 3714 } 3715 return rv; 3716 } 3717 3718 /* 3719 * Function: 3720 * disc_run 3721 * Purpose: 3722 * Run the discovery process 3723 * Parameters: 3724 * db_ref - The database reference to use; see notes 3725 * Returns: 3726 * BCM_E_XXX 3727 * Notes: 3728 * This routine is not re-entrant. 3729 * 3730 * The discovery sequence number will be extracted from the local 3731 * CPU DB entry. 3732 */ 3733 STATIC int 3734 _disc_run_prep(cpudb_ref_t db_ref) 3735 { 3736 int rv = BCM_E_NONE; 3737 3738 DISC_LOCK; 3739 if (disc_flags & DF_DISC_RUNNING) { 3740 DISC_UNLOCK; 3741 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3742 (BSL_META("_disc_run_prep: terminating existing disc\n"))); 3743 if (disc_abort(BCM_E_FAIL, 500000) != BCM_E_NONE) { 3744 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3745 (BSL_META("%s: disc_abort failed.\n"), 3746 FUNCTION_NAME())); 3747 return BCM_E_BUSY; 3748 } 3749 DISC_LOCK; 3750 } else { 3751 /* reset internal flags */ 3752 disc_flags = 0; 3753 } 3754 3755 if (disc_trans_ptr == NULL) { 3756 DISC_UNLOCK; 3757 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3758 (BSL_META("_disc_run ERR: Need transport pointers\n"))); 3759 return BCM_E_FAIL; 3760 } 3761 3762 if (db_ref == NULL) { 3763 DISC_UNLOCK; 3764 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3765 (BSL_META("%s ERR: Need DB ref pointers\n"), 3766 FUNCTION_NAME())); 3767 return BCM_E_PARAM; 3768 } 3769 3770 #if defined(BROADCOM_DEBUG) 3771 rv = _check_start_values(db_ref); 3772 if (BCM_FAILURE(rv)) { 3773 DISC_UNLOCK; 3774 return rv; 3775 } 3776 #endif /* BROADCOM_DEBUG */ 3777 3778 rv = disc_prep(db_ref); 3779 DISC_UNLOCK; 3780 3781 return rv; 3782 } 3783 3784 /* 3785 * Function: 3786 * 3787 * Purpose: 3788 * Register discovery packet processing 3789 * Parameters: 3790 * db_ref - The database reference to use; see notes 3791 * Returns: 3792 * BCM_E_XXX 3793 * Notes: 3794 * This routine is not re-entrant. 3795 * 3796 * The discovery sequence number will be extracted from the local 3797 * CPU DB entry. 3798 */ 3799 STATIC int 3800 _disc_run_reg(cpudb_ref_t *db_refp) 3801 { 3802 int rv = BCM_E_NONE; 3803 3804 /* Register with next hop */ 3805 rv = next_hop_register(disc_rx_pkt, db_refp, DISC_NH_PKT_TYPE); 3806 if (BCM_FAILURE(rv)) { 3807 LOG_ERROR(BSL_LS_TKS_DISCOVER, 3808 (BSL_META("disc ERR: Could not register RX callback"))); 3809 DISC_LOCK; 3810 disc_flags |= DF_DISC_ERROR; 3811 DISC_UNLOCK; 3812 } else { 3813 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3814 (BSL_META("disc: registered with nexthop\n"))); 3815 } 3816 return rv; 3817 } 3818 3819 /* 3820 * Function: 3821 * _disc_run_unreg 3822 * Purpose: 3823 * Unregister discovery packet processing 3824 * Parameters: 3825 * none 3826 * Returns: 3827 * BCM_E_XXX 3828 * Notes: 3829 */ 3830 STATIC int 3831 _disc_run_unreg(void) 3832 { 3833 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3834 (BSL_META("disc: unregistered with nexthop\n"))); 3835 return next_hop_unregister(disc_rx_pkt, DISC_NH_PKT_TYPE); 3836 } 3837 3838 /* 3839 * Function: 3840 * _disc_run_loop 3841 * Purpose: 3842 * Procoess discovery packets until discovery termination 3843 * Parameters: 3844 * db_ref - The database reference to use; see notes 3845 * Returns: 3846 * BCM_E_XXX 3847 * Notes: 3848 */ 3849 STATIC int 3850 _disc_run_loop(cpudb_ref_t db_ref) 3851 { 3852 int rv = BCM_E_NONE; 3853 3854 /* Main discovery loop */ 3855 while (TRUE) { 3856 DISC_SLEEP(disc_retrx_us); 3857 DISC_LOCK; 3858 disc_flags &= ~DF_IGNORE_PACKETS; /* Time to check pkts */ 3859 DISC_UNLOCK; 3860 3861 disc_status_update(db_ref); 3862 if (disc_done_check(db_ref, &rv, FALSE)) { 3863 break; 3864 } 3865 3866 disc_pkts_process(db_ref); /* incoming and outgoing pkts */ 3867 if (disc_done_check(db_ref, &rv, FALSE)) { 3868 break; 3869 } 3870 3871 disc_status_update(db_ref); 3872 if (disc_done_check(db_ref, &rv, FALSE)) { 3873 break; 3874 } 3875 } 3876 3877 return rv; 3878 } 3879 3880 /* 3881 * Function: 3882 * _disc_run_complete 3883 * Purpose: 3884 * Mark completion of the discovery process 3885 * Parameters: 3886 * db_ref - The database reference to use; see notes 3887 * Returns: 3888 * BCM_E_XXX 3889 * Notes: 3890 */ 3891 STATIC int 3892 _disc_run_complete(cpudb_ref_t db_ref) 3893 { 3894 int rv = BCM_E_NONE; 3895 3896 DISC_LOCK; 3897 disc_flags |= DF_ABORT_ACK; 3898 DISC_UNLOCK; 3899 3900 return rv; 3901 } 3902 3903 /* 3904 * Function: 3905 * _disc_run 3906 * Purpose: 3907 * Run the discovery process once through 3908 * Parameters: 3909 * db_ref - The database reference to use; see notes 3910 * Returns: 3911 * BCM_E_XXX 3912 * Notes: 3913 * This routine is not re-entrant. 3914 * 3915 * The discovery sequence number will be extracted from the local 3916 * CPU DB entry. 3917 */ 3918 STATIC int 3919 _disc_run(cpudb_ref_t db_ref) 3920 { 3921 int rv = BCM_E_NONE; 3922 3923 DISC_INIT_CHECK; 3924 3925 BCM_IF_ERROR_RETURN(_disc_run_prep(db_ref)); 3926 3927 if (!DISC_TASK) { 3928 BCM_IF_ERROR_RETURN(_disc_run_reg(&db_ref)); 3929 } 3930 3931 rv = _disc_run_loop(db_ref); 3932 3933 if (!DISC_TASK) { 3934 BCM_IF_ERROR_RETURN(_disc_run_unreg()); 3935 } 3936 3937 BCM_IF_ERROR_RETURN(_disc_run_complete(db_ref)); 3938 3939 return rv; 3940 } 3941 3942 static int _disc_sequence_number; 3943 3944 3945 STATIC int 3946 _disc_run_restart_loop(cpudb_ref_t db_ref) 3947 { 3948 int rv = BCM_E_NONE; 3949 int co_rv = BCM_E_NONE; 3950 3951 do { 3952 /* clear any non-local entries, either from the cpudb supplied, 3953 or a populated cpudb from a restart. */ 3954 cpudb_clear(db_ref, TRUE); 3955 3956 /* set sequence number */ 3957 if (rv != DISC_RESTART_REQUEST) { 3958 CUR_DSEQ_NUM(db_ref) = _disc_sequence_number++; 3959 } 3960 3961 /* run discovery */ 3962 rv = _disc_run(db_ref); 3963 co_rv = disc_callout(db_ref, rv); 3964 3965 3966 /* Keep looping while there is a restart return value from 3967 _disc_run() and the callout has allowed the restart. */ 3968 3969 } while ( (rv == DISC_RESTART_REQUEST || rv == DISC_RESTART_NEW_SEQ) && 3970 BCM_SUCCESS(co_rv) ); 3971 3972 return rv; 3973 } 3974 3975 STATIC int 3976 disc_callout(cpudb_ref_t db_ref, int status) 3977 { 3978 int rv = BCM_E_PARAM; 3979 3980 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3981 (BSL_META("disc: callout status:%d\n"), 3982 status)); 3983 if (_disc_callback.callback) { 3984 rv = _disc_callback.callback(db_ref, status, _disc_callback.user_data); 3985 } 3986 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 3987 (BSL_META("disc: callout returns %d\n"), 3988 rv)); 3989 3990 return rv; 3991 } 3992 3993 /* 3994 * Discovery thread for asynchronous callback 3995 */ 3996 STATIC void 3997 _disc_run_thread(void *user_data) 3998 { 3999 do { 4000 disc_status_set(DISC_STATUS_TASK_IDLE); 4001 DISC_TASK_SLEEP; 4002 4003 if (disc_task_cmd == DISC_TASK_CMD_RUN) { 4004 (void)_disc_run_restart_loop(disc_task_db); 4005 } 4006 } while (disc_task_cmd == DISC_TASK_CMD_RUN); 4007 disc_status_set(DISC_STATUS_INACTIVE); 4008 4009 _disc_tid = SAL_THREAD_ERROR; 4010 sal_thread_exit(0); 4011 } 4012 4013 /* 4014 * Start discovery thread. 4015 */ 4016 STATIC int 4017 disc_run_task(void) 4018 { 4019 int rv = BCM_E_NONE; 4020 4021 if ((_disc_tid = sal_thread_create("bcmDISC", 4022 DISC_THREAD_STACK, 4023 DISC_THREAD_PRIORITY, 4024 _disc_run_thread, 4025 NULL)) 4026 == SAL_THREAD_ERROR) { 4027 LOG_ERROR(BSL_LS_TKS_DISCOVER, 4028 (BSL_META("disc ERR: Could not create discovery thread\n"))); 4029 rv = BCM_E_FAIL; 4030 } 4031 return rv; 4032 } 4033 4034 /* 4035 * Function: 4036 * int disc_run(cpudb_ref_t db_ref) 4037 * Purpose: 4038 * Initiate the discovery protocol 4039 * Parameters: 4040 * db_ref - CPUDB containing local entry 4041 * Returns: 4042 * BCM_E_NONE - no errors 4043 * BCM_E_BUSY - the discovery protocol is currently running. 4044 * BCM_E_INIT - module uninitialized 4045 * Notes: 4046 * Discovery completion status is returned via a discovery 4047 * completion callback registered by disc_register() 4048 * 4049 * Only one instance of discovery, regardless of the mode, 4050 * can be running at one time. 4051 * 4052 * CPUDB is cleared to just the local entry. 4053 */ 4054 4055 int 4056 disc_run(cpudb_ref_t db_ref) 4057 { 4058 int rv = BCM_E_INTERNAL; 4059 cpudb_ref_t disc_db; 4060 4061 if (!_disc_callback.callback) { 4062 return BCM_E_CONFIG; 4063 } 4064 4065 sal_mutex_take(disc_status_lock, sal_mutex_FOREVER); 4066 { 4067 if (disc_stat == DISC_STATUS_INACTIVE) { 4068 rv = BCM_E_INIT; 4069 } else if (disc_stat != DISC_STATUS_TASK_IDLE) { 4070 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 4071 (BSL_META("disc_run busy = %d @ %d\n"), 4072 disc_stat, sal_time_usecs())); 4073 rv = BCM_E_BUSY; 4074 } else { 4075 rv = BCM_E_NONE; 4076 disc_stat = DISC_STATUS_TASK_RUNNING; 4077 } 4078 } 4079 sal_mutex_give(disc_status_lock); 4080 4081 if (BCM_SUCCESS(rv)) { 4082 disc_db = cpudb_copy(db_ref); 4083 if (disc_db) { 4084 disc_task_db = disc_db; 4085 LOG_VERBOSE(BSL_LS_TKS_DISCOVER, 4086 (BSL_META("disc_run @ %d\n"), 4087 sal_time_usecs())); 4088 DISC_TASK_WAKE; 4089 sal_thread_yield(); 4090 } else { 4091 rv = BCM_E_MEMORY; 4092 } 4093 } 4094 4095 return rv; 4096 } 4097 4098 4099 /* 4100 * Function: 4101 * disc_register(disc_cb_t callback, void *user_data) 4102 * Purpose: 4103 * Register a discovery completion callback 4104 * Parameters: 4105 * callback - function to call on completion 4106 * user_data - user data passed to callback 4107 * Returns: 4108 * BCM_E_PARAM - callback is NULL 4109 * BCM_E_NONE - no errors 4110 * Notes: 4111 * Only one registration allowed at a time. New registrations 4112 * overwrite previous registrations. 4113 * 4114 * Callback status: 4115 * 4116 * BCM_E_NONE 4117 * 4118 * Discovery has completed successfully. 4119 * 4120 * BCM_E_TIMEOUT 4121 * 4122 * Discovery has timed out while trying to complete. 4123 * 4124 * BCM_E_FAIL 4125 * 4126 * Discovery has failed for some other reason. 4127 * 4128 * DISC_RESTART_REQUEST 4129 * 4130 * Discovery requests restart with same sequence number. Request 4131 * is accepted by returning BCM_E_NONE, denied by returning 4132 * BCM_E_FAIL from the status callback. 4133 * 4134 * DISC_RESTART_NEW_SEQ 4135 * 4136 * Discovery requests restart with new sequence number. 4137 * Request is accepted by returning BCM_E_NONE, denied by 4138 * returning BCM_E_FAIL from the status callback. 4139 * 4140 * DISC_PROBE_RECEIVED 4141 * 4142 * A probe packet has been received which the discovery 4143 * process is idle. 4144 * 4145 * This will not automatically initiate discovery - the event 4146 * callback is responsible for calling or scheduling 4147 * disc_run() if discovery needs to be initiated. Called from 4148 * a packet receive callback context. 4149 */ 4150 4151 int 4152 disc_register(disc_cb_t callback, void *user_data) 4153 { 4154 int rv = BCM_E_PARAM; 4155 4156 if (callback) { 4157 _disc_callback.callback = callback; 4158 _disc_callback.user_data = user_data; 4159 rv = BCM_E_NONE; 4160 } 4161 4162 return rv; 4163 } 4164 4165 /* 4166 * Function: 4167 * disc_unregister(disc_cb_t callback, void *user_data) 4168 * Purpose: 4169 * Unregister a discovery completion callback 4170 * Parameters: 4171 * callback - function to unregister 4172 * user_data - user data passed to callback 4173 * Returns: 4174 * BCM_E_NONE - no errors 4175 * BCM_E_PARAM - callback and/or user_data was not initially registered 4176 * Notes: 4177 */ 4178 4179 int 4180 disc_unregister(disc_cb_t callback, void *user_data) 4181 { 4182 int rv = BCM_E_PARAM; 4183 4184 if (_disc_callback.callback == callback && 4185 _disc_callback.user_data == user_data) { 4186 _disc_callback.callback = NULL; 4187 _disc_callback.user_data = NULL; 4188 rv = BCM_E_NONE; 4189 } 4190 4191 return rv; 4192 } 4193 4194 /* 4195 * Function: 4196 * disc_init(void) 4197 * Purpose: 4198 * Initialize discovery subsystem. 4199 * Parameters: 4200 * none 4201 * Returns: 4202 * BCM_E_NONE - no errors 4203 * BCM_E_FAIL - Discovery thread failed to initialize 4204 * BCM_E_MEMORY - not enough memory 4205 * Notes: 4206 * Does not initiate discovery protocol. 4207 * Not required if application just uses disc_start(). 4208 */ 4209 4210 int 4211 disc_init(void) 4212 { 4213 int rv = BCM_E_INTERNAL; 4214 4215 if (disc_task_sem) { 4216 disc_deinit(); 4217 } 4218 4219 DISC_INIT_CHECK; 4220 4221 if (disc_task_sem != NULL) { 4222 sal_sem_destroy(disc_task_sem); 4223 } 4224 4225 disc_task_sem = sal_sem_create("disc_task_sem", sal_sem_BINARY, 0); 4226 4227 if (disc_task_sem != NULL) { 4228 disc_task_cmd = DISC_TASK_CMD_RUN; 4229 rv = disc_run_task(); 4230 if (BCM_SUCCESS(rv)) { 4231 disc_stat = DISC_STATUS_TASK_IDLE; 4232 rv = _disc_run_reg(&disc_task_db); 4233 } 4234 } else { 4235 rv = BCM_E_MEMORY; 4236 } 4237 4238 if (BCM_FAILURE(rv)) { 4239 (void)disc_deinit(); 4240 } 4241 4242 return rv; 4243 } 4244 4245 4246 /* 4247 * Function: 4248 * int disc_deinit(void) 4249 * Purpose: 4250 * Shutdown discovery and deallocate resources. 4251 * Parameters: 4252 * none 4253 * Returns: 4254 * BCM_E_NONE - no errors 4255 * Notes: 4256 */ 4257 4258 #ifndef DISC_DEINIT_RETRY 4259 #define DISC_DEINIT_RETRY 5 4260 #endif 4261 4262 #ifndef DISC_DEINIT_SLEEP 4263 #define DISC_DEINIT_SLEEP 10000 4264 #endif 4265 4266 4267 int 4268 disc_deinit(void) 4269 { 4270 disc_status_t stat; 4271 int i; 4272 4273 for ( i=0; i<DISC_DEINIT_RETRY; i++ ) { 4274 BCM_IF_ERROR_RETURN(disc_status_get(&stat)); 4275 4276 /* Stop running disc protocol */ 4277 if (stat == DISC_STATUS_TASK_RUNNING || 4278 stat == DISC_STATUS_SYNC_RUNNING) { 4279 disc_abort(BCM_E_FAIL, 0); 4280 sal_thread_yield(); 4281 sal_usleep(DISC_DEINIT_SLEEP); 4282 } else { 4283 break; 4284 } 4285 } 4286 4287 if (DISC_TASK) { 4288 (void) _disc_run_unreg(); 4289 /* Signal thread to stop */ 4290 disc_task_cmd = DISC_TASK_CMD_STOP; 4291 DISC_TASK_WAKE; 4292 /* May need to take extra steps if thread doesn't exit */ 4293 } 4294 4295 if (disc_task_sem) { 4296 sal_sem_destroy(disc_task_sem); 4297 } 4298 4299 if (disc_sem) { 4300 sal_sem_destroy(disc_sem); 4301 } 4302 4303 if (disc_lock) { 4304 sal_mutex_destroy(disc_lock); 4305 } 4306 4307 if (disc_status_lock) { 4308 sal_mutex_destroy(disc_status_lock); 4309 } 4310 4311 return BCM_E_NONE; 4312 } 4313 4314