Files
m241Neelima/components/ip_net2-6.9/ipcom/src/ipcom_forwarder_svlan.c
T
2026-07-30 11:19:44 +05:30

955 lines
28 KiB
C

/* ipcom_forwarder_svlan.c - VLAN stacking on NAE routines */
/*
* Copyright (c) 2010 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement. No license to Wind River intellectual property rights
* is granted herein. All rights not licensed by Wind River are reserved
* by Wind River.
*/
/*
modification history
--------------------
01f,18nov10,tlu Inline optimization
01e,20oct10,tlu Optimized: memcopy, record egress tagged ports and preformt
S-VLAN & C-VLAN at config time
01d,14sep10,tlu Optimize S-VLAN code
01c,08jul10,tlu Added VLAN and VID filtering on Nehalem NAE
01b,15jun10,tlu Added S-VLAN to Nehalem NAE
01a,10nov09,tlu Created.
*/
/*
****************************************************************************
* DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* CONFIGURATION
****************************************************************************
*/
#include "ipcom_config.h"
#ifdef IPCOM_USE_FORWARDER_VLAN_STACKING
/*
****************************************************************************
* INCLUDE FILES
****************************************************************************
*/
/* Ipcom include files */
#define IPCOM_USE_CLIB_PROTO
#include "ipcom_type.h"
#include "ipcom_cstyle.h"
#include "ipcom_clib.h"
#include "ipcom_inet.h"
#include "ipcom_forwarder.h"
#include "ipcom_sock.h"
#include "ipcom_syslog.h"
#include <ipcom_forwarder_svlan.h>
#include <ipnet_eth.h>
#include <ipnet_svlan.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define FW_VLAN_MAC_EXPIRE (5*60)
#ifdef IP_PORT_LKM
extern void printk(const char *fmt, ...);
#define ipcom_printf printk
#endif
/* Define the following flag to build debug msg into image */
/* #define FW_VLAN_DEBUG */
#define IPCOM_CACHELINE_SZ 128
#define VLAN_EACH_FWD_TBL_ENTRIES 4096
#define IPCOM_FWD_VLAN_MAC_TBL 4096
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN int ipcom_forwarder_if_hw_port(Ipcom_netif *netif);
#ifdef IPCOM_USE_OCTEON_FORWARDER
IP_EXTERN void *ipcom_svlan_shm_malloc(Ip_size_t size);
IP_EXTERN void ipcom_svlan_shm_free(void *ptr);
IP_EXTERN __inline__ int ipcom_svlan_hw_tx(fw_msg_t *fw_msg, void *fw_cookie);
#endif
#ifdef IPCOM_USE_NEHALEM_FORWARDER
IP_EXTERN __inline__ int ipcom_svlan_pe_hw_tx(fw_msg_t *fw_msg,
void *fw_cookie);
IP_EXTERN __inline__ int ipcom_svlan_s_hw_tx(fw_msg_t *fw_msg, void *fw_cookie);
IP_EXTERN int ipcom_svlan_hw_filter_ioctl(Ipcom_netif *netif,
Ip_u32 command, void *data);
IP_EXTERN int ipcom_svlan_hw_drop_vid(Ipnet_netif *netif);
IP_EXTERN int ipcom_svlan_hw_mark_vid(Ipnet_netif *netif);
#endif
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/* MAC station table: organized as hash table of size 4k entries */
IP_PUBLIC fw_mac_station_t *mac_stations = IP_NULL;
/* Record NAE time */
IP_PUBLIC Ip_time_t svlan_time = 0;
IP_PUBLIC int (*ipcom_forwarder_vlan_hw_tx[MAX_FW_PORTS])
(fw_msg_t *fw_msg, void *fw_cookie);
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_forwarder_reverse
*===========================================================================
* Description: Reverse the number's order
* Parameters:
* Returns:
*
*/
IP_STATIC __inline__ Ip_u16
ipcom_fowarder_reverse(Ip_u16 vid)
{
Ip_u16 rev = 0;
while (vid > 0)
{
rev = (rev << 1) + (vid & 0x1);
vid = vid >> 1;
}
return rev;
}
/*
*===========================================================================
* ipcom_forwarder_get_svlan_fwd_entry
*===========================================================================
* Context:
* Description: Obtain a fwd cache entry
* Parameters:
* Returns: Pointer to matching entry if found, IP_NULL otherwise
*
*/
IP_STATIC fw_cache_entry_vlan_stacking_t *
ipcom_forwarder_get_svlan_fwd_entry(Ipnet_netif *in_netif,
Ip_u16 vid, Ip_u16 svid)
{
Ip_s8 in_port_id;
fw_cache_entry_vlan_stacking_t *evlan = IP_NULL;
#ifdef SVLAN_SC_FWD_TABLE
Ip_u16 ix = 0;
#endif
/* Get input HW port id */
in_port_id = ipcom_forwarder_if_hw_port(&(in_netif->ipcom));
if (in_port_id == -1)
return IP_NULL;
/* Get the forwarding cache entry */
switch (in_netif->eth->vlan_param.vlan_type)
{
case IPNET_VLAN_CS_VLAN:
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][vid];
break;
case IPNET_VLAN_S_VLAN:
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][svid];
break;
#ifdef SVLAN_SC_FWD_TABLE
case IPNET_VLAN_SC_VLAN:
ix = ipcom_fowarder_reverse(vid) ^ svid;
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][ix];
if (evlan->s_vlan_id != svid)
evlan = IP_NULL;
break;
#endif
default:
break;
}
#ifdef FW_VLAN_DEBUG
ipcom_printf("VLAN stacking entry: evlan %x, tx_ports_num %d\n",
evlan, evlan?evlan->tx_ports_num:0);
#endif
if (evlan && evlan->tx_ports_num)
return evlan;
else
return IP_NULL;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_forwarder_svlan_time
*===========================================================================
* Description: Invoked by NAE events to obtain NAE clock tick and hz
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipcom_forwarder_svlan_time(unsigned long ticks, unsigned hz)
{
svlan_time = ticks/hz;
}
#ifndef SVLAN_SC_FWD_TABLE
/*
*===========================================================================
* ipcom_forwarder_sc_fwd_entry
*===========================================================================
* Description: fill a fwd entry for the pkt
* Parameters:
* Returns:
*
*/
IP_PUBLIC __inline__ void
ipcom_forwarder_sc_fwd_entry(fw_msg_t *msg)
{
Ip_u8 i;
fw_cache_entry_vlan_stacking_t *evlan;
Ip_u16 cvid = msg->ctci & 0x0fff;
#ifdef FW_VLAN_DEBUG
ipcom_printf("sc_fwd_entry: ipprt %d, fw_key %d, cvid %d, stci %d\n",
msg->ipprt, msg->fw_key, cvid, msg->stci);
#endif
msg->evlan = ipcom_calloc(1, sizeof(fw_cache_entry_vlan_stacking_t));
msg->evlan->s_vlan_id = msg->fw_key;
msg->evlan->c_vlan_tag = ip_htonl((IP_VLAN << 16) + cvid);
msg->evlan->s_vlan_tag = ip_htonl((ipcom_fw->vlan_s_tpid<<16)+msg->fw_key);
for (i = 0; i < MAX_FW_PORTS; i++)
{
if ((ipcom_fw->port_type[i] & IPCOM_FWD_VLAN_PORT_CS) &&
ipcom_fw->fw_cache_tbl_vlan[i])
{
evlan = (fw_cache_entry_vlan_stacking_t *)
&ipcom_fw->fw_cache_tbl_vlan[i][cvid];
if (evlan->s_vlan_id == msg->fw_key)
{
msg->evlan->tx_ports_num ++;
msg->evlan->tx_ports[i>>5] |= (1 << (i&0x1f));
if (ipcom_fw->rule_flags[i] & IPCOM_FWD_VLAN_ADD_CVLAN)
msg->evlan->port_egress_tagged ++;
#ifdef FW_VLAN_DEBUG
ipcom_printf("sc_fwd_entry: add tx port %d\n", i);
ipcom_printf("sc_fwd_entry: tx_ports_num %d, evlan->tx_ports[0]:[1] %x:%x\n",
msg->evlan->tx_ports_num, msg->evlan->tx_ports[0],
msg->evlan->tx_ports[1]);
#endif
}
}
}
if (msg->evlan->tx_ports_num == 0)
{
ipcom_free(msg->evlan);
msg->evlan = IP_NULL;
}
}
#endif
/*
*===========================================================================
* ipcom_forwarder_svlan_add_cache_entry
*===========================================================================
* Context:
* Description: Add a VLAN stacking cache forwarding entry on NAE
* Parameters: in_netif - The input network port
* vid - The customer VID
* svid - The service VID
* pri_mapping - 8 bytes of priority mapping
* out_netif - The output network port
* Returns:
*
*/
IP_PUBLIC int
ipcom_forwarder_svlan_add_cache_entry(Ipnet_netif *in_netif,
Ip_u16 vid, Ip_u16 svid, Ip_u8 *pri_mapping,
Ipnet_netif *out_netif)
{
int ret = 0;
Ip_s8 in_port_id, out_port_id;
fw_cache_entry_vlan_stacking_t *evlan;
#if defined(SVLAN_SC_FWD_TABLE) || defined(FW_VLAN_DEBUG)
Ip_u16 ix = 0;
#endif
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwarder_svlan_add_cache_entry, in_netif %s, vid %d, svid %d, out_netif %s\n",
in_netif->ipcom.name, vid, svid, out_netif->ipcom.name);
#endif
if (!ipcom_forwarder_is_master())
/* Only create cache entry on the master NAE */
return 0;
/* Get input and output HW port id */
in_port_id = ipcom_forwarder_if_hw_port(&(in_netif->ipcom));
if (in_port_id == -1)
return -1;
out_port_id = ipcom_forwarder_if_hw_port(&(out_netif->ipcom));
if (out_port_id == -1)
return -1;
/* Get the forwarding cache entry */
switch (in_netif->eth->vlan_param.vlan_type)
{
case IPNET_VLAN_CS_VLAN:
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][vid];
break;
case IPNET_VLAN_S_VLAN:
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][svid];
break;
#ifdef SVLAN_SC_FWD_TABLE
case IPNET_VLAN_SC_VLAN:
ix = ipcom_fowarder_reverse(vid) ^ svid;
evlan = &ipcom_fw->fw_cache_tbl_vlan[in_port_id][ix];
if (evlan->s_vlan_id && evlan->s_vlan_id != svid)
{
IPCOM_LOG2(ERR, "SC fast fowarder collision, svid %d, vid %d\n",
svid, vid);
return -1;
}
break;
#endif
default:
return 0;
}
#ifdef FW_VLAN_DEBUG
ipcom_printf("VLAN stacking entry: evlan %x, in_p_id %d, out_p_id %d, ix %d\n",
evlan, in_port_id, out_port_id, ix);
#endif
/* Record the output port and svid */
evlan->tx_ports[out_port_id>>5] |= (1 << (out_port_id&0x1f));
evlan->s_vlan_id = svid;
switch (in_netif->eth->vlan_param.vlan_type)
{
case IPNET_VLAN_CS_VLAN:
/* input is a customer edge/network port on provider edge node */
/* record priority mapping */
*(Ip_u64 *)(evlan->pri_mapping) = *(Ip_u64 *)pri_mapping;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Mark vid in VLAN filter table */
ret = ipcom_svlan_hw_filter_ioctl(&(in_netif->ipcom),
IP_SIOCXETHSVIDFILTER,
&vid);
if (ret)
IPCOM_LOG1(ERR,
"ipcom_forwarder_svlan_add_cache_entry: fail to mark vid %d\n",
vid);
#endif
break;
default:
break;
}
if (in_netif->eth->vlan_param.vlan_type != IPNET_VLAN_S_VLAN)
{
if ((evlan->c_vlan_tag == 0) && (evlan->s_vlan_tag == 0))
{
/* pre-format the C-VLAN and S-VLAN tags */
evlan->c_vlan_tag = ip_htonl((IP_VLAN << 16) + vid);
/* format S-VLAN tag without mapped priority */
evlan->s_vlan_tag = ip_htonl((ipcom_fw->vlan_s_tpid << 16) + svid);
}
/* record port egress tagged */
if (out_netif->eth->vlan_param.egress_rule == IPNET_VLAN_EGRESS_TAGGED)
evlan->port_egress_tagged++;
}
/* Increment the number of the output ports */
evlan->tx_ports_num ++;
#ifdef FW_VLAN_DEBUG
ipcom_printf("Add to VLAN stacking entry: evlan %x, tx_ports_num %d\n",
evlan, evlan->tx_ports_num);
#endif
return ret;
}
/*
*===========================================================================
* ipcom_forwarder_svlan_del_cache_entry
*===========================================================================
* Context:
* Description: Delete a VLAN stacking cache forwarding entry on NAE
* Parameters: in_netif - The input network port
* vid - The customer VID
* svid - The service VID
* out_netif - The output network port
* Returns:
*
*/
IP_PUBLIC int
ipcom_forwarder_svlan_del_cache_entry(Ipnet_netif *in_netif,
Ip_u16 vid, Ip_u16 svid,
Ipnet_netif *out_netif)
{
int ret = 0, i;
Ip_s8 in_port_id, out_port_id;
fw_cache_entry_vlan_stacking_t *evlan = IP_NULL;
fw_mac_station_t *station;
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwarder_svlan_del_cache_entry, in_netif %s, vid %d, svid %d, out_netif %s\n",
in_netif->ipcom.name, vid, svid,
out_netif?out_netif->ipcom.name:"NULL");
#endif
/* Get input HW port id */
in_port_id = ipcom_forwarder_if_hw_port(&(in_netif->ipcom));
if (in_port_id == -1) return -1;
if (!ipcom_forwarder_is_master())
/* Only delete cache entry on the master NAE */
goto free_mac_stations;
/* Get output HW port id */
out_port_id = ipcom_forwarder_if_hw_port(&(out_netif->ipcom));
if (out_port_id == -1) return -1;
/* Get the forward cache entry for VLAN stacking */
evlan = ipcom_forwarder_get_svlan_fwd_entry(in_netif, vid, svid);
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwarder_svlan_del_cache_entry, evlan %x\n", evlan);
#endif
if (evlan && (evlan->tx_ports[out_port_id>>5] & (1 << (out_port_id&0x1f))))
{
/* Clear the tx port */
evlan->tx_ports[out_port_id>>5] &= ~(1 << (out_port_id&0x1f));
if ((evlan->tx_ports[0] == 0) && (evlan->tx_ports[1] == 0))
/* Invalidate the fwd cache entry */
ipcom_memset(evlan, 0, sizeof(fw_cache_entry_vlan_stacking_t));
else
{
/* Decrements the tx port number */
evlan->tx_ports_num --;
/* Decrements the egress tagged port number */
if ((in_netif->eth->vlan_param.vlan_type != IPNET_VLAN_S_VLAN) &&
(out_netif->eth->vlan_param.egress_rule ==
IPNET_VLAN_EGRESS_TAGGED))
evlan->port_egress_tagged++;
}
}
#ifdef IPCOM_USE_NEHALEM_FORWARDER
if (in_netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
{
/* Clr vid in VLAN filter table */
ret = ipcom_svlan_hw_filter_ioctl(&(in_netif->ipcom),
IP_SIOCXETHCVIDFILTER,
&vid);
if (ret)
IPCOM_LOG1(ERR,
"ipcom_forwarder_svlan_del_cache_entry: fail to clr vid %d\n", vid);
}
#endif
/* Free MAC stations */
free_mac_stations:
if (mac_stations && evlan && (evlan->tx_ports_num == 0))
{
/* search the MAC station table */
for (i = 0, station = &(mac_stations[0]);
i < IPCOM_FWD_VLAN_MAC_TBL;
i++, station++)
{
if ((*(Ip_u16 *)(&(station->macAddr_svid[6])) == svid) &&
(station->ipprt == in_port_id))
{
/* invalidate station entry */
*(Ip_u16 *)(&(station->macAddr_svid[6])) = station->ipprt = 0;
}
}
}
return ret;
}
/*
*===========================================================================
* ipcom_forwarder_svlan_update_config
*===========================================================================
* Context:
* Description: Set/Update VLAN stacking configuration on NAE
* Parameters:
* Returns:
*
*/
IP_PUBLIC int
ipcom_forwader_svlan_update_config(unsigned long request,
struct Ip_vlanreq *vlan_req, Ip_u8 old_rule,
Ipnet_netif *netif)
{
int ret = 0;
int port_id, i, j;
fw_cache_entry_vlan_stacking_t *evlan;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
Ip_u16 vid = 0;
#endif
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_update_config, netif %s\n",
netif?netif->ipcom.name:"NULL");
#endif
if (!ipcom_forwarder_is_master())
/* Only modify ipcom_fw and cache entry on the master NAE */
return 0;
if (request == IP_SIOCSETSTPID)
{
/* Reset STPID */
ipcom_fw->vlan_s_tpid_net = vlan_req->vlr_stpid;
ipcom_fw->vlan_s_tpid = ip_ntohs(ipcom_fw->vlan_s_tpid_net);
/* Update stpid in fast fwd cache entries */
for (i = 0; i < MAX_FW_PORTS; i++)
{
if (ipcom_fw->fw_cache_tbl_vlan[i] &&
(ipcom_fw->port_type[i] == IPCOM_FWD_VLAN_PORT_CS))
{
/* Port i is configured as CS-VLAN port */
for (j = 0; j < VLAN_EACH_FWD_TBL_ENTRIES; j++)
{
evlan = &(ipcom_fw->fw_cache_tbl_vlan[i][j]);
if (evlan->tx_ports_num)
evlan->s_vlan_tag = ip_htonl(
(ipcom_fw->vlan_s_tpid<<16)+evlan->s_vlan_id);
}
}
}
return ret;
}
/* Get HW port id */
port_id = ipcom_forwarder_if_hw_port(&(netif->ipcom));
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_upd_config, port_id %d\n", port_id);
#endif
if (port_id == -1)
return -1;
switch (request)
{
case IP_SIOCSETVLANPVID:
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_upd_config(SETPVID)\n");
#endif
/* Reset port VID */
ipcom_fw->hw_pvid[port_id] = vlan_req->vlr_tag;
break;
case IP_SIOCSETVLANPRIMAP:
/* Reset VLAN priority mapping on a customer edge/network port */
/* Modify a VLAN stacking forward cache entry */
/* Get the forward cache entry for VLAN stacking */
evlan = ipcom_forwarder_get_svlan_fwd_entry(netif, vlan_req->vlr_tag,
vlan_req->vlr_stag);
if (evlan)
{
/* Modify the priority mapping */
evlan->pri_mapping[vlan_req->vlr_pri&0x07] = vlan_req->vlr_spri&0x07;
}
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_upd_config(SETPRI), pri %d, spri\n",
vlan_req->vlr_pri&0x07,
evlan->pri_mapping[vlan_req->vlr_pri&0x07]);
#endif
break;
case IP_SIOCSETVLANINRULE:
/* Reset VLAN ingress rule */
/* Modify a VLAN stacking forward cache entry */
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_upd_config(SETIN), old_ir %d, new_ir %d\n",
old_rule, vlan_req->vlr_inrule);
#endif
switch (old_rule)
{
case IPNET_VLAN_INGRESS_ADMIT_ALL:
if (vlan_req->vlr_inrule == IPNET_VLAN_INGRESS_ADMIT_TAG)
{
/* Mark port-level drop_no_vid bit */
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_DROP_NO_VID;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Clr VID 0 filter */
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom),
IP_SIOCXETHCVIDFILTER, &vid);
#endif
}
else
{
/* Admit-all to Admit-other */
/* Mark port-level drop_vid bit */
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_DROP_VID;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
ipcom_svlan_hw_drop_vid(netif);
#endif
}
break;
case IPNET_VLAN_INGRESS_ADMIT_TAG:
if (vlan_req->vlr_inrule == IPNET_VLAN_INGRESS_ADMIT_ALL)
{
/* Clear/Un-mark port-level drop_no_vid bit */
ipcom_fw->rule_flags[port_id] &= ~IPCOM_FWD_VLAN_DROP_NO_VID;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Set VID 0 filter */
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom),
IP_SIOCXETHSVIDFILTER, &vid);
#endif
}
else
{
/* Reset to OTHER: */
/* Clear/Un-mark port-level drop_no_vid bit */
/* Mark port-level drop_vid bit */
ipcom_fw->rule_flags[port_id] &= ~IPCOM_FWD_VLAN_DROP_NO_VID;
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_DROP_VID;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
ipcom_svlan_hw_drop_vid(netif);
#endif
}
break;
case IPNET_VLAN_INGRESS_ADMIT_OTHER:
if (vlan_req->vlr_inrule == IPNET_VLAN_INGRESS_ADMIT_ALL)
{
/* Clear/Un-mark port-level drop_vid bit */
ipcom_fw->rule_flags[port_id] &= ~IPCOM_FWD_VLAN_DROP_VID;
}
else
{
/* Reset to ADMIT-TAG: */
/* Mark port-level drop_no_vid bit */
/* Clear/Un-mark port-level drop_vid bit */
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_DROP_NO_VID;
ipcom_fw->rule_flags[port_id] &= ~IPCOM_FWD_VLAN_DROP_VID;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Clr VID 0 filter */
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom),
IP_SIOCXETHCVIDFILTER, &vid);
#endif
}
#ifdef IPCOM_USE_NEHALEM_FORWARDER
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
ipcom_svlan_hw_mark_vid(netif);
#endif
break;
default:
break;
}
break;
case IP_SIOCSETVLANOUTRULE:
/* Reset VLAN egress rule */
/* Modify a VLAN stacking forward cache entry */
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwader_svlan_upd_config(SETOUT), old_or %d\n", old_rule);
#endif
switch (old_rule)
{
case IPNET_VLAN_EGRESS_TAGGED:
/* reset to untagged from tagged */
ipcom_fw->rule_flags[port_id] &= ~IPCOM_FWD_VLAN_ADD_CVLAN;
break;
case IPNET_VLAN_EGRESS_UNTAGGED:
/* reset to tagged from untagged */
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_ADD_CVLAN;
break;
default:
break;
}
/* Update port_egress_tagged in fast fwd cache entries */
for (i = 0; i < MAX_FW_PORTS; i++)
{
if (ipcom_fw->fw_cache_tbl_vlan[i] &&
(ipcom_fw->port_type[i] != ipcom_fw->port_type[port_id]))
{
/* Port i is configured as S-VLAN port and has different type */
for (j = 0; j < VLAN_EACH_FWD_TBL_ENTRIES; j++)
{
evlan = &(ipcom_fw->fw_cache_tbl_vlan[i][j]);
if (evlan->tx_ports[port_id>>5] & (1 << (port_id & 0x1f)))
{
/* port_id is a tx port of the fwd cache entry */
if (old_rule == IPNET_VLAN_EGRESS_TAGGED)
evlan->port_egress_tagged --;
else
evlan->port_egress_tagged ++;
}
}
}
}
break;
default:
break;
}
return ret;
}
/*
*===========================================================================
* ipcom_forwarder_if_set_vlan_stacking
*===========================================================================
* Context: Set the PIP port as VLAN stacking port
* Description:
* Parameters:
* Returns: 0 succeed; < 0 if error.
*
*/
IP_PUBLIC int
ipcom_forwarder_if_set_vlan_stacking(Ipnet_netif *netif)
{
Ip_u8 port_id;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
Ip_bool filter = IP_TRUE;
Ip_u16 vid = 0;
#endif
port_id = ipcom_forwarder_if_hw_port(&(netif->ipcom));
if (!ipcom_forwarder_is_master())
/* Only init cache entry on the master NAE */
goto common_init;
#ifdef FW_VLAN_DEBUG
ipcom_printf("ipcom_forwarder_if_set_vlan_stacking, netif %s, port_id %d, pvid %d\n",
netif->ipcom.name, port_id, netif->eth->vlan_param.id);
#endif
/* Set VLAN stacking port bit mask and record PVID */
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
{
ipcom_fw->port_type[port_id] |= IPCOM_FWD_VLAN_PORT_CS;
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_DEL_SVLAN;
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_PRI_REMAP;
if (netif->eth->vlan_param.egress_rule == IPNET_VLAN_EGRESS_TAGGED)
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_ADD_CVLAN;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Enable H/W VLAN filter */
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom), IP_SIOCXETHSVLANFILTER,
&filter);
/* Set VID 0 filtering: accept priority VLAN pkts (default) */
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom), IP_SIOCXETHSVIDFILTER,
&vid);
#endif
}
else if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_SC_VLAN)
{
ipcom_fw->port_type[port_id] |= IPCOM_FWD_VLAN_PORT_SC;
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_ADD_SVLAN;
if (netif->eth->vlan_param.egress_rule == IPNET_VLAN_EGRESS_TAGGED)
ipcom_fw->rule_flags[port_id] |= IPCOM_FWD_VLAN_ADD_CVLAN;
}
else
ipcom_fw->port_type[port_id] |= IPCOM_FWD_VLAN_PORT_S;
ipcom_fw->hw_pvid[port_id] = IPNET_VLAN_DEFAULT_PVID;
/* Record MAC address */
*(Ip_u32 *)(ipcom_fw->hw_mac[port_id]) =
*(Ip_u32 *)(netif->ipcom.link_addr);
*(Ip_u16 *)(&(ipcom_fw->hw_mac[port_id][4])) =
*(Ip_u16 *)(&(netif->ipcom.link_addr[4]));
/* Allocate fast forwarding table in shared memory */
#ifndef SVLAN_SC_FWD_TABLE
if (netif->eth->vlan_param.vlan_type != IPNET_VLAN_SC_VLAN &&
ipcom_fw->fw_cache_tbl_vlan[port_id] == IP_NULL)
{
#endif
#ifdef IPCOM_USE_OCTEON_FORWARDER
ipcom_fw->fw_cache_tbl_vlan[port_id] =
ipcom_svlan_shm_malloc( VLAN_EACH_FWD_TBL_ENTRIES *
sizeof (fw_cache_entry_vlan_stacking_t));
#elif defined(IPCOM_USE_NEHALEM_FORWARDER)
ipcom_fw->fw_cache_tbl_vlan[port_id] =
ipcom_forwarder_alloc_aligned(ipcom_cache_line_size(),
VLAN_EACH_FWD_TBL_ENTRIES*sizeof(fw_cache_entry_vlan_stacking_t));
#endif
#ifdef FW_VLAN_DEBUG
ipcom_printf("sizeof(fw_cache_entry_vlan_stacking_t): %d\n",
sizeof(fw_cache_entry_vlan_stacking_t));
#endif
if (ipcom_fw->fw_cache_tbl_vlan[port_id] == IP_NULL)
{
IPCOM_LOG0(ERR,"Fail to allocate shm memory(fw_cache_tbl_vlan)\n");
ipcom_forwarder_if_clr_vlan_stacking(netif);
return IPCOM_ERR_NO_MEMORY;
}
#ifndef SVLAN_SC_FWD_TABLE
}
#endif
common_init:
#ifdef IPCOM_USE_NEHALEM_FORWARDER
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_S_VLAN)
ipcom_forwarder_vlan_hw_tx[port_id] = ipcom_svlan_s_hw_tx;
else
ipcom_forwarder_vlan_hw_tx[port_id] = ipcom_svlan_pe_hw_tx;
#endif
#ifdef IPCOM_USE_OCTEON_FORWARDER
ipcom_forwarder_vlan_hw_tx[port_id] = ipcom_svlan_hw_tx;
#endif
/* Init station hash table: allocate 4K entries */
if (!mac_stations)
mac_stations = ipcom_calloc(1, IPCOM_FWD_VLAN_MAC_TBL *
sizeof(fw_mac_station_t));
if (mac_stations == IP_NULL)
{
IPCOM_LOG0(ERR,"Fail to allocate memory (mac_stations)\n");
ipcom_forwarder_if_clr_vlan_stacking(netif);
return -IP_ERRNO_ENOMEM;
}
return 0;
}
/*
*===========================================================================
* ipcom_forwarder_if_clr_vlan_stacking
*===========================================================================
* Context: Clear the port as VLAN stacking port
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipcom_forwarder_if_clr_vlan_stacking(Ipnet_netif *netif)
{
Ip_u8 port_id;
#ifdef IPCOM_USE_NEHALEM_FORWARDER
Ip_bool filter = IP_FALSE;
#endif
/* Clear VLAN stacking port bit mask */
port_id = ipcom_forwarder_if_hw_port(&(netif->ipcom));
if (!ipcom_forwarder_is_master())
/* Only free cache entry on the master NAE */
goto common_free;
#ifdef FW_VLAN_DEBUG
printf("ipcom_forwarder_if_clr_vlan_stacking, netif %s, port_id %d\n",
netif->ipcom.name, port_id);
#endif
ipcom_fw->port_type[port_id] &= ~IPCOM_FWD_VLAN_PORT_STACKING;
ipcom_fw->rule_flags[port_id] = 0;
ipcom_fw->hw_pvid[port_id] = 0;
/* free the fast forwarding table in shared memory */
if (ipcom_fw->fw_cache_tbl_vlan[port_id])
{
#ifdef IPCOM_USE_OCTEON_FORWARDER
ipcom_svlan_shm_free(ipcom_fw->fw_cache_tbl_vlan[port_id]);
#elif defined(IPCOM_USE_NEHALEM_FORWARDER)
ipcom_fw_cpu_mem_free(ipcom_fw->fw_cache_tbl_vlan[port_id]);
#endif
ipcom_fw->fw_cache_tbl_vlan[port_id] = IP_NULL;
}
#ifdef IPCOM_USE_NEHALEM_FORWARDER
/* Disable VLAN filter */
if (netif->eth->vlan_param.vlan_type == IPNET_VLAN_CS_VLAN)
ipcom_svlan_hw_filter_ioctl(&(netif->ipcom), IP_SIOCXETHSVLANFILTER,
&filter);
#endif
common_free:
ipcom_forwarder_vlan_hw_tx[port_id] = IP_NULL;
}
#else
int ipcom_forwarder_svlan_empty_file;
#endif /* IPCOM_USE_FORWARDER_VLAN_STACKING */