rlink.c (72188B)
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 * Remote asynchronous operations including linkscan, L2 address 8 * change notification and RX tunnelling. Only provides connection 9 * service for tunnelling. The tunnelled packet handler is registered 10 * directly with RX and doesn't go through RLink notify. 11 * 12 * The client side: 13 * - remembers the application callbacks 14 * - sends an RPC to the server side indicating that registration has 15 * happended 16 * - registers with ATP to receive remote link notifications 17 * - For linkscanning, when an ATP packet is received, does a 18 * bcm_port_info_get to the remote side and then calls the 19 * application callback 20 * 21 * The server side: 22 * - receives the registration RPC from the client 23 * - remembers which units have been registered 24 * - Registers with the proper local function 25 * (eg, bcm_linkscan_register) on the local unit 26 * - when a local callback happens, sends an ATP back to any 27 * registered clients 28 * 29 * There is a thread that's started on both client and server sides to 30 * handle the RPCs and packet handling without deadlock. A single thread 31 * handles both client and server side. 32 * 33 * rlink was originally designed for a master-slave architecture. 34 * There are two master change situations that may occur: The stack 35 * changes so that the master is still present but is no longer the 36 * master. For this case, there are two sub cases: The slave remains 37 * a slave to the new master, or it becomes the master itself. 38 * 39 * The second scenario is that the master disappears from the stack. 40 * This has the same two subcases as above. 41 * 42 * In the second case, we might get a "de-registration" call from the 43 * old master when it detaches. But if communication is already torn 44 * down, we may not; and in the second case, we definitely won't get 45 * a teardown message. 46 * 47 * Because of these situations, rlink now will overwrite information if 48 * a new registration appears from a different requesting CPU. This 49 * has two implications. 50 * 51 * First, rlink will not support peer-to-peer connections. Some L2 52 * synchronization code may be peer-to-peer; either it won't use rlink, 53 * or rlink will change. 54 * 55 * Second, this may open a security hole since a rogue might be able 56 * to overwrite the current info. rlink expects a layer of security 57 * above its calls. 58 */ 59 60 #include <shared/bsl.h> 61 62 #include <shared/alloc.h> 63 #include <sal/core/libc.h> 64 #include <sal/core/sync.h> 65 #include <sal/core/thread.h> 66 67 #include <bcm/types.h> 68 #include <bcm/error.h> 69 #include <bcm/l2.h> 70 #include <bcm/link.h> 71 #include <bcm/port.h> 72 #include <bcm/rx.h> 73 #include <bcm/auth.h> 74 75 #include <soc/property.h> 76 #include <soc/drv.h> 77 78 #include <bcm_int/control.h> 79 #include <bcm_int/rpc/pack.h> 80 #include <bcm_int/rpc/rlink.h> 81 #include <bcm_int/esw/rx.h> 82 83 #include <appl/cpudb/cpudb.h> 84 #include <appl/cputrans/atp.h> 85 #include <appl/cputrans/ct_tun.h> 86 #include "rlink.h" 87 #include "traverse.h" 88 89 #ifdef BCM_RPC_SUPPORT 90 91 #ifndef RLINK_THREAD_STACK 92 #define RLINK_THREAD_STACK SAL_THREAD_STKSZ 93 #endif 94 95 #ifndef RLINK_THREAD_PRIO 96 #define RLINK_THREAD_PRIO 50 97 #endif 98 99 #define RLINK_INIT (_rlink_lock != NULL) 100 #define RLINK_SLEEP sal_sem_take(_rlink_sem, sal_sem_FOREVER) 101 #define RLINK_WAKE sal_sem_give(_rlink_sem) 102 #define RLINK_LOCK sal_mutex_take(_rlink_lock, sal_mutex_FOREVER) 103 #define RLINK_UNLOCK sal_mutex_give(_rlink_lock) 104 #define RLINK_NOTIFY_LOCK \ 105 sal_mutex_take(_rlink_notify_lock, sal_mutex_FOREVER) 106 #define RLINK_NOTIFY_UNLOCK \ 107 sal_mutex_give(_rlink_notify_lock) 108 109 #define RLINK_ENQUEUE_NOTIFY(_rnot) do { \ 110 _rnot->next = NULL; \ 111 RLINK_NOTIFY_LOCK; \ 112 if (_rlink_notify_tail == NULL) { \ 113 _rlink_notify_head = _rlink_notify_tail = _rnot; \ 114 } else { \ 115 _rlink_notify_tail->next = _rnot; \ 116 _rlink_notify_tail = _rnot; \ 117 } \ 118 ++_rlink_queue_size; \ 119 RLINK_NOTIFY_UNLOCK; \ 120 RLINK_WAKE; \ 121 } while (0) 122 123 #define MSG_STR(_m) \ 124 (((_m) == RLINK_MSG_ADD) ? "add" : \ 125 ((_m) == RLINK_MSG_DELETE) ? "delete" : \ 126 ((_m) == RLINK_MSG_NOTIFY) ? "notify" : \ 127 ((_m) == RLINK_MSG_TRAVERSE) ? "traverse" : \ 128 "?") 129 130 #define TYPE_STR(_t) \ 131 (((_t) == RLINK_TYPE_LINK) ? "link" : \ 132 ((_t) == RLINK_TYPE_AUTH) ? "auth" : \ 133 ((_t) == RLINK_TYPE_L2) ? "l2" : \ 134 ((_t) == RLINK_TYPE_RX) ? "rx" : \ 135 ((_t) == RLINK_TYPE_OAM) ? "oam" : \ 136 ((_t) == RLINK_TYPE_BFD) ? "bfd" : \ 137 ((_t) == RLINK_TYPE_ADD) ? "add" : \ 138 ((_t) == RLINK_TYPE_DELETE) ? "delete" : \ 139 ((_t) == RLINK_TYPE_START) ? "start" : \ 140 ((_t) == RLINK_TYPE_NEXT) ? "next" : \ 141 ((_t) == RLINK_TYPE_QUIT) ? "quit" : \ 142 ((_t) == RLINK_TYPE_ERROR) ? "error" : \ 143 ((_t) == RLINK_TYPE_MORE) ? "more" : \ 144 ((_t) == RLINK_TYPE_DONE) ? "done" : \ 145 "?") 146 147 /* Arguments for registration routines */ 148 typedef struct _rlink_register_args_s { 149 union { 150 struct { 151 bcm_oam_event_types_t events; 152 } oam; 153 #if defined(INCLUDE_BFD) 154 struct { 155 bcm_bfd_event_types_t events; 156 } bfd; 157 #endif 158 } u; 159 } _rlink_register_args_t; 160 161 /* client side link handlers */ 162 typedef struct _rlink_handle_s { 163 struct _rlink_handle_s *next; 164 int unit; 165 rlink_type_t type; 166 union { 167 void *generic_func_ptr; 168 bcm_linkscan_handler_t link; 169 bcm_auth_cb_t auth; 170 bcm_l2_addr_callback_t l2; 171 /* No function registration is needed for RX tunnelling since 172 * applications use bcm_rx_register directly. */ 173 bcm_oam_event_cb oam; 174 #if defined(INCLUDE_BFD) 175 bcm_bfd_event_cb bfd; 176 #endif 177 } func; 178 void *cookie; 179 cpudb_key_t cpu; 180 int cunit; 181 } _rlink_handle_t; 182 183 /* server side link handlers */ 184 typedef struct _rlink_scan_s { 185 struct _rlink_scan_s *next; 186 int unit; 187 rlink_type_t type; 188 cpudb_key_t cpu; 189 } _rlink_scan_t; 190 191 /* client side notifications (also used for server side add/delete/send) */ 192 typedef struct _rlink_notify_s { 193 struct _rlink_notify_s *next; 194 cpudb_key_t cpu; 195 int unit; 196 rlink_type_t type; 197 int pkt_send; /* Boolean: Send notify pkt? */ 198 union { 199 struct { /* For client notification ops */ 200 uint8 *buf; 201 int len; 202 int check_cpu; 203 uint32 ct_flags; 204 } cli; 205 struct { 206 bcm_port_t port; 207 bcm_port_info_t info; 208 } link; 209 struct { 210 bcm_port_t port; 211 int reason; 212 } auth; 213 struct { 214 int insert; 215 bcm_l2_addr_t addr; 216 } l2; 217 struct { 218 uint32 flags; 219 bcm_oam_event_type_t event_type; 220 bcm_oam_group_t group; 221 bcm_oam_endpoint_t endpoint; 222 } oam; 223 #if defined(INCLUDE_BFD) 224 struct { 225 uint32 flags; 226 bcm_bfd_event_types_t event_types; 227 bcm_bfd_endpoint_t endpoint; 228 } bfd; 229 #endif 230 struct { 231 rlink_type_t type; 232 } msg; 233 struct { 234 bcm_pkt_t *pkt; 235 uint8 *buf; 236 int len; 237 } traverse; 238 } u; 239 _rlink_register_args_t register_args; 240 } _rlink_notify_t; 241 242 static sal_mutex_t _rlink_lock; 243 static sal_mutex_t _rlink_notify_lock; 244 static sal_sem_t _rlink_sem; 245 static sal_thread_t _rlink_thread = SAL_THREAD_ERROR; 246 static int _rlink_thread_exit; 247 248 /* 249 * Example RLINK call sequence: 250 * 251 * CLIENT CPU: 252 * App -> linkscan_register -> client_linkscan_register 253 * RLINK adds entry to _handle_ list. 254 * Makes remote MSG_ADD call to remote CPU controlling unit 255 * ===> to remote CPU 256 * -> _rlink_pkt_handler ->_rlink_scan_add 257 * RLINK adds entry to _scan_ list. 258 * Later, a link event comes in on the remote system 259 * -> _bcm_rlink_linkscan_handler on REMOTE system 260 * Enqueues entry on _notify_ list 261 * -> rlink_thread runs through _scan_ list and 262 * sends MSG_NOTIFY to CLIENT CPUs. 263 * CLIENT CPU enqueues request on its _notify_ list. 264 * CLIENT RLINK thread dequeues notify event, 265 * runs through _handle_ list and makes callbacks. 266 * 267 * The length of the _notify_ list may be limited to avoid 268 * overload due to RX or L2 notifies. 269 */ 270 271 static _rlink_handle_t *_rlink_handle_head; 272 static _rlink_handle_t *_rlink_handle_tail; 273 static _rlink_scan_t *_rlink_scan_head; 274 static _rlink_scan_t *_rlink_scan_tail; 275 static _rlink_notify_t *_rlink_notify_head; 276 static _rlink_notify_t *_rlink_notify_tail; 277 278 /* Some counters */ 279 #if defined(BROADCOM_DEBUG) 280 #define INCR_COUNTER(counter) ++(counter) 281 volatile int rlink_link_out; 282 volatile int rlink_link_out_disc; 283 volatile int rlink_link_in; 284 volatile int rlink_link_in_disc; 285 volatile int rlink_auth_out; 286 volatile int rlink_auth_out_disc; 287 volatile int rlink_auth_in; 288 volatile int rlink_auth_in_disc; 289 volatile int rlink_l2_out; 290 volatile int rlink_l2_out_disc; 291 volatile int rlink_l2_in; 292 volatile int rlink_l2_in_disc; 293 volatile int rlink_rx_out; 294 volatile int rlink_rx_out_disc; 295 volatile int rlink_rx_in; 296 volatile int rlink_rx_in_disc; 297 volatile int rlink_oam_out; 298 volatile int rlink_oam_out_disc; 299 volatile int rlink_oam_in; 300 volatile int rlink_oam_in_disc; 301 volatile int rlink_bfd_out; 302 volatile int rlink_bfd_out_disc; 303 volatile int rlink_bfd_in; 304 volatile int rlink_bfd_in_disc; 305 306 volatile int rlink_add_req_in; 307 volatile int rlink_del_req_in; 308 volatile int rlink_notify_in; 309 volatile int rlink_trav_req_in; 310 volatile int rlink_buff_alloc_fail; 311 volatile int rlink_pkt_send_fail; 312 #else 313 #define INCR_COUNTER(counter) 314 #endif /* BROADCOM_DEBUG */ 315 316 /* The rlink queue length may be limited */ 317 static int _rlink_queue_size; 318 319 /* 320 * Since notify requests are now queued, rather than sent in 321 * the calling thread context, a queue size limiting mechanism 322 * is implemented. 323 * 324 * If foo_max > 0 and queue_size > foo_max, then foo requests are 325 * not enqueued (but without notice). This applies to L2 notification, 326 * link notification and RX tunnels. For RX, the max is checked on a 327 * per-COS basis. 328 * 329 * In addition, the local and remote operations are checked independently, 330 * although local RX requests go directly to RX which does its own 331 * rate limiting. 332 * 333 * It is recommended that link notifications not be limited. 334 * 335 * Currently, these are exported to allow applications to set them 336 * directly. In the future, accessors or "bcm_rlink_control" may be 337 * implemented depending on scalability requirements. 338 */ 339 340 int bcm_rlink_link_remote_max; 341 int bcm_rlink_auth_remote_max; 342 int bcm_rlink_l2_remote_max = BCM_RLINK_L2_REMOTE_MAX_DEFAULT; 343 int bcm_rlink_rx_remote_max[BCM_COS_COUNT] = BCM_RLINK_RX_REMOTE_MAX_DEFAULT; 344 int bcm_rlink_oam_remote_max; 345 int bcm_rlink_bfd_remote_max; 346 347 int bcm_rlink_link_local_max; /* 0 -> no limit; recommended setting */ 348 int bcm_rlink_auth_local_max; /* 0 -> no limit; recommended setting */ 349 int bcm_rlink_l2_local_max; 350 int bcm_rlink_oam_local_max; /* 0 -> no limit; recommended setting */ 351 int bcm_rlink_bfd_local_max; /* 0 -> no limit; recommended setting */ 352 353 int _rlink_nexthop = 0; 354 355 356 /* Array size for bcm_oam_event_types_t bit declare type */ 357 #define _BCM_OAM_EVENT_TYPES_ARRAY_SIZE _SHR_BITDCLSIZE(bcmOAMEventCount) 358 #if defined(INCLUDE_BFD) 359 /* Array size for bcm_bfd_event_types_t bit declare type */ 360 #define _BCM_BFD_EVENT_TYPES_ARRAY_SIZE _SHR_BITDCLSIZE(bcmBFDEventCount) 361 #endif 362 363 STATIC void 364 _bcm_rlink_send_enqueue(int unit, 365 rlink_type_t type, 366 uint8 *buf, 367 int len, 368 int check_cpu, 369 cpudb_key_t cpu, 370 uint32 ct_flags) 371 { 372 _rlink_notify_t *rnot; 373 374 rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify"); 375 if (rnot == NULL) { 376 return; /* Failure */ 377 } 378 379 CPUDB_KEY_COPY(rnot->cpu, cpu); 380 rnot->unit = unit; 381 rnot->type = type; 382 rnot->pkt_send = TRUE; 383 rnot->u.cli.buf = buf; 384 rnot->u.cli.len = len; 385 rnot->u.cli.check_cpu = check_cpu; 386 rnot->u.cli.ct_flags = ct_flags; 387 388 RLINK_ENQUEUE_NOTIFY(rnot); 389 } 390 391 392 /* 393 * Server side handlers. 394 * Registered for any units of interest to requesting clients. 395 * Send off a notify packet to any clients interested in this unit. 396 */ 397 #define cpudb_key_ignore cpudb_bcast_key 398 399 /* 400 * Tail end of linkscan and l2 handlers. 401 * Send notify to appropriate clients. 402 */ 403 STATIC void 404 _bcm_rlink_send_notify(int unit, 405 rlink_type_t type, 406 uint8 *buf, 407 int len, 408 int check_cpu, 409 cpudb_key_t cpu, 410 uint32 ct_flags) 411 { 412 int rv = BCM_E_NONE; 413 _rlink_scan_t *rscan; 414 415 LOG_VERBOSE(BSL_LS_BCM_RX, 416 (BSL_META_U(unit, 417 "Sending RLINK %s notify for unit %d\n"), 418 TYPE_STR(type), unit)); 419 RLINK_LOCK; 420 for (rscan = _rlink_scan_head; rscan != NULL; rscan = rscan->next) { 421 if (rscan->unit == unit && rscan->type == type) { 422 if (check_cpu) { 423 if (!CPUDB_KEY_EQUAL(cpu, rscan->cpu)) { 424 continue; 425 } 426 } 427 LOG_VERBOSE(BSL_LS_BCM_RX, 428 (BSL_META_U(unit, 429 "RLINK to " CPUDB_KEY_FMT_EOLN), 430 CPUDB_KEY_DISP(rscan->cpu))); 431 rv = atp_tx(rscan->cpu, RLINK_CLIENT_ID, 432 buf, len, ct_flags, NULL, NULL); 433 if (BCM_FAILURE(rv)) { 434 INCR_COUNTER(rlink_pkt_send_fail); 435 } 436 } 437 } 438 RLINK_UNLOCK; 439 440 /* coverity[identical_branches] */ 441 if (type != RLINK_TYPE_RX) { 442 atp_tx_data_free(buf); 443 } else { 444 atp_tx_data_free(buf); 445 } 446 } 447 448 /**************************************************************** 449 * 450 * Callbacks registered at the BCM layer on local units on the 451 * (rlink) server side. These handle the async events on the 452 * CPUs where they first occur. They forward notification via 453 * "send_notify" (above) when configuration is right for the 454 * given event. 455 */ 456 457 /* 458 * Registered with RX at server to check if pkts should be 459 * tunnelled. 460 */ 461 462 STATIC bcm_rx_t 463 _bcm_rlink_rx_handler(int unit, bcm_pkt_t *pkt, void *cookie) 464 { 465 uint32 ct_flags = 0; 466 bcm_cpu_tunnel_mode_t tunnel_pkt; 467 int no_ack; 468 uint8 *buf, *bp; 469 int len; 470 cpudb_key_t cpu; 471 int check_cpu; 472 473 if (_rlink_thread_exit) { /* Not running */ 474 return BCM_RX_NOT_HANDLED; 475 } 476 477 /* 478 * Find out if the packet should be tunnelled; if so, should 479 * it be directed to one CPU? 480 */ 481 tunnel_pkt = ct_rx_tunnel_check(unit, pkt, &no_ack, &check_cpu, &cpu); 482 483 if (tunnel_pkt == BCM_CPU_TUNNEL_NONE) { /* Don't tunnel */ 484 return BCM_RX_NOT_HANDLED; 485 } 486 487 INCR_COUNTER(rlink_rx_out); 488 489 if (bcm_rlink_rx_remote_max[pkt->cos] > 0 && 490 _rlink_queue_size > bcm_rlink_rx_remote_max[pkt->cos]) { 491 INCR_COUNTER(rlink_rx_out_disc); 492 /* No space in queue */ 493 return BCM_RX_NOT_HANDLED; 494 } 495 496 CPUTRANS_COS_SET(ct_flags, pkt->cos); 497 if (no_ack) { /* Mark packet as tunnelled via best effort */ 498 ct_flags |= CPUTRANS_NO_ACK; 499 } 500 501 /* msg, type, unit, port, info */ 502 len = 1 + 1 + 4 + ct_rx_tunnel_header_bytes_get() + pkt->pkt_len; 503 504 505 buf = atp_tx_data_alloc(len); 506 if (buf == NULL) { 507 INCR_COUNTER(rlink_buff_alloc_fail); 508 LOG_WARN(BSL_LS_SOC_COMMON, 509 (BSL_META_U(unit, 510 "RLINK Tunnel Src: alloc failed\n"))); 511 return BCM_RX_NOT_HANDLED; 512 } 513 514 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_RX, unit); 515 (void)ct_rx_tunnel_pkt_pack(pkt, bp); 516 517 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_RX, buf, len, check_cpu, 518 cpu, ct_flags); 519 520 return BCM_RX_HANDLED; 521 } 522 523 524 /* 525 * Server side linkscan handler 526 */ 527 STATIC void 528 _bcm_rlink_linkscan_handler(int unit, 529 bcm_port_t port, 530 bcm_port_info_t *info) 531 { 532 uint8 *buf, *bp; 533 int len; 534 535 if (_rlink_thread_exit) { /* Not running */ 536 return; 537 } 538 539 INCR_COUNTER(rlink_link_out); 540 541 if (bcm_rlink_link_remote_max > 0 && 542 _rlink_queue_size > bcm_rlink_link_remote_max) { 543 INCR_COUNTER(rlink_link_out_disc); 544 /* No space in queue */ 545 return; 546 } 547 548 /* msg, type, unit, port, info */ 549 len = 1 + 1 + 4 + 4 + BCM_PACKLEN_PORT_INFO; 550 buf = atp_tx_data_alloc(len); 551 if (buf == NULL) { 552 INCR_COUNTER(rlink_buff_alloc_fail); 553 return; 554 } 555 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_LINK, unit); 556 BCM_PACK_U32(bp, port); 557 (void) _bcm_pack_port_info(bp, info); 558 559 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_LINK, buf, len, FALSE, 560 cpudb_key_ignore, 0); 561 } 562 563 /* 564 * Server side linkscan handler 565 */ 566 STATIC void 567 _bcm_rlink_auth_handler(void *cookie, 568 int unit, 569 int port, 570 int reason) 571 { 572 uint8 *buf, *bp; 573 int len; 574 575 if (_rlink_thread_exit) { /* Not running */ 576 return; 577 } 578 579 INCR_COUNTER(rlink_auth_out); 580 581 if (bcm_rlink_auth_remote_max > 0 && 582 _rlink_queue_size > bcm_rlink_auth_remote_max) { 583 INCR_COUNTER(rlink_auth_out_disc); 584 /* No space in queue */ 585 return; 586 } 587 588 /* msg, type, unit, port, reason */ 589 len = 1 + 1 + 4 + 4 + 4; 590 buf = atp_tx_data_alloc(len); 591 if (buf == NULL) { 592 INCR_COUNTER(rlink_buff_alloc_fail); 593 return; 594 } 595 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_AUTH, unit); 596 BCM_PACK_U32(bp, port); 597 BCM_PACK_U32(bp, reason); 598 599 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_AUTH, buf, len, FALSE, 600 cpudb_key_ignore, 0); 601 } 602 603 604 /* 605 * Server side l2 handler. Not all L2 events should be sent to 606 * clients. This is determined by a callback that can be 607 * registered here. 608 * 609 * In addition, the most important criteria is whether the L2 610 * address is "native" to the unit (learned on a front panel 611 * port). This can be set up directly using the calls below. 612 */ 613 614 static bcm_rlink_l2_cb_f _l2_cb = NULL; 615 static uint32 _l2_native_only = FALSE; 616 617 void 618 bcm_rlink_l2_cb_set(bcm_rlink_l2_cb_f l2_cb) 619 { 620 _l2_cb = l2_cb; 621 } 622 623 void 624 bcm_rlink_l2_cb_get(bcm_rlink_l2_cb_f *l2_cb) 625 { 626 *l2_cb = _l2_cb; 627 } 628 629 void 630 bcm_rlink_l2_native_only_set(int native_only) 631 { 632 _l2_native_only = native_only; 633 } 634 635 void 636 bcm_rlink_l2_native_only_get(int *native_only) 637 { 638 *native_only = _l2_native_only; 639 } 640 641 STATIC void 642 _bcm_rlink_l2_handler(int unit, 643 bcm_l2_addr_t *l2addr, 644 int insert, 645 void *cookie) 646 { 647 uint8 *buf, *bp; 648 int len; 649 650 if (_rlink_thread_exit) { /* Not running */ 651 return; 652 } 653 654 /* See if callback present; if it is and returns FALSE, return */ 655 if (_l2_cb != NULL) { 656 if (_l2_cb(unit, l2addr, insert) == FALSE) { 657 return; 658 } 659 } 660 661 /* Check for native only setting */ 662 if (_l2_native_only == TRUE) { 663 if (!(l2addr->flags & BCM_L2_NATIVE)) { 664 return; 665 } 666 } 667 668 INCR_COUNTER(rlink_l2_out); 669 670 if (bcm_rlink_l2_remote_max > 0 && 671 _rlink_queue_size > bcm_rlink_l2_remote_max) { 672 INCR_COUNTER(rlink_l2_out_disc); 673 /* No space in queue */ 674 return; 675 } 676 677 /* msg, type, unit, insert, l2addr */ 678 len = 1 + 1 + 4 + 1 + BCM_PACKLEN_L2_ADDR; 679 buf = atp_tx_data_alloc(len); 680 if (buf == NULL) { 681 INCR_COUNTER(rlink_buff_alloc_fail); 682 return; 683 } 684 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_L2, unit); 685 BCM_PACK_U8(bp, insert ? 1 : 0); 686 (void) _bcm_pack_l2_addr(bp, l2addr); 687 688 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_L2, buf, len, FALSE, 689 cpudb_key_ignore, 0); 690 } 691 692 /* 693 * Server side oam event handler 694 */ 695 STATIC int 696 _bcm_rlink_oam_handler(int unit, 697 uint32 flags, 698 bcm_oam_event_type_t event_type, 699 bcm_oam_group_t group, 700 bcm_oam_endpoint_t endpoint, 701 void *cookie) 702 { 703 uint8 *buf, *bp; 704 int len; 705 706 if (_rlink_thread_exit) { /* Not running */ 707 return BCM_E_FAIL; 708 } 709 710 INCR_COUNTER(rlink_oam_out); 711 712 if (bcm_rlink_oam_remote_max > 0 && 713 _rlink_queue_size > bcm_rlink_oam_remote_max) { 714 INCR_COUNTER(rlink_oam_out_disc); 715 /* No space in queue */ 716 return BCM_E_FULL; 717 } 718 719 /* msg, type, unit, flags, event_type, group, endpoint */ 720 len = 1 + 1 + 4 + 4 + 4 + 4 + 4; 721 buf = atp_tx_data_alloc(len); 722 if (buf == NULL) { 723 INCR_COUNTER(rlink_buff_alloc_fail); 724 return BCM_E_MEMORY; 725 } 726 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_OAM, unit); 727 BCM_PACK_U32(bp, flags); 728 BCM_PACK_U32(bp, event_type); 729 BCM_PACK_U32(bp, group); 730 BCM_PACK_U32(bp, endpoint); 731 732 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_OAM, buf, len, FALSE, 733 cpudb_key_ignore, 0); 734 return BCM_E_NONE; 735 } 736 737 #if defined(INCLUDE_BFD) 738 /* 739 * Server side bfd event handler 740 */ 741 STATIC int 742 _bcm_rlink_bfd_handler(int unit, 743 uint32 flags, 744 bcm_bfd_event_types_t event_types, 745 bcm_bfd_endpoint_t endpoint, 746 void *cookie) 747 { 748 uint8 *buf, *bp; 749 int len, i; 750 751 if (_rlink_thread_exit) { /* Not running */ 752 return BCM_E_FAIL; 753 } 754 755 INCR_COUNTER(rlink_bfd_out); 756 757 if (bcm_rlink_bfd_remote_max > 0 && 758 _rlink_queue_size > bcm_rlink_bfd_remote_max) { 759 INCR_COUNTER(rlink_bfd_out_disc); 760 /* No space in queue */ 761 return BCM_E_FULL; 762 } 763 764 /* msg, type, unit, flags, group */ 765 len = 1 + 1 + 4 + 4 + 4; 766 /* events */ 767 for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) { 768 len += 4; 769 } 770 buf = atp_tx_data_alloc(len); 771 if (buf == NULL) { 772 INCR_COUNTER(rlink_buff_alloc_fail); 773 return BCM_E_MEMORY; 774 } 775 bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_BFD, unit); 776 BCM_PACK_U32(bp, flags); 777 for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) { 778 BCM_PACK_U32(bp, event_types.w[i]); 779 } 780 BCM_PACK_U32(bp, endpoint); 781 782 _bcm_rlink_send_enqueue(unit, RLINK_TYPE_BFD, buf, len, FALSE, 783 cpudb_key_ignore, 0); 784 return BCM_E_NONE; 785 } 786 #endif 787 788 /**************************************************************** 789 * 790 * Server side registration control. 791 * Invoked when a client CPU sends an "add" or "delete" request. 792 */ 793 794 STATIC void 795 _bcm_rlink_scan_add(cpudb_key_t cpu, int unit, rlink_type_t type, 796 _rlink_register_args_t *args) 797 { 798 _rlink_scan_t *rscan; 799 int present; 800 801 if(!BCM_CONTROL_UNIT_LEGAL(unit)) { 802 LOG_WARN(BSL_LS_SOC_COMMON, 803 (BSL_META_U(unit, 804 "RLINK unit is out of range\n"))); 805 return; 806 } 807 808 /* For RX in particular, unit must be local */ 809 if (!BCM_IS_LOCAL(unit)) { 810 LOG_WARN(BSL_LS_SOC_COMMON, 811 (BSL_META_U(unit, 812 "RLINK scan add on non-local unit %d, " 813 "type %s\n"), unit, TYPE_STR(type))); 814 } 815 LOG_VERBOSE(BSL_LS_SOC_COMMON, 816 (BSL_META_U(unit, 817 "RLINK add on unit %d, type %s for CPU " 818 CPUDB_KEY_FMT_EOLN), unit, TYPE_STR(type), 819 CPUDB_KEY_DISP(cpu))); 820 821 /* If (cpu, unit, type) is in scan chain, don't add again */ 822 823 RLINK_LOCK; 824 present = FALSE; 825 for (rscan = _rlink_scan_head; rscan != NULL; rscan = rscan->next) { 826 if (type == rscan->type && unit == rscan->unit && 827 CPUDB_KEY_EQUAL(cpu, rscan->cpu)) { 828 present = TRUE; 829 break; 830 } 831 } 832 833 if (!present) { /* Okay, add entry */ 834 rscan = sal_alloc(sizeof(*rscan), "bcm_rlink_scan"); 835 if (rscan == NULL) { 836 RLINK_UNLOCK; 837 return; /* failure */ 838 } 839 CPUDB_KEY_COPY(rscan->cpu, cpu); 840 rscan->unit = unit; 841 rscan->type = type; 842 rscan->next = NULL; 843 844 if (_rlink_scan_tail == NULL) { 845 _rlink_scan_head = _rlink_scan_tail = rscan; 846 } else { 847 _rlink_scan_tail->next = rscan; 848 _rlink_scan_tail = rscan; 849 } 850 } 851 RLINK_UNLOCK; 852 853 /* always attempt to re-register to lower level */ 854 switch (type) { 855 case RLINK_TYPE_LINK: 856 (void)bcm_linkscan_register(unit, 857 _bcm_rlink_linkscan_handler); 858 break; 859 case RLINK_TYPE_AUTH: 860 (void)bcm_auth_unauth_callback(unit, 861 _bcm_rlink_auth_handler, NULL); 862 break; 863 case RLINK_TYPE_L2: 864 (void)bcm_l2_addr_register(unit, 865 _bcm_rlink_l2_handler, NULL); 866 break; 867 case RLINK_TYPE_RX: 868 (void)bcm_rx_queue_register(unit, "rlink", 869 BCM_RX_COS_ALL, 870 _bcm_rlink_rx_handler, 871 ct_rx_tunnel_priority_get(), NULL, 872 BCM_RCO_F_ALL_COS); 873 874 break; 875 case RLINK_TYPE_OAM: 876 (void)bcm_oam_event_register(unit, 877 args->u.oam.events, 878 _bcm_rlink_oam_handler, 879 NULL); 880 break; 881 case RLINK_TYPE_BFD: 882 #if defined(INCLUDE_BFD) 883 (void)bcm_bfd_event_register(unit, 884 args->u.bfd.events, 885 _bcm_rlink_bfd_handler, 886 NULL); 887 #endif 888 break; 889 default: 890 break; 891 } 892 } 893 894 895 STATIC void 896 _bcm_rlink_scan_delete(cpudb_key_t cpu, int unit, rlink_type_t type, 897 _rlink_register_args_t *args) 898 { 899 _rlink_scan_t *rscan, *pscan; 900 int last; 901 902 if(!BCM_CONTROL_UNIT_LEGAL(unit)) { 903 LOG_WARN(BSL_LS_SOC_COMMON, 904 (BSL_META_U(unit, 905 "RLINK unit is out of range\n"))); 906 return; 907 } 908 909 if (!BCM_IS_LOCAL(unit)) { 910 LOG_WARN(BSL_LS_SOC_COMMON, 911 (BSL_META_U(unit, 912 "RLINK scan delete on non-local unit %d, " 913 "type %s\n"), unit, TYPE_STR(type))); 914 } 915 LOG_VERBOSE(BSL_LS_SOC_COMMON, 916 (BSL_META_U(unit, 917 "RLINK scan delete on unit %d, type %s for CPU " 918 CPUDB_KEY_FMT_EOLN), unit, TYPE_STR(type), 919 CPUDB_KEY_DISP(cpu))); 920 921 RLINK_LOCK; 922 pscan = NULL; 923 for (rscan = _rlink_scan_head; rscan != NULL; 924 pscan = rscan, rscan = rscan->next) { 925 if (rscan->type == type && rscan->unit == unit && 926 CPUDB_KEY_EQUAL(rscan->cpu, cpu)) { 927 if (pscan == NULL) { 928 _rlink_scan_head = rscan->next; 929 } else { 930 pscan->next = rscan->next; 931 } 932 if (rscan == _rlink_scan_tail) { 933 _rlink_scan_tail = pscan; 934 } 935 break; 936 } 937 } 938 939 if (rscan == NULL) { 940 RLINK_UNLOCK; 941 return; /* not found */ 942 } 943 944 /* Check if no more entries of this type, on this unit */ 945 last = TRUE; 946 for (pscan = _rlink_scan_head; pscan != NULL; pscan = pscan->next) { 947 if (type == pscan->type && unit == pscan->unit) { 948 last = FALSE; 949 break; 950 } 951 } 952 953 RLINK_UNLOCK; 954 955 sal_free(rscan); 956 957 if (last) { 958 switch (type) { 959 case RLINK_TYPE_LINK: 960 (void)bcm_linkscan_unregister(unit, 961 _bcm_rlink_linkscan_handler); 962 break; 963 case RLINK_TYPE_AUTH: /* Clear callback with NULL as function */ 964 (void)bcm_auth_unauth_callback(unit, NULL, NULL); 965 break; 966 case RLINK_TYPE_L2: 967 (void)bcm_l2_addr_unregister(unit, 968 _bcm_rlink_l2_handler, NULL); 969 break; 970 case RLINK_TYPE_RX: 971 (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler, 972 ct_rx_tunnel_priority_get()); 973 break; 974 case RLINK_TYPE_OAM: 975 (void)bcm_oam_event_unregister(unit, 976 args->u.oam.events, 977 _bcm_rlink_oam_handler); 978 break; 979 case RLINK_TYPE_BFD: 980 #if defined(INCLUDE_BFD) 981 (void)bcm_bfd_event_unregister(unit, 982 args->u.bfd.events, 983 _bcm_rlink_bfd_handler); 984 #endif 985 break; 986 default: 987 break; 988 } 989 } 990 } 991 992 /* 993 * Function: 994 * bcm_rlink_device_clear 995 * Purpose: 996 * Clear the RLINK state for the given LOCAL unit (server clear). 997 * Parameters: 998 * unit - LOCAL unit number 999 * Notes: 1000 * Removes all RLINK refs for the given unit. It might be 1001 * better to do this on a per-CPU basis as well, but currently, 1002 * only the master CPU ever gets referenced here. In addition, 1003 * this could probably be done once for all local units 1004 * controlled, but this is more consistent with the rest of the API. 1005 * 1006 * See rlink_device_detach for sending a cleanup call to a remote 1007 * device. 1008 */ 1009 1010 void 1011 bcm_rlink_device_clear(int unit) 1012 { 1013 _rlink_scan_t *cur_entry, *next_entry, *prev_entry; 1014 bcm_oam_event_types_t oam_events; 1015 #if defined(INCLUDE_BFD) 1016 bcm_bfd_event_types_t bfd_events; 1017 #endif 1018 if (!RLINK_INIT) { 1019 return; 1020 } 1021 1022 prev_entry = NULL; 1023 1024 RLINK_LOCK; 1025 for (cur_entry = _rlink_scan_head; cur_entry != NULL; 1026 cur_entry = next_entry) { 1027 next_entry = cur_entry->next; 1028 1029 if (cur_entry->unit == unit) { /* Remove entry */ 1030 if (prev_entry != NULL) { 1031 prev_entry->next = cur_entry->next; 1032 } else { 1033 _rlink_scan_head = cur_entry->next; 1034 } 1035 sal_free(cur_entry); 1036 1037 } else { 1038 prev_entry = cur_entry; 1039 } 1040 } 1041 RLINK_UNLOCK; 1042 1043 /* Set all bits to clear all oam events */ 1044 sal_memset(&(oam_events), 1, sizeof(bcm_oam_event_types_t)); 1045 #if defined(INCLUDE_BFD) 1046 sal_memset(&(bfd_events), 1, sizeof(bcm_bfd_event_types_t)); 1047 #endif 1048 (void)bcm_linkscan_unregister(unit, _bcm_rlink_linkscan_handler); 1049 (void)bcm_auth_unauth_callback(unit, NULL, NULL); 1050 (void)bcm_l2_addr_unregister(unit, _bcm_rlink_l2_handler, NULL); 1051 (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler, 1052 ct_rx_tunnel_priority_get()); 1053 (void)bcm_oam_event_unregister(unit, oam_events, 1054 _bcm_rlink_oam_handler); 1055 #if defined(INCLUDE_BFD) 1056 (void)bcm_bfd_event_unregister(unit, bfd_events, 1057 _bcm_rlink_bfd_handler); 1058 #endif 1059 } 1060 1061 /* 1062 * Function: 1063 * bcm_rlink_server_clear 1064 * Purpose: 1065 * Clear all RLINK server (local) information. 1066 * Notes: 1067 * Forces de-registration of rlink callbacks on local units 1068 */ 1069 1070 void 1071 bcm_rlink_server_clear(void) 1072 { 1073 _rlink_scan_t *cur_entry, *next_entry; 1074 int unit; 1075 bcm_oam_event_types_t oam_events; 1076 #if defined(INCLUDE_BFD) 1077 bcm_bfd_event_types_t bfd_events; 1078 #endif 1079 1080 /* Set all bits to clear all oam events */ 1081 sal_memset(&(oam_events), 1, sizeof(bcm_oam_event_types_t)); 1082 #if defined(INCLUDE_BFD) 1083 sal_memset(&(bfd_events), 1, sizeof(bcm_bfd_event_types_t)); 1084 #endif 1085 RLINK_LOCK; 1086 1087 /* Clear server information */ 1088 for (cur_entry = _rlink_scan_head; cur_entry != NULL; 1089 cur_entry = next_entry) { 1090 next_entry = cur_entry->next; 1091 sal_free(cur_entry); 1092 } 1093 1094 _rlink_scan_head = _rlink_scan_tail = NULL; 1095 1096 for (unit = 0; unit < BCM_MAX_NUM_UNITS; unit++) { 1097 (void)bcm_linkscan_unregister(unit, _bcm_rlink_linkscan_handler); 1098 (void)bcm_auth_unauth_callback(unit, NULL, NULL); 1099 (void)bcm_l2_addr_unregister(unit, _bcm_rlink_l2_handler, NULL); 1100 (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler, 1101 ct_rx_tunnel_priority_get()); 1102 (void)bcm_oam_event_unregister(unit, oam_events, 1103 _bcm_rlink_oam_handler); 1104 #if defined(INCLUDE_BFD) 1105 (void)bcm_bfd_event_unregister(unit, bfd_events, 1106 _bcm_rlink_bfd_handler); 1107 #endif 1108 } 1109 1110 bcm_rlink_traverse_server_clear(); 1111 RLINK_UNLOCK; 1112 } 1113 1114 /* 1115 * Function: 1116 * bcm_rlink_client_clear 1117 * Purpose: 1118 * Clear all client (remote related) information 1119 */ 1120 1121 void 1122 bcm_rlink_client_clear(void) 1123 { 1124 _rlink_handle_t *cur_hand, *next_hand; 1125 1126 RLINK_LOCK; 1127 1128 /* Clear client information */ 1129 for (cur_hand = _rlink_handle_head; cur_hand != NULL; 1130 cur_hand = next_hand) { 1131 next_hand = cur_hand->next; 1132 sal_free(cur_hand); 1133 } 1134 1135 _rlink_handle_head = _rlink_handle_tail = NULL; 1136 1137 bcm_rlink_traverse_client_clear(); 1138 RLINK_UNLOCK; 1139 } 1140 1141 /* 1142 * Function: 1143 * bcm_rlink_clear 1144 * Purpose: 1145 * Clear both client and server state 1146 */ 1147 1148 void 1149 bcm_rlink_clear(void) 1150 { 1151 bcm_rlink_server_clear(); 1152 bcm_rlink_client_clear(); 1153 } 1154 1155 /* 1156 * Client side packet send 1157 */ 1158 STATIC int 1159 _bcm_rlink_send_control(cpudb_key_t cpu, int unit, 1160 rlink_msg_t msg, rlink_type_t type, 1161 _rlink_register_args_t *args) 1162 { 1163 uint8 *buf, *bp; 1164 int len; 1165 int i; 1166 int rv = BCM_E_NONE; 1167 1168 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1169 (BSL_META_U(unit, 1170 "RLINK ctl msg %s, cpu-unit %d, type %s to " 1171 CPUDB_KEY_FMT_EOLN), MSG_STR(msg), unit, TYPE_STR(type), 1172 CPUDB_KEY_DISP(cpu))); 1173 len = 1 + 1 + 4; /* msg, type, unit */ 1174 /* Other arguments for register function */ 1175 if (args) { 1176 switch (type) { 1177 case RLINK_TYPE_OAM: /* event_types */ 1178 for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) { 1179 len += 4; 1180 } 1181 break; 1182 case RLINK_TYPE_BFD: /* event_types */ 1183 #if defined(INCLUDE_BFD) 1184 for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) { 1185 len += 4; 1186 } 1187 #endif 1188 break; 1189 default: 1190 break; 1191 } 1192 } 1193 1194 buf = atp_tx_data_alloc(len); 1195 if (buf == NULL) { 1196 INCR_COUNTER(rlink_buff_alloc_fail); 1197 return BCM_E_MEMORY; 1198 } 1199 bp = bcm_rlink_encode(buf, msg, type, unit); 1200 1201 /* Other arguments for register function */ 1202 if (args) { 1203 switch (type) { 1204 case RLINK_TYPE_OAM: 1205 for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) { 1206 BCM_PACK_U32(bp, args->u.oam.events.w[i]); 1207 } 1208 break; 1209 case RLINK_TYPE_BFD: 1210 #if defined(INCLUDE_BFD) 1211 for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) { 1212 BCM_PACK_U32(bp, args->u.bfd.events.w[i]); 1213 } 1214 #endif 1215 break; 1216 default: 1217 break; 1218 } 1219 } 1220 1221 rv = atp_tx(cpu, RLINK_CLIENT_ID, buf, len, 0, NULL, NULL); 1222 if (BCM_FAILURE(rv)) { 1223 INCR_COUNTER(rlink_pkt_send_fail); 1224 } 1225 atp_tx_data_free(buf); 1226 return rv; 1227 } 1228 1229 /* 1230 * Function: 1231 * _bcm_rlink_handle_list_add 1232 * 1233 * Purpose: 1234 * Internal function to add data to list _rlink_handle_head/tail. 1235 * Data would only be added if it is already not exising in the 1236 * list. Fields 'unit', 'type' and 'function' from the parameter 1237 * 'data_node' would be used as keys to search the list. 1238 * 1239 * Parameters: 1240 * data_node - (IN) Node with data to be added. 1241 * 1242 * Returns: 1243 * BCM_E_NONE - Successfully added the data to the list 1244 * BCM_E_EXISTS - Data not added as it already exists in the list 1245 * BCM_E_MEMORY - Data not added as memory Allocation failed 1246 * 1247 * Note: 1248 */ 1249 STATIC int 1250 _bcm_rlink_handle_list_add(_rlink_handle_t *data_node) { 1251 1252 int rv = BCM_E_NONE; 1253 _rlink_handle_t *rhand = NULL; 1254 1255 /* Lock the list */ 1256 RLINK_LOCK; 1257 1258 /* See if already registered */ 1259 for (rhand = _rlink_handle_head; rhand != NULL; rhand = rhand->next) { 1260 if (rhand->type == data_node->type && 1261 rhand->unit == data_node->unit && 1262 rhand->func.generic_func_ptr == data_node->func.generic_func_ptr) { 1263 RLINK_UNLOCK; 1264 return BCM_E_EXISTS; 1265 } 1266 } 1267 1268 /* Allocate memory for the node */ 1269 rhand = sal_alloc(sizeof(*rhand), "bcm_rlink_handle"); 1270 if (rhand == NULL) { 1271 RLINK_UNLOCK; 1272 return BCM_E_MEMORY; 1273 } 1274 1275 /* Fill in the data */ 1276 rhand->unit = data_node->unit; 1277 rhand->type = data_node->type; 1278 rhand->func.generic_func_ptr = data_node->func.generic_func_ptr; 1279 rhand->cookie = data_node->cookie; 1280 CPUDB_KEY_COPY(rhand->cpu, data_node->cpu); 1281 rhand->cunit = data_node->cunit; 1282 rhand->next = NULL; 1283 1284 /* Call routine to add it to the list */ 1285 if (_rlink_handle_tail == NULL) { 1286 _rlink_handle_head = _rlink_handle_tail = rhand; 1287 } else { 1288 _rlink_handle_tail->next = rhand; 1289 _rlink_handle_tail = rhand; 1290 } 1291 1292 /* Unlock the list */ 1293 RLINK_UNLOCK; 1294 1295 return rv; 1296 } 1297 1298 /* 1299 * Function: 1300 * _bcm_rlink_handle_list_delete 1301 * 1302 * Purpose: 1303 * Internal function to delete data from list _rlink_handle_head/tail. 1304 * Data would only be deleted if it exists in the list. Fields 'unit' 1305 * , 'type' and 'function' in parameter data_node would be used as keys 1306 * to search the list for pre-existence check. 1307 * 1308 * Parameters: 1309 * data_node - (IN/OUT) Node with data to be deleted. It acts in INPUT for 1310 * fields unit, type, and OUTPUT for fields cookie, cpukey, 1311 * cunit 1312 * last - (OUT) Indicates if the deleted node was the last of its kind 1313 * 1314 * Returns: 1315 * BCM_E_NONE - Successfully deleted the data from the list 1316 * BCM_E_NOT_FOUND - Data did not delete as it does not exist 1317 * 1318 * Note: 1319 * 1) Matching Node will be removed from the list and its memory deallocated 1320 * 2) Fields cookie, cpu and cunit in the given node are populated before 1321 * the node is de-allocated. 1322 */ 1323 STATIC int 1324 _bcm_rlink_handle_list_delete(_rlink_handle_t *data_node, int *last) { 1325 1326 int rv = BCM_E_NONE; 1327 _rlink_handle_t *rhand = NULL, *phand = NULL; 1328 1329 /* Lock the list */ 1330 RLINK_LOCK; 1331 1332 for (rhand = _rlink_handle_head; 1333 rhand != NULL; 1334 phand = rhand, rhand = rhand->next) { 1335 if (rhand->type == data_node->type && 1336 rhand->unit == data_node->unit && 1337 rhand->func.generic_func_ptr == data_node->func.generic_func_ptr) 1338 { 1339 if (phand == NULL) { 1340 _rlink_handle_head = rhand->next; 1341 } else { 1342 phand->next = rhand->next; 1343 } 1344 if (rhand == _rlink_handle_tail) { 1345 _rlink_handle_tail = phand; 1346 } 1347 rhand->next = NULL; 1348 break; 1349 } 1350 } 1351 1352 if (NULL == rhand) { 1353 /* Since entry not found, mark it so */ 1354 rv = BCM_E_NOT_FOUND; 1355 } else { 1356 /* Save cookie, cpu_key and cunit infortmation */ 1357 CPUDB_KEY_COPY(data_node->cpu, rhand->cpu); 1358 data_node->cunit = rhand->cunit; 1359 data_node->cookie = rhand->cookie; 1360 1361 /* De-allocate the node memory */ 1362 sal_free(rhand); 1363 1364 /* See if this was the last entry for this unit */ 1365 if (NULL != last) { 1366 *last = 1; /* Mark it to be the last at first */ 1367 1368 for (phand = _rlink_handle_head; phand != NULL; phand = phand->next) 1369 { 1370 if (phand->type == data_node->type && 1371 phand->unit == data_node->unit) { 1372 *last = 0; 1373 break; 1374 } 1375 } 1376 } 1377 } 1378 1379 /* Unlock the list */ 1380 RLINK_UNLOCK; 1381 1382 return rv; 1383 } 1384 1385 /* 1386 * Function: 1387 * _bcm_rlink_register 1388 * 1389 * Purpose: 1390 * Generic function to register a rlink callback. 1391 * Initially the callback data is added to a client rlink list pointed 1392 * by '_rlink_handle_head'. Next the remote device is sent a RLINK_MSG 1393 * with type ADD. If the MSG returns back with an error or the send 1394 * itself failed then the previous step of adding the data to the list 1395 * is reverted by deleting it back from the list. 1396 * 1397 * Parameters: 1398 * node - (IN/OUT) List node. 1399 * args - (IN) register event, if any 1400 * 1401 * Returns: 1402 * BCM_E_NONE - Successful registration 1403 * BCM_E_XXX - Other failures 1404 */ 1405 STATIC int 1406 _bcm_rlink_register(_rlink_handle_t *node, _rlink_register_args_t *args) 1407 { 1408 int is_new_data = 1; 1409 int rv = BCM_E_NONE; 1410 1411 if (!RLINK_INIT) { 1412 return BCM_E_UNAVAIL; 1413 } 1414 1415 /* Deduce and store CPUDB_KEY and CUNIT */ 1416 CPUDB_KEY_COPY(node->cpu, 1417 *((cpudb_key_t *)BCM_CONTROL(node->unit)->drv_control)); 1418 node->cunit = BCM_CONTROL(node->unit)->unit; 1419 1420 /* Call internal routine to add the data to the list */ 1421 rv = _bcm_rlink_handle_list_add(node); 1422 if (BCM_E_EXISTS == rv) { 1423 is_new_data = 0; 1424 } else if(BCM_FAILURE(rv)) { 1425 return rv; 1426 } 1427 1428 /* always send an ADD, just in case */ 1429 rv = _bcm_rlink_send_control( 1430 node->cpu, node->cunit, RLINK_MSG_ADD, node->type, args); 1431 1432 /* Perform graceful error handling */ 1433 if (BCM_FAILURE(rv) && (1 == is_new_data)) { 1434 /* Delete the just added entry from the list */ 1435 (void)_bcm_rlink_handle_list_delete(node, NULL); 1436 } 1437 1438 return rv; 1439 } 1440 1441 /* 1442 * Function: 1443 * _bcm_rlink_unregister 1444 * 1445 * Purpose: 1446 * Generic function to deregister a rlink callback. 1447 * Initially the callback data is deleted from the client rlink list 1448 * pointed by '_rlink_handle_head'. Next the remote device is sent a 1449 * RLINK_MSG with type DELETE. If the MSG returns back with an error 1450 * or the send itself failed then the previous step of removing the 1451 * data from the list is reverted by adding it back to the list. 1452 * 1453 * Parameters: 1454 * node - (IN/OUT) Node with data which has to be deleted. 1455 * args - (IN) register event, if any 1456 * 1457 * Returns: 1458 * BCM_E_NONE - Successful de-registration 1459 * BCM_E_XXX - Other failures 1460 */ 1461 STATIC int 1462 _bcm_rlink_unregister(_rlink_handle_t *node, _rlink_register_args_t *args) 1463 { 1464 int last = 1; 1465 int rv = BCM_E_NONE; 1466 1467 if (!RLINK_INIT) { 1468 return BCM_E_UNAVAIL; 1469 } 1470 1471 /* Delete the details from the internal list */ 1472 rv = _bcm_rlink_handle_list_delete(node, &last); 1473 1474 if (BCM_E_NOT_FOUND == rv) { /* Entry not found- NOOP and return success */ 1475 rv = BCM_E_NONE; 1476 } else if (BCM_E_NONE == rv) { /* Found an entry which was removed */ 1477 if (last) { 1478 rv = _bcm_rlink_send_control(node->cpu, node->cunit, 1479 RLINK_MSG_DELETE, node->type, args); 1480 } 1481 1482 if (BCM_FAILURE(rv)) { 1483 /* If send Msg failed then revert the list changes */ 1484 (void) _bcm_rlink_handle_list_add(node); 1485 } 1486 } 1487 1488 return rv; 1489 } 1490 1491 uint8 *bcm_rlink_decode(uint8 *buf, 1492 rlink_msg_t *msgp, rlink_type_t *typep, int *unitp) 1493 { 1494 1495 uint8 *bp = buf; 1496 rlink_msg_t msg; 1497 rlink_type_t type; 1498 int unit; 1499 1500 BCM_UNPACK_U8(bp, msg); 1501 BCM_UNPACK_U8(bp, type); 1502 BCM_UNPACK_U32(bp, unit); 1503 1504 *msgp = msg; 1505 *typep = type; 1506 *unitp = unit; 1507 return bp; 1508 } 1509 1510 uint8 *bcm_rlink_encode(uint8 *buf, 1511 rlink_msg_t msg, rlink_type_t type, int unit) 1512 { 1513 1514 uint8 *bp = buf; 1515 1516 BCM_PACK_U8(bp, msg); 1517 BCM_PACK_U8(bp, type); 1518 BCM_PACK_U32(bp, unit); 1519 1520 return bp; 1521 } 1522 1523 /* 1524 * Packet handler. 1525 * On client side receives notify packets from server. 1526 * On server side receives add/delete packets from client. 1527 */ 1528 STATIC bcm_rx_t 1529 _bcm_rlink_pkt_handler(cpudb_key_t cpu, 1530 int client_id, 1531 bcm_pkt_t *pkt, 1532 uint8 *buf, 1533 int buf_len, 1534 void *cookie) 1535 { 1536 uint8 *bp; 1537 int unit; 1538 rlink_msg_t msg; 1539 rlink_type_t type; 1540 _rlink_notify_t *rnot; 1541 int i; 1542 bcm_rx_t rv; 1543 1544 COMPILER_REFERENCE(client_id); 1545 COMPILER_REFERENCE(cookie); 1546 1547 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1548 (BSL_META("RLINK msg IN from " 1549 CPUDB_KEY_FMT_EOLN), 1550 CPUDB_KEY_DISP(cpu))); 1551 1552 if (!RLINK_INIT || _rlink_thread_exit) { 1553 return BCM_RX_NOT_HANDLED; 1554 } 1555 1556 bp = bcm_rlink_decode(buf, &msg, &type, &unit); 1557 1558 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1559 (BSL_META_U(unit, 1560 "RLINK IN msg %s, local-unit %d, type %s\n"), 1561 MSG_STR(msg), unit, TYPE_STR(type))); 1562 1563 rnot = NULL; 1564 rv = BCM_RX_HANDLED; 1565 1566 switch (msg) { 1567 case RLINK_MSG_TRAVERSE: 1568 INCR_COUNTER(rlink_trav_req_in); 1569 rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify"); 1570 if (rnot == NULL) { 1571 return BCM_RX_HANDLED; /* failure */ 1572 } 1573 CPUDB_KEY_COPY(rnot->cpu, cpu); 1574 rnot->unit = unit; 1575 rnot->type = type; 1576 rnot->pkt_send = FALSE; 1577 rnot->next = NULL; 1578 rnot->u.traverse.pkt = pkt; 1579 rnot->u.traverse.buf = buf; 1580 rnot->u.traverse.len = buf_len; 1581 rv = BCM_RX_HANDLED_OWNED; 1582 break; 1583 case RLINK_MSG_ADD: 1584 INCR_COUNTER(rlink_add_req_in); 1585 rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify"); 1586 if (rnot == NULL) { 1587 return BCM_RX_HANDLED; /* failure */ 1588 } 1589 CPUDB_KEY_COPY(rnot->cpu, cpu); 1590 rnot->unit = unit; 1591 rnot->type = RLINK_TYPE_ADD; 1592 rnot->u.msg.type = type; 1593 rnot->pkt_send = FALSE; 1594 rnot->next = NULL; 1595 /* Other parameters in the registration routine */ 1596 switch (type) { 1597 case RLINK_TYPE_OAM: 1598 for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) { 1599 BCM_UNPACK_U32(bp, rnot->register_args.u.oam.events.w[i]); 1600 } 1601 break; 1602 case RLINK_TYPE_BFD: 1603 #if defined(INCLUDE_BFD) 1604 for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) { 1605 BCM_UNPACK_U32(bp, rnot->register_args.u.bfd.events.w[i]); 1606 } 1607 #endif 1608 break; 1609 default: 1610 break; 1611 } 1612 break; 1613 case RLINK_MSG_DELETE: 1614 INCR_COUNTER(rlink_del_req_in); 1615 rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify"); 1616 if (rnot == NULL) { 1617 return BCM_RX_HANDLED; /* failure */ 1618 } 1619 CPUDB_KEY_COPY(rnot->cpu, cpu); 1620 rnot->unit = unit; 1621 rnot->type = RLINK_TYPE_DELETE; 1622 rnot->u.msg.type = type; 1623 rnot->pkt_send = FALSE; 1624 rnot->next = NULL; 1625 break; 1626 case RLINK_MSG_NOTIFY: 1627 INCR_COUNTER(rlink_notify_in); 1628 /* See if currently space in the queue */ 1629 switch (type) { 1630 case RLINK_TYPE_LINK: 1631 INCR_COUNTER(rlink_link_in); 1632 if (bcm_rlink_link_local_max > 0 && 1633 _rlink_queue_size > bcm_rlink_link_local_max) { 1634 INCR_COUNTER(rlink_link_in_disc); 1635 return BCM_RX_HANDLED; 1636 } 1637 break; 1638 case RLINK_TYPE_AUTH: 1639 INCR_COUNTER(rlink_auth_in); 1640 if (bcm_rlink_auth_local_max > 0 && 1641 _rlink_queue_size > bcm_rlink_auth_local_max) { 1642 INCR_COUNTER(rlink_auth_in_disc); 1643 return BCM_RX_HANDLED; 1644 } 1645 break; 1646 case RLINK_TYPE_L2: 1647 INCR_COUNTER(rlink_l2_in); 1648 if (bcm_rlink_l2_local_max > 0 && 1649 _rlink_queue_size > bcm_rlink_l2_local_max) { 1650 INCR_COUNTER(rlink_l2_in_disc); 1651 return BCM_RX_HANDLED; 1652 } 1653 break; 1654 case RLINK_TYPE_RX: 1655 INCR_COUNTER(rlink_rx_in); 1656 ct_rx_tunnelled_pkt_handler(cpu, bp, buf_len - 1 - 1 - 4); 1657 return BCM_RX_HANDLED; 1658 break; 1659 case RLINK_TYPE_OAM: 1660 INCR_COUNTER(rlink_oam_in); 1661 if (bcm_rlink_oam_local_max > 0 && 1662 _rlink_queue_size > bcm_rlink_oam_local_max) { 1663 INCR_COUNTER(rlink_oam_in_disc); 1664 return BCM_RX_HANDLED; 1665 } 1666 break; 1667 default: 1668 break; 1669 } 1670 rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify"); 1671 if (rnot == NULL) { 1672 return BCM_RX_HANDLED; /* failure */ 1673 } 1674 CPUDB_KEY_COPY(rnot->cpu, cpu); 1675 rnot->unit = unit; 1676 rnot->type = type; 1677 rnot->pkt_send = FALSE; 1678 rnot->next = NULL; 1679 switch (type) { 1680 case RLINK_TYPE_LINK: 1681 BCM_UNPACK_U32(bp, rnot->u.link.port); 1682 (void) _bcm_unpack_port_info(bp, &rnot->u.link.info); 1683 break; 1684 case RLINK_TYPE_AUTH: 1685 BCM_UNPACK_U32(bp, rnot->u.auth.port); 1686 BCM_UNPACK_U32(bp, rnot->u.auth.reason); 1687 break; 1688 case RLINK_TYPE_L2: 1689 BCM_UNPACK_U8(bp, rnot->u.l2.insert); 1690 (void) _bcm_unpack_l2_addr(bp, &rnot->u.l2.addr); 1691 break; 1692 case RLINK_TYPE_OAM: 1693 BCM_UNPACK_U32(bp, rnot->u.oam.flags); 1694 BCM_UNPACK_U32(bp, rnot->u.oam.event_type); 1695 BCM_UNPACK_U32(bp, rnot->u.oam.group); 1696 BCM_UNPACK_U32(bp, rnot->u.oam.endpoint); 1697 break; 1698 default: 1699 break; 1700 } 1701 break; 1702 } 1703 1704 if (rnot != NULL) { 1705 RLINK_ENQUEUE_NOTIFY(rnot); 1706 } 1707 return rv; 1708 } 1709 1710 /* 1711 * Process a notify record. 1712 */ 1713 STATIC void 1714 _bcm_rlink_notify(_rlink_notify_t *rnot) 1715 { 1716 _rlink_handle_t *rhand, *nhand; 1717 1718 if (rnot->pkt_send) { /* Send out prepared packet */ 1719 _bcm_rlink_send_notify(rnot->unit, 1720 rnot->type, 1721 rnot->u.cli.buf, 1722 rnot->u.cli.len, 1723 rnot->u.cli.check_cpu, 1724 rnot->cpu, 1725 rnot->u.cli.ct_flags); 1726 return; 1727 } 1728 1729 /* server side scan add/delete requests */ 1730 switch (rnot->type) { 1731 case RLINK_TYPE_ADD: 1732 _bcm_rlink_scan_add(rnot->cpu, rnot->unit, rnot->u.msg.type, 1733 &rnot->register_args); 1734 return; 1735 case RLINK_TYPE_DELETE: 1736 _bcm_rlink_scan_delete(rnot->cpu, rnot->unit, rnot->u.msg.type, 1737 &rnot->register_args); 1738 return; 1739 1740 /* traverse server and client messages are handles identically */ 1741 case RLINK_TYPE_START: 1742 case RLINK_TYPE_NEXT: 1743 case RLINK_TYPE_QUIT: 1744 case RLINK_TYPE_ERROR: 1745 case RLINK_TYPE_MORE: 1746 case RLINK_TYPE_DONE: 1747 (void)bcm_rlink_traverse_request(rnot->type, 1748 rnot->cpu, 1749 rnot->u.traverse.pkt, 1750 rnot->u.traverse.buf, 1751 rnot->u.traverse.len); 1752 return; 1753 default: 1754 break; 1755 } 1756 1757 /* client side handler callbacks */ 1758 RLINK_LOCK; 1759 for (rhand = _rlink_handle_head; rhand != NULL; rhand = nhand) { 1760 nhand = rhand->next; 1761 if (rhand->cunit != rnot->unit) { 1762 continue; 1763 } 1764 if (rhand->type != rnot->type) { 1765 continue; 1766 } 1767 if (CPUDB_KEY_COMPARE(rhand->cpu, rnot->cpu) != 0) { 1768 continue; 1769 } 1770 switch (rnot->type) { 1771 case RLINK_TYPE_LINK: 1772 (*rhand->func.link)(rhand->unit, 1773 rnot->u.link.port, 1774 &rnot->u.link.info); 1775 break; 1776 case RLINK_TYPE_AUTH: 1777 (*rhand->func.auth)(rhand->cookie, 1778 rhand->unit, 1779 rnot->u.auth.port, 1780 rnot->u.auth.reason); 1781 break; 1782 case RLINK_TYPE_L2: 1783 (*rhand->func.l2)(rhand->unit, 1784 &rnot->u.l2.addr, 1785 rnot->u.l2.insert, 1786 rhand->cookie); 1787 break; 1788 case RLINK_TYPE_OAM: 1789 (*rhand->func.oam)(rhand->unit, 1790 rnot->u.oam.flags, 1791 rnot->u.oam.event_type, 1792 rnot->u.oam.group, 1793 rnot->u.oam.endpoint, 1794 rhand->cookie); 1795 break; 1796 default: 1797 break; 1798 } 1799 } 1800 RLINK_UNLOCK; 1801 } 1802 1803 /* 1804 * Client (and now server) side callback thread. 1805 * Notify packets are sent to this thread to be executed. 1806 */ 1807 STATIC void 1808 _bcm_rlink_thread(void *cookie) 1809 { 1810 _rlink_notify_t *rnot, *fnot; 1811 1812 COMPILER_REFERENCE(cookie); 1813 1814 _rlink_thread_exit = 0; 1815 for (;;) { 1816 RLINK_SLEEP; 1817 1818 /* grab a set of notifications off the queue */ 1819 RLINK_NOTIFY_LOCK; 1820 rnot = _rlink_notify_head; 1821 _rlink_notify_head = _rlink_notify_tail = NULL; 1822 _rlink_queue_size = 0; 1823 RLINK_NOTIFY_UNLOCK; 1824 1825 /* run the notifications */ 1826 while (rnot != NULL) { 1827 _bcm_rlink_notify(rnot); 1828 fnot = rnot; 1829 rnot = rnot->next; 1830 sal_free(fnot); 1831 } 1832 if (_rlink_thread_exit) { 1833 _rlink_thread = SAL_THREAD_ERROR; 1834 sal_thread_exit(0); 1835 return; 1836 } 1837 } 1838 } 1839 1840 /* 1841 * Externally visible api routines. 1842 * Thread start/stop controls. 1843 * Client registration functions. 1844 */ 1845 1846 /* 1847 * Start the remote registration system 1848 */ 1849 int 1850 bcm_rlink_start(void) 1851 { 1852 int rv, flags, i; 1853 int rlink_auth_remote_max, rlink_auth_local_max; 1854 int rlink_l2_remote_max, rlink_l2_local_max; 1855 int rlink_link_remote_max, rlink_link_local_max; 1856 int rlink_oam_remote_max, rlink_oam_local_max; 1857 int rlink_rx_remote_max[BCM_COS_COUNT] = BCM_RLINK_RX_REMOTE_MAX_DEFAULT; 1858 char *rlink_rx_remote_properties[BCM_COS_COUNT] = {spn_RLINK_RX0_REMOTE_MAX, 1859 spn_RLINK_RX1_REMOTE_MAX, 1860 spn_RLINK_RX2_REMOTE_MAX, 1861 spn_RLINK_RX3_REMOTE_MAX, 1862 spn_RLINK_RX4_REMOTE_MAX, 1863 spn_RLINK_RX5_REMOTE_MAX, 1864 spn_RLINK_RX6_REMOTE_MAX, 1865 spn_RLINK_RX7_REMOTE_MAX}; 1866 1867 if (RLINK_INIT) { 1868 return BCM_E_BUSY; 1869 } 1870 1871 _rlink_lock = sal_mutex_create("bcm_rlink"); 1872 _rlink_notify_lock = sal_mutex_create("bcm_rlink_notify"); 1873 _rlink_sem = sal_sem_create("bcm_rlink", sal_sem_BINARY, 0); 1874 1875 /* Get max values if different then default */ 1876 /* Givving 0 hard coded as unit to soc_property_get is fine 1877 since these are unitless settings anyway */ 1878 if (SOC_UNIT_VALID(0)) { 1879 rlink_auth_remote_max = soc_property_get(0, spn_RLINK_AUTH_REMOTE_MAX, -1); 1880 rlink_auth_local_max = soc_property_get(0, spn_RLINK_AUTH_LOCAL_MAX, -1); 1881 rlink_l2_remote_max = soc_property_get(0, spn_RLINK_L2_REMOTE_MAX, -1); 1882 rlink_l2_local_max = soc_property_get(0, spn_RLINK_L2_LOCAL_MAX, -1); 1883 rlink_link_remote_max = soc_property_get(0, spn_RLINK_LINK_REMOTE_MAX, -1); 1884 rlink_link_local_max = soc_property_get(0, spn_RLINK_LINK_LOCAL_MAX, -1); 1885 rlink_oam_remote_max = soc_property_get(0, spn_RLINK_OAM_REMOTE_MAX, -1); 1886 rlink_oam_local_max = soc_property_get(0, spn_RLINK_OAM_LOCAL_MAX, -1); 1887 } else { 1888 rlink_auth_remote_max = -1; 1889 rlink_auth_local_max = -1; 1890 rlink_l2_remote_max = -1; 1891 rlink_l2_local_max = -1; 1892 rlink_link_remote_max = -1; 1893 rlink_link_local_max = -1; 1894 rlink_oam_remote_max = -1; 1895 rlink_oam_local_max = -1; 1896 } 1897 1898 if (-1 != rlink_auth_remote_max) { 1899 bcm_rlink_auth_remote_max = rlink_auth_remote_max; 1900 } 1901 if (-1 != rlink_auth_local_max) { 1902 bcm_rlink_auth_local_max = rlink_auth_local_max; 1903 } 1904 if (-1 != rlink_l2_remote_max) { 1905 bcm_rlink_l2_remote_max = rlink_l2_remote_max; 1906 } 1907 if (-1 != rlink_l2_local_max) { 1908 bcm_rlink_l2_local_max = rlink_l2_local_max; 1909 } 1910 if (-1 != rlink_link_remote_max) { 1911 bcm_rlink_link_remote_max = rlink_link_remote_max; 1912 } 1913 if (-1 != rlink_link_local_max) { 1914 bcm_rlink_link_local_max = rlink_link_local_max; 1915 } 1916 if (-1 != rlink_oam_remote_max) { 1917 bcm_rlink_oam_remote_max = rlink_oam_remote_max; 1918 } 1919 if (-1 != rlink_oam_local_max) { 1920 bcm_rlink_oam_local_max = rlink_oam_local_max; 1921 } 1922 1923 for (i = 0 ; i < BCM_COS_COUNT; i++) { 1924 if (SOC_UNIT_VALID(0)) { 1925 rlink_rx_remote_max[i] = soc_property_get(0, rlink_rx_remote_properties[i], -1); 1926 } else { 1927 rlink_rx_remote_max[i] = -1; 1928 } 1929 if (-1 != rlink_rx_remote_max[i]) { 1930 bcm_rlink_rx_remote_max[i] = rlink_rx_remote_max[i]; 1931 } 1932 } 1933 1934 _rlink_thread = sal_thread_create("bcmRLINK", 1935 RLINK_THREAD_STACK, 1936 RLINK_THREAD_PRIO, 1937 _bcm_rlink_thread, 1938 NULL); 1939 if (_rlink_thread == SAL_THREAD_ERROR) { 1940 sal_sem_destroy(_rlink_sem); 1941 sal_mutex_destroy(_rlink_notify_lock); 1942 _rlink_notify_lock = NULL; 1943 sal_mutex_destroy(_rlink_lock); 1944 _rlink_lock = NULL; 1945 1946 return BCM_E_RESOURCE; 1947 } 1948 1949 /* can be configured to use nexthop or cpu2cpu */ 1950 if (_rlink_nexthop) { 1951 flags = ATP_F_REASSEM_BUF | ATP_F_NEXT_HOP; 1952 } else { 1953 flags = ATP_F_REASSEM_BUF; 1954 } 1955 rv = atp_register(RLINK_CLIENT_ID, flags, 1956 _bcm_rlink_pkt_handler, NULL, -1, -1); 1957 1958 if (BCM_SUCCESS(rv)) { 1959 rv = bcm_rlink_traverse_init(); 1960 } 1961 return rv; 1962 } 1963 1964 /* 1965 * Stop the remote registration system 1966 */ 1967 int 1968 bcm_rlink_stop(void) 1969 { 1970 _rlink_notify_t *rnot, *nnot; 1971 1972 if (!RLINK_INIT) { 1973 return BCM_E_NONE; 1974 } 1975 atp_unregister(RLINK_CLIENT_ID); 1976 1977 /* destroy thread */ 1978 _rlink_thread_exit = 1; 1979 RLINK_WAKE; 1980 sal_thread_yield(); 1981 while (_rlink_thread != SAL_THREAD_ERROR) { 1982 RLINK_WAKE; 1983 sal_usleep(10000); 1984 } 1985 1986 /* free any queued notification */ 1987 RLINK_NOTIFY_LOCK; 1988 rnot = _rlink_notify_head; 1989 _rlink_notify_head = _rlink_notify_tail = NULL; 1990 _rlink_queue_size = 0; 1991 RLINK_NOTIFY_UNLOCK; 1992 while (rnot != NULL) { 1993 nnot = rnot->next; 1994 sal_free(rnot); 1995 rnot = nnot; 1996 } 1997 1998 sal_sem_destroy(_rlink_sem); 1999 sal_mutex_destroy(_rlink_notify_lock); 2000 _rlink_notify_lock = NULL; 2001 sal_mutex_destroy(_rlink_lock); 2002 _rlink_lock = NULL; 2003 (void) bcm_rlink_traverse_deinit(); 2004 return BCM_E_NONE; 2005 } 2006 2007 /* 2008 * When a unit is detached from the system, this should be called. 2009 * It will flush all rlink handlers asssociated with the unit. 2010 * It should only be called for remote units. Since it assumes the 2011 * unit is gone, it does not do commands back to the controlling CPU. 2012 */ 2013 2014 int 2015 bcm_rlink_device_detach(int unit) 2016 { 2017 _rlink_handle_t *rhand, *phand, *nhand; 2018 2019 if (!RLINK_INIT) { 2020 return BCM_E_UNAVAIL; 2021 } 2022 2023 RLINK_LOCK; 2024 phand = NULL; 2025 for (rhand = _rlink_handle_head; rhand != NULL; /* see below */) { 2026 nhand = rhand->next; /* rhand my be deallocated */ 2027 if (unit == rhand->unit) { /* Remove from list */ 2028 if (phand == NULL) { 2029 _rlink_handle_head = rhand->next; 2030 } else { 2031 phand->next = rhand->next; 2032 } 2033 if (rhand == _rlink_handle_tail) { 2034 _rlink_handle_tail = phand; 2035 } 2036 sal_free(rhand); 2037 } else { 2038 phand = rhand; 2039 } 2040 rhand = nhand; 2041 } 2042 RLINK_UNLOCK; 2043 2044 return BCM_E_NONE; 2045 } 2046 2047 /* 2048 * Auth registration for de-authorization callback. 2049 * 2050 * Due to the implementation of the auth_unauth callback 2051 * structure (there is only one call; it's not a register/unregister 2052 * protocol) we make the following convention: Multiple callbacks 2053 * may be registered per device (unit). 2054 * 2055 * To de-register, func is passed as NULL. This causes all 2056 * registered entries that match unit and cookie to be deleted. 2057 */ 2058 2059 int 2060 bcm_client_auth_unauth_callback(int unit, 2061 bcm_auth_cb_t func, 2062 void *cookie) 2063 { 2064 int rv = BCM_E_NONE; 2065 2066 if (!RLINK_INIT) { 2067 return BCM_E_UNAVAIL; 2068 } 2069 2070 if (func == NULL) { /* Unregister entries matching unit and cookie */ 2071 int last = 1; 2072 int cunit = 0; 2073 int deleted = 0; 2074 cpudb_key_t cpukey; 2075 _rlink_handle_t *rhand = NULL; /* Iterator thru handler list */ 2076 _rlink_handle_t *phand = NULL; /* Track previous node in the list */ 2077 _rlink_handle_t *to_delete = NULL; 2078 _rlink_handle_t *tmp_list_head = NULL; 2079 _rlink_handle_t *tmp_list_tail = NULL; 2080 2081 RLINK_LOCK; 2082 for (rhand = _rlink_handle_head; rhand != NULL; ) { 2083 if (rhand->type == RLINK_TYPE_AUTH && rhand->unit == unit) { 2084 if (rhand->cookie == cookie) { 2085 /* Record info in case disconnection done later */ 2086 deleted = 1; 2087 CPUDB_KEY_COPY(cpukey, rhand->cpu); 2088 cunit = rhand->cunit; 2089 /* Remove this entry */ 2090 if (phand == NULL) { /* First item on list being removed */ 2091 _rlink_handle_head = rhand->next; 2092 } else { 2093 phand->next = rhand->next; 2094 } 2095 if (rhand == _rlink_handle_tail) { /* Last in list */ 2096 _rlink_handle_tail = phand; 2097 } 2098 /* Safe deletion of pointer; don't update phand */ 2099 to_delete = rhand; 2100 rhand = rhand->next; 2101 2102 /* Insert node to be deleted in the tmp list */ 2103 to_delete->next = NULL; 2104 if (NULL == tmp_list_tail) { 2105 tmp_list_head = tmp_list_tail = to_delete; 2106 } else { 2107 tmp_list_tail->next = to_delete; 2108 tmp_list_tail = to_delete; 2109 } 2110 } else { /* Entry matches type and device, but not cookie */ 2111 last = 0; /* Won't disconnect from CPU */ 2112 phand = rhand; /* Update pointers */ 2113 rhand = rhand->next; 2114 } 2115 } else { /* Move to next entry in list */ 2116 phand = rhand; 2117 rhand = rhand->next; 2118 } 2119 } 2120 RLINK_UNLOCK; 2121 2122 if (deleted) { 2123 if (last) { 2124 rv = _bcm_rlink_send_control(cpukey, cunit, 2125 RLINK_MSG_DELETE, RLINK_TYPE_AUTH, 2126 NULL); 2127 } 2128 2129 if (BCM_SUCCESS(rv)) { 2130 /* Now de-allocate the deleted nodes */ 2131 for (rhand = tmp_list_head; rhand != NULL;) { 2132 to_delete = rhand; 2133 rhand = rhand->next; 2134 sal_free(to_delete); 2135 } 2136 } else { 2137 /* DEL Msg send failed, add back removed nodes to the list */ 2138 RLINK_LOCK; 2139 if (NULL == _rlink_handle_tail) { 2140 _rlink_handle_head = tmp_list_head; 2141 } else { 2142 _rlink_handle_tail->next = tmp_list_head; 2143 } 2144 _rlink_handle_tail = tmp_list_tail; 2145 RLINK_UNLOCK; 2146 } 2147 } 2148 } else { /* Non-null function, register */ 2149 _rlink_handle_t node = {0}; 2150 2151 /* Fill in required details */ 2152 node.unit = unit; 2153 node.type = RLINK_TYPE_AUTH; 2154 node.func.auth = func; 2155 node.cookie = cookie; 2156 2157 rv = _bcm_rlink_register(&node, NULL); 2158 } 2159 2160 return rv; 2161 } 2162 2163 /* 2164 * Register a linkscan callback function on the rpc client 2165 * Referenced from the client dispatch table 2166 */ 2167 int 2168 bcm_client_linkscan_register(int unit, bcm_linkscan_handler_t f) 2169 { 2170 _rlink_handle_t node = {0}; 2171 2172 /* Fill in required details */ 2173 node.unit = unit; 2174 node.type = RLINK_TYPE_LINK; 2175 node.func.link = f; 2176 node.cookie = NULL; 2177 2178 return _bcm_rlink_register(&node, NULL); 2179 } 2180 2181 /* 2182 * Remove a linkscan callback function on the rpc client 2183 * Referenced from the client dispatch table 2184 */ 2185 2186 int 2187 bcm_client_linkscan_unregister(int unit, bcm_linkscan_handler_t f) 2188 { 2189 _rlink_handle_t node = {0}; 2190 2191 /* Fill in required details */ 2192 node.unit = unit; 2193 node.type = RLINK_TYPE_LINK; 2194 node.func.link = f; 2195 node.cookie = NULL; 2196 2197 return _bcm_rlink_unregister(&node, NULL); 2198 } 2199 2200 /* 2201 * Register an l2 callback function on the rpc client 2202 * Referenced from the client dispatch table 2203 */ 2204 int 2205 bcm_client_l2_addr_register(int unit, 2206 bcm_l2_addr_callback_t f, 2207 void *cookie) 2208 { 2209 _rlink_handle_t node = {0}; 2210 2211 /* Fill in required details */ 2212 node.unit = unit; 2213 node.type = RLINK_TYPE_L2; 2214 node.func.l2 = f; 2215 node.cookie = cookie; 2216 2217 return _bcm_rlink_register(&node, NULL); 2218 } 2219 2220 /* 2221 * Remove an l2 callback function on the rpc client 2222 * Referenced from the client dispatch table 2223 */ 2224 int 2225 bcm_client_l2_addr_unregister(int unit, 2226 bcm_l2_addr_callback_t f, 2227 void *cookie) 2228 { 2229 _rlink_handle_t node = {0}; 2230 2231 /* Fill in required details */ 2232 node.unit = unit; 2233 node.type = RLINK_TYPE_L2; 2234 node.func.l2 = f; 2235 node.cookie = cookie; 2236 ; 2237 return _bcm_rlink_unregister(&node, NULL); 2238 } 2239 2240 2241 /* 2242 * Register an oam event callback function on the rpc client 2243 * Referenced from the client dispatch table 2244 */ 2245 int 2246 bcm_client_oam_event_register(int unit, 2247 bcm_oam_event_types_t event_types, 2248 bcm_oam_event_cb f, 2249 void *cookie) 2250 { 2251 _rlink_handle_t node = {0}; 2252 _rlink_register_args_t register_args; 2253 2254 /* Fill in required details */ 2255 node.unit = unit; 2256 node.type = RLINK_TYPE_OAM; 2257 node.func.oam = f; 2258 node.cookie = cookie; 2259 register_args.u.oam.events = event_types; 2260 2261 return _bcm_rlink_register(&node, ®ister_args); 2262 } 2263 2264 /* 2265 * Remove an oam event callback function on the rpc client 2266 * Referenced from the client dispatch table 2267 */ 2268 int 2269 bcm_client_oam_event_unregister(int unit, 2270 bcm_oam_event_types_t event_types, 2271 bcm_oam_event_cb f) 2272 { 2273 _rlink_handle_t node = {0}; 2274 _rlink_register_args_t register_args; 2275 2276 /* Fill in required details */ 2277 node.unit = unit; 2278 node.type = RLINK_TYPE_OAM; 2279 node.func.oam = f; 2280 node.cookie = NULL; 2281 register_args.u.oam.events = event_types; 2282 2283 return _bcm_rlink_unregister(&node, ®ister_args); 2284 } 2285 2286 #if defined(INCLUDE_BFD) 2287 /* 2288 * Register an bfd event callback function on the rpc client 2289 * Referenced from the client dispatch table 2290 */ 2291 int 2292 bcm_client_bfd_event_register(int unit, 2293 uint32 event_types, 2294 bcm_bfd_event_cb f, 2295 void *cookie) 2296 { 2297 /* to be done for BFD, including this function to compile */ 2298 return BCM_E_NONE; 2299 } 2300 2301 /* 2302 * Remove an bfd event callback function on the rpc client 2303 * Referenced from the client dispatch table 2304 */ 2305 int 2306 bcm_client_bfd_event_unregister(int unit, 2307 uint32 event_types, 2308 bcm_bfd_event_cb f) 2309 { 2310 /* to be done for BFD, including this function to compile */ 2311 return BCM_E_NONE; 2312 } 2313 #endif 2314 2315 /* 2316 * Special connect and disconnect code for RX. 2317 * 2318 * These correspond to register and unregister above, but are slightly 2319 * different because the function callbacks for RX are handled by 2320 * the RX subsystem (so that the packets can go through the normal 2321 * RX stack). 2322 * 2323 * The functions below make the proper setup happen for the RLink portion 2324 * of the process. 2325 * 2326 * This assumes that the upper layer is keeping track of redundant 2327 * calls for connecting, so no checking of that is done here. 2328 * 2329 * Unit must be a remote unit number; it is translated here to 2330 * a physical unit number on the remote CPU. 2331 */ 2332 2333 int 2334 bcm_rlink_rx_connect(int unit) 2335 { 2336 cpudb_key_t *cpu; 2337 int cpu_unit; 2338 2339 if (!RLINK_INIT) { 2340 return BCM_E_UNAVAIL; 2341 } 2342 2343 if (BCM_IS_LOCAL(unit)) { 2344 return BCM_E_PARAM; 2345 } 2346 2347 cpu = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control; 2348 cpu_unit = BCM_CONTROL(unit)->unit; 2349 2350 return (_bcm_rlink_send_control( 2351 *cpu, cpu_unit, RLINK_MSG_ADD, RLINK_TYPE_RX, NULL)); 2352 } 2353 2354 int 2355 bcm_rlink_rx_disconnect(int unit) 2356 { 2357 cpudb_key_t *cpu; 2358 int cpu_unit; 2359 2360 if (!RLINK_INIT) { 2361 return BCM_E_UNAVAIL; 2362 } 2363 2364 if (BCM_IS_LOCAL(unit)) { 2365 return BCM_E_PARAM; 2366 } 2367 2368 cpu = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control; 2369 cpu_unit = BCM_CONTROL(unit)->unit; 2370 2371 return (_bcm_rlink_send_control( 2372 *cpu, cpu_unit, RLINK_MSG_DELETE, RLINK_TYPE_RX, NULL)); 2373 } 2374 2375 #if defined(BROADCOM_DEBUG) 2376 void 2377 bcm_rlink_dump(void) 2378 { 2379 _rlink_handle_t *h_ent; 2380 _rlink_scan_t *s_ent; 2381 2382 if (_rlink_lock == NULL) { 2383 LOG_CLI((BSL_META("RLink not initialized\n"))); 2384 return; 2385 } 2386 2387 LOG_CLI((BSL_META("RLink thread %x; thread exit %d\n"), 2388 PTR_TO_INT(_rlink_thread), _rlink_thread_exit)); 2389 2390 LOG_CLI((BSL_META("Server side scan list\n"))); 2391 for (s_ent = _rlink_scan_head; s_ent != NULL; s_ent = s_ent->next) { 2392 LOG_CLI((BSL_META(" Unit %d. Type %s. CPU " CPUDB_KEY_FMT_EOLN), 2393 s_ent->unit, TYPE_STR(s_ent->type), 2394 CPUDB_KEY_DISP(s_ent->cpu))); 2395 } 2396 2397 LOG_CLI((BSL_META("Client side handler registrants\n"))); 2398 for (h_ent = _rlink_handle_head; h_ent != NULL; h_ent = h_ent->next) { 2399 LOG_CLI((BSL_META(" Fn %p. Unit %d. Type %s. CPU " CPUDB_KEY_FMT_EOLN), 2400 h_ent->func.link, 2401 h_ent->unit, 2402 TYPE_STR(h_ent->type), 2403 CPUDB_KEY_DISP(h_ent->cpu))); 2404 } 2405 2406 LOG_CLI((BSL_META("Counters:\n"))); 2407 LOG_CLI((BSL_META(" l2 in %d. l2 in disc %d. l2 out %d. l2 out disc %d\n"), 2408 rlink_l2_in, rlink_l2_in_disc, 2409 rlink_l2_out, rlink_l2_out_disc)); 2410 LOG_CLI((BSL_META(" link in %d. link in disc %d. link out %d. link out " 2411 "disc %d\n"), rlink_link_in, rlink_link_in_disc, 2412 rlink_link_out, rlink_link_out_disc)); 2413 LOG_CLI((BSL_META(" auth in %d. auth in disc %d. auth out %d. auth out disc %d\n"), 2414 rlink_auth_in, rlink_auth_in_disc, 2415 rlink_auth_out, rlink_auth_out_disc)); 2416 LOG_CLI((BSL_META(" rx in %d. rx in disc %d. rx out %d. rx out disc %d\n"), 2417 rlink_rx_in, rlink_rx_in_disc, 2418 rlink_rx_out, rlink_rx_out_disc)); 2419 LOG_CLI((BSL_META(" oam event in %d. oam event in disc %d. oam event out %d. " 2420 "oam event out disc %d\n"), 2421 rlink_oam_in, rlink_oam_in_disc, 2422 rlink_oam_out, rlink_oam_out_disc)); 2423 LOG_CLI((BSL_META(" bfd event in %d. bfd event in disc %d. bfd event out %d. " 2424 "bfd event out disc %d\n"), 2425 rlink_bfd_in, rlink_bfd_in_disc, 2426 rlink_bfd_out, rlink_bfd_out_disc)); 2427 LOG_CLI((BSL_META(" add req %d. del req %d. notify %d\n"), 2428 rlink_add_req_in, rlink_del_req_in, rlink_notify_in)); 2429 LOG_CLI((BSL_META(" trav req %d.\n"), 2430 rlink_trav_req_in)); 2431 LOG_CLI((BSL_META(" pkt buffer alloc failure %d. pkt send failure %d\n"), 2432 rlink_buff_alloc_fail, rlink_pkt_send_fail)); 2433 2434 bcm_linkscan_dump(0); 2435 } 2436 #endif /* BROADCOM_DEBUG */ 2437 2438 #endif /* BCM_RPC_SUPPORT */