blob: acb85d312ac071812d8a1f77992d2d49c08761b7 [file] [log] [blame]
/******************************************************************************
*
* <: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.
*
* :>
*
*****************************************************************************/
/**
* @file bal_switch_flow.c
* @brief BAL Switch util functions that handle flow requests
* @addtogroup sw_util
*/
/*@{*/
#include <bal_common.h>
#include <bcm_dev_log.h>
#include <bal_msg.h>
#include "bal_switch_flow.h"
#include "flow_fsm.h"
#include "bcmos_errno.h"
#include "bal_switch_util.h"
#ifndef TEST_SW_UTIL_LOOPBACK
#include <bcm/types.h>
#include <sal/core/libc.h>
#ifndef sal_memset
#define sal_memset memset
#endif
#include <bcm/port.h>
#include <bcm/vlan.h>
#include <bcm/field.h>
#include <bcm/error.h>
#include <sal/core/libc.h>
#include "bal_switch_acc_term.h"
#include "esw/bal_esw_flow.h"
#include "dpp/bal_dpp_flow.h"
#include "dpp/bal_dpp_vswitch.h"
#endif /* #ifndef TEST_SW_UTIL_LOOPBACK */
/* A golbal link list to keep track of flows in the switch */
TAILQ_HEAD(bal_sw_flow_list_head, bal_sw_flow) g_swutil_flow_list;
static void sw_util_flow_dump_classifier(bcmbal_flow_cfg *p_flow)
{
char dst_ip_str[16];
bcmos_inet_ntoa(&p_flow->data.classifier.dst_ip, dst_ip_str);
/* Do not use normal BCM_LOG() (but BCM_LOG_CALLER_FMT()), as IP address is a stack variable. */
BCM_LOG_CALLER_FMT(DEBUG, log_id_sw_util,
" classifier - otpid=0x%x itpid=0x%x ovid=0x%x ivid=0x%x opcp=0x%x, ipcp=0x%x "
"ether_type=0x%x dst_mac=%02x:%02x:%02x:%02x:%02x:%02x ip_proto=0x%x dst_ip=%s src_port=%u dst_port=%u attr_mask=0x%x\n",
p_flow->data.classifier.o_tpid, p_flow->data.classifier.i_tpid,
p_flow->data.classifier.o_vid, p_flow->data.classifier.i_vid,
p_flow->data.classifier.o_pbits,
p_flow->data.classifier.i_pbits,
p_flow->data.classifier.ether_type,
p_flow->data.classifier.dst_mac.u8[0], p_flow->data.classifier.dst_mac.u8[1], p_flow->data.classifier.dst_mac.u8[2],
p_flow->data.classifier.dst_mac.u8[3], p_flow->data.classifier.dst_mac.u8[4], p_flow->data.classifier.dst_mac.u8[5],
p_flow->data.classifier.ip_proto,
dst_ip_str,
p_flow->data.classifier.src_port,
p_flow->data.classifier.dst_port,
(unsigned int)p_flow->data.classifier.presence_mask);
}
static void sw_util_flow_dump_sla(bcmbal_flow_cfg *p_flow)
{
BCM_LOG(DEBUG, log_id_sw_util, " sla - min_rate=%u max_rate=%u attr_mask=0x%x\n",
p_flow->data.sla.min_rate,
p_flow->data.sla.max_rate,
(unsigned int)p_flow->data.sla.presence_mask);
}
#define OUTER_VLAN_TAG_REQ_BITMASK (BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG | \
BCMBAL_ACTION_CMD_ID_XLATE_OUTER_TAG | \
BCMBAL_ACTION_CMD_ID_XLATE_TWO_TAGS | \
BCMBAL_ACTION_CMD_ID_REMOVE_TWO_TAGS | \
BCMBAL_ACTION_CMD_ID_REMARK_PBITS | \
BCMBAL_ACTION_CMD_ID_COPY_PBITS | \
BCMBAL_ACTION_CMD_ID_REVERSE_COPY_PBITS | \
BCMBAL_ACTION_CMD_ID_DSCP_TO_PBITS)
#define NOT_WORKING_ACTION_BITMASK (BCMBAL_ACTION_CMD_ID_ADD_TWO_TAGS | \
BCMBAL_ACTION_CMD_ID_REMOVE_TWO_TAGS | \
BCMBAL_ACTION_CMD_ID_XLATE_TWO_TAGS | \
BCMBAL_ACTION_CMD_ID_DISCARD_DS_BCAST | \
BCMBAL_ACTION_CMD_ID_DISCARD_DS_UNKNOWN | \
BCMBAL_ACTION_CMD_ID_COPY_PBITS | \
BCMBAL_ACTION_CMD_ID_REVERSE_COPY_PBITS | \
BCMBAL_ACTION_CMD_ID_DSCP_TO_PBITS)
/**
* @brief The flow check function validate the flow parameters from the core
*
* @param p_msg A pointer to the flow object to validate
* @return error code
*/
bcmos_errno sw_util_flow_info_validate(void *p_msg)
{
bcmbal_flow_cfg *p_flow = (bcmbal_flow_cfg *)p_msg;
bcmos_errno ret = BCM_ERR_OK;
if (p_flow == NULL)
{
BCM_LOG(ERROR, log_id_sw_util,
" No flow specified during validation\n" );
return BCM_ERR_PARM;
}
else
{
BCM_LOG(INFO, log_id_sw_util,
" Got a flow request - flow_id=%d sub_port=%d svc_id=%d, attr_mask=0x%x\n",
p_flow->key.flow_id, p_flow->data.access_int_id,
p_flow->data.svc_port_id, (unsigned int)p_flow->hdr.hdr.presence_mask);
sw_util_flow_dump_classifier(p_flow);
if (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM)
sw_util_flow_dump_sla(p_flow);
}
/* validate the NNI range */
if((BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id)) &&
(BCMOS_FALSE == bcm_topo_nni_is_valid(p_flow->data.network_int_id )) )
{
uint32_t max_nni_ports = 0;
#ifndef TEST_SW_UTIL_LOOPBACK
bcm_topo_dev_get_max_nni(bal_bcm_net_inf_dev_get(p_flow->data.network_int_id), &max_nni_ports);
#else
bcm_topo_dev_get_max_nni(0, &max_nni_ports);
#endif
BCM_LOG(ERROR, log_id_sw_util,
" Request network interface %d is out of max range %d\n",p_flow->data.network_int_id, max_nni_ports );
return BCM_ERR_PARM;
}
/* return BCM_ERR_NOT_SUPPORTED for actions that has not yet implemented */
if((BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action)) &&
(p_flow->data.action.cmds_bitmask & NOT_WORKING_ACTION_BITMASK))
{
BCM_LOG(ERROR, log_id_sw_util,
" Request Action Command 0x%x not supported yet\n",p_flow->data.action.cmds_bitmask );
return BCM_ERR_NOT_SUPPORTED;
}
if(BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, classifier))
{
BCM_LOG(ERROR, log_id_sw_util,
" a classifier must be specified in a flow\n" );
ret = BCM_ERR_PARM;
}
else
{
/* ING SDK allows priority range from 0x7fffffff to 0 */
/* Need to check the configuration range if unit32_t is used for the attribute */
/* An outer vid is required in the classifier for all actions that operate on the outer vlan tag */
if(BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid) &&
((BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action)) &&
(p_flow->data.action.cmds_bitmask & OUTER_VLAN_TAG_REQ_BITMASK)))
{
BCM_LOG(ERROR, log_id_sw_util,
" o_vid must be specified when actions requiring an outer vlan tag is specified\n" );
ret = BCM_ERR_PARM;
}
/*An outer vid must be specified when an inner vid is specified */
if((BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid)) &&
(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid)))
{
BCM_LOG(ERROR, log_id_sw_util,
" o_vid must be specified when i_vid is specified\n" );
ret = BCM_ERR_PARM;
}
/* Check that user has specified pbits when the action is pbit remarking */
if((BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action)) &&
(p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_REMARK_PBITS) )
{
if((BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid)) ||
(BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.action, action, o_pbits)) )
{
BCM_LOG(ERROR, log_id_sw_util,
" o_vid in classifier and o_pibts in action must be specified when outer pbit remarking is specified\n" );
ret = BCM_ERR_PARM;
}
}
/* Check that the user has specified a valid packet tag type given the o_vid and i_vid choices (if any)*/
if(((BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid)) ||
(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid))))
{
if((BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type)) ||
((BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type)) &&
(BCMBAL_PKT_TAG_TYPE_UNTAGGED == p_flow->data.classifier.pkt_tag_type)))
{
BCM_LOG(ERROR, log_id_sw_util,
" pkt_tag_type must be either SINGLE or DOUBLE tagged when o_vid or i_vid are specified\n" );
ret = BCM_ERR_PARM;
}
}
else
{
/* If the pkt_tag_type is not specified OR the pkt_tag_type is not UNTAGGED (and it's not destined
* to the host CPU), then it's an error
*/
if(!(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action) &&
(p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST)))
{
if(BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type) ||
(!(BCMBAL_PKT_TAG_TYPE_UNTAGGED == p_flow->data.classifier.pkt_tag_type)))
{
BCM_LOG(ERROR, log_id_sw_util,
" pkt_tag_type must be UNTAGGED when neither o_vid nor i_vid are specified\n" );
ret = BCM_ERR_PARM;
}
}
}
/* Now test the multicast flow cases */
if (BCMOS_TRUE == (BCMBAL_FLOW_TYPE_MULTICAST == p_flow->key.flow_type))
{
if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action) &&
(p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST))
{
BCM_LOG(ERROR, log_id_sw_util, " A multicast flow must not terminate in the host\n");
ret = BCM_ERR_PARM;
}
/* A Multicast flow must have a group_id that is valid (i.e. an active group) */
if(BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, group_id))
{
BCM_LOG(ERROR, log_id_sw_util, " A multicast flow must have a specified group_id\n");
ret = BCM_ERR_PARM;
}
else
{
/* Now check that the referenced group is valid */
bcmbal_group_key group_key = { .group_id = p_flow->data.group_id };
bcmbal_group_owner group_owner;
/* make sure the group owner is multicast */
if(BCM_ERR_OK == group_owner_get(group_key, &group_owner))
{
if ( BCMBAL_GROUP_OWNER_MULTICAST != group_owner)
{
BCM_LOG(ERROR, log_id_sw_util,
" A multicast flow must have group owner of type Multicast, group_id:%d\n",
group_key.group_id);
ret = BCM_ERR_PARM;
}
}
else
{
BCM_LOG(ERROR, log_id_sw_util,
" A multicast flow must have an valid group_id (Active group_id:%d not found)\n",
group_key.group_id);
ret = BCM_ERR_PARM;
}
}
}
/* check N:1 service Group Owner to be UNICAST */
if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, group_id) &&
(BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow->key.flow_type ||
BCMBAL_FLOW_TYPE_UPSTREAM == p_flow->key.flow_type )
)
{
/* Now check that the referenced group is valid */
bcmbal_group_key group_key = { .group_id = p_flow->data.group_id };
bcmbal_group_owner group_owner;
/* make sure the group owner is unicast */
if(BCM_ERR_OK == group_owner_get(group_key, &group_owner))
{
if ( BCMBAL_GROUP_OWNER_UNICAST != group_owner)
{
BCM_LOG(ERROR, log_id_sw_util,
" A N:1 flow must have group owner of type unicast, group_id:%d\n",
group_key.group_id);
ret = BCM_ERR_PARM;
}
}
else
{
BCM_LOG(ERROR, log_id_sw_util,
" A N:1 flow must have an valid group_id (Active group_id:%d not found)\n",
group_key.group_id);
ret = BCM_ERR_PARM;
}
}
}
return ret;
}
/* Below local functions are used for real logic only */
#ifndef TEST_SW_UTIL_LOOPBACK
/**
* @brief The flow add function program the switch to forward packets that have
* specified attributes to the designated ports.
* The packets is modified before egress
* On the downstream, an access id (outer vlan tag) is added to the packets
* On the upstream, outer vlan tag (access id) is removed from the packets
*
* @param p_flow_inst A pointer to the flow instance being referenced
* @return error code
*/
static bcmos_errno bal_sw_util_flow_add(flow_inst *p_flow_inst)
{
bcmbal_flow_cfg *p_flow = &p_flow_inst->api_req_flow_info;
bcmos_errno ret = BCM_ERR_OK;
int unit;
uint32_t dev_type;
bcmbal_iwf_mode iwf_mode;
BCM_LOG(INFO, log_id_sw_util,
" Got a flow request - flow_id=%d sub_port=%d svc_id=%d\n",
p_flow->key.flow_id, p_flow->data.access_int_id, p_flow->data.svc_port_id);
unit = bal_bcm_pon_inf_dev_get(p_flow->data.access_int_id);
dev_type = bal_bcm_dev_type_get(unit);
iwf_mode = bal_bcm_iwf_mode_get();
/* call the flow add function based on device type */
if (dev_type == BCM_DEVICE_KT2)
{
ret = bal_sw_util_esw_flow_add(iwf_mode, p_flow);
}
else if (dev_type == BCM_DEVICE_ARAD || dev_type == BCM_DEVICE_ARAD_PLUS || dev_type == BCM_DEVICE_QAX)
{
ret = bal_sw_util_dpp_flow_add(iwf_mode, p_flow);
}
else
{
BCM_LOG(ERROR, log_id_sw_util, " Unknown device type found on flow add: 0x%x\n", dev_type );
ret = BCM_ERR_INTERNAL;
}
BCM_LOG(INFO, log_id_sw_util, " Return flow add request with %d on device 0x%x\n", ret, dev_type );
return ret;
}
/**
* @brief The flow remove function program switch to release resource that have
* been allocated during the flow add operation.
*
* @param p_flow_inst A pointer to the flow instance being referenced
* @return error code
*/
static bcmos_errno bal_sw_util_flow_remove(flow_inst *p_flow_inst)
{
bcmbal_flow_cfg *p_flow = &p_flow_inst->api_req_flow_info;
bcmos_errno ret = BCM_ERR_OK;
int unit;
uint32_t dev_type;
bcmbal_iwf_mode iwf_mode;
BCM_LOG(INFO, log_id_sw_util,
" Got a flow remove request - flow_id=%d sub_port=%d svc_id=%d\n",
p_flow->key.flow_id, p_flow->data.access_int_id, p_flow->data.svc_port_id);
unit = bal_bcm_pon_inf_dev_get(p_flow->data.access_int_id);
dev_type = bal_bcm_dev_type_get(unit);
iwf_mode = bal_bcm_iwf_mode_get();
/* call the flow add function based on device type */
if (dev_type == BCM_DEVICE_KT2)
{
ret = bal_sw_util_esw_flow_remove(iwf_mode, p_flow);
}
else if (dev_type == BCM_DEVICE_ARAD || dev_type == BCM_DEVICE_ARAD_PLUS || dev_type == BCM_DEVICE_QAX)
{
ret = bal_sw_util_dpp_flow_remove(iwf_mode, p_flow);
}
else
{
BCM_LOG(ERROR, log_id_sw_util, " Unknown device type found on flow remove: 0x%x\n", dev_type );
ret = BCM_ERR_INTERNAL;
}
BCM_LOG(INFO, log_id_sw_util, " Return flow remove request with %d on device 0x%x\n", ret, dev_type );
return ret;
}
/**
* @brief The flow list init function prepare a link list to keep track of flows in the switch util
*
* @return error code
*/
static bcmos_errno bal_sw_util_flow_list_init(void)
{
TAILQ_INIT(&g_swutil_flow_list);
return BCM_ERR_OK;
}
/**
* @brief The flow list finish function release all resources allocated in the flow list
*
* @return error code
*/
static bcmos_errno bal_sw_util_flow_list_finish(void)
{
bal_sw_flow *current_entry, *p_temp_entry;
/* Free all the entries in the list */
TAILQ_FOREACH_SAFE(current_entry,
&g_swutil_flow_list,
flow_next,
p_temp_entry)
{
/* Remove it from the list */
TAILQ_REMOVE(&g_swutil_flow_list, current_entry, flow_next);
bcmos_free(current_entry);
}
return BCM_ERR_OK;
}
/**
* @brief The flow list search function by flow id
*
* @param id Flow id that need to match the entry in the list
* @return pointer to an element in the list
*/
bal_sw_flow *bal_sw_util_flow_list_get_by_id(uint32_t id)
{
bal_sw_flow *p_entry, *p_temp;
TAILQ_FOREACH_SAFE(p_entry, &g_swutil_flow_list, flow_next, p_temp)
{
if( p_entry->id == id)
{
break;
}
}
/* if reach the end of the list, TAILQ_FOREACH_SAFE set the p_entry to NULL */
return p_entry;
}
/**
* @brief The flow list search function by flow id
*
* @param trap_code Trap id that need to match the entry in the list
* @return pointer to an element in the list
*/
bal_sw_flow *bal_sw_util_flow_list_get_by_trap_code(uint32_t trap_code)
{
bal_sw_flow *p_entry, *p_temp;
if (trap_code == 0)
{
BCM_LOG(WARNING, log_id_sw_util, "Invalid trap code %d in Flow list search by trap code\n", trap_code);
return NULL;
}
TAILQ_FOREACH_SAFE(p_entry, &g_swutil_flow_list, flow_next, p_temp)
{
if( p_entry->trap_code == trap_code)
{
break;
}
}
/* if reach the end of the list, TAILQ_FOREACH_SAFE set the p_entry to NULL */
return p_entry;
}
/*
* @brief The flow list insert function
*
* @param entry the element to be added in the link list
* @return error code
*/
bcmos_errno bal_sw_util_flow_list_insert(bal_sw_flow entry)
{
bal_sw_flow *p_new_entry;
p_new_entry = bcmos_calloc(sizeof(bal_sw_flow));
if(NULL == p_new_entry)
{
BCM_LOG(ERROR, log_id_sw_util, "Flow list insert out of memory\n");
return BCM_ERR_NOMEM;
}
*p_new_entry = entry;
TAILQ_INSERT_TAIL(&g_swutil_flow_list, p_new_entry, flow_next);
return BCM_ERR_OK;
}
/*
* @brief The flow list remove function
*
* @param p_entry Pointer to the element in the link list result from one of the search functions
* @return error code
*/
bcmos_errno bal_sw_util_flow_list_remove(bal_sw_flow *p_entry)
{
TAILQ_REMOVE(&g_swutil_flow_list, p_entry, flow_next);
bcmos_free(p_entry);
return BCM_ERR_OK;
}
/*
* @brief down Stream Flow classifier check to see if an ACL rule is needed for classification
*
* In ING SDK, vswitch LIF is mostly used to classify VLAN and ingress port only.
* Any packet classification more than that requires an ACL rule to filter the
* traffics. This routine check if an ACL is needed.
* If only VLAN ids are classify, return FALSE, otherwise return TRUE
*
* @param p_flow Pointer to the flow object that contains the classifier
* @return TRUE or FALSE
*/
bcmos_bool bal_sw_util_flow_ds_acl_cls_chk(bcmbal_flow_cfg *p_flow)
{
if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ether_type) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ip_proto) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_port) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_port) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_pbits) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_pbits) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_mac) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_mac) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_ip) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_ip)
)
return BCMOS_TRUE;
else
return BCMOS_FALSE;
}
/*
* @brief Up Stream Flow classifier check to see if an ACL rule is needed for classification
*
* In ING SDK, vswitch LIF is mostly used to classify VLAN and ingress port only.
* Any packet classification more than that requires an ACL rule to filter the
* traffics. This routine check if an ACL is needed.
* If only VLAN ids are classify, return FALSE, otherwise return TRUE
*
* @param p_flow Pointer to the flow object that contains the classifier
* @return TRUE or FALSE
*/
bcmos_bool bal_sw_util_flow_us_acl_cls_chk(bcmbal_flow_cfg *p_flow)
{
/* Up Stream Outer Pbits classification is done using PON LIF, no need to use ACL */
if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ether_type) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ip_proto) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_port) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_port) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_pbits) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_mac) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_mac) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_ip) ||
BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_ip)
)
return BCMOS_TRUE;
else
return BCMOS_FALSE;
}
static uint32_t g_flow_inited = 0;
#endif /* #ifndef TEST_SW_UTIL_LOOPBACK */
/**
* @brief SWITCH module: flow SET handler
*
* This routine is called by flow_fsm in the BAL core upon
* SET request for flow object.
*
* @param p_flow Pointer to flow instance
* @param opt_type Operation type on flow instance
*
* @return bcmos_errno
*/
bcmos_errno sw_util_flow_set(flow_inst *p_flow, bal_util_oper_flow opt_type)
{
bcmos_errno ret = BCM_ERR_OK;
#ifndef TEST_SW_UTIL_LOOPBACK
bal_sw_util_vsi_list_init();
if (opt_type == BAL_UTIL_OPER_FLOW_ADD)
{
if (g_flow_inited == 0)
{
/* initialized the internal flow link list */
bal_sw_util_flow_list_init();
/* call flow_init in switch device */
bal_sw_util_dpp_flow_init();
g_flow_inited = 1;
}
ret = bal_sw_util_flow_add(p_flow);
}
else if( BAL_UTIL_OPER_FLOW_REMOVE == opt_type )
{
ret = bal_sw_util_flow_remove(p_flow);
}
else if( BAL_UTIL_OPER_FLOW_CLEAR == opt_type )
{
ret = bal_sw_util_flow_remove(p_flow);
}
else
{
BCM_LOG(ERROR, log_id_sw_util, "Only ADD/REMOVE/CLEAR request is supported for FLOW object\n");
return BCM_ERR_NOT_SUPPORTED;
}
#else
BCM_LOG(INFO, log_id_sw_util, "dummy flow %s SUCCESS\n",
( BAL_UTIL_OPER_FLOW_ADD == opt_type ) ? "flow add" : "flow remove");
#endif
return ret;
}
/**
* @brief SWITCH module: flow clean up function
*
* This routine is called by bal_switch_util() when the BAL core issue finish request
*
* @return bcmos_errno
*/
bcmos_errno sw_util_flow_finish()
{
bcmos_errno ret = BCM_ERR_OK;
#ifndef TEST_SW_UTIL_LOOPBACK
if (g_flow_inited )
{
/* release the internal flow link list */
bal_sw_util_flow_list_finish();
g_flow_inited = 0;
}
#endif
return ret;
}
/*@}*/