ct_tun.c (38386B)
1 /* 2 * 3 * 4 * 5 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 6 * 7 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 8 * 9 * File: ct_tun.c 10 * Purpose: 11 * Requires: 12 */ 13 14 /**************************************************************** 15 * 16 * Packet RX tunnelling code: 17 * 18 * This code originally lived in BCM. It has been moved to 19 * be an ATP application and live in src/appl/cputrans. 20 * 21 * Tunnelling is meant to forward packets between two different 22 * CPUs. However, 23 * the function that actually forwards the packet data is programmed 24 * into this API with the ct_rx_tunnel_tx_set call. Having both 25 * tunnel send and tunnel accept running on the same CPU probably will 26 * not work. 27 * 28 * Reliable and best effort tunnelling are both supported. 29 * 30 * The code is divided into that which runs on the slave (most of 31 * the code) and that which runs on the master (just the unpack 32 * routine). 33 * 34 * A local callback may be installed (tunnel_filter) which will be called 35 * as a filter on packets that may be tunnelled. The filter may 36 * return: 37 * 38 * BCM_CPU_TUNNEL_NONE Do not tunnel the packet 39 * BCM_CPU_TUNNEL_PACKET_RELIABLE Use reliable trx 40 * BCM_CPU_TUNNEL_PACKET_BEST_EFFORT Use best effort 41 * BCM_CPU_TUNNEL_PACKET Use the current default mode 42 * 43 * The default is BCM_CPU_TUNNEL_PACKET. Otherwise, BCM_RX_NOT_HANDLED 44 * is returned to the RX thread. 45 * 46 * If no filter function is installed, then all packets received by the 47 * tunnel routine are forwarded. 48 * 49 * Only one set of data is supported across all local units. This 50 * includes the filter function, the filter cookie (if implemented), 51 * and the TX functions. Note that receive unit is sent to the callback. 52 * 53 * Packets are queued to a tunneling thread, which then transmits the 54 * packet. 55 * 56 * The current implementation does alloc/frees, so will be very 57 * slow. Packet pools may be added in the future. 58 * For now, BCM_RX_HANDLED is returned when tunnelled. If a queue and 59 * separate thread are added in the future, packets will be stolen 60 * from BCM RX (BCM_RX_HANDLED_OWNED is returned). 61 * 62 * TO DO: 63 * Use RX pool code for tunnelled packet data. See 64 * rx_tunnel_pkt and ct_rx_tunnel_done_cb. 65 */ 66 #include <shared/bsl.h> 67 68 #include <sdk_config.h> 69 #include <assert.h> 70 #include <sal/core/thread.h> 71 72 #include <shared/util.h> 73 #include <shared/idents.h> 74 75 #include <bcm/rx.h> 76 #include <bcm/init.h> 77 #include <bcm/port.h> 78 79 #include <appl/cputrans/ct_tun.h> 80 81 #include "t_util.h" 82 83 #if defined(BCM_RPC_SUPPORT) 84 85 #include <appl/cputrans/atp.h> 86 87 /* Filter function callback */ 88 STATIC bcm_cpu_tunnel_mode_t 89 _ct_rx_tunnel_filter_default(int unit, bcm_pkt_t *pkt); 90 static ct_rx_tunnel_filter_f ct_rx_tunnel_filter = _ct_rx_tunnel_filter_default; 91 92 static sal_mutex_t _tunnel_cfg_lock; 93 94 /* Tunnel TX queueing */ 95 96 #ifndef CT_TUNNEL_QUEUE_ENABLE 97 #define CT_TUNNEL_QUEUE_ENABLE 1 98 #endif 99 100 #if CT_TUNNEL_QUEUE_ENABLE 101 102 #ifndef CT_TUNNEL_QUEUE_SIZE 103 #define CT_TUNNEL_QUEUE_SIZE 32 104 #endif 105 106 typedef struct { 107 uint8 *data; 108 int len; 109 void *pkt; 110 } ct_tunnel_q_element; 111 112 static sal_thread_t _tunnel_q_thread = SAL_THREAD_ERROR; 113 static int _tunnel_q_top_full; /* Pkts dropped when queue full */ 114 static int _tunnel_q_thread_exit; /* Set to exit thread */ 115 static int _tunnel_q_error; /* TX error count */ 116 static sal_mutex_t _tunnel_q_lock; /* Queue lock */ 117 static sal_sem_t _tunnel_q_sem; /* Queue thread semaphore */ 118 static int _tunnel_q_head; /* Insertion index */ 119 static int _tunnel_q_tail; /* Removal index */ 120 static ct_tunnel_q_element _tunnel_q[CT_TUNNEL_QUEUE_SIZE]; /* Queue */ 121 122 #define TUNNEL_Q_LOCK sal_mutex_take(_tunnel_q_lock, sal_mutex_FOREVER) 123 #define TUNNEL_Q_UNLOCK sal_mutex_give(_tunnel_q_lock) 124 #define TUNNEL_Q_SLEEP sal_sem_take(_tunnel_q_sem, sal_sem_FOREVER) 125 #define TUNNEL_Q_WAKE sal_sem_give(_tunnel_q_sem) 126 127 #ifndef TUNNEL_Q_THREAD_STACK 128 #define TUNNEL_Q_THREAD_STACK SAL_THREAD_STKSZ 129 #endif 130 131 #ifndef TUNNEL_Q_THREAD_PRIO 132 #define TUNNEL_Q_THREAD_PRIO 255 133 #endif 134 135 STATIC int ct_tx_tunnel_thread_init(void); 136 STATIC int ct_tx_tunnel_thread_stop(void); 137 138 #endif 139 140 #define CHECK_INIT if (_tunnel_cfg_lock == NULL && \ 141 ((_tunnel_cfg_lock = sal_mutex_create("rx_tunnel")) == NULL)) \ 142 return BCM_E_MEMORY 143 144 #define TUNNEL_LOCK sal_mutex_take(_tunnel_cfg_lock, sal_mutex_FOREVER) 145 #define TUNNEL_UNLOCK sal_mutex_give(_tunnel_cfg_lock) 146 147 /* These are exposed */ 148 static bcm_cpu_tunnel_mode_t ct_rx_tunnel_mode_default = 149 BCM_CPU_TUNNEL_PACKET_BEST_EFFORT; 150 151 static int ct_rx_tunnel_priority = 100; /* Warning: Don't change when running */ 152 153 /* Accessors for mode and priority */ 154 int 155 ct_rx_tunnel_mode_default_set(int mode) 156 { 157 switch (mode) { 158 case BCM_CPU_TUNNEL_NONE: 159 case BCM_CPU_TUNNEL_PACKET_RELIABLE: 160 case BCM_CPU_TUNNEL_PACKET_BEST_EFFORT: 161 case BCM_CPU_TUNNEL_PACKET: 162 ct_rx_tunnel_mode_default = (bcm_cpu_tunnel_mode_t)mode; 163 return BCM_E_NONE; 164 165 default: 166 break; 167 } 168 169 return BCM_E_PARAM; 170 } 171 172 bcm_cpu_tunnel_mode_t 173 ct_rx_tunnel_mode_default_get(void) 174 { 175 return ct_rx_tunnel_mode_default; 176 } 177 178 int 179 ct_rx_tunnel_priority_set(int priority) 180 { 181 ct_rx_tunnel_priority = priority; 182 183 return BCM_E_NONE; 184 } 185 186 int 187 ct_rx_tunnel_priority_get(void) 188 { 189 return ct_rx_tunnel_priority; 190 } 191 192 #define CT_TUNNEL_RX_REASONS_WORDS (_SHR_BITDCLSIZE(_SHR_RX_REASON_COUNT)) 193 #define CT_TUNNEL_RX_HDR_BYTES (2 + 4 + (6*1) + 2 + 1 + 2 + (2*1) + (2*4) + \ 194 2 + (2*1) + (CT_TUNNEL_RX_REASONS_WORDS * 4)\ 195 + (2*4) + 4 + \ 196 2 + (2*1) + 2 + (2*1) + (15*4) + (2*4)) 197 198 /**************************************************************** 199 * 200 * Forward declarations 201 */ 202 203 STATIC bcm_rx_t ct_tx_tunnelled_pkt_handler(cpudb_key_t src_key, 204 int client_id, 205 bcm_pkt_t *pkt, 206 uint8 *payload, 207 int payload_len, 208 void *cookie); 209 210 /* 211 * Function: 212 * ct_rx_tunnel_header_bytes_get 213 * Purpose: 214 * Returns the number of bytes in a CT tunneled packet 215 * Returns: 216 * BCM_E_XXX on error (unsupported) 217 * Otherwise, number of bytes in the header 218 * Notes: 219 * Needed by RPC rlink code 220 */ 221 222 int 223 ct_rx_tunnel_header_bytes_get(void) 224 { 225 return CT_TUNNEL_RX_HDR_BYTES; 226 } 227 228 229 /* 230 * Tunnel pack and unpack functions 231 * 232 * These pack up the meta-data; for the pack function the data 233 * is copied into the buffer as well. For unpack, the pointers 234 * to the data are provided, but the data is not copied from the 235 * original buffer. 236 */ 237 238 uint8 * 239 ct_rx_tunnel_pkt_pack(bcm_pkt_t *pkt, uint8 *pkt_data) 240 { 241 int i; 242 243 #if defined(BROADCOM_DEBUG) 244 uint8 *pkt_data0 = pkt_data; 245 #endif 246 /* Change CT_TUNNEL_RX_HDR_BYTES when the packing changes. */ 247 CT_INCR_PACK_U16(pkt_data, pkt->pkt_len); 248 CT_INCR_PACK_U32(pkt_data, pkt->rx_reason); 249 CT_INCR_PACK_U8(pkt_data, pkt->rx_unit); 250 CT_INCR_PACK_U8(pkt_data, pkt->rx_port); 251 CT_INCR_PACK_U8(pkt_data, pkt->rx_cpu_cos); 252 CT_INCR_PACK_U8(pkt_data, pkt->rx_untagged); 253 CT_INCR_PACK_U8(pkt_data, pkt->cos); 254 CT_INCR_PACK_U8(pkt_data, pkt->prio_int); 255 CT_INCR_PACK_U16(pkt_data, pkt->src_port); 256 CT_INCR_PACK_U8(pkt_data, pkt->src_mod & 0xFF); 257 CT_INCR_PACK_U16(pkt_data, pkt->dest_port); 258 CT_INCR_PACK_U8(pkt_data, pkt->dest_mod & 0xFF); 259 CT_INCR_PACK_U8(pkt_data, pkt->opcode); 260 CT_INCR_PACK_U32(pkt_data, pkt->rx_matched); 261 CT_INCR_PACK_U32(pkt_data, pkt->flags); 262 CT_INCR_PACK_U16(pkt_data, pkt->src_trunk); 263 264 /* to maintain backwards compatibility, pack the extented src & dest mod 265 * bits at the end of the buffer 266 */ 267 CT_INCR_PACK_U8(pkt_data, (pkt->src_mod >> 8) & 0xFF); 268 CT_INCR_PACK_U8(pkt_data, (pkt->dest_mod >> 8) & 0xFF); 269 270 /* rx_reasons rx_classification_tag rx_timestamp */ 271 for (i=0; i<CT_TUNNEL_RX_REASONS_WORDS; i++) { 272 CT_INCR_PACK_U32(pkt_data, (uint32)pkt->rx_reasons.pbits[i]); 273 } 274 CT_INCR_PACK_U32(pkt_data, pkt->rx_classification_tag); 275 CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp); 276 277 for (i=0; i<4; i++) { 278 CT_INCR_PACK_U8(pkt_data, pkt->_vtag[i]); 279 } 280 281 CT_INCR_PACK_U16(pkt_data, pkt->vlan); 282 CT_INCR_PACK_U8(pkt_data, pkt->vlan_pri); 283 CT_INCR_PACK_U8(pkt_data, pkt->vlan_cfi); 284 CT_INCR_PACK_U16(pkt_data, pkt->inner_vlan); 285 CT_INCR_PACK_U8(pkt_data, pkt->inner_vlan_pri); 286 CT_INCR_PACK_U8(pkt_data, pkt->inner_vlan_cfi); 287 CT_INCR_PACK_U32(pkt_data, pkt->color); 288 CT_INCR_PACK_U32(pkt_data, pkt->dst_gport); 289 CT_INCR_PACK_U32(pkt_data, pkt->src_gport); 290 CT_INCR_PACK_U32(pkt_data, pkt->multicast_group); 291 CT_INCR_PACK_U32(pkt_data, pkt->stk_flags); 292 CT_INCR_PACK_U32(pkt_data, pkt->stk_forward); 293 CT_INCR_PACK_U32(pkt_data, pkt->stk_classification_tag); 294 CT_INCR_PACK_U32(pkt_data, pkt->stk_pkt_prio); 295 CT_INCR_PACK_U32(pkt_data, pkt->stk_dscp); 296 CT_INCR_PACK_U32(pkt_data, pkt->stk_load_balancing_number); 297 CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp_upper); 298 CT_INCR_PACK_U32(pkt_data, pkt->rx_l3_intf); 299 CT_INCR_PACK_U32(pkt_data, pkt->rx_outer_tag_action); 300 CT_INCR_PACK_U32(pkt_data, pkt->rx_inner_tag_action); 301 CT_INCR_PACK_U32(pkt_data, pkt->stk_encap_id); 302 303 CT_INCR_PACK_U32(pkt_data, pkt->flags2); 304 305 /* OAM SOMBH header fields */ 306 CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_type); 307 CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_offset); 308 CT_INCR_PACK_U16(pkt_data, pkt->oam_lm_counter_index); 309 310 #if defined(BROADCOM_DEBUG) 311 assert((pkt_data - pkt_data0) == CT_TUNNEL_RX_HDR_BYTES); 312 #endif 313 314 sal_memcpy(pkt_data, pkt->pkt_data[0].data, pkt->pkt_len); 315 316 317 return pkt_data + pkt->pkt_len; 318 } 319 320 int 321 ct_rx_tunnel_pkt_unpack(uint8 *pkt_data, int pkt_len, bcm_pkt_t *pkt, 322 uint8 **payload_start, int *payload_len) 323 { 324 uint8 tmp; 325 int i; 326 327 if (pkt_len < CT_TUNNEL_RX_HDR_BYTES) { 328 return BCM_E_PARAM; 329 } 330 331 CT_INCR_UNPACK_U16(pkt_data, pkt->pkt_len); 332 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_reason); 333 CT_INCR_UNPACK_U8(pkt_data, pkt->rx_unit); 334 CT_INCR_UNPACK_U8(pkt_data, pkt->rx_port); 335 CT_INCR_UNPACK_U8(pkt_data, pkt->rx_cpu_cos); 336 CT_INCR_UNPACK_U8(pkt_data, pkt->rx_untagged); 337 CT_INCR_UNPACK_U8(pkt_data, pkt->cos); 338 CT_INCR_UNPACK_U8(pkt_data, pkt->prio_int); 339 CT_INCR_UNPACK_U16(pkt_data, pkt->src_port); 340 CT_INCR_UNPACK_U8(pkt_data, pkt->src_mod); 341 CT_INCR_UNPACK_U16(pkt_data, pkt->dest_port); 342 CT_INCR_UNPACK_U8(pkt_data, pkt->dest_mod); 343 CT_INCR_UNPACK_U8(pkt_data, pkt->opcode); 344 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_matched); 345 CT_INCR_UNPACK_U32(pkt_data, pkt->flags); 346 CT_INCR_UNPACK_U16(pkt_data, pkt->src_trunk); 347 348 /* to maintain backwards compatibility, pack the extented src & dest mod 349 * bits at the end of the buffer 350 */ 351 CT_INCR_UNPACK_U8(pkt_data, tmp); 352 pkt->src_mod |= tmp << 8; 353 354 CT_INCR_UNPACK_U8(pkt_data, tmp); 355 pkt->dest_mod |= tmp << 8; 356 357 for (i=0; i<CT_TUNNEL_RX_REASONS_WORDS; i++) { 358 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_reasons.pbits[i]); 359 } 360 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_classification_tag); 361 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp); 362 363 for (i=0; i<4; i++) { 364 CT_INCR_UNPACK_U8(pkt_data, pkt->_vtag[i]); 365 } 366 367 CT_INCR_UNPACK_U16(pkt_data, pkt->vlan); 368 CT_INCR_UNPACK_U8(pkt_data, pkt->vlan_pri); 369 CT_INCR_UNPACK_U8(pkt_data, pkt->vlan_cfi); 370 CT_INCR_UNPACK_U16(pkt_data, pkt->inner_vlan); 371 CT_INCR_UNPACK_U8(pkt_data, pkt->inner_vlan_pri); 372 CT_INCR_UNPACK_U8(pkt_data, pkt->inner_vlan_cfi); 373 CT_INCR_UNPACK_U32(pkt_data, pkt->color); 374 CT_INCR_UNPACK_U32(pkt_data, pkt->dst_gport); 375 CT_INCR_UNPACK_U32(pkt_data, pkt->src_gport); 376 CT_INCR_UNPACK_U32(pkt_data, pkt->multicast_group); 377 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_flags); 378 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_forward); 379 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_classification_tag); 380 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_pkt_prio); 381 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_dscp); 382 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_load_balancing_number); 383 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp_upper); 384 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_l3_intf); 385 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_outer_tag_action); 386 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_inner_tag_action); 387 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_encap_id); 388 389 CT_INCR_UNPACK_U32(pkt_data, pkt->flags2); 390 391 /* OAM SOMBH header fields */ 392 CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_type); 393 CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_offset); 394 CT_INCR_UNPACK_U16(pkt_data, pkt->oam_lm_counter_index); 395 396 *payload_start = pkt_data; 397 *payload_len = pkt_len - CT_TUNNEL_RX_HDR_BYTES; 398 399 return BCM_E_NONE; 400 } 401 402 403 static ct_rx_tunnel_direct_f _rx_tunnel_direct = NULL; 404 405 int 406 ct_rx_tunnel_direct_set(ct_rx_tunnel_direct_f dif_fn) 407 { 408 _rx_tunnel_direct = dif_fn; 409 410 return BCM_E_NONE; 411 } 412 413 int 414 ct_rx_tunnel_direct_get(ct_rx_tunnel_direct_f *dif_fn) 415 { 416 *dif_fn = _rx_tunnel_direct; 417 418 return BCM_E_NONE; 419 } 420 421 /* 422 * ct_rx_tunnel_check: 423 * 424 * Check if a packet should be tunnelled; if so, see if it should 425 * be directed to some particular CPU. 426 * 427 * Returns BCM_CPU_TUNNEL_NONE if packet should _not_ be tunnelled; 428 * Any other value means packet should be tunnelled. 429 */ 430 431 bcm_cpu_tunnel_mode_t 432 ct_rx_tunnel_check(int unit, bcm_pkt_t *pkt, int *no_ack, int *check_cpu, 433 cpudb_key_t *cpu) 434 { 435 bcm_cpu_tunnel_mode_t mode = BCM_CPU_TUNNEL_PACKET; 436 437 if (ct_rx_tunnel_filter != NULL) { 438 mode = ct_rx_tunnel_filter(unit, pkt); 439 } 440 441 switch (mode) { 442 case BCM_CPU_TUNNEL_PACKET_RELIABLE: 443 *no_ack = FALSE; 444 break; 445 case BCM_CPU_TUNNEL_PACKET_BEST_EFFORT: 446 *no_ack = TRUE; 447 break; 448 case BCM_CPU_TUNNEL_PACKET: /* Check if default is currently no-ack */ 449 *no_ack = (ct_rx_tunnel_mode_default == 450 BCM_CPU_TUNNEL_PACKET_BEST_EFFORT); 451 break; 452 case BCM_CPU_TUNNEL_NONE: /* Don't tunnel */ 453 default: /* Bad mode; treat as none. */ 454 return BCM_CPU_TUNNEL_NONE; 455 456 } 457 458 if (_rx_tunnel_direct != NULL) { 459 *check_cpu = _rx_tunnel_direct(unit, pkt, cpu); 460 } else { 461 *check_cpu = FALSE; 462 } 463 464 return mode; 465 } 466 467 468 /**************************************************************** 469 * 470 * RX filter function accessors and default. 471 * 472 * Default tunnel filter callback. This filters out packets 473 * that come from stack ports. 474 */ 475 476 STATIC bcm_cpu_tunnel_mode_t 477 _ct_rx_tunnel_filter_default(int unit, bcm_pkt_t *pkt) 478 { 479 bcm_port_config_t port_config; 480 481 if (bcm_port_config_get(unit, &port_config) < 0) { 482 LOG_ERROR(BSL_LS_TKS_TUNNEL, 483 (BSL_META_U(unit, 484 "Tunnel filter: could not get port config " 485 " for %d\n"), 486 unit)); 487 return BCM_CPU_TUNNEL_NONE; 488 } 489 490 if (BCM_PBMP_MEMBER(port_config.stack_ext, pkt->rx_port)) { 491 return BCM_CPU_TUNNEL_NONE; 492 } 493 494 return BCM_CPU_TUNNEL_PACKET; 495 } 496 497 498 /* 499 * Function: 500 * ct_rx_tunnel_filter_set/get 501 * Purpose: 502 * Set/get the RX tunnel filter function 503 * Parameters: 504 * t_cb - The function to use. May be NULL. 505 * Returns: 506 * BCM_E_NONE 507 */ 508 509 int 510 ct_rx_tunnel_filter_set(ct_rx_tunnel_filter_f t_cb) 511 { 512 CHECK_INIT; 513 TUNNEL_LOCK; 514 ct_rx_tunnel_filter = t_cb; 515 TUNNEL_UNLOCK; 516 517 return BCM_E_NONE; 518 } 519 520 521 int 522 ct_rx_tunnel_filter_get(ct_rx_tunnel_filter_f *t_cb) 523 { 524 *t_cb = ct_rx_tunnel_filter; 525 526 return BCM_E_NONE; 527 } 528 529 /**************************************************************** 530 * 531 * Client Side RX tunnelling code. Handle a tunnel (encapsulated) 532 * packet. 533 */ 534 535 536 /* 537 * Function: 538 * ct_rx_tunnelled_pkt_handler 539 * Purpose: 540 * Handler for RX tunnelled packets, 541 * Parameters: 542 * src_key - Source of tunnelled pkt 543 * payload - Pointer to start of tunnelled encap pkt 544 * len - Total length of pkt with encap header 545 * Returns: 546 * BCM_E_XXX 547 */ 548 549 void 550 ct_rx_tunnelled_pkt_handler(cpudb_key_t src_key, uint8 *payload, int len) 551 { 552 uint8 *ap_data; 553 int ap_len; 554 bcm_pkt_t *rx_pkt; 555 int rv; 556 int bcm_unit; 557 char keybuf[CPUDB_KEY_STRING_LEN]; 558 559 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 560 (BSL_META("Tunnel handler from " CPUDB_KEY_FMT_EOLN), 561 CPUDB_KEY_DISP(src_key))); 562 563 if (payload == NULL || len < CT_TUNNEL_RX_HDR_BYTES) { 564 LOG_WARN(BSL_LS_TKS_TUNNEL, 565 (BSL_META("Tunnel RX pkt: no payload (%p, len %d)\n"), 566 payload, len - CT_TUNNEL_RX_HDR_BYTES)); 567 return; 568 } 569 570 rx_pkt = NULL; 571 rv = bcm_rx_remote_pkt_alloc(len - CT_TUNNEL_RX_HDR_BYTES, &rx_pkt); 572 if (rv != BCM_E_NONE) { 573 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 574 (BSL_META("Tunnel RX pkt: remote pkt alloc failed " 575 "for %d bytes\n"), 576 len - CT_TUNNEL_RX_HDR_BYTES)); 577 return; 578 } 579 580 rv = ct_rx_tunnel_pkt_unpack(payload, len, rx_pkt, &ap_data, &ap_len); 581 582 if (rv < 0) { 583 LOG_ERROR(BSL_LS_TKS_TUNNEL, 584 (BSL_META("Tunnel RX pkt: unpack failed\n"))); 585 bcm_rx_remote_pkt_free(rx_pkt); 586 return; 587 } 588 589 rx_pkt->flags |= BCM_RX_TUNNELLED; 590 591 /* Copy the data into the packet */ 592 sal_memcpy(rx_pkt->_pkt_data.data, ap_data, ap_len); 593 594 /* Map the cpu/unit to the BCM unit number */ 595 cpudb_key_format(src_key, keybuf, CPUDB_KEY_STRING_LEN); 596 bcm_unit = bcm_find("client", keybuf, rx_pkt->rx_unit); 597 if (bcm_unit < 0) { 598 LOG_INFO(BSL_LS_TKS_TUNNEL, 599 (BSL_META("Tunnel RX pkt: unit/cpu not found: %s.%d;" 600 CPUDB_KEY_FMT_EOLN), 601 keybuf, rx_pkt->rx_unit, 602 CPUDB_KEY_DISP(src_key))); 603 bcm_rx_remote_pkt_free(rx_pkt); 604 return; 605 } 606 /* Insert the packet into the RX queues */ 607 608 /* Overwrite unit number with locally meaningful unit number */ 609 rx_pkt->rx_unit = bcm_unit; 610 611 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 612 (BSL_META("Tunnel handler bcm_u %d. u %d p %d. sm %d " 613 "sp %d cos %d prio_int %d.\n"), 614 bcm_unit, rx_pkt->rx_unit, rx_pkt->rx_port, 615 rx_pkt->src_mod, rx_pkt->src_port, rx_pkt->cos, 616 rx_pkt->prio_int)); 617 618 rv = bcm_rx_remote_pkt_enqueue(bcm_unit, rx_pkt); 619 if (rv < 0) { 620 LOG_WARN(BSL_LS_TKS_TUNNEL, 621 (BSL_META("Tunnel RX pkt: rx enqueue failed %d: %s\n"), 622 rv, bcm_errmsg(rv))); 623 bcm_rx_remote_pkt_free(rx_pkt); 624 } 625 626 return; 627 } 628 629 630 631 632 /**************************************************************** 633 * 634 * Packet TX tunnelling code 635 * 636 * TX Tunnelling is meant to forward packets from the master to slave 637 * units only. Again, the transmit function is programmable. 638 * 639 * Reliable and best effort tunnelling are both supported. 640 * 641 * The code is divided into that which runs on the slave and that 642 * which runs on the master. 643 * 644 * BCM_CPU_TUNNEL_PACKET_RELIABLE Use reliable trx 645 * BCM_CPU_TUNNEL_PACKET_BEST_EFFORT Use best effort 646 * BCM_CPU_TUNNEL_PACKET Use best effort if present; 647 * otherwise use reliable. 648 * 649 * The current implementation does alloc/frees, so will be very 650 * slow. Packet pools may be added in the future. 651 */ 652 653 654 /**************************************************************** 655 * 656 * TUNNEL TX CODE, SOURCE (master) 657 */ 658 659 /* Function called back after TX */ 660 STATIC void 661 ct_tx_tunnel_done_cb(uint8 *pkt_data, void *cookie, int rv) 662 { 663 bcm_pkt_t *pkt = (bcm_pkt_t *)cookie; 664 665 /* allocated in ct_tx_tunnel */ 666 atp_tx_data_free(pkt_data); 667 if (pkt != NULL && pkt->call_back != NULL) { 668 pkt->call_back(pkt->unit, pkt, NULL); 669 } 670 } 671 672 /* Bytes in a packed port bitmap */ 673 #define PBMP_BYTES (4 * _SHR_PBMP_WORD_MAX) 674 675 #define TUNNEL_TX_HEADER_BYTES \ 676 (2 + (2*1) + 2 + 1 + 2 + (2*1) + 4 + 1 + 1 + 4 + \ 677 (2 * PBMP_BYTES) + 1 + 1 + 4 + 2 + (13*4) + (2*4)) 678 679 int 680 ct_tx_tunnel_setup(void) 681 { 682 int rv; 683 684 #if CT_TUNNEL_QUEUE_ENABLE 685 rv = ct_tx_tunnel_thread_init(); 686 if (rv < 0) { 687 LOG_ERROR(BSL_LS_TKS_TUNNEL, 688 (BSL_META("Could not init tunnel thread %d: %s"), 689 rv, bcm_errmsg(rv))); 690 return rv; 691 } 692 #endif 693 694 rv = atp_register( 695 SHARED_CLIENT_ID_TUNNEL_TX_PKT, 696 ATP_F_REASSEM_BUF, 697 ct_tx_tunnelled_pkt_handler, NULL, -1, -1); 698 if (rv < 0) { 699 LOG_ERROR(BSL_LS_TKS_TUNNEL, 700 (BSL_META("Tunnel: Failed to register for tx tunnel %d: %s\n"), 701 rv, bcm_errmsg(rv))); 702 return rv; 703 } 704 705 rv = atp_register( 706 SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK, 707 ATP_F_NO_ACK | ATP_F_REASSEM_BUF, 708 ct_tx_tunnelled_pkt_handler, NULL, -1, -1); 709 if (rv < 0) { 710 LOG_ERROR(BSL_LS_TKS_TUNNEL, 711 (BSL_META("Tunnel: Failed to register for tx best effort %d: %s\n"), 712 rv, bcm_errmsg(rv))); 713 return rv; 714 } 715 716 /* Install the CT TX tunnel routine to the BCM layer */ 717 rv = bcm_tx_cpu_tunnel_set(ct_tx_tunnel); 718 if (rv < 0) { 719 LOG_ERROR(BSL_LS_TKS_TUNNEL, 720 (BSL_META("Tunnel: Failed to register tunnel TX " 721 "with BCM layer %d: %s\n"), 722 rv, bcm_errmsg(rv))); 723 return rv; 724 } 725 726 return BCM_E_NONE; 727 } 728 729 int 730 ct_tx_tunnel_stop(void) 731 { 732 int rv; 733 734 /* Unregister hook */ 735 rv = bcm_tx_cpu_tunnel_set(NULL); 736 737 /* Unregister ATP */ 738 atp_unregister(SHARED_CLIENT_ID_TUNNEL_TX_PKT); 739 atp_unregister(SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK); 740 741 #if CT_TUNNEL_QUEUE_ENABLE 742 /* Stop thread */ 743 rv = ct_tx_tunnel_thread_stop(); 744 #endif 745 746 return rv; 747 } 748 749 /* Pack/unpack TX tunnelled header data; return the updated data pointer */ 750 STATIC uint8 * 751 ct_tx_tunnel_pack(uint8 *pkt_data, bcm_pkt_t *pkt, int dest_unit, 752 int remote_port, uint32 flags, int dlen) 753 { 754 uint32 word; 755 int i; 756 int remunit; 757 #if defined(BROADCOM_DEBUG) 758 uint8 *pkt_data0 = pkt_data; 759 #endif 760 761 /* Change TUNNEL_TX_HEADER_BYTES when the packing changes. */ 762 CT_INCR_PACK_U16(pkt_data, dlen); 763 CT_INCR_PACK_U8(pkt_data, pkt->cos); 764 CT_INCR_PACK_U8(pkt_data, pkt->prio_int); 765 CT_INCR_PACK_U16(pkt_data, pkt->src_port); 766 CT_INCR_PACK_U8(pkt_data, pkt->src_mod & 0xFF); 767 CT_INCR_PACK_U16(pkt_data, pkt->dest_port); 768 CT_INCR_PACK_U8(pkt_data, pkt->dest_mod & 0xFF); 769 CT_INCR_PACK_U8(pkt_data, pkt->opcode); 770 CT_INCR_PACK_U32(pkt_data, pkt->flags); 771 772 (void)bcm_unit_remote_unit_get(dest_unit, &remunit); 773 CT_INCR_PACK_U8(pkt_data, remunit); 774 CT_INCR_PACK_U8(pkt_data, remote_port); 775 CT_INCR_PACK_U32(pkt_data, flags); 776 777 if (flags & BCM_CPU_TUNNEL_F_PBMP) { 778 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 779 word = _SHR_PBMP_WORD_GET(pkt->tx_pbmp, i); 780 _SHR_PACK_LONG(pkt_data, word); 781 pkt_data += 4; 782 } 783 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 784 word = _SHR_PBMP_WORD_GET(pkt->tx_upbmp, i); 785 _SHR_PACK_LONG(pkt_data, word); 786 pkt_data += 4; 787 } 788 } 789 790 /* to maintain backwards compatibility, pack the extented src & dest mod 791 * bits at the end of the buffer 792 */ 793 CT_INCR_PACK_U8(pkt_data, (pkt->src_mod >> 8) & 0xFF); 794 CT_INCR_PACK_U8(pkt_data, (pkt->dest_mod >> 8) & 0xFF); 795 796 for (i=0; i<4; i++) { 797 CT_INCR_PACK_U8(pkt_data, pkt->_vtag[i]); 798 } 799 800 CT_INCR_PACK_U16(pkt_data, pkt->vlan); 801 CT_INCR_PACK_U32(pkt_data, pkt->color); 802 CT_INCR_PACK_U32(pkt_data, pkt->dst_gport); 803 CT_INCR_PACK_U32(pkt_data, pkt->src_gport); 804 CT_INCR_PACK_U32(pkt_data, pkt->multicast_group); 805 CT_INCR_PACK_U32(pkt_data, pkt->stk_flags); 806 CT_INCR_PACK_U32(pkt_data, pkt->stk_forward); 807 CT_INCR_PACK_U32(pkt_data, pkt->stk_classification_tag); 808 CT_INCR_PACK_U32(pkt_data, pkt->stk_pkt_prio); 809 CT_INCR_PACK_U32(pkt_data, pkt->stk_dscp); 810 CT_INCR_PACK_U32(pkt_data, pkt->stk_load_balancing_number); 811 CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp_upper); 812 CT_INCR_PACK_U32(pkt_data, pkt->timestamp_flags); 813 CT_INCR_PACK_U32(pkt_data, pkt->stk_encap_id); 814 815 CT_INCR_PACK_U32(pkt_data, pkt->flags2); 816 817 /* OAM SOMBH header fields */ 818 CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_type); 819 CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_offset); 820 CT_INCR_PACK_U16(pkt_data, pkt->oam_lm_counter_index); 821 822 #if defined(BROADCOM_DEBUG) 823 assert((pkt_data - pkt_data0) == TUNNEL_TX_HEADER_BYTES); 824 #endif 825 826 return pkt_data; 827 } 828 829 STATIC uint8 * 830 ct_tx_tunnel_unpack(uint8 *pkt_data, int len, bcm_pkt_t *pkt, int *pkt_len_p, 831 int *local_unit, int *local_port, uint32 *flags) 832 { 833 int i; 834 uint32 word; 835 uint8 tmp; 836 int pkt_len; 837 838 CT_INCR_UNPACK_U16(pkt_data, pkt_len); 839 if (len < pkt_len + TUNNEL_TX_HEADER_BYTES) { 840 return NULL; /* Not enough bytes in packet */ 841 } 842 843 *pkt_len_p = pkt_len; 844 CT_INCR_UNPACK_U8(pkt_data, pkt->cos); 845 CT_INCR_UNPACK_U8(pkt_data, pkt->prio_int); 846 CT_INCR_UNPACK_U16(pkt_data, pkt->src_port); 847 CT_INCR_UNPACK_U8(pkt_data, pkt->src_mod); 848 CT_INCR_UNPACK_U16(pkt_data, pkt->dest_port); 849 CT_INCR_UNPACK_U8(pkt_data, pkt->dest_mod); 850 CT_INCR_UNPACK_U8(pkt_data, pkt->opcode); 851 CT_INCR_UNPACK_U32(pkt_data, pkt->flags); 852 CT_INCR_UNPACK_U8(pkt_data, *local_unit); 853 CT_INCR_UNPACK_U8(pkt_data, *local_port); 854 CT_INCR_UNPACK_U32(pkt_data, *flags); 855 856 857 if (*flags & BCM_CPU_TUNNEL_F_PBMP) { 858 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 859 _SHR_UNPACK_LONG(pkt_data, word); 860 pkt_data += 4; 861 _SHR_PBMP_WORD_SET(pkt->tx_pbmp, i, word); 862 } 863 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 864 _SHR_UNPACK_LONG(pkt_data, word); 865 pkt_data += 4; 866 _SHR_PBMP_WORD_SET(pkt->tx_upbmp, i, word); 867 } 868 } 869 870 /* to maintain backwards compatibility, unpack the extented src & dest mod 871 * bits at the end of the buffer 872 */ 873 CT_INCR_UNPACK_U8(pkt_data, tmp); 874 pkt->src_mod |= tmp << 8; 875 876 CT_INCR_UNPACK_U8(pkt_data, tmp); 877 pkt->dest_mod |= tmp << 8; 878 879 for (i=0; i<4; i++) { 880 CT_INCR_UNPACK_U8(pkt_data, pkt->_vtag[i]); 881 } 882 883 CT_INCR_UNPACK_U16(pkt_data, pkt->vlan); 884 CT_INCR_UNPACK_U32(pkt_data, pkt->color); 885 CT_INCR_UNPACK_U32(pkt_data, pkt->dst_gport); 886 CT_INCR_UNPACK_U32(pkt_data, pkt->src_gport); 887 CT_INCR_UNPACK_U32(pkt_data, pkt->multicast_group); 888 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_flags); 889 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_forward); 890 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_classification_tag); 891 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_pkt_prio); 892 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_dscp); 893 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_load_balancing_number); 894 CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp_upper); 895 CT_INCR_UNPACK_U32(pkt_data, pkt->timestamp_flags); 896 CT_INCR_UNPACK_U32(pkt_data, pkt->stk_encap_id); 897 898 CT_INCR_UNPACK_U32(pkt_data, pkt->flags2); 899 900 /* OAM SOMBH header fields */ 901 CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_type); 902 CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_offset); 903 CT_INCR_UNPACK_U16(pkt_data, pkt->oam_lm_counter_index); 904 905 return pkt_data; 906 } 907 908 /* 909 * Function: 910 * ct_tx_tunnel 911 * Purpose: 912 * Tunnel a packet out a single port via a remote CPU 913 * Parameters: 914 * pkt - The packet data and meta-data to tunnel 915 * dest_unit - The BCM unit to tunnel to 916 * remote_port - The port on dest_unit on which packet should egress 917 * flags - Indicates untagged settings 918 * mode - Reliable/best effort tunnelling 919 * Returns: 920 * BCM_E_XXX 921 * Notes: 922 * Always sends async, but data is copied from parameter; 923 * If a callback is indicated in the packet, that will be made after 924 * local transmit 925 * 926 * If flags & BCM_CPU_TUNNEL_F_PBMP is set, then remote_port is ignored 927 * and the port bitmaps are taken from the packet directly. 928 */ 929 930 #define KEY_BUF_LEN 8 931 int 932 ct_tx_tunnel(bcm_pkt_t *pkt, 933 int dest_unit, 934 int remote_port, 935 uint32 flags, 936 bcm_cpu_tunnel_mode_t mode) 937 { 938 uint8 *pkt_data, *alloc_ptr; 939 int len, dlen; 940 int i; 941 int rv; 942 int client_id; 943 uint32 ct_flags = 0; 944 cpudb_key_t dest_key; 945 char dest_key_str[CPUDB_KEY_STRING_LEN]; 946 947 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 948 (BSL_META("CT Tunnel pkt out to (%d, %d), flags 0x%x, mode %d\n"), 949 dest_unit, remote_port, flags, mode)); 950 951 if (!bcm_unit_valid(dest_unit)) { 952 return BCM_E_PARAM; 953 } 954 955 if (bcm_unit_local(dest_unit)) { 956 return BCM_E_PARAM; 957 } 958 959 dlen = 0; 960 for (i = 0; i < pkt->blk_count; i++) { 961 dlen += pkt->pkt_data[i].len; 962 } 963 964 len = dlen + TUNNEL_TX_HEADER_BYTES; 965 /* Freed either in this function (on error) or in ct_tx_tunnel_done_cb */ 966 pkt_data = alloc_ptr = atp_tx_data_alloc(len); 967 if (alloc_ptr == NULL) { 968 return BCM_E_MEMORY; 969 } 970 971 /* Pack up the metadata for the packet */ 972 pkt_data = ct_tx_tunnel_pack(pkt_data, pkt, dest_unit, remote_port, 973 flags, dlen); 974 975 /* Copy the packet data to send out */ 976 for (i = 0; i < pkt->blk_count; i++) { 977 sal_memcpy(pkt_data, pkt->pkt_data[i].data, pkt->pkt_data[i].len); 978 pkt_data += pkt->pkt_data[i].len; 979 } 980 981 if (mode == BCM_CPU_TUNNEL_PACKET_RELIABLE) { 982 client_id = SHARED_CLIENT_ID_TUNNEL_TX_PKT; 983 } else { 984 client_id = SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK; 985 } 986 987 CPUTRANS_COS_SET(ct_flags, pkt->cos); 988 if (pkt->flags & BCM_TX_PRIO_INT) { 989 CPUTRANS_INT_PRIO_SET(ct_flags, pkt->prio_int); 990 } 991 992 /* Only pass the packet as a cookie if the callback is != NULL; 993 * Otherwise app may free pkt before it's examined by callback. 994 */ 995 996 rv = bcm_unit_subtype_get(dest_unit, dest_key_str, 997 sizeof(dest_key_str)); 998 if (rv < 0) { 999 LOG_WARN(BSL_LS_TKS_TUNNEL, 1000 (BSL_META("Tunnel TX: Could not get dest key string, %d: %s\n"), 1001 rv, bcm_errmsg(rv))); 1002 atp_tx_data_free(alloc_ptr); 1003 return rv; 1004 } 1005 1006 1007 rv = cpudb_key_parse(dest_key_str, &dest_key); 1008 if (rv < 0) { 1009 LOG_WARN(BSL_LS_TKS_TUNNEL, 1010 (BSL_META("Tunnel TX: Could not parse dest key string, %d: %s\n"), 1011 rv, bcm_errmsg(rv))); 1012 atp_tx_data_free(alloc_ptr); 1013 return rv; 1014 } 1015 1016 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 1017 (BSL_META("CT Tunnel dest key %x %x %x %x %x %x\n"), 1018 dest_key.key[0], 1019 dest_key.key[1], 1020 dest_key.key[2], 1021 dest_key.key[3], 1022 dest_key.key[4], 1023 dest_key.key[5])); 1024 rv = atp_tx(dest_key, 1025 client_id, 1026 alloc_ptr, 1027 len, 1028 ct_flags, 1029 ct_tx_tunnel_done_cb, 1030 (void *)(pkt->call_back != NULL ? pkt : NULL)); 1031 1032 if (rv < 0) { 1033 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 1034 (BSL_META("Tunnel TX: Error sending %d: %s\n"), 1035 rv, bcm_errmsg(rv))); 1036 atp_tx_data_free(alloc_ptr); 1037 } 1038 1039 return rv; 1040 } 1041 1042 /**************************************************************** 1043 * 1044 * TUNNEL TX CODE, FORWARDER (slave) 1045 * 1046 * This is the code that accepts a tunnelled packet and 1047 * forwards it out the indicated local port. 1048 */ 1049 1050 #if CT_TUNNEL_QUEUE_ENABLE 1051 1052 STATIC int 1053 ct_tx_tunnel_enqueue(void *pkt, bcm_rx_t *handled, uint8 *pkt_data, int len) 1054 { 1055 int head, new_head, rv; 1056 1057 TUNNEL_Q_LOCK; 1058 head = new_head = _tunnel_q_head; 1059 rv = BCM_E_NONE; 1060 1061 /* Incr new_head, handle wraparound */ 1062 if (++new_head >= CT_TUNNEL_QUEUE_SIZE) { 1063 new_head = 0; 1064 } 1065 1066 /* Check for queue full */ 1067 if (new_head != _tunnel_q_tail) { 1068 _tunnel_q_head = new_head; 1069 _tunnel_q[head].data = pkt_data; 1070 _tunnel_q[head].len = len; 1071 _tunnel_q[head].pkt = pkt; 1072 } else { 1073 rv = BCM_E_RESOURCE; 1074 _tunnel_q_top_full++; 1075 } 1076 1077 TUNNEL_Q_UNLOCK; 1078 1079 if (BCM_SUCCESS(rv)) { 1080 TUNNEL_Q_WAKE; 1081 *handled = BCM_RX_HANDLED_OWNED; 1082 } else { 1083 *handled = BCM_RX_HANDLED; 1084 } 1085 1086 return rv; 1087 } 1088 1089 STATIC ct_tunnel_q_element * 1090 ct_tx_tunnel_dequeue(void) 1091 { 1092 ct_tunnel_q_element *element = NULL; 1093 1094 TUNNEL_Q_LOCK; 1095 if (_tunnel_q_head != _tunnel_q_tail) { 1096 element = _tunnel_q + _tunnel_q_tail; 1097 /* Incr tail, handle wraparound */ 1098 if (++_tunnel_q_tail >= CT_TUNNEL_QUEUE_SIZE) { 1099 _tunnel_q_tail = 0; 1100 } 1101 } 1102 TUNNEL_Q_UNLOCK; 1103 1104 return element; 1105 } 1106 1107 STATIC void 1108 ct_tx_tunnel_thread(void *cookie) 1109 { 1110 ct_tunnel_q_element *element = NULL; 1111 int rv; 1112 1113 COMPILER_REFERENCE(cookie); 1114 _tunnel_q_thread_exit = 0; 1115 for (;;) { 1116 1117 TUNNEL_Q_SLEEP; 1118 1119 while ((element = ct_tx_tunnel_dequeue()) != NULL) { 1120 rv = ct_tx_tunnel_forward(element->data, element->len); 1121 atp_rx_free(element->data, element->pkt); 1122 if (rv < 0) { 1123 _tunnel_q_error++; 1124 } 1125 } 1126 1127 if (_tunnel_q_thread_exit) { 1128 _tunnel_q_thread = SAL_THREAD_ERROR; 1129 sal_thread_exit(0); 1130 return; 1131 } 1132 } 1133 } 1134 1135 STATIC int 1136 ct_tx_tunnel_thread_init(void) 1137 { 1138 if (_tunnel_q_thread != SAL_THREAD_ERROR) { 1139 return BCM_E_BUSY; 1140 } 1141 1142 /* Reset variables */ 1143 _tunnel_q_top_full = 0; 1144 _tunnel_q_error = 0; 1145 _tunnel_q_head = _tunnel_q_tail = 0; 1146 1147 _tunnel_q_lock = sal_mutex_create("bcm_tunnel_q"); 1148 _tunnel_q_sem = sal_sem_create("bcm_tunnel_q", sal_sem_BINARY, 0); 1149 _tunnel_q_thread = sal_thread_create("bcmTUNQ", 1150 TUNNEL_Q_THREAD_STACK, 1151 TUNNEL_Q_THREAD_PRIO, 1152 ct_tx_tunnel_thread, 1153 NULL); 1154 if (_tunnel_q_thread == SAL_THREAD_ERROR) { 1155 sal_sem_destroy(_tunnel_q_sem); 1156 sal_mutex_destroy(_tunnel_q_lock); 1157 _tunnel_q_lock = NULL; 1158 return BCM_E_RESOURCE; 1159 } 1160 1161 return BCM_E_NONE; 1162 1163 } 1164 1165 /* 1166 * Stop the tunnel queue thread 1167 */ 1168 STATIC int 1169 ct_tx_tunnel_thread_stop(void) 1170 { 1171 if (_tunnel_q_thread == SAL_THREAD_ERROR) { 1172 return BCM_E_NONE; 1173 } 1174 _tunnel_q_thread_exit = 1; 1175 TUNNEL_Q_WAKE; 1176 sal_thread_yield(); 1177 while (_tunnel_q_thread != SAL_THREAD_ERROR) { 1178 TUNNEL_Q_WAKE; 1179 sal_usleep(10000); 1180 } 1181 sal_sem_destroy(_tunnel_q_sem); 1182 sal_mutex_destroy(_tunnel_q_lock); 1183 _tunnel_q_lock = NULL; 1184 return BCM_E_NONE; 1185 } 1186 1187 #define ct_tx_tunnel_forward_function ct_tx_tunnel_enqueue 1188 1189 #else 1190 1191 #define ct_tx_tunnel_forward_function ct_tx_tunnel_forward_sync 1192 1193 STATIC int 1194 ct_tx_tunnel_forward_sync(void *pkt, bcm_rx_t *handled, 1195 uint8 *pkt_data, int len) 1196 { 1197 COMPILER_REFERENCE(pkt); 1198 *handled = BCM_RX_HANDLED; 1199 return ct_tx_tunnel_forward(pkt_data, len); 1200 } 1201 1202 #endif /* CT_TUNNEL_QUEUE_ENABLE */ 1203 1204 /* ATP handler for TX tunnelled packet */ 1205 STATIC bcm_rx_t 1206 ct_tx_tunnelled_pkt_handler(cpudb_key_t src_key, 1207 int client_id, 1208 bcm_pkt_t *pkt, 1209 uint8 *payload, 1210 int payload_len, 1211 void *cookie) 1212 { 1213 int rv; 1214 bcm_rx_t handled; 1215 1216 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 1217 (BSL_META("CT Tunnel pkt in from " CPUDB_KEY_FMT " cli %d, len %d\n"), 1218 CPUDB_KEY_DISP(src_key), client_id, payload_len)); 1219 1220 if (payload == NULL) { 1221 /* Unsupported forwarding mode */ 1222 LOG_WARN(BSL_LS_TKS_TUNNEL, 1223 (BSL_META("Tunnel TX: Received segmented packet to " 1224 "forward. Unsupported\n"))); 1225 return BCM_RX_HANDLED; 1226 } 1227 1228 rv = ct_tx_tunnel_forward_function(pkt, &handled, 1229 payload, payload_len); 1230 1231 if (rv < 0) { 1232 LOG_VERBOSE(BSL_LS_TKS_TUNNEL, 1233 (BSL_META("Tunnel TX: Error forwarding %d: %s\n"), 1234 rv, bcm_errmsg(rv))); 1235 } 1236 1237 return handled; 1238 } 1239 1240 /* 1241 * Function: 1242 * ct_tx_tunnel_forward 1243 * Purpose: 1244 * Forward a packet received for tunnelling 1245 * Parameters: 1246 * pkt_data - The start of the encapsulated packet 1247 * len - Length of encapsulated packet 1248 * Returns: 1249 * BCM_E_XXX 1250 * Notes: 1251 * Sends sync only. 1252 * Assumes data in pkt_data is DMA'able 1253 */ 1254 1255 int 1256 ct_tx_tunnel_forward(uint8 *pkt_data, int len) 1257 { 1258 int pkt_len; 1259 int local_unit; 1260 int local_port; /* Not used if PBMP flag is set */ 1261 bcm_pkt_t pkt; 1262 uint32 flags; 1263 int rv; 1264 1265 if (len <= TUNNEL_TX_HEADER_BYTES) { 1266 return BCM_E_PARAM; 1267 } 1268 sal_memset(&pkt, 0, sizeof(pkt)); 1269 1270 /* Unpack the metadata */ 1271 pkt_data = 1272 ct_tx_tunnel_unpack(pkt_data, len, &pkt, &pkt_len, 1273 &local_unit, &local_port, &flags); 1274 if (pkt_data == NULL) { 1275 return BCM_E_RESOURCE; /* Not enough bytes in packet */ 1276 } 1277 /* pkt_data now points to start of payload to send out */ 1278 1279 if (!(flags & BCM_CPU_TUNNEL_F_PBMP)) { 1280 /* Generate bitmap from single local port */ 1281 BCM_PBMP_PORT_SET(pkt.tx_pbmp, local_port); 1282 if (flags & BCM_CPU_TUNNEL_F_UNTAGGED) { 1283 BCM_PBMP_PORT_SET(pkt.tx_upbmp, local_port); 1284 } 1285 } 1286 1287 BCM_PKT_ONE_BUF_SETUP(&pkt, pkt_data, pkt_len); 1288 1289 /* Send synchronosly using packet data passed to us. */ 1290 rv = bcm_tx(local_unit, &pkt, NULL); 1291 1292 1293 return rv; 1294 } 1295 1296 #endif /* BCM_RPC_SUPPORT */