| /****************************************************************************** |
| * |
| * <: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. |
| * |
| * :> |
| * |
| *****************************************************************************/ |
| |
| #ifndef TEST_SW_UTIL_LOOPBACK |
| |
| #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_dpp_acc_term.h" |
| #include "bal_dpp_qos.h" |
| #include "bal_dpp_qos_map.h" |
| |
| #include <bcm/types.h> |
| #include <bcm/port.h> |
| #include <bcm/rx.h> /* for dpp rpc rx register callback */ |
| #include <bcm/switch.h> |
| #include <bcm/l2.h> |
| |
| /** |
| * @file bal_dpp_acc_term.c |
| * @brief BAL Switch util functions that handle access terminal requests on DUNE PACKET PROCESSOR |
| * @addtogroup sw_util |
| * |
| */ |
| |
| /*@{*/ |
| |
| /* @brief L2 Table Operation Control |
| * |
| * This routine set the HW L2 learning and aging |
| * |
| * @param unit The device id |
| * @param flags Operation flags |
| * BCM_L2_LEARN_CPU 0x20 |
| * BCM_L2_INGRESS_DIST 0x02 |
| * BCM_L2_INGRESS_CENT 0x01 |
| * @param age_seconds L2 entry age out time in seconds |
| * @return BCM error code |
| */ |
| static int sw_util_dpp_l2_entry_control_set(int unit, int flags, int age_seconds) |
| { |
| int rv = 0; |
| |
| rv = bcm_switch_control_set(unit, bcmSwitchL2LearnMode, flags); |
| if (rv) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " bcm_switch_control_set failed ret = %d\n", rv); |
| return rv; |
| } |
| |
| /* set aging time */ |
| rv = bcm_l2_age_timer_set(unit, age_seconds); |
| if (rv) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " bcm_l2_age_timer_set failed ret = %d\n", rv); |
| return rv; |
| } |
| else |
| { |
| BCM_LOG(INFO, log_id_sw_util, " Set L2 table aging time to %d seconds\n", age_seconds); |
| } |
| |
| return rv; |
| |
| } |
| |
| |
| /** |
| * @brief L2 Table event handler |
| * |
| * This routine is a callback triggered by HW L2 Table events |
| * |
| * @param unit The device id |
| * @param p_l2addr Pointer to the L2 entry where the event is happen |
| * @param operation The type of event |
| * @param userdata Pointer to a user provided data when the handler is registered |
| */ |
| static void sw_util_dpp_l2_entry_event_handler(int unit, bcm_l2_addr_t *p_l2addr, int operation, void *userdata) |
| { |
| |
| if (p_l2addr == NULL) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " L2 entry callback with NULL L2 address, op = %d\n", operation); |
| return; |
| } |
| if (operation == BCM_L2_CALLBACK_LEARN_EVENT) |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " BCM_L2_CALLBACK_LEARN_EVENT handler\n"); |
| } |
| else if (operation == BCM_L2_CALLBACK_MOVE_EVENT) |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " BCM_L2_CALLBACK_MOVE_EVENT handler\n"); |
| } |
| else if (operation == BCM_L2_CALLBACK_AGE_EVENT) |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " BCM_L2_CALLBACK_AGE_EVENT handler\n"); |
| } |
| else |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " BCM_L2_CALLBACK_OPERATION %d handler\n", operation); |
| } |
| |
| BCM_LOG(DEBUG, log_id_sw_util, " MAC %02x:%02x:%02x:%02x:%02x:%02x\n", |
| (0xff & p_l2addr->mac[0]), |
| (0xff & p_l2addr->mac[1]), |
| (0xff & p_l2addr->mac[2]), |
| (0xff & p_l2addr->mac[3]), |
| (0xff & p_l2addr->mac[4]), |
| (0xff & p_l2addr->mac[5]) ); |
| |
| if(!(p_l2addr->flags & BCM_L2_MCAST)) |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " UC VID=0x%x| PORT=0x%08x\n", p_l2addr->vid, p_l2addr->port); |
| /* print_gport_part - p_l2addr->port */ |
| { |
| int a = -1, b = 0; |
| char* type = ""; |
| if (a==-1){ |
| a=BCM_GPORT_LOCAL_GET(p_l2addr->port); |
| type ="local"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_MODPORT_MODID_GET(p_l2addr->port); |
| b=BCM_GPORT_MODPORT_PORT_GET(p_l2addr->port); |
| type ="modport"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_TRUNK_GET(p_l2addr->port); |
| type ="trunk"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_MCAST_GET(p_l2addr->port); |
| type ="mact"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_MPLS_PORT_ID_GET(p_l2addr->port); |
| type ="mpls_port"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_VLAN_PORT_ID_GET(p_l2addr->port); |
| type ="vlan_port"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_SYSTEM_PORT_ID_GET(p_l2addr->port); |
| type ="sys_port"; |
| } |
| if (a==-1){ |
| a=BCM_GPORT_MIRROR_GET(p_l2addr->port); |
| } |
| BCM_LOG(DEBUG, log_id_sw_util, " GPORT %s <0x%x,%d>\n", type, a, b); |
| } |
| } |
| else |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, " MC 0x%08x\n",p_l2addr->l2mc_group); |
| } |
| BCM_LOG(DEBUG, log_id_sw_util, " static %d|\n", (p_l2addr->flags & BCM_L2_STATIC)!=0 ); |
| |
| } |
| |
| /** |
| * @brief Connect access terminal with DPP as part of the components |
| * |
| * This routine is called by sw_util_access_terminal_connect in the BAL core |
| * to execute DPP specific API for access_terminal_connect request |
| * |
| * @param p_net_map Pointer to the net ports mapping from logical numbrer to physical number |
| * @param p_pon_map Pointer to the pon ports mapping from logical numbrer to physical number |
| * @return bcmos_errno |
| */ |
| bcmos_errno sw_util_dpp_acc_term_connect(bal_swapp_port *p_net_map, bal_swapp_port *p_pon_map ) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| int rc = 0; |
| bal_swapp_port *port; |
| |
| BCM_LOG(INFO, log_id_sw_util, " DPP - Got a access terminal CONNECT\n"); |
| |
| do |
| { |
| /* setup the device ID - This is very hardware specific */ |
| port = p_net_map; |
| /* -1 indicate the end of table */ |
| while(port->pbm_id != -1) |
| { |
| |
| /* the default TPID is 0x8100, add 0x88a8 to the allow TPID */ |
| |
| rc = bcm_port_tpid_delete_all(port->device_id, port->pbm_id); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to clear the nni TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| rc = bcm_port_tpid_add(port->device_id, port->pbm_id, 0x8100, 0); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to add 0x8100 to the nni TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| rc = bcm_port_tpid_add(port->device_id, port->pbm_id, 0x88a8, 0); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to add 0x88a8 to the nni TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| |
| port++; |
| } |
| |
| port = p_pon_map; |
| while(port->pbm_id != -1) |
| { |
| |
| /* the default TPID is 0x8100, add 0x88a8 to the allow TPID */ |
| |
| rc = bcm_port_tpid_delete_all(port->device_id, port->pbm_id); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to clear the pon TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| rc = bcm_port_tpid_add(port->device_id, port->pbm_id, 0x8100, 0); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to add 0x8100 to the pon TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| rc = bcm_port_tpid_add(port->device_id, port->pbm_id, 0x88a8, 0); |
| if (rc) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to add 0x88a8 to the pon TPID list on interface %d\n", port->pbm_id); |
| ret = BCM_ERR_INTERNAL; |
| } |
| |
| port++; |
| } |
| |
| if(ret != BCM_ERR_OK) |
| { |
| /* exit if port init failed */ |
| break; |
| } |
| |
| /* Remove all ports from VLAN 1, so the L2 broadcast won't send to CPU port by default */ |
| bcm_vlan_gport_delete_all(bal_bcm_dft_dev_get(), 1); |
| |
| /* configure all qos map tables */ |
| ret = bal_sw_dpp_pcp_remark_maps_init(bal_bcm_dft_dev_get()); |
| if (ret) |
| { |
| BCM_LOG(WARNING, log_id_sw_util, " DPP - fail to init qos map tables\n"); |
| break; |
| } |
| |
| /* init the DS QOS hierarchical scheduling - ignore error if HW dos not support QOS */ |
| ret =bal_sw_dpp_qos_init(bal_bcm_dft_dev_get(), bal_bcm_intf_maptable_get()); |
| if (ret) |
| { |
| BCM_LOG(WARNING, log_id_sw_util, " DPP - fail to init qos HR scheduler\n"); |
| break; |
| } |
| |
| rc = bcm_l2_addr_register(bal_bcm_dft_dev_get(), sw_util_dpp_l2_entry_event_handler, NULL); |
| if (rc) |
| { |
| BCM_LOG(WARNING, log_id_sw_util, " DPP - fail to register l2_addr callback \n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| |
| rc = sw_util_dpp_l2_entry_control_set(bal_bcm_dft_dev_get(), BCM_L2_LEARN_CPU|BCM_L2_INGRESS_DIST, bal_bcm_l2_age_time_get()); |
| if (rc) |
| { |
| BCM_LOG(WARNING, log_id_sw_util, " DPP - fail to set l2_addr control \n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| }while(0); |
| return ret; |
| } |
| |
| /* internal structure used by the trap receiving thread */ |
| typedef struct |
| { |
| int udp_port; |
| pthread_t threadid; |
| dpp_rx_cb_f callback; |
| } trap_context; |
| |
| static trap_context g_trap_ctx = {0}; |
| |
| /* the adjustment needed for ING trap packet header */ |
| #define DEFAULT_SOP_ADJ 2 |
| #define DEFAULT_REASON_ADJ 4 |
| /* compiler restirct the total local variables size < 16384 */ |
| #define DEFAULT_TRAP_BUF_SIZE (10 *1024) |
| /* |
| the listener thread that wait for the trap packet_in message from the switch |
| */ |
| static void *trap_receive(void *p_user_data) |
| { |
| int rc; |
| int sUDPSocket; |
| unsigned char cBuffer[DEFAULT_TRAP_BUF_SIZE]; |
| int nBytesRecv = 0; |
| int nBufSize = DEFAULT_TRAP_BUF_SIZE; |
| socklen_t nReceiveAddrSize = 0; |
| int maxfd; |
| fd_set read_fds; |
| struct timeval tv; |
| uint16_t tmp_src_port, src_port; |
| trap_context *p_trap_ctx = (trap_context *)p_user_data; |
| uint32_t tmp_reason, reason; |
| /* Create a connectionless socket */ |
| sUDPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| /* Check to see if we have a valid socket */ |
| if(sUDPSocket < 0) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - trap_receive:create socket failed\n"); |
| return NULL; |
| } |
| |
| // Setup a bind on the socket, telling us what port and |
| // adapter to receive datagrams on. |
| struct sockaddr_in sReceiveFromAddr; |
| memset(&sReceiveFromAddr, 0, sizeof(struct sockaddr_in)); |
| |
| sReceiveFromAddr.sin_family = AF_INET; |
| sReceiveFromAddr.sin_port = htons(p_trap_ctx->udp_port); |
| sReceiveFromAddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| |
| rc = bind(sUDPSocket, (struct sockaddr *)&sReceiveFromAddr, |
| sizeof(struct sockaddr_in)); |
| if (rc < 0) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - trap_receive:bind failed\n"); |
| return NULL; |
| } |
| |
| BCM_LOG(INFO, log_id_sw_util, " DPP - trap_receive start listen at %d\n", p_trap_ctx->udp_port); |
| |
| // Receive a datagram from another device |
| while(1) |
| { |
| FD_ZERO(&read_fds); |
| FD_SET(sUDPSocket, &read_fds); |
| maxfd = sUDPSocket; |
| /* Set the timeout */ |
| tv.tv_sec = 3; |
| tv.tv_usec = 0; /* 3 seconds */ |
| rc = select(maxfd + 1, &read_fds, NULL, NULL, &tv); |
| |
| if (rc < 0) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - trap_receive:select failed err = %d\n", rc); |
| break; |
| } |
| if (rc == 0) /* timeout */ |
| { |
| continue; |
| } |
| // Get the datagrama |
| nBytesRecv = recvfrom(sUDPSocket, cBuffer, nBufSize, 0, |
| (struct sockaddr *) &sReceiveFromAddr, |
| &nReceiveAddrSize); |
| BCM_LOG(INFO, log_id_sw_util, " DPP - Got %d bytes message \n", nBytesRecv); |
| |
| /* the first 4 bytes are reason */ |
| /* compiler generate cast-align warning -> p_reason = (uint32_t *)(cBuffer); */ |
| memcpy(&tmp_reason, cBuffer, sizeof(uint32_t) ); |
| reason = ntohl(tmp_reason); |
| /* the next 2 bytes are srouce port */ |
| /* compiler generate cast-align warning -> p_src_port = (uint16 *)(cBuffer + DEFAULT_REASON_ADJ); */ |
| memcpy(&tmp_src_port, cBuffer + DEFAULT_REASON_ADJ, sizeof(uint16_t)); |
| src_port = ntohs(tmp_src_port); |
| |
| /* call the register callback here - set unit to 0 as it is don't care */ |
| if(p_trap_ctx->callback) |
| { |
| p_trap_ctx->callback(0, src_port, reason, cBuffer+DEFAULT_SOP_ADJ+DEFAULT_REASON_ADJ, nBytesRecv-DEFAULT_SOP_ADJ-DEFAULT_REASON_ADJ); |
| } |
| } |
| close(sUDPSocket); |
| |
| return NULL; |
| } |
| |
| /** |
| * @brief Start a receiving thread and add the callbck to process CPU trapped packets |
| * |
| * This routine is called by sw_util_access_terminal_connect in the BAL core |
| * to execute DPP specific API for process the trapping packets |
| * |
| * @param unit the switch device number the callback applied |
| * @param cb_f a callback function that process the trapped packets |
| * @return bcmos_errno |
| */ |
| bcmos_errno sw_util_dpp_rx_cb_register(uint32_t unit, dpp_rx_cb_f cb_f) |
| { |
| int ret; |
| |
| /* if the receiving thread already started, return error */ |
| if (g_trap_ctx.threadid) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - There is an existing trap receiving thread\n"); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| g_trap_ctx.udp_port = bal_bcm_trap_rcv_port_get(); |
| g_trap_ctx.callback = cb_f; |
| |
| /* use default attribute to create the thread */ |
| ret = pthread_create(&g_trap_ctx.threadid, NULL, &trap_receive, &g_trap_ctx); |
| |
| if(ret) |
| { |
| BCM_LOG(ERROR, log_id_sw_util, " DPP - fail to create trap receiving thread - %d\n", ret); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| /* To make compiler happy when build with ESW switch only */ |
| #ifdef ESW_SWITCH |
| void dpp_dft_rx_cb(int unit, int dst_port, int reason, unsigned char *payload, int payload_len) |
| { |
| return; |
| } |
| #else |
| extern void dpp_dft_rx_cb(int unit, int dst_port, int reason, unsigned char *payload, int payload_len); |
| #endif |
| |
| #define L2_HEADER_SIZE (12) /* bytes */ |
| |
| #define TUNNEL_TAG_TPID_LEN (2) /* bytes - TPID (2 bytes) */ |
| #define TUNNEL_TAG_PBITS_CFI_VLAN_ID_LEN (2) /* PBITS+CFI+VLAN ID (2 bytes) */ |
| #define TUNNEL_TAG_SIZE (TUNNEL_TAG_TPID_LEN + TUNNEL_TAG_PBITS_CFI_VLAN_ID_LEN) |
| |
| bcmos_errno sw_util_dpp_pkt_send(int target_port_id, |
| int reason, |
| unsigned char *p_user_pkt, |
| int user_pkt_len, |
| trap_target target_device, |
| int target_tunnel_id) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| char *p_pktout_msg; |
| uint8_t dst_port_id; |
| int dst_device_id; |
| char *p_pktout_ptr; |
| uint32_t total_msg_size; |
| uint32_t uint32_num; |
| uint16_t uint16_num; |
| |
| /* |
| * Allocate a message to be sent to the bcm.user instance. This will contain |
| * the packet to be sent out of the switch, as well has header metadata. |
| */ |
| p_pktout_msg = bcmos_calloc(user_pkt_len + |
| DEFAULT_SOP_ADJ + |
| DEFAULT_REASON_ADJ + |
| TUNNEL_TAG_SIZE); |
| |
| if(NULL == p_pktout_msg) |
| { |
| return BCM_ERR_NOMEM; |
| } |
| |
| /* translate the output port to the bcm.user's mapping */ |
| switch(reason) |
| { |
| case REASON_SEND_TO_NNI: |
| dst_port_id = bal_bcm_net_inf_pbm_get(target_port_id); |
| dst_device_id = bal_bcm_net_inf_dev_get(target_port_id); |
| break; |
| case REASON_SEND_TO_PON: |
| dst_port_id = bal_bcm_pon_inf_pbm_get(target_port_id); |
| dst_device_id = bal_bcm_pon_inf_dev_get(target_port_id); |
| break; |
| default: |
| return BCM_ERR_PARM; |
| break; |
| } |
| |
| /* Format of the message to the bcm.user instance is: |
| * |
| * reason code: 4 bytes |
| * dst_port: 2 bytes |
| * user packet: pkt_size bytes |
| */ |
| |
| /* Insert the 4 bytes with reason code */ |
| uint32_num = (htonl(reason)); |
| memcpy(p_pktout_msg, &uint32_num, sizeof(uint32_num)); |
| |
| /* Replace 2 bytes with packet_out destination port info. This is the bcm.user's |
| * mapping of output port (NNI or PON) to BCM SDK port mapping */ |
| uint16_num = htons(dst_port_id & 0xff); /* dst_port contents is actually only 1 byte */ |
| memcpy(&p_pktout_msg[DEFAULT_REASON_ADJ], &uint16_num, sizeof(uint16_num)); |
| |
| /* Copy in the user packet to send to the bcm.user for transmission out of the switch. |
| * Remember to insert the proper tunnel tag in the message for out_ports that are |
| * associated with the PON |
| */ |
| p_pktout_ptr = p_pktout_msg + DEFAULT_REASON_ADJ + DEFAULT_SOP_ADJ; |
| total_msg_size = user_pkt_len + DEFAULT_REASON_ADJ + DEFAULT_SOP_ADJ; |
| |
| if(reason == REASON_SEND_TO_NNI) |
| { |
| /* Copy in the entire packet as-is */ |
| memcpy(p_pktout_ptr, p_user_pkt, user_pkt_len); |
| } |
| else |
| { |
| uint16_t pktout_offset = 0; |
| |
| /* Copy in the L2 header (MAC DA/SA) */ |
| memcpy(&p_pktout_ptr[pktout_offset], p_user_pkt, L2_HEADER_SIZE); |
| |
| /* Point to the tunnel tag area in the outgoing message */ |
| pktout_offset += L2_HEADER_SIZE; |
| |
| /* Insert the TPID in the tag for the output destination */ |
| uint16_num = htons(0x8100); |
| memcpy(&p_pktout_ptr[pktout_offset], &uint16_num, sizeof(uint16_num)); |
| |
| /* Point to the remainder of the outgoing message */ |
| pktout_offset += TUNNEL_TAG_TPID_LEN; |
| /* Insert the tunnel tag vlan ID for the output destination */ |
| uint16_num = htons(target_tunnel_id); |
| memcpy(&p_pktout_ptr[pktout_offset], &uint16_num, sizeof(uint16_num)); |
| |
| /* Point to the remainder of the outgoing message */ |
| pktout_offset += TUNNEL_TAG_PBITS_CFI_VLAN_ID_LEN; |
| |
| /* Copy in the rest of the message */ |
| memcpy(&p_pktout_ptr[pktout_offset], |
| (p_user_pkt + L2_HEADER_SIZE), |
| (user_pkt_len - L2_HEADER_SIZE)); |
| |
| total_msg_size += TUNNEL_TAG_SIZE; |
| } |
| |
| |
| BCM_LOG(DEBUG, log_id_sw_util, "Packet send (user pkt_size:%d) destined for %s port %d\n", |
| user_pkt_len, |
| (reason == REASON_SEND_TO_PON) ? "PON" : "NNI", |
| dst_port_id); |
| |
| if(reason == REASON_SEND_TO_PON) |
| { |
| BCM_LOG(DEBUG, log_id_sw_util, "Sending via GEM %d\n", target_tunnel_id); |
| } |
| |
| if (bal_bcm_use_rpc_get()) |
| { |
| /* On systems where BAL runs remotely from the switch hardware, we |
| * send the packet out message to the remote bcm.user process. |
| * That process then sends the attached user packet to the specified switch port. |
| */ |
| |
| sendto(target_device.socket, |
| p_pktout_msg, |
| total_msg_size, 0, |
| (struct sockaddr *) &(target_device.addr), |
| sizeof(struct sockaddr_in)); |
| |
| } |
| else |
| { |
| /* On systems where BAL runs on the CPU co-located with the switch hardware, |
| * we send the attached user packet to the specified switch port directly. |
| */ |
| |
| total_msg_size = total_msg_size - ( DEFAULT_REASON_ADJ + DEFAULT_SOP_ADJ ); |
| dpp_dft_tx_cb(dst_device_id, |
| dst_port_id, |
| reason, |
| (unsigned char *)p_pktout_ptr, |
| total_msg_size); |
| } |
| |
| bcmos_free(p_pktout_msg); |
| |
| BCM_LOG(INFO, log_id_sw_util, "CPU packet msg sent to bcm.user for packet with msg size of %d (payload size: %d)\n", |
| total_msg_size, user_pkt_len); |
| |
| return ret; |
| } |
| |
| /*@}*/ |
| #endif /* #ifndef TEST_SW_UTIL_LOOPBACK */ |