/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name$ $RCSfile$ $Revision$ * $Source$ * $Author$ * $State$ $Locker$ * * INTERPEAK_COPYRIGHT_STRING ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #define IPCOM_FORWARDER_CTRL_C #define IPCOM_FORWARDER_C #include #if defined(IPCOM_USE_FORWARDER) && !defined(IP_PORT_UNIX) /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ /* #define FW_DEBUG */ /* Ipcom include files */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IPIPSEC2 #include #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #ifdef IPCOM_SYSLOG_ENABLE #undef IPCOM_SYSLOG_ENABLE #define IPCOM_SYSLOG_ENABLE(x) (1) #endif #ifdef IPCOM_SYSLOG_FACILITY #undef IPCOM_SYSLOG_FACILITY #endif #define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPCOM #ifdef IPCOM_SYSLOG_PRIORITY #undef IPCOM_SYSLOG_PRIORITY #endif #define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_ERR #define IPCOM_FORWARDER_PIPE_SIZE (50) #define IPCOM_FORWARDER_MAX_TASKNAME_LEN (10) #define IPCOM_FORWARDER_OVERWRITE_MAX (10000) #define IPCOM_FORWARDER_MAX_PACKETS_QUEUED (256 * 4) #define SADDR_V4_OFFSET(p) ((Ip_u32 *)p + 3) #define DADDR_V4_OFFSET(p) ((Ip_u32 *)p + 3 + 1) #define ADDR_V4_OFFSET(p) ((Ip_u64 *)(SADDR_V4_OFFSET(p))) #define SADDR_V6_OFFSET(p) ((Ip_u8 *)p + 8) #define DADDR_V6_OFFSET(p) ((Ip_u8 *)p + 8 + 16) #define DADDR_V6_OFFSET0(p) ((Ip_u64 *)((Ip_u8 *)p + 8 + 16)) #define DADDR_V6_OFFSET1(p) ((Ip_u64 *)((Ip_u8 *)p + 8 + 16 + 8)) /* Rikards new defines */ #define IS_IPV4(p) ((((Ip_u8 *)p)[0] >> 4) == 4) #define IS_IPV6(p) ((((Ip_u8 *)p)[0] >> 4) == 6) #define GET_IPV(p) (((Ip_u8 *)p)[0] >> 4) #define SET_IPV(p, v) (((Ip_u8 *)p)[0] = (v << 4)) #define ETH_TYPE(p) (((Ip_u16 *)p)[-1]) #define GET_V4_HDR_SZ(p) ((((Ip_u8 *)p)[0] & 0xf) << 2) #define GET_V4_TTL(p) ((Ip_u8 *)p)[8] #define SET_V4_TTL(p, t) (((Ip_u8 *)p)[8] = t) #define GET_V4_PROTO(p) ((Ip_u8 *)p)[9] #define GET_V4_CHKSUM(p) ip_ntons(((Ip_u16 *)p)[5]) #define SET_V4_CHKSUM(p, a) (((Ip_u16 *)p)[5] = ip_htons(a)) #define GET_V6_HOPL(p) ((Ip_u8 *)p)[7] #define SET_V6_HOPL(p, t) (((Ip_u8 *)p)[7] = t) #define SPORT_V4_OFFSET(p) ((Ip_u8 *)p + GET_V4_HDR_SZ(p)) #define DPORT_V4_OFFSET(p) ((Ip_u8 *)p + GET_V4_HDR_SZ(p) + 2) /* VLAN */ #define VLAN_TAG_SZ (4) #define VLAN_TAG(p) (((Ip_u16 *)(p))[0]) #define VLAN_ETH_TYPE(p) (((Ip_u16 *)p)[1]) #define SADDR_VLAN_V4_OFFSET(p) ((Ip_u32 *)p + 1 + 3) #define DADDR_VLAN_V4_OFFSET(p) ((Ip_u32 *)p + 1 + 3 + 1) #define SADDR_VLAN_V6_OFFSET(p) ((Ip_u8 *)p + 4 + 8) #define DADDR_VLAN_V6_OFFSET(p) ((Ip_u8 *)p + 4 + 8 + 16) #define IP_V6_EQ(a, b) ((((Ip_u32 *)a)[0] == ((Ip_u32 *)b)[0]) && (((Ip_u32 *)a)[1] == ((Ip_u32 *)b)[1]) && (((Ip_u32 *)a)[2] == ((Ip_u32 *)b)[2]) && (((Ip_u32 *)a)[3] == ((Ip_u32 *)b)[3])) #ifdef IP_PORT_LKM extern void printk(const char *fmt, ...); #define ipcom_printf printk #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* In ipcom_config.c */ IP_EXTERN void ipcom_forwarder_startup_delay(void); IP_EXTERN int ipcom_forwarder_get_fwcache_util_level_limit(void); IP_EXTERN void *ipcom_allocate_fw_cache(int entry_size, int *entries); IP_EXTERN void *ipcom_forwarder_netif_to_port_cookie(Ipcom_netif *netif); /* In ipcom_cmd_fwctrl.c */ IP_EXTERN void ipcom_forwarder_cmd_add(void); #ifdef IPIPSEC_USE_DAEMONS IP_GLOBAL Ipnet_sig *ipipsec_suspend_daemons(void); IP_GLOBAL void ipipsec_resume_daemons(Ipnet_sig *sig); #endif #if defined(IPCOM_FORWARDER_AMP) || defined(IPCOM_FORWARDER_NAE) IP_EXTERN Ipcom_shared_mem_pool_t * ipcom_shared_mem_pool_for_caller(void); IP_EXTERN int ipcom_forwarder_ifproxy_init(void); #endif #ifdef IPCOM_USE_FORWARDER_VLAN_STACKING IP_EXTERN void ipcom_forwarder_svlan_shm_init(void); #endif /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC int ipcom_forwarder_set_fw_if(Ipcom_pkt *pkt, int port_index); IPCOM_PROCESS(ipcom_forwarder); /* **************************************************************************** * 8 DATA **************************************************************************** */ IP_STATIC Ip_u32 overwrite_cnt = 0; IP_STATIC Ip_u32 skip_packet_cnt = 0; IP_EXTERN int ipcom_forwarder_ipsec_sa_cache_size; IP_STATIC void *tx_port_temp_storage[MAX_FW_PORTS]; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_forwarder_get_v4_update_entry *=========================================================================== * Context: ipnetd * Description: Obtain a cache entry * Parameters: * Returns: Pointer to claimed entry * */ #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS IP_STATIC fw_cache_entry_v4_t * ipcom_forwarder_get_v4_update_entry(fw_cache_entry_v4_t *e4, Ip_u32 addr) { int i; for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (e4[i].ip4.rci == (Ip_u32)*ipcom_fw->rt_cache_id && e4[i].ip4.addr == addr) { /* A valid entry for this flow already exists */ return e4 + i; } } for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (e4[i].ip4.rci != (Ip_u32)*ipcom_fw->rt_cache_id) { /* First unused slot */ if (i) IPCOM_LOGX(DEBUG2, "%s: set %d unused\n"), __FUNCTION__, i IPCOM_ENDX; return e4 + i; } } /* All slots in set are in use => use random slot */ i = (ipcom_random() % IPCOM_FORWARDER_CACHE_WAYS); IPCOM_LOGX(DEBUG2, "%s: set %d used\n"), __FUNCTION__, i IPCOM_ENDX; return e4 + i; } #endif /* *=========================================================================== * ipcom_forwarder_get_v6_update_entry *=========================================================================== * Context: ipnetd * Description: Obtain a cache entry * Parameters: * Returns: Pointer to claimed entry * */ #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS IP_STATIC fw_cache_entry_v6_t * ipcom_forwarder_get_v6_update_entry(fw_cache_entry_v6_t *e6, Ip_u64 *addr) { int i; for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (e6[i].ip6.rci == (Ip_u32)*ipcom_fw->rt_cache_id && #ifdef IPCOM_USE_FORWARDER_VLAN e6->ip6.type == IPCOM_FORWARDER_PACKET_TYPE_IPV6 && #endif e6[i].ip6.addr[0] == addr[0] && e6[i].ip6.addr[1] == addr[1]) { /* A valid entry for this flow already exists */ return e6 + i; } } for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (e6[i].ip6.rci != (Ip_u32)*ipcom_fw->rt_cache_id) { /* First unused slot */ if (i) IPCOM_LOGX(DEBUG2, "%s: set %d unused\n"), __FUNCTION__, i IPCOM_ENDX; return e6 + i; } } /* All slots in set are in use => use random slot */ i = (ipcom_random() % IPCOM_FORWARDER_CACHE_WAYS); IPCOM_LOGX(DEBUG2, "%s: set %d used\n"), __FUNCTION__, i IPCOM_ENDX; return e6 + i; } #endif /* *=========================================================================== * ipcom_forwarder_get_vlan_update_entry *=========================================================================== * Context: ipnetd * Description: Obtain a cache entry * Parameters: * Returns: Pointer to claimed entry * */ #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS #ifdef IPCOM_USE_FORWARDER_VLAN IP_STATIC fw_cache_entry_vlan_t * ipcom_forwarder_get_vlan_update_entry(fw_cache_entry_vlan_t *ev, int vlan_id, Ip_u32 v4addr, Ip_u64 *v6addr) { int i; for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (ev[i].ipvlan.rci == *ipcom_fw->rt_cache_id) { if (!v6addr && ev->ipvlan.type == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN && ev->ipvlan.vlan_id == vlan_id && ev[i].ipvlan.a.addr_v4 == v4addr) { /* A valid entry for this flow already exists */ return ev + i; } else if (v6addr && ev->ipvlan.type == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN && ev->ipvlan.vlan_id == vlan_id && ev[i].ipvlan.a.addr_v6[0] == v6addr[0] && ev[i].ipvlan.a.addr_v6[1] == v6addr[1]) { /* A valid entry for this flow already exists */ return ev + i; } } } for (i = 0; i < IPCOM_FORWARDER_CACHE_WAYS; i++) { if (ev[i].ipvlan.rci != *ipcom_fw->rt_cache_id) { /* First unused slot */ if (i) IPCOM_LOGX(DEBUG2, "%s: set %d unused\n"), __FUNCTION__, i IPCOM_ENDX; return ev + i; } } /* All slots in set are in use => use random slot */ i = (ipcom_random() % IPCOM_FORWARDER_CACHE_WAYS); IPCOM_LOGX(DEBUG2, "%s: set %d used\n"), __FUNCTION__, i IPCOM_ENDX; return ev + i; } #endif #endif /* *=========================================================================== * ipcom_forwarder_set_fw_if *=========================================================================== * Context: ipnetd * Description: Add/update an entry in the IP forwarders cache * Parameters: * Returns: non-zero if a possibly valid entry was overwritten * */ IP_STATIC int ipcom_forwarder_set_fw_if(Ipcom_pkt *pkt, int port_index) { Ip_u32 ix; Ip_u8 *p; fw_cache_entry_v4_t *e4; fw_cache_entry_v6_t *e6; #ifdef IPCOM_USE_FORWARDER_VLAN fw_cache_entry_vlan_t *ev; #endif int fw_ix = port_index; Ip_u8 ipsec; #ifdef IPCOM_USE_FORWARDER_IPSEC fw_ipsec_t fw_ipsec; #endif int ret = 0; #ifdef IPIPSEC_USE_DAEMONS Ipnet_sig *suspend; /* * This function is called by IPNET. The forwarders lock/unlock mechanism requires * the IPSec daemons to be suspended since they may try to lock the forwarders too. */ suspend = ipipsec_suspend_daemons(); if (suspend == IP_NULL) return 0; #endif p = &pkt->data[pkt->start + LL_ETH_HDR_SZ]; /* Point after an initial Ethernet header */ #ifdef IPCOM_USE_FORWARDER_IPSEC ipsec = ipcom_forwarder_ipsec_set_fw_if(p, pkt, ipcom_fw->fw_port[fw_ix].mtu, &fw_ipsec); if (ipsec == IPCOM_FWD_IPSEC_NOCACHE) { #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(suspend); #endif return 0; } if (ipsec == IPCOM_FWD_IPSEC_CLEARTXT) ipcom_memset(&fw_ipsec, 0, sizeof(fw_ipsec)); #else ipsec = IPCOM_FWD_IPSEC_CLEARTXT; #endif /* IPCOM_USE_FORWARDER_IPSEC */ #ifdef IPCOM_FORWARDER_SMP { IP_EXTERN Ip_u16 ipcom_forwarder_get_key_from_pkt(Ipcom_pkt *pkt); #ifdef IPCOM_USE_FORWARDER_IPSEC if (ipsec == IPCOM_FWD_IPSEC_DECRYPT) ix = pkt->nae_key; else #endif ix = ipcom_forwarder_get_key_from_pkt(pkt); } #endif #if defined(IPCOM_FORWARDER_NAE) || defined(IPCOM_FORWARDER_AMP) ix = pkt->nae_key; #endif #define IPCOM_FW_PKT_TYPE(p) *((Ip_u16 *)p - 1) IPCOM_LOG1(DEBUG, "ipcom_forwarder_set_fw_if() :: adding entry, ix=%d", ix); switch(IPCOM_FW_PKT_TYPE(p)) { case ip_htons(IP_IPv4): e4 = &ipcom_fw->fw_cache_tbl_v4[ix]; #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS e4 = ipcom_forwarder_get_v4_update_entry(e4, *DADDR_V4_OFFSET(p)); #endif if (e4->ip4.rci == (Ip_u32)*ipcom_fw->rt_cache_id && e4->ip4.addr != *DADDR_V4_OFFSET(p)) { ret = 4; /* Potential collision */ } IPCOM_LOGX(DEBUG, "%s: added IPv4 entry at index %x(%d)\n"), __FUNCTION__, ix, ix IPCOM_ENDX; e4->ip4.addr = 0; e4->ip4.rci = *ipcom_fw->rt_cache_id; e4->mac_if.dst_mac[0] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - 2); e4->mac_if.dst_mac[1] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ + 2); e4->mac_if.ix[0] = fw_ix; #ifdef IPCOM_USE_PER_PACKET_SRC_MAC ipcom_fw->fw_port[fw_ix].src_type[0] = *(Ip_u32 *)(p - 8); #ifdef IP_BIG_ENDIAN ipcom_fw->fw_port[fw_ix].src_type[1] = (*(Ip_u16 *)(p - 4) << 16) + ip_htons(IP_IPv6); #else ipcom_fw->fw_port[fw_ix].src_type[1] = (ip_htons(IP_IPv6) << 16) + *(Ip_u16 *)(p - 4); #endif #endif e4->mac_if.enc[1] = ipsec; #ifdef IPCOM_USE_FORWARDER_IPSEC ipcom_memcpy(&e4->ipsec, &fw_ipsec, sizeof(fw_ipsec)); #endif e4->ip4.addr = *DADDR_V4_OFFSET(p); break; case ip_htons(IP_IPv6): e6 = &ipcom_fw->fw_cache_tbl_v6[ix]; #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS e6 = ipcom_forwarder_get_v6_update_entry(e6, DADDR_V6_OFFSET0(p)); #endif e6->ip6.addr[0] = 0; e6->ip6.addr[1] = 0; if (e6->ip6.rci == (Ip_u32)*ipcom_fw->rt_cache_id) { ret = 6; } IPCOM_LOGX(DEBUG, "%s: added IPv6 entry at index %x(%d)\n"), __FUNCTION__, ix, ix IPCOM_ENDX; e6->ip6.rci = *ipcom_fw->rt_cache_id; e6->mac_if.dst_mac[0] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - 2); e6->mac_if.dst_mac[1] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ + 2); e6->mac_if.ix[0] = fw_ix; #ifdef IPCOM_USE_PER_PACKET_SRC_MAC ipcom_fw->fw_port[fw_ix].src_type[0] = *(Ip_u32 *)(p - 8); ipcom_fw->fw_port[fw_ix].src_type[1] = *(Ip_u32 *)(p - 4); #endif e6->mac_if.enc[1] = ipsec; #ifdef IPCOM_USE_FORWARDER_IPSEC ipcom_memcpy(&e6->ipsec, &fw_ipsec, sizeof(fw_ipsec)); #endif #ifdef IPCOM_USE_FORWARDER_VLAN e6->ip6.type = IPCOM_FORWARDER_PACKET_TYPE_IPV6; #endif e6->ip6.addr[0] = *DADDR_V6_OFFSET0(p); e6->ip6.addr[1] = *DADDR_V6_OFFSET1(p); break; #ifdef IPCOM_USE_FORWARDER_VLAN case ip_htons(IP_VLAN): ev = (fw_cache_entry_vlan_t *)&ipcom_fw->fw_cache_tbl_v6[ix]; p += LL_ETH_VLAN_ADD; if (IPCOM_FW_PKT_TYPE(p) == ip_htons(IP_IPv4)) { #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS ev = ipcom_forwarder_get_vlan_update_entry(ev, VLAN_TAG(p - LL_ETH_VLAN_ADD), *DADDR_V4_OFFSET(p), IP_NULL); #endif ev->ipvlan.a.addr_v4 = 0; if (ev->ipvlan.rci == *ipcom_fw->rt_cache_id) { ret = 6; } ev->ipvlan.rci = *ipcom_fw->rt_cache_id; ev->mac_if.dst_mac[0] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - LL_ETH_VLAN_ADD - 2); ev->mac_if.dst_mac[1] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - LL_ETH_VLAN_ADD + 2); ev->mac_if.ix[0] = fw_ix; #ifdef IPCOM_USE_PER_PACKET_SRC_MAC ipcom_fw->fw_port[fw_ix].src_type[0] = *(Ip_u32 *)(p - LL_ETH_VLAN_ADD - 8); *(Ip_u16 *)(&ipcom_fw->fw_port[fw_ix].src_type[1]) = *(Ip_u16 *)(p - LL_ETH_VLAN_ADD - 4); #endif ev->mac_if.enc[1] = ipsec; #ifdef IPCOM_USE_FORWARDER_IPSEC ipcom_memcpy(&ev->ipsec, &fw_ipsec, sizeof(fw_ipsec)); #endif ev->ipvlan.type = IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN; ev->ipvlan.vlan_id = VLAN_TAG(p - LL_ETH_VLAN_ADD); ev->ipvlan.a.addr_v4 = *DADDR_V4_OFFSET(p); } else if (IPCOM_FW_PKT_TYPE(p) == ip_htons(IP_IPv6)) { #ifdef IPCOM_USE_FORWARDER_CACHE_WAYS ev = ipcom_forwarder_get_vlan_update_entry(ev, VLAN_TAG(p - LL_ETH_VLAN_ADD), 0, DADDR_V6_OFFSET0(p)); #endif ev->ipvlan.a.addr_v6[0] = 0; ev->ipvlan.a.addr_v6[1] = 0; if (ev->ipvlan.rci == *ipcom_fw->rt_cache_id) { ret = 6; } ev->ipvlan.rci = *ipcom_fw->rt_cache_id; ev->mac_if.dst_mac[0] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - LL_ETH_VLAN_ADD - 2); ev->mac_if.dst_mac[1] = *(Ip_u32 *)(p - LL_ETH_HDR_SZ - LL_ETH_VLAN_ADD + 2); ev->mac_if.ix[0] = fw_ix; #ifdef IPCOM_USE_PER_PACKET_SRC_MAC ipcom_fw->fw_port[fw_ix].src_type[0] = *(Ip_u32 *)(p - LL_ETH_VLAN_ADD - 8); *(Ip_u16 *)(&ipcom_fw->fw_port[fw_ix].src_type[1]) = *(Ip_u16 *)(p - LL_ETH_VLAN_ADD - 4); #endif ev->mac_if.enc[1] = ipsec; #ifdef IPCOM_USE_FORWARDER_IPSEC ipcom_memcpy(&ev->ipsec, &fw_ipsec, sizeof(fw_ipsec)); #endif ev->ipvlan.type = IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN; ev->ipvlan.vlan_id = VLAN_TAG(p - LL_ETH_VLAN_ADD); ev->ipvlan.a.addr_v6[0] = *DADDR_V6_OFFSET0(p); ev->ipvlan.a.addr_v6[1] = *DADDR_V6_OFFSET1(p); } break; #endif default: break; } #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(suspend); #endif return ret; } #if defined(IPCOM_FORWARDER_NAE) || defined(IPCOM_FORWARDER_SMP) /* *=========================================================================== * ipcom_create_rx_fw_tx *=========================================================================== * Context: * Description: Creates a combined receiver, forwarder, and transmitter * daemon. * Parameters: fw_i: Index of forwarder (0 - 9) * Returns: * */ IP_PUBLIC Ip_err ipcom_create_rx_fw_tx(int fw_i) { int retval; Ip_pid_t pid; Ipcom_proc_attr attr; char name[IPCOM_FORWARDER_MAX_TASKNAME_LEN]; ipcom_proc_attr_init(&attr); attr.priority = IPCOM_PRIORITY_MIN; attr.stacksize = IPCOM_PROC_STACK_LARGE; /* Create the Forwarder task name */ ipcom_sprintf(name, "%s%d", IP_FORWARDER_TASK_NAME, fw_i + 1); IPCOM_LOGX(INFO, "Creating forwarder, \'%s\'.\n"), name IPCOM_ENDX; /* Spawn a new forwarder task */ retval = ipcom_proc_acreate(name, (Ipcom_proc_func)ipcom_forwarder, &attr, &pid); return retval; } #endif /* IPCOM_FORWARDER_AMP */ /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_forwarder_set_tx_port *=========================================================================== * Context: any * Description: * */ IP_PUBLIC void ipcom_forwarder_set_tx_port(int port, void *txqueue) { if (port >= 0 && port < MAX_FW_PORTS) { if (ipcom_fw) { ipcom_fw->fw_port[port].fwd = txqueue; } else { /* Shared storage not available yet, store in temporary storage */ tx_port_temp_storage[port] = txqueue; } } } #if defined(IPCOM_FORWARDER_NAE) || defined(IPCOM_FORWARDER_SMP) /* *=========================================================================== * ipcom_forwarder_update_tx_port *=========================================================================== * Context: any * Description: Transfer output ports stored in temporary storage to shared memory * */ IP_STATIC void ipcom_forwarder_update_tx_port(void) { int i; for (i = 0; i < MAX_FW_PORTS; i++) { if (tx_port_temp_storage[i]) { ipcom_fw->fw_port[i].fwd = tx_port_temp_storage[i]; } } } #endif /* *=========================================================================== * ipcom_forwarder_get_port_cookie *=========================================================================== * Context: any * Description: * */ IP_PUBLIC void * ipcom_forwarder_get_port_cookie(int port) { if (port >= 0 && port < MAX_FW_PORTS) { return ipcom_fw->fw_port[port].fwd; } return IP_NULL; } #if defined(IPCOM_FORWARDER_SMP) || defined(IPCOM_FORWARDER_NAE) /* *=========================================================================== * ipcom_forwarder_ioctl *=========================================================================== * Context: * Description: * Parameters: * */ #ifndef IP_PORT_LKM IP_PUBLIC Ip_err ipcom_forwarder_ioctl(Ipcom_netif *netif, int code, struct Ip_fwreq *fwreq) { #ifdef IP_PORT_VXWORKS port_statistics_t ps; #else (void)fwreq; #endif if (netif->hw_ix < 0) { return -1; } switch (code) { case IP_SIOCGHWSTATS: #ifdef IP_PORT_VXWORKS ipcom_forwarder_get_statistics(ipcom_forwarder_netif_to_port_cookie(netif), &ps); fwreq->u.ps.packets = ps.packets; fwreq->u.ps.octets_hw = (Ip_u32)(ps.inb_octets >> 32); fwreq->u.ps.octets_lw = (Ip_u32)ps.inb_octets; fwreq->u.ps.multicast_packets = ps.multicast_packets; fwreq->u.ps.broadcast_packets = ps.broadcast_packets; fwreq->u.ps.len_64_packets = ps.len_64_packets; fwreq->u.ps.len_65_127_packets = ps.len_65_127_packets; fwreq->u.ps.len_128_255_packets = ps.len_128_255_packets; fwreq->u.ps.len_256_511_packets = ps.len_256_511_packets; fwreq->u.ps.len_512_1023_packets = ps.len_512_1023_packets; fwreq->u.ps.len_1024_1518_packets = ps.len_1024_1518_packets; fwreq->u.ps.len_1519_max_packets = ps.len_1519_max_packets; fwreq->u.ps.dropped_packets = ps.dropped_packets; fwreq->u.ps.dropped_octets = ps.dropped_octets; fwreq->u.ps.tx_packets = ps.tx_packets; fwreq->u.ps.tx_octets_hw = (Ip_u32)(ps.tx_octets >> 32); fwreq->u.ps.tx_octets_lw = (Ip_u32)ps.tx_octets; break; case IP_SIOCSRESETHWSTATS: ipcom_forwarder_reset_statistics(ipcom_forwarder_netif_to_port_cookie(netif)); break; #endif default: break; } return 0; } #endif #endif /* IPCOM_FORWARDER_LOCAL_STACK */ /* *=========================================================================== * ipcom_forwarder_start_stop_fw *=========================================================================== * Context: shell * Description: Start/stop forwarders by send messages and trigger them * Parameters: sig: IPCOM_SIG_STOP_FW or IPCOM_SIG_START_FW * */ IP_GLOBAL void ipcom_forwarder_start_stop_fw(int sig) { #if defined(IPCOM_FORWARDER_AMP) || defined(IPCOM_FORWARDER_NAE) /* TODO */ #else int i; int fw_cnt; static int stop_msg = IPCOM_SIG_STOP_FW; static int start_msg = IPCOM_SIG_START_FW; if (sig == IPCOM_SIG_START_FW) { ipcom_forwarder_fw_started = 1; } fw_cnt = ipcom_forwarder_get_fw_cnt(); for (i = 0; i < fw_cnt; i++) { ipcom_pipe_send(ipcom_fw->control_pipe[i], (sig == IPCOM_SIG_STOP_FW) ? (int *)&stop_msg : (int *)&start_msg); } if (sig == IPCOM_SIG_STOP_FW) { for (i = 0; i < fw_cnt; i++) { ipcom_forwarder_trigger_pipe_read(i + 1); } ipcom_forwarder_fw_started = 0; } #endif /* IPCOM_FORWARDER_AMP */ } /* *=========================================================================== * ipcom_forwarder_get_fwdebug_mask *=========================================================================== * Context: shell * Description: * Returns: current value of 'FW_DEBUG' * */ IP_GLOBAL int ipcom_forwarder_get_fwdebug_mask(void) { #ifdef FW_DEBUG return FW_DEBUG; #else return 0; #endif } /* *=========================================================================== * ipcom_forwarder_get_fw_enable *=========================================================================== * Context: shell * Description: * Returns: current value of ipcom_forwarder_fw_enable * */ IP_GLOBAL int ipcom_forwarder_get_fw_enable(void) { return ipcom_forwarder_fw_enable; } /* *=========================================================================== * ipcom_forwarder_get_fw_started *=========================================================================== * Context: shell * Description: * Returns: current value of fw_started * */ IP_GLOBAL int ipcom_forwarder_get_fw_started(void) { return ipcom_forwarder_fw_started; } /* *=========================================================================== * ipcom_forwarder_cache_util *=========================================================================== * Context: shell * Description: Retrieve the current fw cache usage in percent * Return: Fw cache usage in percent * */ IP_PUBLIC int ipcom_forwarder_cache_util(int v4_v6) { int i; int used = 0; int entries = 0; fw_cache_entry_v4_t *fw4; fw_cache_entry_v6_t *fw6; int limit; if (v4_v6 & IPCOM_FWD_V4) { #if IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT > 0 limit = ipcom_fw->fw_v4_entries << IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT; #else limit = ipcom_fw->fw_v4_entries + IPCOM_FORWARDER_CACHE_WAYS - 1; #endif for (i = 0, fw4 = ipcom_fw->fw_cache_tbl_v4; i < limit; i++) { entries++; if (fw4[i].ip4.rci == (Ip_u32)*ipcom_fw->rt_cache_id) { used++; } } } if (v4_v6 & IPCOM_FWD_V6) { #if IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT > 0 limit = ipcom_fw->fw_v6_entries << IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT; #else limit = ipcom_fw->fw_v6_entries + IPCOM_FORWARDER_CACHE_WAYS - 1; #endif for (i = 0, fw6 = ipcom_fw->fw_cache_tbl_v6; i < limit; i++) { entries++; if (fw6[i].ip6.rci == (Ip_u32)*ipcom_fw->rt_cache_id) { used++; } } } if (entries) { return 100 * used / entries; } return 0; } /* *=========================================================================== * ipcom_forwarder_route_cache_invalidate *=========================================================================== * Context: control NAE * Description: quick, global invalidate of all forwarding cache entries * Parameters: * * This routine works by incrementing the shared route_cache_id counter. * Note that if the 32-bit route cache ID wraps around, it is possible * though unlikely that an old invalid route cache entry becomes valid * again; to prevent this, we call the slower ipcom_forwarder_invalidate() * in case of wraparound. */ IP_PUBLIC void ipcom_forwarder_route_cache_invalidate(void) { volatile int *rt_cache_id; int id; if (!ipcom_fw) return; rt_cache_id = ipcom_fw->rt_cache_id; id = *rt_cache_id; if (++id == 0) { id = 1; ipcom_forwarder_invalidate(-1, IPCOM_FWD_V4|IPCOM_FWD_V6); } *rt_cache_id = id; } /* *=========================================================================== * ipcom_forwarder_invalidate *=========================================================================== * Context: any * Description: Invalidate fw cache entries * Parameters: id : index of entry to invalidate; * a negative value means all entries * * When IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT is * greater than zero, then the index should be the set * index rather than the entry index. In this case, all ways * of the set will be invalidated. */ IP_PUBLIC void ipcom_forwarder_invalidate(int id, int v4_v6) { int i; fw_cache_entry_v4_t *fw4; fw_cache_entry_v6_t *fw6; int limit; if (v4_v6 & IPCOM_FWD_V4) { #if IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT > 0 limit = ipcom_fw->fw_v4_entries << IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT; #else limit = ipcom_fw->fw_v4_entries + IPCOM_FORWARDER_CACHE_WAYS - 1; #endif for (i = 0, fw4 = ipcom_fw->fw_cache_tbl_v4; i < limit; i++) { if (id < 0 || id == i >> IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT) { fw4[i].ip4.rci = 0; } } } if (v4_v6 & IPCOM_FWD_V6) { #if IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT > 0 limit = ipcom_fw->fw_v6_entries << IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT; #else limit = ipcom_fw->fw_v6_entries + IPCOM_FORWARDER_CACHE_WAYS - 1; #endif for (i = 0, fw6 = ipcom_fw->fw_cache_tbl_v6; i < limit; i++) { if (id < 0 || id == i >> IPCOM_FORWARDER_TRUE_CACHE_WAYS_SHIFT) { fw6[i].ip6.rci = 0; } } } } /* *=========================================================================== * ipcom_forwarder_set_seed *=========================================================================== * Context: shell * Description: Set the packet 'tag' calculation seed (used to generate flow index) * Parameters: 'seed': 32 bit "random" value * */ IP_PUBLIC void ipcom_forwarder_set_seed(Ip_u32 seed) { ipcom_forwarder_seed = seed; ipcom_forwarder_set_tag_seed(seed); ipcom_forwarder_invalidate(-1, IPCOM_FWD_V4_V6); skip_packet_cnt = IPCOM_FORWARDER_MAX_PACKETS_QUEUED; } /* *=========================================================================== * ipcom_forwarder_get_seed *=========================================================================== * Context: shell * Description: Get the current packet 'tag' calculation seed * Return: 32 bit "random" value * */ IP_PUBLIC Ip_u32 ipcom_forwarder_get_seed(void) { return ipcom_forwarder_seed; } /* *=========================================================================== * ipcom_forwarder_print_cache *=========================================================================== * Context: shell * Description: Print cache statistics * Parameters: * Returns: * */ IP_PUBLIC void ipcom_forwarder_print_cache(int v) { (void)v; ipcom_printf("No cache info available\n"); } #if defined(IPCOM_FORWARDER_SMP) || defined(IPCOM_FORWARDER_NAE) /* *=========================================================================== * ipcom_forwarder_transmit_pkt *=========================================================================== * Context: ipnetd * Description: Send packet via forwarder * Parameters: * Returns: 0 : packet was handled by this function * 1 : packet was not handled by this function and should be transmitted by ipnet * */ IP_PUBLIC int ipcom_forwarder_transmit_pkt(Ipcom_pkt *pkt, Ipcom_netif *netif) { if (!ipcom_forwarder_fw_started) return 1; #ifdef IPCOM_USE_FORWARDER_IPSEC if (pkt->ipsec_hlen && pkt->next_original) { int offset = LL_ETH_HDR_SZ; if (netif->type == IP_IFT_L2VLAN) offset += LL_ETH_VLAN_ADD; /* Restore original packet start pointer */ pkt->next_original->start = pkt->next_original->ipstart - offset; /* Copy link layer header to original packet */ ipcom_memcpy(&pkt->next_original->data[pkt->next_original->start], &pkt->data[pkt->start], offset); pkt->next_original->ipsec_hlen = pkt->ipsec_hlen; pkt = pkt->next_original; if ((pkt->data[pkt->start + offset] & 0xf0) == 0x40) IP_SET_HTONS(&pkt->data[pkt->start + offset - 2], IP_IPv4); else if ((pkt->data[pkt->start + offset] & 0xf0) == 0x60) IP_SET_HTONS(&pkt->data[pkt->start + offset - 2], IP_IPv6); else return 1; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ #ifdef IPCOM_FORWARDER_NAE /* No key? */ if (pkt->nae_ctx == IP_NULL) return 1; #endif /* IPCOM_FORWARDER_NAE */ if (!IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_FORWARDED)) return 1; if (!ipcom_forwarder_fw_enable) return 1; #ifdef IPCOM_USE_FORWARDER_VLAN if (netif->type == IP_IFT_L2VLAN) netif = (Ipcom_netif *)(((Ipnet_netif *)netif)->eth->vlan.parent); #endif #if defined(IPNET_USE_BOND) && defined(IPCOM_FORWARDER_NAE) if (IP_BIT_ISSET(netif->flags, IP_IFF_MASTER)) { /* * This is a bond interface. Need to find out * the appropriate physical transmit slave * interface via the load balancing algorithm. */ netif = ipnet_bond_get_tx_slave(pkt, netif); if (netif == IP_NULL) return 1; } #endif /* IPNET_USE_BOND */ /* TODO: Remove this! */ #ifdef __VERIFY__THIS_MUST_BE_RESOLVED_PRIOR_IN_DKREJSA /* If netif->hw_priv is not setup it must be done before the fw cache is updated */ #ifdef IPCOM_FORWARDER_SMP if (!netif->hw_priv) netif->hw_priv = ipcom_forwarder_get_tx_queue(netif); if (netif->hw_ix < 0) netif->hw_ix = ipcom_forwarder_get_hw_ix(netif->hw_priv); #endif #endif #if defined(IPCOM_FORWARDER_NAE) /* TODO: Remove this! */ if (!netif->hw_priv) { if (netif->hw_ix < 0) { fw_port_t *fw_port = netif->pdrv; netif->hw_ix = fw_port? fw_port->port : 0; } netif->hw_priv = (void *)1; } #endif if (netif->hw_ix < 0) return 1; if (ipcom_fw && netif->hw_priv) ipcom_forwarder_port_mtu_update(netif->hw_ix, netif->mtu); return ipcom_forwarder_transmit_pkt_ext(pkt, netif->hw_ix); } #endif /* defined(IPCOM_FORWARDER_SMP) || defined(IPCOM_FORWARDER_NAE) */ /* *=========================================================================== * ipcom_forwarder_transmit_pkt_ext *=========================================================================== * Context: ipnetd * Description: Forwarder output processing (update forwarding cache) * Parameters: pkt - the packet being sent * port_index - the forwarder output port index * Returns: 0 : packet was handled by this function * 1 : packet was not handled by this function and should be transmitted by ipnet * * Note: currently, always returns 1. */ IP_PUBLIC int ipcom_forwarder_transmit_pkt_ext(Ipcom_pkt *pkt, int port_index) { int v; #if defined(IPCOM_FORWARDER_NAE) ipcom_enter_critical_region(); #endif if (!skip_packet_cnt) { if ((v = ipcom_forwarder_set_fw_if(pkt, port_index)) > 0) { /* Overwrote a valid entry */ if (++overwrite_cnt > IPCOM_FORWARDER_OVERWRITE_MAX) { if (ipcom_forwarder_cache_util((v == 4) ? IPCOM_FWD_V4 : IPCOM_FWD_V6) < ipcom_forwarder_get_fwcache_util_level_limit()) { struct Ip_timeval now; ipcom_microtime(&now); ipcom_forwarder_seed ^= (Ip_u32)(now.tv_usec + (now.tv_usec << 17) + (now.tv_usec >> 5)); IPCOM_LOGX(DEBUG2, "%s: Updated tag seed: %x\n"), __FUNCTION__, ipcom_forwarder_seed IPCOM_ENDX; ipcom_forwarder_set_tag_seed(ipcom_forwarder_seed); skip_packet_cnt = IPCOM_FORWARDER_MAX_PACKETS_QUEUED; ipcom_forwarder_invalidate(-1, IPCOM_FWD_V4_V6); } overwrite_cnt = 0; } } } else { skip_packet_cnt--; } #if defined(IPCOM_FORWARDER_NAE) ipcom_exit_critical_region(); #endif return 1; } /* *=========================================================================== * ipcom_forwarder_register_port *=========================================================================== * Context: any (initialization; no mutual exclusion) * Description: set the forwarder port cookie for a specified * port index * Parameters: port - the forwarder port index * port_cookie - the forwarder port cookie * mtu - the port's MTU * hwaddr - the ports ethernet station address */ IP_PUBLIC void ipcom_forwarder_register_port(int port, void *port_cookie, Ip_u32 mtu, const Ip_u8 *hwaddr) { fw_port_t *fw_port; if (port >= 0 && port < MAX_FW_PORTS) { fw_port = &ipcom_fw->fw_port[port]; fw_port->fwd = port_cookie; fw_port->mtu = mtu; if (hwaddr != IP_NULL) { ipcom_memcpy(&fw_port->src_type, hwaddr, LL_ETH_ADDR_SZ); *((Ip_u16 *)fw_port->src_type + 3) = ip_htons(IP_IPv6); } } } /* *=========================================================================== * ipcom_forwarder_set_port_cookie *=========================================================================== * Context: any (initialization; no mutual exclusion) * Description: set the forwarder port cookie for a specified * port index */ IP_PUBLIC void ipcom_forwarder_set_port_cookie(int port, void *port_cookie) { if (port >= 0 && port < MAX_FW_PORTS) { ipcom_fw->fw_port[port].fwd = port_cookie; } } /* *=========================================================================== * ipcom_forwarder_port_mac_update *=========================================================================== * Context: any * Description: Change the MAC station address of a forwarder port. * Parameters: port - the port index * hwaddr - pointer to the first byte of the port's new * ethernet station address. */ IP_PUBLIC void ipcom_forwarder_port_mac_update(int port, Ip_u8 *hwaddr) { fw_port_t *fw_port; if (port >= 0 && port < MAX_FW_PORTS && hwaddr != IP_NULL) { fw_port = &ipcom_fw->fw_port[port]; ipcom_memcpy(&fw_port->src_type, hwaddr, LL_ETH_ADDR_SZ); *((Ip_u16 *)fw_port->src_type + 3) = ip_htons(IP_IPv6); } } /* *=========================================================================== * ipcom_forwarder_port_mtu_update *=========================================================================== * Context: any * Description: Change the MTU of a forwarder port. * Parameters: port - the port index * mtu - the port's new mtu */ IP_PUBLIC void ipcom_forwarder_port_mtu_update(int port, Ip_u32 mtu) { fw_port_t *fw_port; if (port >= 0 && port < MAX_FW_PORTS) { fw_port = &ipcom_fw->fw_port[port]; fw_port->mtu = mtu; } } #ifdef IPCOM_FORWARDER_SMP /* *=========================================================================== * ipcom_forwarder_start_fw_tasks *=========================================================================== * Context: init * Description: Create the number of forwarders requested by the kernel * configuration */ IP_STATIC void ipcom_forwarder_start_fw_tasks(void) { int i, fw_cnt; Ipcom_pipe_attr pattr; pattr.msg_limit = IPCOM_FORWARDER_PIPE_SIZE; ipcom_fw->fw_pipe = ipcom_pipe_new(IPCOM_PIPE_GENERIC, &pattr); /* Start forwarders */ fw_cnt = ipcom_forwarder_get_fw_cnt(); for (i = 0; i < fw_cnt; i++) { /* Create forwarders */ if (ipcom_create_rx_fw_tx(i) != IPCOM_SUCCESS) { IPCOM_LOGX(ERR, "%s: could not create forwarder %d\n"), i IPCOM_ENDX; return; } /* Send start message to forwarder */ ipcom_fw->control_pipe[i] = ipcom_pipe_new(IPCOM_PIPE_GENERIC, &pattr); ipcom_pipe_send(ipcom_fw->fw_pipe, &ipcom_fw->control_pipe[i]); } } #endif /* IPCOM_FORWARDER_SMP */ /* *=========================================================================== * ipcom_forwarder_create *=========================================================================== * Context: init * Description: Create the number of forwarders requested by the kernel * configuration * */ IP_PUBLIC int ipcom_forwarder_create(void) { #ifdef IPCOM_USE_FORWARDER_IPSEC int i; #endif unsigned int cpu; IPCOM_LOGX(DEBUG, "%s: sleeping 2 seconds...\n"), "ipcom_forwarder_create" IPCOM_ENDX; ipcom_sleep(2); #if !defined(IPCOM_FORWARDER_SMP) if (!ipcom_forwarder_is_master()) return ipcom_forwarder_create_slave(); #endif cpu = ipcom_forwarder_init(); if (ipcom_fw == IP_NULL) { IPCOM_LOGX(ERR, "%s: could not allocate memory (ipcom_fw)\n"), __FUNCTION__ IPCOM_ENDX; return IPCOM_ERR_NO_MEMORY; } /* Initialize common members after allocating structure */ ipcom_fw->rt_cache_id = ipnet_usr_sock_get_route_cache_id(); /* Create the backend (hardware, ifproxy, etc) */ ipcom_forwarder_backend_create(); ipcom_fw->fw_cache_tbl_v4 = ipcom_allocate_fw_cache(sizeof(fw_cache_entry_v4_t), &ipcom_fw->fw_v4_entries); if (ipcom_fw->fw_cache_tbl_v4 == IP_NULL) { IPCOM_LOGX(ERR, "%s: could not allocate memory (fw_cache_tbl_v4)\n"), __FUNCTION__ IPCOM_ENDX; return IPCOM_ERR_NO_MEMORY; } ipcom_fw->fw_cache_tbl_v6 = ipcom_allocate_fw_cache(sizeof(fw_cache_entry_v6_t), &ipcom_fw->fw_v6_entries); if (ipcom_fw->fw_cache_tbl_v6 == IP_NULL) { IPCOM_LOGX(ERR, "%s: could not allocate memory (fw_cache_tbl_v6)\n"), __FUNCTION__ IPCOM_ENDX; return IPCOM_ERR_NO_MEMORY; } #ifdef IPCOM_USE_FORWARDER_IPSEC /* * Hmm, this algorithm will result in ipcom_fw.fw_ipsec_entries smaller * than the requested ipcom_forwarder_ipsec_sa_cache_size if the latter * is not a power of two... */ for (i = 15; i >= 0; i--) { if (IP_BIT_ISSET(ipcom_forwarder_ipsec_sa_cache_size, (1 << i))) { ipcom_fw->fw_ipsec_entries = 1 << i; break; } } ipcom_fw->fw_cache_tbl_enc = ipcom_forwarder_alloc_aligned(sizeof(Ipcom_fw_ipsec_sa_t), sizeof(Ipcom_fw_ipsec_sa_t) * ipcom_fw->fw_ipsec_entries); if (ipcom_fw->fw_cache_tbl_enc == IP_NULL) { IPCOM_LOGX(ERR, "%s: could not allocate memory (fw_cache_tbl_enc)\n"), __FUNCTION__ IPCOM_ENDX; return IPCOM_ERR_NO_MEMORY; } ipcom_fw->fw_cache_tbl_dec = ipcom_forwarder_alloc_aligned(sizeof(Ipcom_fw_ipsec_sa_t), sizeof(Ipcom_fw_ipsec_sa_t) * ipcom_fw->fw_ipsec_entries); if (ipcom_fw->fw_cache_tbl_dec == IP_NULL) { IPCOM_LOGX(ERR, "%s: could not allocate memory (fw_cache_tbl_dec)\n"), __FUNCTION__ IPCOM_ENDX; return IPCOM_ERR_NO_MEMORY; } IPCOM_LOGX(DEBUG, "%s: FW_IPSEC :: allocated ipsec encrypt cache at %p, total bytes = %d, entry = %d bytes\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_enc, sizeof(Ipcom_fw_ipsec_sa_t) * ipcom_fw->fw_ipsec_entries, sizeof(Ipcom_fw_ipsec_sa_t) IPCOM_ENDX; IPCOM_LOGX(DEBUG, "%s: FW_IPSEC :: allocated ipsec decrypt cache at %p, total bytes = %d, entry = %d bytes\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_dec, sizeof(Ipcom_fw_ipsec_sa_t) * ipcom_fw->fw_ipsec_entries, sizeof(Ipcom_fw_ipsec_sa_t) IPCOM_ENDX; #endif /* IPCOM_USE_FORWARDER_IPSEC */ #if defined(IPCOM_USE_FORWARDER_VLAN_STACKING) && defined(IPCOM_USE_OCTEON_FORWARDER) ipcom_forwarder_svlan_shm_init(); #endif IPCOM_LOGX(DEBUG, "%s: ipcom_fw = %p\n"), __FUNCTION__, ipcom_fw IPCOM_ENDX; IPCOM_LOGX(DEBUG, "%s: route_cache_id = %p\n"), __FUNCTION__, ipcom_fw->rt_cache_id IPCOM_ENDX; IPCOM_LOGX(DEBUG, "%s: fw_cache_tbl_v4 = %p\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_v4 IPCOM_ENDX; IPCOM_LOGX(DEBUG, "%s: fw_cache_tbl_v6 = %p\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_v6 IPCOM_ENDX; #ifdef IPCOM_USE_FORWARDER_IPSEC IPCOM_LOGX(DEBUG, "%s: fw_cache_tbl_enc = %p\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_enc IPCOM_ENDX; IPCOM_LOGX(DEBUG, "%s: fw_cache_tbl_dec = %p\n"), __FUNCTION__, ipcom_fw->fw_cache_tbl_dec IPCOM_ENDX; #endif #if defined(IPCOM_FORWARDER_NAE) || defined(IPCOM_FORWARDER_SMP) /* RIME: Output ports reported before 'ipcom_fw' was allocated needs to be copied from temporary storage */ ipcom_forwarder_update_tx_port(); #endif #ifdef IPCOM_FORWARDER_USE_UPPER_TAG_BITS /* Set up key shift value (based on cache size and number of sets)*/ ipcom_fw->fw_key_shift = ipcom_forwarder_get_key_shift(); IPCOM_LOGX(DEBUG, "%s: Key shift value: %d\n"),__FUNCTION__, ipcom_fw->fw_key_shift IPCOM_ENDX; #endif /* Finalize the backend */ ipcom_forwarder_backend_setup(); #ifdef IPCOM_FORWARDER_SMP ipcom_forwarder_start_fw_tasks(); #endif #if defined(IPCOM_FORWARDER_NAE) ipcom_fw->fw_map = (1 << MIPC_CNAE_NODE); /* Register master forwarder */ #endif /* IPCOM_FORWARDER_NAE */ /* Indicate forwarder started */ ipcom_forwarder_fw_started = 1; /* Switch off receive interrupts */ ipcom_forwarder_enter_poll(); ipcom_forwarder_set_tag_seed(ipcom_forwarder_seed); #ifndef IP_PORT_LKM ipcom_forwarder_cmd_add(); #ifdef IPCOM_USE_FORWARDER_VLAN_STACKING ipcom_svlan_forwarder_cmd_add(); #endif #endif return IPCOM_SUCCESS; } #else int ipcom_forwarder_ctrl_empty_file; #endif /* IPCOM_USE_FORWARDER */ /* **************************************************************************** * END OF FILE **************************************************************************** */