955 lines
28 KiB
C
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 */
|