int mvFpProcess(MV_U32 ifIndex, MV_PKT_INFO *pPkt, MV_IP_HEADER *pIpHdr, MV_FP_STATS *pFpStats) { MV_FP_RULE *pRt; MV_U32 dip, sip; MV_U8 proto; MV_U16 srcPort, dstPort; MV_STATUS status; #ifdef CONFIG_MV_ETH_NFP_NAT MV_FP_NAT_RULE *pDnatRule, *pSnatRule; #endif /* CONFIG_MV_ETH_NFP_NAT */ #ifdef CONFIG_MV_ETH_NFP_FDB MV_FP_FDB_RULE *pFdb; #endif MV_U8 *pEth = pPkt->pFrags->bufVirtPtr; #ifdef CONFIG_MV_ETH_NFP_PPP MV_BUF_INFO *pBuf = pPkt->pFrags; #endif #ifdef CONFIG_MV_ETH_NFP_SEC MV_NFP_SEC_SPD_RULE *pSpd; MV_NFP_SEC_SA_ENTRY *pSAEntry; MV_ESP_HEADER *pEspHdr; #endif MV_NFP_STAT(pFpStats->process++); /* Check MAC address: * WAN - non-promiscous mode. * Unicast packets - NFP, * Multicast, Broadcast - Linux * LAN - Promiscous mode. * LAN Unicast MAC - NFP, * Multicast, Broadcast, Unknown Unicast - Linux */ if (pEth[ETH_MV_HEADER_SIZE] == 0x01) { MV_NFP_STAT(pFpStats->multicast++); return -1; } #ifdef CONFIG_MV_ETH_NFP_FDB if (mvFpFdbMember(ifIndex)) { pFdb = mvFpFdbLookup(ifIndex, pEth + ETH_MV_HEADER_SIZE); if (!pFdb) { MV_NFP_STAT(pFpStats->fdb_rx_unknown++); return -1; } if (pFdb->fdbInfo.flags & MV_FP_FDB_IS_LOCAL) { /* DA is local, continue with routing */ MV_NFP_STAT(pFpStats->fdb_rx_local++); } else { /* perform bridging */ MV_NFP_STAT(pFpStats->fdb_bridged++); return pFdb->fdbInfo.ifIndex; } } #endif /* CONFIG_MV_ETH_NFP_FDB */ #ifdef CONFIG_MV_ETH_NFP_PPP /* Decapsulate PPPoE */ if (!pIpHdr) { MV_PPPoE_HEADER *pPPP = (MV_PPPoE_HEADER *) pEth; if ((pPPP->ethertype == 0x6488) && (pPPP->proto == 0x2100)) { pIpHdr = (MV_IP_HEADER *) (pEth + ETH_MV_HEADER_SIZE + sizeof(MV_802_3_HEADER) + ETH_FP_PPPOE_HDR); /* do not process fragments */ if (pIpHdr->fragmentCtrl & 0xFF3F) { MV_NFP_STAT(pFpStats->ppp_rx_frag++); goto out; } pBuf->bufAddrShift -= ETH_FP_PPPOE_HDR; pBuf->bufPhysAddr += ETH_FP_PPPOE_HDR; pBuf->bufVirtPtr += ETH_FP_PPPOE_HDR; pBuf->dataSize -= ETH_FP_PPPOE_HDR; pEth += ETH_FP_PPPOE_HDR; pPkt->status = ETH_TX_IP_NO_FRAG | ETH_TX_GENERATE_IP_CHKSUM_MASK | (0x5 << ETH_TX_IP_HEADER_LEN_OFFSET); switch (pIpHdr->protocol) { case MV_IP_PROTO_TCP: pPkt->status |= ETH_TX_L4_TCP_TYPE | ETH_TX_GENERATE_L4_CHKSUM_MASK; break; case MV_IP_PROTO_UDP: pPkt->status |= ETH_TX_L4_UDP_TYPE | ETH_TX_GENERATE_L4_CHKSUM_MASK; break; } MV_NFP_STAT(pFpStats->ppp_rx++); MV_NFP_STAT(pFpStats->ethertype_unknown--); } } if (!pIpHdr) goto out; #endif /* CONFIG_MV_ETH_NFP_PPP */ proto = mvFpPortsGet(pIpHdr, &dstPort, &srcPort); /* Check TTL value */ if (pIpHdr->ttl <= 1) { /* TTL expired */ MV_NFP_STAT(pFpStats->ip_ttl_expired++); goto out; } dip = pIpHdr->dstIP; sip = pIpHdr->srcIP; #ifdef CONFIG_MV_ETH_NFP_SEC /* TBD - Add statistics counters */ /* inbound ipsec traffic */ if (pIpHdr->protocol == MV_IP_PROTO_ESP) { /* extract esp header */ pEspHdr = (MV_ESP_HEADER *) ((MV_U8 *) pIpHdr + sizeof(MV_IP_HEADER)); /* extract SA according to packet spi */ pSAEntry = mvNfpSecSARuleFind(pEspHdr->spi); if (pSAEntry != NULL) { if (MV_OK == mvNfpSecIncoming(pPkt, pSAEntry)) { MV_NFP_STAT(pFpStats->sec_in++); return MV_NFP_STOLEN; } else { /* TDB- handle pkt gracefully */ MV_NFP_STAT(pFpStats->sec_in_drop++); return MV_NFP_DROP; } } mvOsPrintf("mvFpProcess: no SA found for ESP packet(spi=0x%x)\n", pEspHdr->spi); } else { /* outbound */ pSpd = mvNfpSecSPDRuleFind(dip, sip, proto, dstPort, srcPort, MV_NFP_SEC_RULE_DB_OUT); if (pSpd != NULL) { switch (pSpd->actionType) { case (MV_NFP_SEC_FWD): break; case (MV_NFP_SEC_SECURE): status = mvNfpSecOutgoing(pPkt, pSpd->pSAEntry); if (status == MV_OK) { /* handled by cesa */ MV_NFP_STAT(pFpStats->sec_out++); return MV_NFP_STOLEN; } else if (status == MV_OUT_OF_RANGE) { /* slow path */ MV_NFP_STAT(pFpStats->sec_out_slow++); return MV_NFP_NONE; } else { /* drop packet */ MV_NFP_STAT(pFpStats->sec_out_drop++); return MV_NFP_DROP; } break; case (MV_NFP_SEC_DROP): MV_NFP_STAT(pFpStats->sec_out_drop++); return MV_NFP_DROP; break; } } } #endif #ifdef CONFIG_MV_ETH_NFP_NAT proto = mvFpPortsGet(pIpHdr, &dstPort, &srcPort); if (proto == MV_IP_PROTO_NULL) { /* NAT not supported for this protocol */ MV_NFP_STAT(pFpStats->nat_bad_proto++); pDnatRule = NULL; } else { /* Lookup NAT database accordingly with 5 tuple key */ pDnatRule = mvFpNatRuleFind(dip, sip, proto, dstPort, srcPort); } if (pDnatRule != NULL) { if (pDnatRule->flags & MV_FP_DIP_CMD_MAP) dip = pDnatRule->newIp; if (pDnatRule->flags & MV_FP_DPORT_CMD_MAP) dstPort = pDnatRule->newPort; } else { MV_NFP_STAT(pFpStats->dnat_not_found++); } #endif /* CONFIG_MV_ETH_NFP_NAT */ pRt = mvFpRuleFind(dip, sip); if (pRt == NULL) { /* IP Routing rule is not found: go to Linux IP stack */ MV_NFP_STAT(pFpStats->route_miss++); goto out; } MV_NFP_STAT(pFpStats->route_hit++); #ifdef CONFIG_MV_ETH_NFP_NAT if ((pDnatRule != NULL) && (pDnatRule->flags & MV_FP_DNAT_CMD_MAP)) { MV_NFP_STAT(pFpStats->dnat_found++); pSnatRule = mvFpNatRuleFind(dip, sip, proto, dstPort, srcPort); } else { pSnatRule = pDnatRule; } if ((pSnatRule != NULL) && (pSnatRule->flags & MV_FP_SNAT_CMD_MAP)) MV_NFP_STAT(pFpStats->snat_found++); else MV_NFP_STAT(pFpStats->snat_not_found++); /* Check IP awareness */ if ((pRt->routingInfo.aware_flags & MV_FP_DIP_CMD_MAP) && (pDnatRule == NULL)) { MV_NFP_STAT(pFpStats->dnat_aware++); goto out; } if ((pRt->routingInfo.aware_flags & MV_FP_SIP_CMD_MAP) && (pSnatRule == NULL)) { MV_NFP_STAT(pFpStats->snat_aware++); goto out; } /* Update packet accordingly with NAT rules */ if ((pDnatRule != NULL) || (pSnatRule != NULL)) mvFpNatPktUpdate(pIpHdr, pDnatRule, pSnatRule); #endif /* CONFIG_MV_ETH_NFP_NAT */ ifIndex = pRt->routingInfo.outIfIndex; #ifdef CONFIG_MV_ETH_NFP_PPP /* Encapsulate PPPoE on Tx */ if (mvFpPppLookup(ifIndex)) { if (pBuf->dataSize > 1514 + ETH_MV_HEADER_SIZE - ETH_FP_PPPOE_HDR) { MV_NFP_STAT(pFpStats->ppp_tx_slow++); goto out; } MV_NFP_STAT(pFpStats->ppp_tx++); /* FIXME: pktSize is left unchanged */ pBuf->bufAddrShift += ETH_FP_PPPOE_HDR; pBuf->bufPhysAddr -= ETH_FP_PPPOE_HDR; pBuf->bufVirtPtr -= ETH_FP_PPPOE_HDR; pBuf->dataSize += ETH_FP_PPPOE_HDR; pEth -= ETH_FP_PPPOE_HDR; /* -6B aligment from 32B boundary */ { MV_U32 *d = (MV_U32 *) pEth; MV_U32 *s = pppOpen[ifIndex].pppInfo.u.u32; *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); } /* update payload len */ *(MV_U16 *) (pEth + 20) = htons(pBuf->dataSize - 14 - ETH_FP_PPPOE_HDR); mvFpDecTTL(pIpHdr); #ifdef CONFIG_MV_ETH_NFP_NAT if (pSnatRule) mvFpCSumInc(pIpHdr, pSnatRule->srcIp, pSnatRule->newIp); #endif pPkt->status = 0; ifIndex = pppOpen[ifIndex].pppInfo.if_eth; /* Flush and Invalidate 3rd cacheline */ pEth = (MV_U32) pEth & ~(CPU_D_CACHE_LINE_SIZE - 1); pEth += CPU_D_CACHE_LINE_SIZE * 2; mvOsCacheLineFlushInv(NULL, pEth); goto end; } #endif /* CONFIG_MV_ETH_NFP_PPP */ *(MV_U16 *) (pEth + 2) = *(MV_U16 *) (&pRt->routingInfo.dstMac[0]); *(MV_U32 *) (pEth + 4) = *(MV_U32 *) (&pRt->routingInfo.dstMac[2]); *(MV_U32 *) (pEth + 8) = *(MV_U32 *) (&pRt->routingInfo.srcMac[0]); *(MV_U16 *) (pEth + 12) = *(MV_U16 *) (&pRt->routingInfo.srcMac[4]); #ifdef CONFIG_MV_ETH_NFP_PPP *(MV_U16 *) (pEth + 14) = 0x0008; #endif pIpHdr->ttl--; #ifdef CONFIG_MV_ETH_NFP_TOS pIpHdr->tos = pRt->routingInfo.dscp; pPkt->txq = pRt->routingInfo.txq; #endif #ifdef CONFIG_MV_ETH_NFP_FDB /* find actual port inside bridge, otherwise br->xmit is called */ if (mvFpFdbMember(ifIndex)) { pFdb = mvFpFdbLookup(ifIndex, pEth + ETH_MV_HEADER_SIZE); if (pFdb) { MV_NFP_STAT(pFpStats->fdb_tx_found++); return pFdb->fdbInfo.ifIndex; } } #endif /* CONFIG_MV_ETH_NFP_FDB */ end: return ifIndex; out: #ifdef CONFIG_MV_ETH_NFP_PPP /* restore original packet */ if (pBuf->bufAddrShift) { pBuf->bufPhysAddr += pBuf->bufAddrShift; pBuf->bufVirtPtr += pBuf->bufAddrShift; pBuf->dataSize -= pBuf->bufAddrShift; pBuf->bufAddrShift = 0; MV_NFP_STAT(pFpStats->ppp_rx_slow++); } #endif MV_NFP_STAT(pFpStats->slowpath++); return -1; }
/* if (pRule) MV_NFP_DBG("%s: lookup bridge=%d %02x:%02x:%02x:%02x:%02x:%02x => if=%d flags=%x\n", __FUNCTION__, bridgeId, pDA[0],pDA[1],pDA[2],pDA[3],pDA[4],pDA[5], pRule->fdbInfo.ifIndex, pRule->fdbInfo.flags); else MV_NFP_DBG("%s: lookup bridge=%d %02x:%02x:%02x:%02x:%02x:%02x => unknown\n", __FUNCTION__, bridgeId, pDA[0],pDA[1],pDA[2],pDA[3],pDA[4],pDA[5]); */ return pRule; } #endif /* CONFIG_MV_ETH_NFP_FDB_SUPPORT */ int mvFpProcess(MV_U32 ifIndex, MV_U8* pData, MV_IP_HEADER* pIpHdr, MV_FP_STATS* pFpStats) { MV_FP_RULE *pFpRoute; MV_U32 dip, sip; #ifdef CONFIG_MV_ETH_NFP_NAT_SUPPORT MV_U8 proto; MV_U16 srcPort, dstPort; MV_FP_NAT_RULE *pDnatRule, *pSnatRule; #endif /* CONFIG_MV_ETH_NFP_NAT_SUPPORT */ #ifdef CONFIG_MV_ETH_NFP_FDB_SUPPORT MV_FP_FDB_RULE *pFdb; #endif MV_U8* pEthHeader = pData + ETH_MV_HEADER_SIZE; MV_NFP_STAT( pFpStats->process++ ); /* Check MAC address: * WAN - non-promiscous mode. * Unicast packets - NFP, * Multicast, Broadcast - Linux * LAN - Promiscous mode. * LAN Unicast MAC - NFP, * Multicast, Broadcast, Unknown Unicast - Linux */ if(pEthHeader[0] & 0x1) { /* Go to Linux IP stack */ MV_NFP_STAT( pFpStats->multicast++); return -1; } #ifdef CONFIG_MV_ETH_NFP_FDB_SUPPORT if (mvFpFdbMember(ifIndex)) { pFdb = mvFpFdbLookup(ifIndex, pEthHeader); if (!pFdb) { MV_NFP_STAT( pFpStats->fdb_rx_unknown++ ); return -1; } if (pFdb->fdbInfo.flags & MV_FP_FDB_IS_LOCAL) { /* DA is local, continue with routing */ MV_NFP_STAT( pFpStats->fdb_rx_local++ ); } else { /* perform bridging */ MV_NFP_STAT( pFpStats->fdb_bridged++ ); return pFdb->fdbInfo.ifIndex; } } #endif /* CONFIG_MV_ETH_NFP_FDB_SUPPORT */ /* Check TTL value */ if(pIpHdr->ttl <= 1) { /* TTL expired */ MV_NFP_STAT( pFpStats->ip_ttl_expired++ ); return -1; } dip = pIpHdr->dstIP; sip = pIpHdr->srcIP; #ifdef CONFIG_MV_ETH_NFP_NAT_SUPPORT proto = mvFpNatPortsGet(pIpHdr, &dstPort, &srcPort); if(proto == MV_IP_PROTO_NULL) { /* NAT not supported for this protocol */ MV_NFP_STAT( pFpStats->nat_bad_proto++ ); pDnatRule = NULL; } else { /* Lookup NAT database accordingly with 5 tuple key */ pDnatRule = mvFpNatRuleFind(dip, sip, proto, dstPort, srcPort); } if(pDnatRule != NULL) { if(pDnatRule->flags & MV_FP_DIP_CMD_MAP) { dip = pDnatRule->newIp; } if(pDnatRule->flags & MV_FP_DPORT_CMD_MAP) { dstPort = pDnatRule->newPort; } } else { MV_NFP_STAT( pFpStats->dnat_not_found++ ); } #endif /* CONFIG_MV_ETH_NFP_NAT_SUPPORT */ pFpRoute = mvFpRuleFind(dip, sip); if(pFpRoute == NULL) { /* IP Routing rule is not found: go to Linux IP stack */ MV_NFP_STAT( pFpStats->ip_not_found++ ); return -1; } MV_NFP_STAT(pFpStats->ip_found++); #ifdef CONFIG_MV_ETH_NFP_NAT_SUPPORT if( (pDnatRule != NULL) && (pDnatRule->flags & MV_FP_DNAT_CMD_MAP) ) { MV_NFP_STAT( pFpStats->dnat_found++ ); pSnatRule = mvFpNatRuleFind(dip, sip, proto, dstPort, srcPort); } else { pSnatRule = pDnatRule; } if( (pSnatRule != NULL) && (pSnatRule->flags & MV_FP_SNAT_CMD_MAP) ) { MV_NFP_STAT( pFpStats->snat_found++ ); } else { MV_NFP_STAT( pFpStats->snat_not_found++ ); } /* Check IP awareness */ if( (pFpRoute->routingInfo.aware_flags & MV_FP_DIP_CMD_MAP) && (pDnatRule == NULL) ) { MV_NFP_STAT( pFpStats->dnat_aware++ ); return -1; } if( (pFpRoute->routingInfo.aware_flags & MV_FP_SIP_CMD_MAP) && (pSnatRule == NULL) ) { MV_NFP_STAT( pFpStats->snat_aware++ ); return -1; } /* Update packet accordingly with NAT rules */ if( (pDnatRule != NULL) || (pSnatRule != NULL) ) { mvFpNatPktUpdate(pIpHdr, pDnatRule, pSnatRule); } #endif /* CONFIG_MV_ETH_NFP_NAT_SUPPORT */ if( (unsigned int)pEthHeader & 0x2) { *((MV_U16*)(pEthHeader)) = *(MV_U16*)(&pFpRoute->routingInfo.dstMac[0]); *((MV_U32*)(pEthHeader + 2)) = *(MV_U32*)(&pFpRoute->routingInfo.dstMac[2]); *((MV_U32*)(pEthHeader + 2 + 4)) = *(MV_U32*)(&pFpRoute->routingInfo.srcMac[0]); *((MV_U16*)(pEthHeader + 2 + 4 + 4)) = *(MV_U16*)(&pFpRoute->routingInfo.srcMac[4]); } else { memcpy(pEthHeader, pFpRoute->routingInfo.dstMac, MV_MAC_ADDR_SIZE*2); } pIpHdr->ttl--; #ifdef CONFIG_MV_ETH_NFP_FDB_SUPPORT /* find actual port inside bridge, otherwise br->xmit is called */ if (mvFpFdbMember(pFpRoute->routingInfo.outIfIndex)) { pFdb = mvFpFdbLookup(pFpRoute->routingInfo.outIfIndex, pEthHeader); if (pFdb) { MV_NFP_STAT( pFpStats->fdb_tx_found++ ); return pFdb->fdbInfo.ifIndex; } } #endif /* CONFIG_MV_ETH_NFP_FDB_SUPPORT */ return pFpRoute->routingInfo.outIfIndex; }