| /****************************************************************************** |
| * |
| * <:copyright-BRCM:2016:DUAL/GPL:standard |
| * |
| * Copyright (c) 2016 Broadcom |
| * All Rights Reserved |
| * |
| * Unless you and Broadcom execute a separate written software license |
| * agreement governing use of this software, this software is licensed |
| * to you under the terms of the GNU General Public License version 2 |
| * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| * with the following added to such license: |
| * |
| * As a special exception, the copyright holders of this software give |
| * you permission to link this software with independent modules, and |
| * to copy and distribute the resulting executable under terms of your |
| * choice, provided that you also meet, for each linked independent |
| * module, the terms and conditions of the license of that module. |
| * An independent module is a module which is not derived from this |
| * software. The special exception does not apply to any modifications |
| * of the software. |
| * |
| * Not withstanding the above, under no circumstances may you combine |
| * this software in any way with any other Broadcom software provided |
| * under a license other than the GPL, without Broadcom's express prior |
| * written consent. |
| * |
| * :> |
| * |
| *****************************************************************************/ |
| |
| #include <bal_common.h> |
| #include <bcm_dev_log.h> |
| #include <bal_msg.h> |
| #include "bal_switch_util.h" |
| #include "bal_switch_acc_term.h" |
| #include "bal_switch_flow.h" |
| #include <bal_worker.h> |
| /* declare ENV so that the bcm/rx.h in the bal_dpp_acc_term.h can create the correct bcm_pkt_t structure */ |
| #ifdef ESW_SWITCH |
| #define BCM_ESW_SUPPORT 1 |
| #else |
| #define BCM_DNX_SUPPORT 1 |
| #endif |
| #include "esw/bal_esw_acc_term.h" |
| #include "dpp/bal_dpp_acc_term.h" |
| /* Below local functions are used for real logic only */ |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| #include <arpa/inet.h> |
| #include <bcm/init.h> |
| #include <bcm/types.h> |
| #include <bcm/port.h> |
| #include <appl/diag/shell.h> /* for .soc loading */ |
| |
| extern int socdiag_main(int argc, char *argv[]); |
| |
| /** |
| * @file bal_switch_acc_term.c |
| * @brief BAL Switch util functions that handle access terminal requests |
| * @addtogroup sw_util |
| * |
| */ |
| |
| /*@{*/ |
| /* forward declaration */ |
| static void sw_util_bcm_rx_cb (int unit, int port, int reason, unsigned char *p_payload, int payload_len); |
| |
| /* define a customized dpp packetIn receive registration function. |
| * This function will be called when the HW trap a CPU bound packet |
| */ |
| static bcm_rx_t dpp_rx_cb_register(int unit, bcm_pkt_t *pkt, void *cookie) |
| { |
| int src_port, reason_code, payload_len; |
| unsigned char *p_payload; |
| |
| /* extract trap code, ingress port and payload info */ |
| src_port = pkt->src_port & 0xff; |
| reason_code = pkt->rx_trap_data; |
| p_payload = pkt->_pkt_data.data + (pkt->tot_len - pkt->pkt_len); |
| payload_len = pkt->pkt_len; |
| |
| /* call sw_util_bcm_rx_cb to send packet to the BAL client */ |
| sw_util_bcm_rx_cb(unit, src_port, reason_code, p_payload, payload_len); |
| return BCM_RX_HANDLED; |
| } |
| |
| /* The default switch device the switch app is managed */ |
| #ifdef CONFIG_SWITCH_RPC |
| static uint32_t g_dft_dev_id = 2; |
| #else |
| static uint32_t g_dft_dev_id = 0; |
| #endif |
| static uint32_t g_iwf_mode = 0; |
| static uint32_t g_l2_age_time = 300; |
| |
| /* flag to determine if we need RPC for switch communication */ |
| #ifdef CONFIG_SWITCH_RPC |
| static uint32_t g_use_rpc = 1; |
| #else |
| static uint32_t g_use_rpc = 0; |
| #endif |
| |
| /* Socket to be connected to the switch driver msg receiving UDP port */ |
| bcmos_bool g_pkt_send_is_initialized = BCMOS_FALSE; |
| |
| static trap_target s_target_device; |
| |
| /* Index to determine which interface mapping table should be used. |
| * The mapping table is HW specific and depend on how physical wires are lay out |
| * Any customized board may need a different table entry to reflect the connections |
| */ |
| static bal_swapp_port_map_indx g_intf_maptable = BAL_SWAPP_PORT_MAP_GPON; |
| |
| /* the logical interface to KT2 port mapping table |
| the tables is index by technology then logical interface number that used in the BAL CLI |
| the data is the switch port-bit-map number and device number |
| */ |
| |
| /* table with gpon technology |
| based on KT2 port config option 4 - see page 22 on KT2 data sheet */ |
| /* gpon network interface mapping - |
| * KT2 is for Broadcom experiment purpose - not all function will work */ |
| bal_swapp_port net_inf_map_gpon[] = { |
| { 27, /* xe0 */ 0}, |
| { 28, /* xe1 */ 0}, |
| { 30, /* xe2 */ 0}, |
| { 33, /* xe3 */ 0}, |
| { 40, /* ge24 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| /* ARAD temp mapping xe128 - xe131 as nni ports */ |
| /* ARAD is for Broadcom experiment purpose - not all function will work */ |
| bal_swapp_port net_inf_map_exp[] = { |
| { 128, /* xe128 */ 0}, |
| { 129, /* xe129 */ 0}, |
| { 130, /* xe130 */ 0}, |
| { 131, /* xe131 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| /* QAX temp mapping xe128-132 as nni ports 0-4 */ |
| bal_swapp_port net_inf_map_exp2[] = { |
| { 128, /* xe128 */ 0}, |
| { 129, /* xe129 */ 0}, |
| { 130, /* xe130 */ 0}, |
| { 131, /* xe131 */ 0}, |
| { 132, /* xe132 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* svk4 mapping xe128-133 as nni ports 0-5 */ |
| bal_swapp_port net_inf_map_svk4[] = { |
| { 128, /* xe128 */ 0}, |
| { 129, /* xe129 */ 0}, |
| { 130, /* xe130 */ 0}, |
| { 131, /* xe131 */ 0}, |
| { 132, /* xe132 */ 0}, |
| { 133, /* xe133 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* epon 10g-capable mapping xe128-135 as nni ports 0-7 (best guess - needs to be tested) */ |
| bal_swapp_port net_inf_map_epon_tdma_10g[] = { |
| { 128, /* xe128 */ 0}, |
| { 129, /* xe129 */ 0}, |
| { 130, /* xe130 */ 0}, |
| { 131, /* xe131 */ 0}, |
| { 132, /* xe132 */ 0}, |
| { 133, /* xe133 */ 0}, |
| { 134, /* xe134 */ 0}, |
| { 135, /* xe135 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* epon 1g only mapping - copied from gpon KT2 example above (best guess - needs to be tested) */ |
| bal_swapp_port net_inf_map_epon_1g[] = { |
| { 27, /* xe0 */ 0}, |
| { 28, /* xe1 */ 0}, |
| { 30, /* xe2 */ 0}, |
| { 33, /* xe3 */ 0}, |
| { 40, /* ge24 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* gpon pon interface mapping */ |
| bal_swapp_port pon_inf_map_gpon[] = { |
| { 5, /* ge4 */ 0}, |
| { 6, /* ge5 */ 0}, |
| { 2, /* ge1 */ 0}, |
| { 1, /* ge0 */ 0}, |
| { 8, /* ge7 */ 0}, |
| { 7, /* ge6 */ 0}, |
| { 4, /* ge3 */ 0}, |
| { 3, /* ge2 */ 0}, |
| { 12, /* ge11 */ 0}, |
| { 19, /* ge18 */ 0}, |
| { 10, /* ge9 */ 0}, |
| { 15, /* ge14 */ 0}, |
| { 11, /* ge10 */ 0}, |
| { 17, /* ge16 */ 0}, |
| { 9, /* ge8 */ 0}, |
| { 13, /* ge12 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| bal_swapp_port pon_inf_map_gpon_v3[] = { |
| { 8, /* ge7 */ 0}, |
| { 7, /* ge6 */ 0}, |
| { 4, /* ge3 */ 0}, |
| { 3, /* ge2 */ 0}, |
| { 6, /* ge5 */ 0}, |
| { 5, /* ge4 */ 0}, |
| { 2, /* ge1 */ 0}, |
| { 1, /* ge0 */ 0}, |
| { 15, /* ge14 */ 0}, |
| { 16, /* ge15 */ 0}, |
| { 11, /* ge10 */ 0}, |
| { 12, /* ge11 */ 0}, |
| { 13, /* ge12 */ 0}, |
| { 14, /* ge13 */ 0}, |
| { 9, /* ge8 */ 0}, |
| { 10, /* ge9 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| /* ARAD temp mapping xe0 - xe3 as PON ports */ |
| bal_swapp_port pon_inf_map_exp[] = { |
| { 0, /* xe0 */ 0}, |
| { 1, /* xe1 */ 0}, |
| { 2, /* xe2 */ 0}, |
| { 3, /* xe3 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| /* QAX temp mapping xe1-6, as PON ports 0-5 */ |
| bal_swapp_port pon_inf_map_exp2[] = { |
| { 1, /* xe1 */ 0}, |
| { 2, /* xe2 */ 0}, |
| { 3, /* xe3 */ 0}, |
| { 4, /* xe4 */ 0}, |
| { 5, /* xe5 */ 0}, |
| { 6, /* xe6 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* svk4 mapping xe1-4, as PON ports 0-3 */ |
| bal_swapp_port pon_inf_map_svk4[] = { |
| { 1, /* xe1 */ 0}, |
| { 2, /* xe2 */ 0}, |
| { 3, /* xe3 */ 0}, |
| { 4, /* xe4 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* epon 10g-capable mapping xe1-8, as PON ports 0-7 (best guess - untested) */ |
| bal_swapp_port pon_inf_map_epon_tdma_10g[] = { |
| { 1, /* xe1 */ 0}, |
| { 2, /* xe2 */ 0}, |
| { 3, /* xe3 */ 0}, |
| { 4, /* xe4 */ 0}, |
| { 5, /* xe5 */ 0}, |
| { 6, /* xe6 */ 0}, |
| { 7, /* xe7 */ 0}, |
| { 8, /* xe8 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* epon 1g mapping xe1-16, as PON ports 0-15 (best guess - untested) */ |
| bal_swapp_port pon_inf_map_epon_1g[] = { |
| { 1, /* xe1 */ 0}, |
| { 2, /* xe2 */ 0}, |
| { 3, /* xe3 */ 0}, |
| { 4, /* xe4 */ 0}, |
| { 5, /* xe5 */ 0}, |
| { 6, /* xe6 */ 0}, |
| { 7, /* xe7 */ 0}, |
| { 8, /* xe8 */ 0}, |
| { 9, /* xe9 */ 0}, |
| { 10, /* xe10 */ 0}, |
| { 11, /* xe11 */ 0}, |
| { 12, /* xe12 */ 0}, |
| { 13, /* xe13 */ 0}, |
| { 14, /* xe14 */ 0}, |
| { 15, /* xe15 */ 0}, |
| { 16, /* xe16 */ 0}, |
| { -1, /* end */ 0} |
| }; |
| |
| /* network interface mapping table */ |
| bal_swapp_port *g_net_inf_map_table[BAL_SWAPP_PORT_MAP__NUM_OF] = { |
| net_inf_map_gpon, /* BAL_SWAPP_PORT_MAP_GPON */ |
| net_inf_map_gpon, /* BAL_SWAPP_PORT_MAP_GPON_V3 */ |
| net_inf_map_exp, /* BAL_SWAPP_PORT_MAP_EXP */ |
| net_inf_map_exp2, /* BAL_SWAPP_PORT_MAP_EXP2 */ |
| net_inf_map_svk4, /* BAL_SWAPP_PORT_MAP_SVK4 */ |
| net_inf_map_epon_tdma_10g, /* BAL_SWAPP_PORT_MAP_EPON_TDMA */ |
| net_inf_map_epon_1g, /* BAL_SWAPP_PORT_MAP_EPON_1G */ |
| net_inf_map_epon_tdma_10g, /* BAL_SWAPP_PORT_MAP_EPON_10G */ |
| }; |
| /* pon interface mapping table */ |
| bal_swapp_port *g_pon_inf_map_table[BAL_SWAPP_PORT_MAP__NUM_OF] = { |
| pon_inf_map_gpon, /* BAL_SWAPP_PORT_MAP_GPON */ |
| pon_inf_map_gpon_v3, /* BAL_SWAPP_PORT_MAP_GPON_V3 */ |
| pon_inf_map_exp, /* BAL_SWAPP_PORT_MAP_EXP */ |
| pon_inf_map_exp2, /* BAL_SWAPP_PORT_MAP_EXP2 */ |
| pon_inf_map_svk4, /* BAL_SWAPP_PORT_MAP_SVK4 */ |
| pon_inf_map_epon_tdma_10g, /* BAL_SWAPP_PORT_MAP_EPON_TDMA */ |
| pon_inf_map_epon_1g, /* BAL_SWAPP_PORT_MAP_EPON_1G */ |
| pon_inf_map_epon_tdma_10g, /* BAL_SWAPP_PORT_MAP_EPON_10G */ |
| }; |
| |
| /* network interface mapping table size */ |
| int g_net_inf_map_table_size[BAL_SWAPP_PORT_MAP__NUM_OF] = { |
| sizeof(net_inf_map_gpon)/sizeof(net_inf_map_gpon[0]), /* BAL_SWAPP_PORT_MAP_GPON */ |
| sizeof(net_inf_map_gpon)/sizeof(net_inf_map_gpon[0]), /* BAL_SWAPP_PORT_MAP_GPON_V3 */ |
| sizeof(net_inf_map_exp)/sizeof(net_inf_map_exp[0]), /* BAL_SWAPP_PORT_MAP_EXP */ |
| sizeof(net_inf_map_exp2)/sizeof(net_inf_map_exp2[0]), /* BAL_SWAPP_PORT_MAP_EXP2 */ |
| sizeof(net_inf_map_svk4)/sizeof(net_inf_map_svk4[0]), /* BAL_SWAPP_PORT_MAP_SVK4 */ |
| sizeof(net_inf_map_epon_tdma_10g)/sizeof(net_inf_map_epon_tdma_10g[0]), /* BAL_SWAPP_PORT_MAP_EPON_TDMA */ |
| sizeof(net_inf_map_epon_1g)/sizeof(net_inf_map_epon_1g[0]), /* BAL_SWAPP_PORT_MAP_EPON_1G */ |
| sizeof(net_inf_map_epon_tdma_10g)/sizeof(net_inf_map_epon_tdma_10g[0]), /* BAL_SWAPP_PORT_MAP_EPON_10G */ |
| }; |
| /* pon interface mapping table size */ |
| int g_pon_inf_map_table_size[BAL_SWAPP_PORT_MAP__NUM_OF] = { |
| sizeof(pon_inf_map_gpon)/sizeof(pon_inf_map_gpon[0]), /* BAL_SWAPP_PORT_MAP_GPON */ |
| sizeof(pon_inf_map_gpon_v3)/sizeof(pon_inf_map_gpon_v3[0]), /* BAL_SWAPP_PORT_MAP_GPON_V3 */ |
| sizeof(pon_inf_map_exp)/sizeof(pon_inf_map_exp[0]), /* BAL_SWAPP_PORT_MAP_EXP */ |
| sizeof(pon_inf_map_exp2)/sizeof(pon_inf_map_exp2[0]), /* BAL_SWAPP_PORT_MAP_EXP2 */ |
| sizeof(pon_inf_map_svk4)/sizeof(pon_inf_map_svk4[0]), /* BAL_SWAPP_PORT_MAP_SVK4 */ |
| sizeof(pon_inf_map_epon_tdma_10g)/sizeof(pon_inf_map_epon_tdma_10g[0]), /* BAL_SWAPP_PORT_MAP_EPON_TDMA */ |
| sizeof(pon_inf_map_epon_1g)/sizeof(pon_inf_map_epon_1g[0]), /* BAL_SWAPP_PORT_MAP_EPON_1G */ |
| sizeof(pon_inf_map_epon_tdma_10g)/sizeof(pon_inf_map_epon_tdma_10g[0]), /* BAL_SWAPP_PORT_MAP_EPON_10G */ |
| }; |
| |
| /** |
| * @brief get the number of valid network interface |
| * @return num_nni number of nni interfaces |
| */ |
| int bal_bcm_net_inf_map_size_get() |
| { |
| return g_net_inf_map_table_size[g_intf_maptable]; |
| }; |
| |
| /** |
| * @brief get the number of valid pon interface |
| * @return num_nni number of pon interfaces |
| */ |
| int bal_bcm_pon_inf_map_size_get() |
| { |
| return g_pon_inf_map_table_size[g_intf_maptable]; |
| }; |
| |
| /** |
| * @brief get KT2 PBM of a network interface from current mapping table |
| * |
| * @param net_inf_id logical nni interface number from CLI |
| * |
| * @return pbm PortBitMap that will be used in bcm api calls |
| */ |
| uint32_t bal_bcm_net_inf_pbm_get(uint32_t net_inf_id) |
| { |
| bal_swapp_port *port = (g_net_inf_map_table[g_intf_maptable] + net_inf_id); |
| return port->pbm_id; |
| }; |
| |
| /** |
| * @brief get bal nni port number (index of the mapping table) of a physical nni interface |
| * |
| * @param nni_id physical nni interface in the switch |
| * |
| * @return index index to PortBitMap that contains the physical interface number |
| */ |
| int bal_bcm_net_inf_idx_get(uint32_t nni_id) |
| { |
| int indx; |
| bal_swapp_port *port = g_net_inf_map_table[g_intf_maptable]; |
| for( indx = 0; port->pbm_id != -1; indx++) |
| { |
| if (port->pbm_id == nni_id) |
| { |
| break; |
| } |
| port++; |
| } |
| if (port->pbm_id == -1) |
| { |
| return -1; |
| } |
| else |
| { |
| return indx; |
| } |
| } |
| |
| /** |
| * @brief get KT2 device id of a network interface from current mapping table |
| * |
| * @param net_inf_id logical nni interface number from CLI |
| * |
| * @return pbm device number that will be used in bcm api calls |
| */ |
| int bal_bcm_net_inf_dev_get(uint32_t net_inf_id) |
| { |
| if(net_inf_id > sizeof(g_net_inf_map_table)) |
| { |
| return bal_bcm_dft_dev_get(); |
| } |
| else |
| { |
| bal_swapp_port *port = (g_net_inf_map_table[g_intf_maptable] + net_inf_id); |
| return port->device_id; |
| } |
| }; |
| |
| /** |
| * @brief get KT2 PBM of a pon interface from current mapping table |
| * |
| * @param pon_inf_id logical pon interface number from CLI |
| * |
| * @return pbm PortBitMap that will be used in bcm api calls |
| */ |
| uint32_t bal_bcm_pon_inf_pbm_get(uint32_t pon_inf_id) |
| { |
| bal_swapp_port *port = (g_pon_inf_map_table[g_intf_maptable] + pon_inf_id); |
| return port->pbm_id; |
| }; |
| |
| /** |
| * @brief get bal pon port number (index of the mapping table) of a physical pon interface |
| * |
| * @param pon_id physical pon interface in the switch |
| * |
| * @return index index to PortBitMap that contains the physical interface number |
| */ |
| int bal_bcm_pon_inf_idx_get(uint32_t pon_id) |
| { |
| int indx; |
| bal_swapp_port *port = g_pon_inf_map_table[g_intf_maptable]; |
| for( indx = 0; port->pbm_id != -1; indx++) |
| { |
| if (port->pbm_id == pon_id) |
| { |
| break; |
| } |
| port++; |
| } |
| if (port->pbm_id == -1) |
| { |
| return -1; |
| } |
| else |
| { |
| return indx; |
| } |
| } |
| |
| /** |
| * @brief get KT2 device number of a pon interface from current mapping table |
| * |
| * @param pon_inf_id logical pon interface number from CLI |
| * |
| * @return pbm device number that will be used in bcm api calls |
| */ |
| int bal_bcm_pon_inf_dev_get(uint32_t pon_inf_id) |
| { |
| if(pon_inf_id > sizeof(g_pon_inf_map_table)) |
| { |
| return bal_bcm_dft_dev_get(); |
| } |
| else |
| { |
| bal_swapp_port *port = (g_pon_inf_map_table[g_intf_maptable] + pon_inf_id); |
| return port->device_id; |
| } |
| }; |
| |
| /** |
| * @brief setting the local default device id |
| */ |
| void bal_bcm_dft_dev_set(uint32_t id) |
| { |
| g_dft_dev_id = (int)id; |
| } |
| |
| /** |
| * @brief getting the local default device id |
| */ |
| uint32_t bal_bcm_dft_dev_get() |
| { |
| return g_dft_dev_id; |
| } |
| |
| /** |
| * @brief setting the L2 table aging time (seconds) |
| */ |
| void bal_bcm_l2_age_time_set(uint32_t age_time) |
| { |
| g_l2_age_time = age_time; |
| } |
| |
| /** |
| * @brief getting current L2 table aging time value |
| */ |
| uint32_t bal_bcm_l2_age_time_get() |
| { |
| return g_l2_age_time; |
| } |
| |
| /** |
| * @brief getting the device type |
| */ |
| uint32_t bal_bcm_dev_type_get(uint32_t id) |
| { |
| int rc; |
| bcm_info_t dev_info; |
| |
| rc = bcm_info_get(id, &dev_info); |
| if (rc) |
| { |
| return 0; |
| } |
| |
| return dev_info.device; |
| } |
| |
| /** |
| * @brief getting the iwf mode of an access terminal |
| */ |
| uint32_t bal_bcm_iwf_mode_get() |
| { |
| /* currently only support one access terminal */ |
| BCM_LOG(DEBUG, log_id_sw_util, " Get iwf mode for acc_term\n"); |
| return g_iwf_mode; |
| } |
| |
| /** |
| * @brief setting the use of RPC (remote) or not (local) |
| */ |
| void bal_bcm_use_rpc_set(uint32_t use_rpc) |
| { |
| g_use_rpc = (int)use_rpc; |
| } |
| |
| /** |
| * @brief getting the use of RPC (remote) or not (local) |
| */ |
| bcmos_bool bal_bcm_use_rpc_get(void) |
| { |
| if (g_use_rpc) |
| { |
| return BCMOS_TRUE; |
| } |
| else |
| { |
| return BCMOS_FALSE; |
| } |
| } |
| |
| static void sw_util_bcm_rx_cb (int unit, int port, int reason, unsigned char *p_payload, int payload_len) |
| { |
| int i, len, obj_len; |
| unsigned char *payload; |
| char bytestr[32]; |
| char *p_bytestr = bytestr; |
| |
| BCM_LOG(INFO, log_id_sw_util, "BAL: Captured packet from datapath (len: %d bytes)\n", payload_len); |
| |
| BCM_LOG(DEBUG, log_id_sw_util, " ingress port %d\n", port); |
| BCM_LOG(DEBUG, log_id_sw_util, " rcv reason 0x%x\n", reason); |
| |
| len = (payload_len > 64)? 64 : payload_len; |
| |
| /* dump out the captured packet */ |
| payload = p_payload; |
| BCM_LOG(DEBUG, log_id_sw_util, " payload: (first %d bytes shown)", len); |
| for(i=0; i<len; i++) |
| { |
| if ( i%8 == 0) |
| { |
| sprintf(p_bytestr, "\n"); |
| BCM_LOG(DEBUG, log_id_sw_util, "%s", bytestr); |
| p_bytestr = bytestr; |
| |
| } |
| sprintf(p_bytestr, " %02x", *payload++); |
| p_bytestr += 3; |
| } |
| |
| /* Log the string being crafted when the loop terminated */ |
| sprintf(p_bytestr, "\n"); |
| BCM_LOG(DEBUG, log_id_sw_util, "%s", bytestr); |
| |
| /* Send Auto Indication */ |
| if ( p_bal_core_to_api_ind_queue ) |
| { |
| bcmbal_packet_cfg *p_ind_msg = NULL; |
| bcmbal_packet_key key; |
| bal_sw_flow *p_flow_elm; |
| int tmp_port; |
| |
| /* find the flow info corresponding to this trap REASON */ |
| p_flow_elm = bal_sw_util_flow_list_get_by_trap_code(reason); |
| if(p_flow_elm == NULL) |
| { |
| BCM_LOG(WARNING, log_id_sw_util, " TrapCallBack: Can't match trap code 0x%x to element in flow list\n", reason); |
| return; |
| } |
| |
| /* The packet indication object contains the bcmbal_packet_cfg structure plus the captured packet |
| * content |
| */ |
| obj_len = payload_len + sizeof(bcmbal_packet_cfg); |
| |
| p_ind_msg = bcmbal_msg_calloc(obj_len); |
| |
| if(p_ind_msg == NULL) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " TrapCallBack: No memory to send indication\n"); |
| return; |
| } |
| |
| key.packet_send_dest.type = BCMBAL_DEST_TYPE_HOST; |
| |
| BCMBAL_CFG_INIT(p_ind_msg, packet, key); |
| |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, flow_id, p_flow_elm->id); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, svc_port, p_flow_elm->svc_port); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, flow_cookie, p_flow_elm->flow_cookie); |
| |
| /* first search the PON table */ |
| tmp_port = bal_bcm_pon_inf_idx_get(port); |
| if( tmp_port != -1) |
| { |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, flow_type, BCMBAL_FLOW_TYPE_UPSTREAM); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, intf_id, tmp_port); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, intf_type, BCMBAL_INTF_TYPE_PON); |
| } |
| else /* if failed, search for NNI table */ |
| { |
| tmp_port = bal_bcm_net_inf_idx_get(port); |
| if( tmp_port != -1) |
| { |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, flow_type, BCMBAL_FLOW_TYPE_DOWNSTREAM); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, intf_id, tmp_port); |
| BCMBAL_CFG_PROP_SET(p_ind_msg, packet, intf_type, BCMBAL_INTF_TYPE_NNI); |
| } |
| } |
| /* if both failed, return */ |
| if(tmp_port == -1) |
| { |
| /* something went wrong, free up the message */ |
| bcmbal_msg_free(p_ind_msg); |
| BCM_LOG(ERROR, log_id_sw_util, " TrapCallBack: can't match ingress port to bal port tables\n"); |
| return; |
| } |
| |
| ((bcmbal_obj *)p_ind_msg)->status = BCM_ERR_OK; |
| ((bcmbal_obj *)p_ind_msg)->obj_type = BCMBAL_OBJ_ID_PACKET; |
| ((bcmbal_obj *)p_ind_msg)->group = BCMBAL_MGT_GROUP_AUTO; |
| |
| /* now copy the contents of the packet */ |
| p_ind_msg->data.pkt.val = (uint8_t *)(p_ind_msg + 1); |
| memcpy(p_ind_msg->data.pkt.val, p_payload, payload_len); |
| |
| /* and record the length of the captured packet */ |
| p_ind_msg->data.pkt.len = payload_len; |
| |
| BCMBAL_PROP_SET_PRESENT(p_ind_msg, packet, _cfg, pkt); |
| |
| BCM_LOG(INFO, log_id_sw_util, " TrapCallBack: Flow id = %d, type=%d, Interface id = %d, type=%d, svc_port=%d\n", |
| p_ind_msg->data.flow_id, p_ind_msg->data.flow_type, |
| p_ind_msg->data.intf_id, p_ind_msg->data.intf_type, |
| p_ind_msg->data.svc_port); |
| |
| /* Send this indication straight to the API client |
| */ |
| bcmbal_msg_hdr_set(p_ind_msg, |
| BCMBAL_MGMT_API_IND_MSG, |
| BAL_MSG_TYPE_AUTO_IND, |
| BAL_SUBSYSTEM_CORE, |
| BCMBAL_OBJ_ID_PACKET, |
| 0, /* operation code */ |
| 0); /* exchange id */ |
| |
| if(BCM_ERR_OK != bcmbal_msg_send(p_bal_core_to_api_ind_queue, |
| p_ind_msg, |
| BCMOS_MSG_SEND_AUTO_FREE)) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " TrapCallBack: send auto indication failed\n"); |
| } |
| else |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " TrapCallBack: auto indication sent\n"); |
| } |
| } |
| else |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " TrapCallBack: no auto indication queue\n"); |
| } |
| return; |
| } |
| |
| /** |
| * @brief Connect access terminal |
| * |
| * This routine is called by acc_term_fsm in the BAL core |
| * Upon receiving the request from the core, this function |
| * assign the device number that each logical nni or pon interface belong |
| * and restrict the egress ports of each interface. This mapping is highly |
| * topology dependent and should be customized according to the actual hardware |
| * layout. |
| * @param p_acc_term Pointer to access terminal instance |
| * |
| * @return bcmos_errno |
| */ |
| static bcmos_errno sw_util_access_terminal_connect(acc_term_inst *p_acc_term) |
| { |
| bcmos_errno ret = BCM_ERR_INTERNAL; |
| int rc; |
| bal_swapp_port *port; |
| char *argv[] = { "socdiag", NULL }; |
| uint32_t dev_type; |
| |
| BCM_LOG(INFO, log_id_sw_util, " Got a access terminal SET\n"); |
| |
| /* make sure the abstraction layer is initialized - no harm to initialize multiple time */ |
| bcmos_init(); |
| |
| /* Initialize SDK */ |
| rc = socdiag_main(1, argv); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " Init BCM SDK failed - %d\n", rc); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| BCM_LOG(INFO, log_id_sw_util, " %s RPC\n", (1 == g_use_rpc) ? "Using" : "Not using" ); |
| |
| /* use a soc script to establish rpc connection if switch is remotely located */ |
| if (bal_bcm_use_rpc_get()) |
| { |
| sleep(3); /* allow remote device to settle */ |
| |
| BCM_LOG(INFO, log_id_sw_util, " starting RPC connection\n"); |
| rc = sh_rcload_file(-1, NULL, "rpc.soc", 0); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " start RPC connection failed\n"); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| } |
| |
| BCM_LOG(INFO, log_id_sw_util, " Using interface table: %d Device: %d\n", g_intf_maptable, g_dft_dev_id ); |
| |
| /* setup the device ID - This is very hardware specific */ |
| port = g_net_inf_map_table[g_intf_maptable]; |
| /* -1 indicate end of table */ |
| while(port->pbm_id != -1) |
| { |
| port->device_id = g_dft_dev_id; |
| port++; |
| } |
| |
| port = g_pon_inf_map_table[g_intf_maptable]; |
| while(port->pbm_id != -1) |
| { |
| port->device_id = g_dft_dev_id; |
| port++; |
| } |
| /* get the switch model from the chip */ |
| dev_type = bal_bcm_dev_type_get(g_dft_dev_id); |
| if (dev_type == 0) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " Error retrieving device type on access-terminal connect: 0x%x\n", dev_type); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| /* set up the valid egress ports for net/pon facing ports */ |
| if (dev_type == BCM_DEVICE_KT2) |
| { |
| ret = sw_util_esw_acc_term_connect(g_net_inf_map_table[g_intf_maptable], g_pon_inf_map_table[g_intf_maptable]); |
| } |
| else if (dev_type == BCM_DEVICE_ARAD || dev_type == BCM_DEVICE_ARAD_PLUS || dev_type == BCM_DEVICE_QAX) |
| { |
| /* for rpc case, dpp use a special api to register rx callback. |
| for non-rpc use case, use bcm_rx_register() to register the rx callback |
| */ |
| if (bal_bcm_use_rpc_get()) |
| { |
| /* if the trap receive udp port in bal_config.ini is not zero, start a receiving thread */ |
| if(bal_bcm_trap_rcv_port_get()) |
| { |
| sw_util_dpp_rx_cb_register(bal_bcm_dft_dev_get(), sw_util_bcm_rx_cb); |
| } |
| else |
| { |
| BCM_LOG(ERROR, log_id_sw_util, "Missing UDP port number for RPC packet In receiver \n"); |
| return BCM_ERR_INTERNAL; |
| } |
| } |
| else |
| { |
| bcm_rx_register(bal_bcm_dft_dev_get(), "Bal Cpu Traps", dpp_rx_cb_register, 50, NULL, BCM_RCO_F_ALL_COS); |
| } |
| |
| ret = sw_util_dpp_acc_term_connect(g_net_inf_map_table[g_intf_maptable], g_pon_inf_map_table[g_intf_maptable]); |
| } |
| |
| BCM_LOG(INFO, log_id_sw_util, " Return access terminal connect request with %d on device 0x%x\n", ret, dev_type ); |
| |
| /* for now, only support one iwf */ |
| g_iwf_mode = (uint32_t)p_acc_term->api_req_acc_term_obj_info.data.iwf_mode; |
| |
| return ret; |
| } |
| |
| /** |
| * @brief getting the interface mapping table that applied to the HW connections |
| */ |
| bal_swapp_port_map_indx bal_bcm_intf_maptable_get() |
| { |
| return g_intf_maptable; |
| } |
| |
| /** |
| * @brief SWITCH module: internal packet_send function |
| * |
| * This routine distribute the SEND function to supported switch family |
| * |
| * @param dst_port_id Switch port id the packet is going to be sent out |
| * @param reason REASON_SEND_TO_NNI or REASON_SEND_TO_PON |
| * @param payload pointer to the data |
| * @param payload_len the length of the data |
| * @param tunnel_id pon port tunnel id if REASON_SEND_TO_PON |
| * |
| * @return bcmos_errno |
| */ |
| static bcmos_errno sw_util_pkt_send_intl(int dst_port_id, |
| int reason, |
| unsigned char *payload, |
| int payload_len, |
| int tunnel_id) |
| { |
| uint32_t dev_type; |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| /* get the switch chip type from default device id |
| TBD - in the future, the device id should be obtained from port mapping table */ |
| dev_type = bal_bcm_dev_type_get(g_dft_dev_id); |
| if (dev_type == 0) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " Error retrieving device type on pkt send: 0x%x\n", dev_type); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| /* set up the valid egress ports for net/pon facing ports */ |
| if (dev_type == BCM_DEVICE_KT2) |
| { |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| else if (dev_type == BCM_DEVICE_ARAD || dev_type == BCM_DEVICE_ARAD_PLUS || dev_type == BCM_DEVICE_QAX) |
| { |
| ret = sw_util_dpp_pkt_send(dst_port_id, reason, payload, payload_len, s_target_device, tunnel_id); |
| } |
| else |
| { |
| ret = BCM_ERR_NOT_SUPPORTED; |
| } |
| |
| BCM_LOG(INFO, log_id_sw_util, " Return access terminal connect request with %d on device 0x%x\n", ret, dev_type ); |
| |
| return ret; |
| } |
| |
| #endif /* #ifndef TEST_SW_UTIL_LOOPBACK */ |
| |
| /* the listening UDP port that the switch will send the trapped messages */ |
| static uint32_t g_trap_rcv_port = 0; |
| |
| /** |
| * @brief set the receiving UDP port for trap packets - from config file |
| */ |
| uint32_t bal_bcm_trap_rcv_port_set(uint32_t udp_port) |
| { |
| g_trap_rcv_port = udp_port; |
| return 0; |
| } |
| |
| /** |
| * @brief getting the receiving UDP port for trap packets |
| */ |
| uint32_t bal_bcm_trap_rcv_port_get() |
| { |
| return g_trap_rcv_port; |
| } |
| |
| |
| /* the global portChannel DownStream Max rate scheduling mode */ |
| static uint32_t g_ds_sched_mode = 0; /* default to strict priority */ |
| |
| /** |
| * @brief set the DS max rate scheduling mode - from config file |
| */ |
| uint32_t bal_bcm_ds_sched_mode_set(uint32_t sched_mode) |
| { |
| g_ds_sched_mode = sched_mode; |
| return 0; |
| } |
| |
| /** |
| * @brief getting the DS max rate scheduling mode |
| */ |
| uint32_t bal_bcm_ds_sched_mode_get() |
| { |
| return g_ds_sched_mode; |
| } |
| |
| /** |
| * @brief SWITCH module: access terminal SET handler |
| * |
| * This routine is called by acc_term_fsm in the BAL core upon |
| * SET request for acc_terminal object. |
| * |
| * @param p_acc_term Pointer to access terminal instance |
| * @param opt_type Operation type on access terminal instance |
| * |
| * @return bcmos_errno |
| */ |
| bcmos_errno sw_util_access_terminal_set(acc_term_inst *p_acc_term, |
| bal_util_oper_acc_term opt_type) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| if (opt_type != BAL_UTIL_OPER_ACC_TERM_CONNECT) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " Access terminal currently supports only CONNECT request\n"); |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| ret = sw_util_access_terminal_connect(p_acc_term); |
| #else |
| BCM_LOG(INFO, log_id_sw_util, " dummy SUCCESS\n"); |
| #endif |
| |
| return ret; |
| } |
| |
| /** |
| * @brief setting the interface mapping table that applied to the HW connections |
| */ |
| int bal_bcm_intf_maptable_set(uint32_t intf_maptable) |
| { |
| int ret = 0; |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| switch(intf_maptable) |
| { |
| case 0: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_GPON; |
| break; |
| case 1: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_GPON_V3; |
| break; |
| case 2: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_EXP; |
| break; |
| case 3: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_EXP2; |
| break; |
| case 4: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_SVK4; |
| break; |
| case 5: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_EPON_TDMA; |
| break; |
| case 6: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_EPON_1G; |
| break; |
| case 7: |
| g_intf_maptable = BAL_SWAPP_PORT_MAP_EPON_10G; |
| break; |
| default: |
| BCM_LOG(ERROR, log_id_sw_util, " Mapping Table Id %d is not supported\n", intf_maptable); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| break; |
| } |
| #endif |
| return ret; |
| } |
| |
| /** |
| * @brief SWITCH module: packet_send |
| * |
| * This routine is called by work thread in the BAL core upon |
| * user request to send a raw packet out of a switch port. |
| * |
| * @param dst_port_id Switch port id the packet is going to be sent out |
| * @param reason REASON_SEND_TO_NNI or REASON_SEND_TO_PON |
| * @param payload pointer to the data |
| * @param payload_len the length of the data |
| * @param tunnel_id pon tunnel_id |
| * |
| * @return bcmos_errno |
| */ |
| bcmos_errno sw_util_pkt_send(int dst_port_id, |
| int reason, |
| unsigned char *payload, |
| int payload_len, |
| int tunnel_id) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| if ( reason != REASON_SEND_TO_NNI && reason != REASON_SEND_TO_PON) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " pkt_send currently does not support reason %d\n", reason); |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| |
| if ( reason == REASON_SEND_TO_NNI && BCMOS_FALSE == bcm_topo_nni_is_valid(dst_port_id)) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " pkt_send to invalid nni port %d\n", dst_port_id); |
| return BCM_ERR_PARM; |
| } |
| |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| ret = sw_util_pkt_send_intl(dst_port_id, reason, payload, payload_len, tunnel_id); |
| #else |
| BCM_LOG(INFO, log_id_sw_util, " dummy SUCCESS\n"); |
| #endif |
| |
| return ret; |
| } |
| |
| /* |
| * Called from bal_core to set up the packet out server IP:port (i.e. the bcm_user process location) |
| * when Switch is on the same board where the core is run, there is no RPC and this init function should not be called |
| */ |
| bcmos_errno sw_util_pkt_send_init(const char *pkt_send_server_ip, uint16_t pkt_send_server_listen_port) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| |
| do |
| { |
| /* If the packet_out interface has already been initialized, just return OK */ |
| if(g_pkt_send_is_initialized == BCMOS_FALSE) |
| { |
| #ifdef CONFIG_SWITCH_RPC |
| /* |
| * Set up the socket to be used for sending "packet send" messages |
| * to the bcm.user server |
| */ |
| if((s_target_device.socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
| { |
| ret = BCM_ERR_NORES; |
| break; |
| } |
| |
| s_target_device.addr.sin_family = AF_INET; |
| inet_pton(s_target_device.addr.sin_family, pkt_send_server_ip, &s_target_device.addr.sin_addr.s_addr); |
| s_target_device.addr.sin_port = htons(pkt_send_server_listen_port); |
| #endif /* CONFIG_SWITCH_RPC */ |
| g_pkt_send_is_initialized = BCMOS_TRUE; |
| } |
| |
| } |
| while(0); |
| |
| #endif /*TEST_SW_UTIL_LOOPBACK*/ |
| |
| return ret; |
| } |
| /*@}*/ |