/* 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 #include #include /* **************************************************************************** * 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 */