blob: b80c1602481a4f8ef8e54aeeb61518b614811fdb [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/*******************************************************************************
* mvNfp.c - Marvell Network Fast Processing
*
* DESCRIPTION:
*
* Supported Features:
* - OS independent.
*
*******************************************************************************/
/* includes */
#include "mvOs.h"
#include "mv802_3.h"
#include "mvDebug.h"
#include "gbe/mvEthRegs.h"
#include "gbe/mvNetaRegs.h"
#include "gbe/mvNeta.h"
#include "mvNfp.h"
/* Set Debug Level */
MV_U32 nfpDebugLevel;
MV_U32 nfp_ports[NFP_MAX_PORTS];
NFP_IF_MAP *nfp_if_map[NFP_DEV_HASH_SZ];
NFP_IF_MAP *nfp_if_real_map[NFP_MAX_PORTS][NFP_MAX_SWITCH_GROUPS];
unsigned int nfp_jhash_iv;
#if (CONFIG_MV_ETH_NFP_DEF == 0)
static int nfpMode = MV_NFP_DISABLED;
#else
static int nfpMode = CONFIG_MV_ETH_NFP_MODE_DEF;
#endif
static int nfpFreeExtPort = MV_ETH_MAX_PORTS;
static NFP_STATS nfp_stats[NFP_MAX_PORTS];
#ifdef NFP_CLASSIFY
MV_NFP_CLASSIFY_MODE classifyMode[MV_NFP_CLASSIFY_FEATURES];
MV_NFP_CLASSIFY_POLICY exactPolicy[MV_NFP_CLASSIFY_FEATURES];
MV_NFP_CLASSIFY_POLICY prioPolicy = MV_NFP_CLASSIFY_POLICY_HIGHEST;
#endif /* NFP_CLASSIFY */
#ifdef NFP_STAT
#define NFP_INC(p, s) nfp_stats[p].s++;
#else
#define NFP_INC(p, s)
#endif
/*
* Init
*/
MV_VOID _INIT mvNfpInit(MV_VOID)
{
mvOsMemset(nfp_ports, 0, sizeof(MV_U32) * NFP_MAX_PORTS);
mvOsMemset(nfp_stats, 0, sizeof(NFP_STATS) * NFP_MAX_PORTS);
mvOsMemset(nfp_if_real_map, 0, sizeof(nfp_if_real_map));
mvOsMemset(nfp_if_map, 0, sizeof(nfp_if_map));
nfpDebugLevel = NFP_WARN_PRINT; /* Note: can also be (NFP_DBG_PRINT | NFP_WARN_PRINT) */
#ifdef NFP_CLASSIFY
{
int i;
for (i = 0; i < MV_NFP_CLASSIFY_FEATURES; i++) {
classifyMode[i] = MV_NFP_CLASSIFY_MODE_DISABLED;
exactPolicy[i] = MV_NFP_CLASSIFY_POLICY_HIGHEST;
}
}
#endif /* NFP_CLASSIFY */
}
MV_VOID mvNfpModeSet(int mode)
{
nfpMode = mode;
}
MV_U32 mvNfpPortCapGet(MV_U32 port)
{
return nfp_ports[port];
}
MV_VOID mvNfpDebugLevelSet(int dbgLevelFlags)
{
nfpDebugLevel = dbgLevelFlags;
}
static INLINE int needFragment(MV_IP_HEADER_INFO *pIpInfo, NFP_IF_MAP *pOutIf)
{
return (pIpInfo->ipLen > pOutIf->mtu);
}
/* Update packet's MAC header, including Marvell Header, DA and SA */
static INLINE void mvNfpFibMacUpdate(MV_U8 *pData, NFP_RULE_FIB *pFib)
{
*(MV_U32 *) (pData + 0) = *(MV_U32 *) (&pFib->mh);
*(MV_U32 *) (pData + 4) = *(MV_U32 *) (&pFib->da[2]);
*(MV_U32 *) (pData + 8) = *(MV_U32 *) (&pFib->sa[0]);
*(MV_U16 *) (pData + 12) = *(MV_U16 *) (&pFib->sa[4]);
}
/* Update packet's IPv4 Header (decrement TTL field) */
static INLINE void mvNfpFibIpUpdate(MV_IP_HEADER_INFO *pIpInfo)
{
if (pIpInfo->family == MV_INET)
pIpInfo->ip_hdr.ip4->ttl--;
else
pIpInfo->ip_hdr.ip6->hoplimit--;
}
#ifdef NFP_CLASSIFY
static INLINE MV_VOID mvNfpClassifyInit(NFP_CLASSIFY_INFO *info)
{
info->flags = 0;
info->pkt_vlan_prio = NFP_INVALID_VPRIO;
info->bridge_vlan_prio = NFP_INVALID_VPRIO;
info->ct_vlan_prio = NFP_INVALID_VPRIO;
info->pkt_dscp = NFP_INVALID_DSCP;
info->ct_dscp = NFP_INVALID_DSCP;
info->iif_prio = NFP_PRIO_INVALID;
info->iif_vlan_prio = NFP_PRIO_INVALID;
info->iif_dscp_prio = NFP_PRIO_INVALID;
}
static INLINE MV_VOID mvNfpVpriPktClassifySave(MV_U16 vlanId, NFP_CLASSIFY_INFO *info)
{
info->pkt_vlan_prio = (vlanId >> 13); /* save 3 MSBits in VLAN ID */
}
static INLINE MV_VOID mvNfpVpriBridgeClassifySave(MV_U8 *pData, NFP_RULE_BRIDGE *bridgeRule, NFP_CLASSIFY_INFO *info)
{
int i;
MV_U16 eth_type;
if (info->pkt_vlan_prio != NFP_INVALID_VPRIO)
eth_type = MV_16BIT_BE(*(MV_U16 *)(pData + MV_ETH_MH_SIZE + MV_MAC_ADDR_SIZE +
MV_MAC_ADDR_SIZE + MV_VLAN_HLEN));
else
eth_type = MV_16BIT_BE(*(MV_U16 *)(pData + MV_ETH_MH_SIZE + MV_MAC_ADDR_SIZE + MV_MAC_ADDR_SIZE));
for (i = 0; i < NFP_VPRI_MAP_GLOBAL; i++) {
if ((bridgeRule->vpri_map[i].eth_type == eth_type) && bridgeRule->vpri_map[i].valid) {
info->bridge_vlan_prio = bridgeRule->vpri_map[i].new_prio;
info->flags |= NFP_F_SET_EXACT_VLAN_PRIO;
info->flags |= NFP_F_SET_VLAN_PRIO;
return;
}
}
if (bridgeRule->vpri_map[NFP_VPRI_MAP_GLOBAL].valid) {
info->bridge_vlan_prio = bridgeRule->vpri_map[NFP_VPRI_MAP_GLOBAL].new_prio;
info->flags |= NFP_F_SET_EXACT_VLAN_PRIO;
info->flags |= NFP_F_SET_VLAN_PRIO;
}
}
#ifdef NFP_CT
static INLINE MV_VOID mvNfpPktDscpClassifySave(MV_IP_HEADER_INFO *pIpHdr, NFP_CLASSIFY_INFO *info)
{
MV_IP6_HEADER *pIp6Hdr = pIpHdr->ip_hdr.ip6;
MV_IP_HEADER *pIph = pIpHdr->ip_hdr.ip4;
MV_U8 *pIp6 = (char *)pIp6Hdr;
/* First get the packet's original DSCP */
if (pIpHdr->family == MV_INET) {
/* 6 MSBits of the TOS field are DSCP, 2 LSBits are ECN */
info->pkt_dscp = ((pIph->tos) >> 2);
info->pkt_ecn = (pIph->tos & 0x3);
} else {
/* TC field is divided on the first 2 bytes of IPv6 header */
info->pkt_dscp = (((*pIp6 & 0xF) << 4) | (*(pIp6 + 1) >> 6));
info->pkt_ecn = ((*(pIp6 + 1) >> 4) & 0x3);
}
}
static INLINE MV_VOID mvNfpDscpClassifySave(NFP_RULE_CT *pCt, NFP_CLASSIFY_INFO *info)
{
/* Now get the DSCP value from the 5 tuple rule */
if (pCt->dscp_map[info->pkt_dscp].valid) {
info->ct_dscp = pCt->dscp_map[info->pkt_dscp].new_dscp;
info->flags |= NFP_F_SET_EXACT_DSCP;
info->flags |= NFP_F_SET_DSCP;
} else if (pCt->dscp_map[NFP_DSCP_MAP_GLOBAL].valid) {
info->ct_dscp = pCt->dscp_map[NFP_DSCP_MAP_GLOBAL].new_dscp;
info->flags |= NFP_F_SET_EXACT_DSCP;
info->flags |= NFP_F_SET_DSCP;
}
}
static INLINE MV_VOID mvNfpVpriCtClassifySave(NFP_RULE_CT *pCt, NFP_CLASSIFY_INFO *info)
{
if (info->pkt_vlan_prio != NFP_INVALID_VPRIO) {
if (pCt->vpri_map[info->pkt_vlan_prio].valid) {
info->ct_vlan_prio = pCt->vpri_map[info->pkt_vlan_prio].new_prio;
info->flags |= NFP_F_SET_EXACT_VLAN_PRIO;
info->flags |= NFP_F_SET_VLAN_PRIO;
return;
}
}
if (pCt->vpri_map[NFP_VPRI_MAP_GLOBAL].valid) {
info->ct_vlan_prio = pCt->vpri_map[NFP_VPRI_MAP_GLOBAL].new_prio;
info->flags |= NFP_F_SET_EXACT_VLAN_PRIO;
info->flags |= NFP_F_SET_VLAN_PRIO;
}
}
#endif /* NFP_CT */
static INLINE MV_VOID mvNfpTxqClassifySave(int txq, NFP_CLASSIFY_INFO *info)
{
if (info->flags & NFP_F_SET_EXACT_TXQ) {
/* update info->txq according to policy */
switch (exactPolicy[MV_NFP_CLASSIFY_FEATURE_TXQ]) {
case MV_NFP_CLASSIFY_POLICY_FIRST:
/* do nothing - this is not the first time this function was called */
break;
case MV_NFP_CLASSIFY_POLICY_LAST:
info->txq = txq;
break;
case MV_NFP_CLASSIFY_POLICY_HIGHEST:
if (txq > info->txq)
info->txq = txq;
break;
case MV_NFP_CLASSIFY_POLICY_LOWEST:
if (txq < info->txq)
info->txq = txq;
break;
default:
NFP_WARN("%s: unknown txq policy %d\n", __func__, exactPolicy[MV_NFP_CLASSIFY_FEATURE_TXQ]);
return;
}
} else {
info->flags |= NFP_F_SET_EXACT_TXQ;
info->flags |= NFP_F_SET_TXQ;
info->txq = txq;
}
}
static INLINE MV_VOID mvNfpTxpClassifySave(MV_U8 txp, NFP_CLASSIFY_INFO *info)
{
if (info->flags & NFP_F_SET_EXACT_TXP) {
/* update info->txp according to policy */
switch (exactPolicy[MV_NFP_CLASSIFY_FEATURE_TXP]) {
case MV_NFP_CLASSIFY_POLICY_FIRST:
/* do nothing - this is not the first time this function was called */
break;
case MV_NFP_CLASSIFY_POLICY_LAST:
info->txp = txp;
break;
case MV_NFP_CLASSIFY_POLICY_HIGHEST:
if (txp > info->txp)
info->txp = txp;
break;
case MV_NFP_CLASSIFY_POLICY_LOWEST:
if (txp < info->txp)
info->txp = txp;
break;
default:
NFP_WARN("%s: unknown txp policy %d\n", __func__, exactPolicy[MV_NFP_CLASSIFY_FEATURE_TXP]);
return;
}
} else {
info->flags |= NFP_F_SET_EXACT_TXP;
info->flags |= NFP_F_SET_TXP;
info->txp = txp;
}
}
static INLINE MV_VOID mvNfpMhClassifySave(MV_U16 mh, NFP_CLASSIFY_INFO *info)
{
if (info->flags & NFP_F_SET_EXACT_MH) {
/* update info->mh according to policy */
switch (exactPolicy[MV_NFP_CLASSIFY_FEATURE_MH]) {
case MV_NFP_CLASSIFY_POLICY_FIRST:
/* do nothing - this is not the first time this function was called */
break;
case MV_NFP_CLASSIFY_POLICY_LAST:
info->mh = mh;
break;
case MV_NFP_CLASSIFY_POLICY_HIGHEST:
if (mh > info->mh)
info->mh = mh;
break;
case MV_NFP_CLASSIFY_POLICY_LOWEST:
if (mh < info->mh)
info->mh = mh;
break;
default:
NFP_WARN("%s: unknown MH policy %d\n", __func__, exactPolicy[MV_NFP_CLASSIFY_FEATURE_MH]);
return;
}
} else {
info->flags |= NFP_F_SET_EXACT_MH;
info->flags |= NFP_F_SET_MH;
info->mh = mh;
}
}
#ifdef NFP_CT
static INLINE int mvNfpClassifyExactDscpGet(NFP_CLASSIFY_INFO *info)
{
int newDscp = NFP_INVALID_DSCP;
/* use dscp from exact match classification */
switch (exactPolicy[MV_NFP_CLASSIFY_FEATURE_DSCP]) {
case MV_NFP_CLASSIFY_POLICY_FIRST:
newDscp = info->pkt_dscp; /* should always be valid */
break;
case MV_NFP_CLASSIFY_POLICY_LAST:
if (info->ct_dscp != NFP_INVALID_DSCP)
newDscp = info->ct_dscp;
else
newDscp = info->pkt_dscp;
break;
case MV_NFP_CLASSIFY_POLICY_HIGHEST:
newDscp = (info->ct_dscp > info->pkt_dscp) ? info->ct_dscp : info->pkt_dscp;
break;
case MV_NFP_CLASSIFY_POLICY_LOWEST:
if (info->ct_dscp != NFP_INVALID_DSCP)
newDscp = (info->ct_dscp < info->pkt_dscp) ? info->ct_dscp : info->pkt_dscp;
else
newDscp = info->pkt_dscp;
break;
default:
NFP_WARN("%s: unknown DSCP policy %d\n", __func__, exactPolicy[MV_NFP_CLASSIFY_FEATURE_DSCP]);
return NFP_INVALID_DSCP;
}
return newDscp;
}
static INLINE int mvNfpClassifyFeatureGetVal(int exactVal, int priorityVal, MV_NFP_CLASSIFY_MODE mode)
{
if (mode == MV_NFP_CLASSIFY_MODE_HIGHEST)
return (exactVal > priorityVal) ? exactVal : priorityVal;
else
return (exactVal < priorityVal) ? exactVal : priorityVal;
}
static INLINE MV_VOID mvNfpDscpClassifyUpdate(MV_IP_HEADER_INFO *pIpHdr, NFP_CLASSIFY_INFO *info)
{
MV_IP6_HEADER *pIp6Hdr = pIpHdr->ip_hdr.ip6;
MV_IP_HEADER *pIph = pIpHdr->ip_hdr.ip4;
MV_U8 *pIp6 = (char *)pIp6Hdr;
int newDscp;
MV_U16 exactDscpFlag , prioDscpFlag;
MV_NFP_CLASSIFY_MODE mode = mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE_DSCP);
if (mode == MV_NFP_CLASSIFY_MODE_DISABLED)
return;
if (!(info->flags & NFP_F_SET_DSCP))
/* both exact and priority values are invalid */
return;
exactDscpFlag = info->flags & NFP_F_SET_EXACT_DSCP;
prioDscpFlag = info->flags & NFP_F_SET_PRIO_DSCP;
switch (mode) {
case MV_NFP_CLASSIFY_MODE_EXACT:
if (exactDscpFlag)
newDscp = mvNfpClassifyExactDscpGet(info);
else
return;
break;
case MV_NFP_CLASSIFY_MODE_PRIO:
if (prioDscpFlag)
newDscp = info->prio_dscp;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_HIGHEST:
case MV_NFP_CLASSIFY_MODE_LOWEST:
if (!exactDscpFlag) {
if (!prioDscpFlag)
return;/*both invalid*/
newDscp = info->prio_dscp;
} else if (!prioDscpFlag)
newDscp = mvNfpClassifyExactDscpGet(info);
else/*both valid*/
newDscp = mvNfpClassifyFeatureGetVal(mvNfpClassifyExactDscpGet(info), info->prio_dscp, mode);
break;
default:
NFP_WARN("%s: unknown DSCP mode %d\n", __func__, mode);
return;
}
if (newDscp != info->pkt_dscp) {
if (pIpHdr->family == MV_INET) {
pIph->tos = ((newDscp << 2) | info->pkt_ecn);
} else {
*pIp6 &= ~0xF; /* Clear 4 LSBits of 1st byte of IPv6 header */
*pIp6 |= (newDscp >> 4); /* Set 4 MSBits of new Traffic Class value */
pIp6++;
*pIp6 &= ~0xF0; /* Clear 4 MSBits of 2nd byte of IPv6 header */
*pIp6 |= (((newDscp & 0x3) << 6) | (info->pkt_ecn << 4)); /* Set 4 LSBits of new Traffic Class value */
}
}
}
#endif /* NFP_CT */
static INLINE int mvNfpClassifyExactVprioGet(NFP_CLASSIFY_INFO *info)
{
int exactVprio = NFP_INVALID_VPRIO;
switch (exactPolicy[MV_NFP_CLASSIFY_FEATURE_VPRIO]) {
case MV_NFP_CLASSIFY_POLICY_FIRST:
if (info->pkt_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->pkt_vlan_prio;
else if (info->bridge_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->bridge_vlan_prio;
else if (info->ct_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->ct_vlan_prio;
break;
case MV_NFP_CLASSIFY_POLICY_LAST:
if (info->ct_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->ct_vlan_prio;
else if (info->bridge_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->bridge_vlan_prio;
else if (info->pkt_vlan_prio != NFP_INVALID_VPRIO)
exactVprio = info->pkt_vlan_prio;
break;
case MV_NFP_CLASSIFY_POLICY_HIGHEST:
exactVprio = info->pkt_vlan_prio;
if (info->bridge_vlan_prio > exactVprio)
exactVprio = info->bridge_vlan_prio;
if (info->ct_vlan_prio > exactVprio)
exactVprio = info->ct_vlan_prio;
break;
case MV_NFP_CLASSIFY_POLICY_LOWEST:
exactVprio = info->pkt_vlan_prio;
if ((info->bridge_vlan_prio != NFP_INVALID_VPRIO) && (info->bridge_vlan_prio < exactVprio))
exactVprio = info->bridge_vlan_prio;
if ((info->ct_vlan_prio != NFP_INVALID_VPRIO) && (info->ct_vlan_prio < exactVprio))
exactVprio = info->ct_vlan_prio;
break;
default:
NFP_WARN("%s: unknown VLAN Priority policy %d\n", __func__, exactPolicy[MV_NFP_CLASSIFY_FEATURE_VPRIO]);
return NFP_INVALID_VPRIO;
}
return exactVprio;
}
static INLINE MV_VOID mvNfpVpriClassifyUpdate(MV_U16 *vid, NFP_CLASSIFY_INFO *info)
{
int vprio;
MV_NFP_CLASSIFY_MODE mode = mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE_VPRIO);
MV_U16 exactVlanPrioFlag , prioVlanPrioFlag;
if (mode == MV_NFP_CLASSIFY_MODE_DISABLED)
return;
if (!(info->flags & NFP_F_SET_VLAN_PRIO))
/* both exact and priority values are invalid */
return;
exactVlanPrioFlag = info->flags & NFP_F_SET_EXACT_VLAN_PRIO;
prioVlanPrioFlag = info->flags & NFP_F_SET_PRIO_VLAN_PRIO;
switch (mode) {
case MV_NFP_CLASSIFY_MODE_EXACT:
if (exactVlanPrioFlag)
vprio = mvNfpClassifyExactVprioGet(info);
else
return;
break;
case MV_NFP_CLASSIFY_MODE_PRIO:
if (prioVlanPrioFlag)
vprio = info->prio_vprio;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_HIGHEST:
case MV_NFP_CLASSIFY_MODE_LOWEST:
if (!exactVlanPrioFlag) {
if (!prioVlanPrioFlag)
return;
vprio = info->prio_vprio;
} else if (!prioVlanPrioFlag)
vprio = mvNfpClassifyExactVprioGet(info);
else/*both valid*/
vprio = mvNfpClassifyFeatureGetVal(mvNfpClassifyExactVprioGet(info), info->prio_vprio, mode);
break;
default:
NFP_WARN("%s: unknown VLAN_PRIO mode %d\n", __func__, mode);
return;
}
(*vid) &= ~0xE000;
(*vid) |= (vprio << 13); /* Set 3 MSBits */
}
static INLINE MV_VOID mvNfpMhClassifyUpdate(MV_U8 *pData, NFP_CLASSIFY_INFO *info)
{
MV_U16 mh;
MV_U16 exactMhFlag , prioMhFlag;
MV_NFP_CLASSIFY_MODE mode = mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE_MH);
if (mode == MV_NFP_CLASSIFY_MODE_DISABLED)
return;
if (!(info->flags & NFP_F_SET_MH))
/* both exact and priority values are invalid */
return;
exactMhFlag = info->flags & NFP_F_SET_EXACT_MH;
prioMhFlag = info->flags & NFP_F_SET_PRIO_MH;
switch (mode) {
case MV_NFP_CLASSIFY_MODE_EXACT:
if (exactMhFlag)
mh = info->mh;
else
return;
break;
case NFP_F_SET_PRIO_MH:
if (prioMhFlag)
mh = info->prio_mh;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_HIGHEST:
case MV_NFP_CLASSIFY_MODE_LOWEST:
if (!exactMhFlag) {
if (!prioMhFlag)
return;
mh = info->prio_mh;
} else if (!prioMhFlag)
mh = info->mh;
else/*both valid*/
mh = mvNfpClassifyFeatureGetVal(info->mh, info->prio_mh, mode);
break;
default:
NFP_WARN("%s: unknown MH mode %d\n", __func__, mode);
return;
}
*(MV_U16 *)(pData) = MV_16BIT_BE(mh);
}
static INLINE MV_VOID mvNfpTxpClassifyUpdate(MV_NFP_RESULT *pRes, NFP_CLASSIFY_INFO *info)
{
MV_U8 newTxp;
MV_U16 exactTxpFlag , prioTxpFlag;
MV_NFP_CLASSIFY_MODE mode = mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE_TXP);
if (mode == MV_NFP_CLASSIFY_MODE_DISABLED)
return;
if (!(info->flags & NFP_F_SET_TXP))
/* both exact and priority values are invalid */
return;
exactTxpFlag = info->flags & NFP_F_SET_EXACT_TXP;
prioTxpFlag = info->flags & NFP_F_SET_PRIO_TXP;
switch (mode) {
case MV_NFP_CLASSIFY_MODE_EXACT:
if (exactTxpFlag)
newTxp = info->txp;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_PRIO:
if (prioTxpFlag)
newTxp = info->prio_txp;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_HIGHEST:
case MV_NFP_CLASSIFY_MODE_LOWEST:
if (!exactTxpFlag) {
if (!prioTxpFlag)
return;
newTxp = info->prio_txp;
} else if (!prioTxpFlag)
newTxp = info->txp;
else/*both valid*/
newTxp = mvNfpClassifyFeatureGetVal(info->txp, info->prio_txp, mode);
break;
default:
NFP_WARN("%s: unknown TPX mode %d\n", __func__, mode);
return;
}
pRes->flags |= MV_NFP_RES_TXP_VALID;
pRes->txp = newTxp;
}
static INLINE MV_VOID mvNfpTxqClassifyUpdate(MV_NFP_RESULT *pRes, NFP_CLASSIFY_INFO *info)
{
MV_U8 newTxq;
MV_U16 exactTxqFlag , prioTxqFlag;
MV_NFP_CLASSIFY_MODE mode = mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE_TXQ);
if (mode == MV_NFP_CLASSIFY_MODE_DISABLED)
return;
if (!(info->flags & NFP_F_SET_TXQ))
/* both exact and priority values are invalid */
return;
exactTxqFlag = info->flags & NFP_F_SET_EXACT_TXQ;
prioTxqFlag = info->flags & NFP_F_SET_PRIO_TXQ;
switch (mode) {
case MV_NFP_CLASSIFY_MODE_EXACT:
if (exactTxqFlag)
newTxq = info->txq;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_PRIO:
if (prioTxqFlag)
newTxq = info->prio_txq;
else
return;
break;
case MV_NFP_CLASSIFY_MODE_HIGHEST:
case MV_NFP_CLASSIFY_MODE_LOWEST:
if (!exactTxqFlag) {
if (!prioTxqFlag)
return;
newTxq = info->prio_txq;
} else if (!prioTxqFlag)
newTxq = info->txq;
else/*both valid*/
newTxq = mvNfpClassifyFeatureGetVal(info->txq, info->prio_txq, mode);
break;
default:
NFP_WARN("%s: unknown TPX mode 3 %d\n", __func__, mode);
return;
}
pRes->flags |= MV_NFP_RES_TXQ_VALID;
pRes->txq = newTxq;
}
/* Get classification priority according to policy
* Priority can come from:
* 1. iif => prio
* 2. iif + vprio => prio
* 3. iif + dscp => prio
* Policy can be Highest or Lowest.
* Return correct priority, or NFP_PRIO_INVALID if no priority is available */
static INLINE int mvNfpClassifyPrioGet(NFP_CLASSIFY_INFO *info)
{
MV_NFP_CLASSIFY_POLICY prioPolicy = mvNfpPrioPolicyGet();
int prio;
if (!info)
return NFP_PRIO_INVALID;
/* get priority from iif/(iif+vprio)/(iif+dscp) according to priority policy (highest/lowest) */
prio = info->iif_prio;
if ((info->iif_vlan_prio != NFP_PRIO_INVALID) &&
((prio == NFP_PRIO_INVALID) ||
((prioPolicy == MV_NFP_CLASSIFY_POLICY_HIGHEST) && (prio < info->iif_vlan_prio)) ||
((prioPolicy == MV_NFP_CLASSIFY_POLICY_LOWEST) && (prio > info->iif_vlan_prio))))
prio = info->iif_vlan_prio;
if ((info->iif_dscp_prio != NFP_PRIO_INVALID) &&
((prio == NFP_PRIO_INVALID) ||
((prioPolicy == MV_NFP_CLASSIFY_POLICY_HIGHEST) && (prio < info->iif_dscp_prio)) ||
((prioPolicy == MV_NFP_CLASSIFY_POLICY_LOWEST) && (prio > info->iif_dscp_prio))))
prio = info->iif_dscp_prio;
return prio;
}
/* save classification data, from priority */
static INLINE MV_VOID mvNfpClassifyPrioSave(NFP_IF_MAP *pOutIf, NFP_CLASSIFY_INFO *info, int prio)
{
NFP_PRIO_CLASSIFY_INFO *classifyFromOif = NULL;
if (!pOutIf || !info || (prio == NFP_PRIO_INVALID))
return;
classifyFromOif = &(pOutIf->prio_to_classify[prio]);
/* for each feature, save classify data */
if (classifyFromOif->flags & NFP_F_PRIO_DSCP) {
info->prio_dscp = classifyFromOif->dscp;
info->flags |= NFP_F_SET_PRIO_DSCP;
info->flags |= NFP_F_SET_DSCP;
} else
info->flags &= ~NFP_F_SET_PRIO_DSCP;
if (classifyFromOif->flags & NFP_F_PRIO_VPRIO) {
info->prio_vprio = classifyFromOif->vprio;
info->flags |= NFP_F_SET_PRIO_VLAN_PRIO;
info->flags |= NFP_F_SET_VLAN_PRIO;
} else
info->flags &= ~NFP_F_SET_PRIO_VLAN_PRIO;
if (classifyFromOif->flags & NFP_F_PRIO_TXQ) {
info->prio_txq = classifyFromOif->txq;
info->flags |= NFP_F_SET_PRIO_TXQ;
info->flags |= NFP_F_SET_TXQ;
} else
info->flags &= ~NFP_F_SET_PRIO_TXQ;
if (classifyFromOif->flags & NFP_F_PRIO_TXP) {
info->prio_txp = classifyFromOif->txp;
info->flags |= NFP_F_SET_PRIO_TXP;
info->flags |= NFP_F_SET_TXP;
} else
info->flags &= ~NFP_F_SET_PRIO_TXP;
if (classifyFromOif->flags & NFP_F_PRIO_MH) {
info->prio_mh = classifyFromOif->mh;
info->flags |= NFP_F_SET_PRIO_MH;
info->flags |= NFP_F_SET_MH;
} else
info->flags &= ~NFP_F_SET_PRIO_MH;
}
#endif /* NFP_CLASSIFY */
#ifdef NFP_VLAN
MV_STATUS mvNfpVlanPvidSet(int if_index, MV_U16 pvid)
{
NFP_IF_MAP *vlanIf = mvNfpIfMapGet(if_index);
if (vlanIf == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, if_index);
return MV_NOT_FOUND;
}
if (pvid == NFP_INVALID_VLAN)
vlanIf->flags &= ~NFP_F_MAP_VLAN_PVID;
else
vlanIf->flags |= NFP_F_MAP_VLAN_PVID;
vlanIf->pvid = pvid;
return MV_OK;
}
MV_STATUS mvNfpVlanVidSet(int if_index, MV_U16 vid)
{
NFP_IF_MAP *vlanIf = mvNfpIfMapGet(if_index);
if (vlanIf == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, if_index);
return MV_NOT_FOUND;
}
vlanIf->vlanId = vid;
return MV_OK;
}
MV_STATUS mvNfpVlanVidGet(int if_index, MV_U16 *vid)
{
NFP_IF_MAP *vlanIf = mvNfpIfMapGet(if_index);
if (vlanIf == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, if_index);
return MV_NOT_FOUND;
}
*vid = vlanIf->vlanId;
return MV_OK;
}
/* Find virtual interface match vlanId */
static INLINE NFP_IF_MAP *mvNfpVlanIfFind(NFP_IF_MAP *ifMap, MV_U16 vlanId)
{
NFP_IF_MAP *vlanIf;
if (ifMap->vlanId == vlanId)
return ifMap;
vlanIf = ifMap->virtIf;
while (vlanIf != NULL) {
if ((vlanIf->vlanId == vlanId))
return vlanIf;
vlanIf = vlanIf->virtNext;
}
return NULL;
}
static INLINE MV_STATUS mvNfpVlanRx(int port, NETA_RX_DESC *pRxDesc, MV_U8 *pData,
MV_ETH_PKT *pPkt, NFP_IF_MAP **ppIfMap,
MV_NFP_RESULT *pRes)
{
MV_U16 vlanId;
NFP_IF_MAP *vlanIfMap = NULL, *ifMap = *ppIfMap;
/* PVID processing */
if (NETA_RX_IS_VLAN(pRxDesc)) {
/* tagged packets */
if (ifMap->flags & NFP_F_MAP_VLAN_RX_DROP_TAGGED) {
/* Drop tagged packets */
NFP_INC(port, vlan_rx_tag_drop);
return MV_DROPPED;
}
vlanId = *((MV_U16 *)(pData + MV_ETH_MH_SIZE + sizeof(MV_802_3_HEADER)));
vlanId = MV_16BIT_BE(vlanId);
#ifdef NFP_CLASSIFY
mvNfpVpriPktClassifySave(vlanId, (NFP_CLASSIFY_INFO *)(pRes->privateData));
#endif /* NFP_CLASSIFY */
vlanId &= 0xFFF;
} else {
/* Untagged packet */
if (ifMap->flags & NFP_F_MAP_VLAN_RX_DROP_UNTAGGED) {
/* Drop untagged packets */
NFP_INC(port, vlan_rx_untag_drop);
return MV_DROPPED;
}
if (ifMap->flags & NFP_F_MAP_VLAN_PVID)
vlanId = ifMap->pvid;
else
vlanId = NFP_INVALID_VLAN;
}
pPkt->vlanId = vlanId;
if (vlanId != NFP_INVALID_VLAN) {
/* Tagged packet */
/* look for vlanId through virtual interfaces mapped to this ifMap */
vlanIfMap = mvNfpVlanIfFind(ifMap, vlanId);
if (vlanIfMap) {
/* found */
NFP_INC(port, vlan_rx_found);
*ppIfMap = vlanIfMap;
return MV_CONTINUE;
}
/* not found */
if (ifMap->flags & NFP_F_MAP_VLAN_RX_DROP_UNKNOWN) {
/* Drop packets with unknown VIDs */
NFP_INC(port, vlan_rx_unknown_drop);
return MV_DROPPED;
}
}
/* Default - Transparent mode */
NFP_INC(port, vlan_rx_trans);
return MV_CONTINUE;
}
static INLINE int mvNfpVlanAdd(int port, MV_U8 *pData, MV_U16 vid, MV_BOOL moveMac, MV_NFP_RESULT *pRes)
{
MV_U8 *pNew;
MV_U16 *pVlan;
NFP_INC(port, vlan_tx_add);
pNew = pData - MV_VLAN_HLEN;
if (moveMac) {
/* move MAC header 4 bytes left. Copy 12 bytes (DA + SA) */
*(MV_U32 *)(pNew + 2) = *(MV_U32 *)(pData + 2);
*(MV_U32 *)(pNew + 2 + 4) = *(MV_U32 *)(pData + 2 + 4);
*(MV_U32 *)(pNew + 2 + 4 + 4) = *(MV_U32 *)(pData + 2 + 4 + 4);
}
pVlan = (MV_U16 *)(pNew + MV_ETH_MH_SIZE + MV_MAC_ADDR_SIZE + MV_MAC_ADDR_SIZE);
/* Set VLAN Type - 0x8100 */
*pVlan = MV_16BIT_BE(MV_VLAN_TYPE);
pVlan++;
/* Set VID + priority */
#ifdef NFP_CLASSIFY
mvNfpVpriClassifyUpdate(&vid, (NFP_CLASSIFY_INFO *)(pRes->privateData));
#endif /* NFP_CLASSIFY */
*pVlan = MV_16BIT_BE(vid);
return -MV_VLAN_HLEN;
}
static INLINE int mvNfpVlanRemove(int port, MV_U8 *pData, MV_BOOL moveMac)
{
MV_U8 *pNew;
NFP_INC(port, vlan_tx_remove);
if (moveMac) {
/* move MAC header 4 bytes right. Copy 12 bytes (DA + SA) */
pNew = pData + MV_VLAN_HLEN;
*(MV_U32 *)(pNew + 2 + 4 + 4) = *(MV_U32 *)(pData + 2 + 4 + 4);
*(MV_U32 *)(pNew + 2 + 4) = *(MV_U32 *)(pData + 2 + 4);
*(MV_U32 *)(pNew + 2) = *(MV_U32 *)(pData + 2);
}
return MV_VLAN_HLEN;
}
static INLINE int mvNfpVlanReplace(int port, MV_U8 *pData, MV_U16 vid, MV_NFP_RESULT *pRes)
{
MV_U16 *pVlan;
NFP_INC(port, vlan_tx_replace);
pVlan = (MV_U16 *)(pData + MV_ETH_MH_SIZE + MV_MAC_ADDR_SIZE + MV_MAC_ADDR_SIZE);
/* Set VLAN Type - 0x8100 */
*pVlan = MV_16BIT_BE(MV_VLAN_TYPE);
pVlan++;
/* Set VID + priority */
#ifdef NFP_CLASSIFY
mvNfpVpriClassifyUpdate(&vid, (NFP_CLASSIFY_INFO *)(pRes->privateData));
#endif /* NFP_CLASSIFY */
*pVlan = MV_16BIT_BE(vid);
return 0;
}
static INLINE int mvNfpVlanTxUpdate(int port, NETA_RX_DESC *pRxDesc, NFP_IF_MAP *pOutIf,
MV_U8 *pData, MV_ETH_PKT *pPkt, MV_BOOL saveMac,
MV_NFP_RESULT *pRes)
{
int vlanShift = 0;
if (NETA_RX_IS_VLAN(pRxDesc)) {
/* Original packet was tagged */
if (pOutIf->flags & NFP_F_MAP_VLAN_TX_UNTAGGED)
vlanShift = mvNfpVlanRemove(port, pData, saveMac);
else if (pOutIf->flags & NFP_F_MAP_VLAN_TX_TAGGED)
vlanShift = mvNfpVlanReplace(port, pData, pOutIf->vlanId, pRes);
} else {
/* Original packet was untagged */
if (pOutIf->flags & NFP_F_MAP_VLAN_TX_TAGGED)
vlanShift = mvNfpVlanAdd(port, pData, pOutIf->vlanId, saveMac, pRes);
else if (pPkt->vlanId != NFP_INVALID_VLAN) /* PVID case */
vlanShift = mvNfpVlanAdd(port, pData, pPkt->vlanId, saveMac, pRes);
}
pPkt->bytes -= vlanShift;
return vlanShift;
}
#endif /* NFP_VLAN */
#ifdef NFP_PPP
/* Find PPPoE interface with the "sid" */
static INLINE NFP_IF_MAP *mvNfpPppIfFind(NFP_IF_MAP *ifMap, MV_U16 sid)
{
NFP_IF_MAP *virtIf;
if ((ifMap->flags & NFP_F_MAP_PPPOE) && (ifMap->sid == sid))
return ifMap;
virtIf = ifMap->virtIf;
while (virtIf != NULL) {
if ((virtIf->flags & NFP_F_MAP_PPPOE) && (virtIf->sid == sid))
return virtIf;
virtIf = virtIf->virtNext;
}
return NULL;
}
MV_STATUS mvNfpPppAdd(int ifIndex, MV_U16 sid, MV_U8 *remoteMac)
{
NFP_IF_MAP *pppIf = mvNfpIfMapGet(ifIndex);
if (pppIf == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, ifIndex);
return MV_NOT_FOUND;
}
/* Copy SA MAC address from parent interface */
memcpy(pppIf->mac, pppIf->parentIf->mac, MV_MAC_ADDR_SIZE);
memcpy(pppIf->remoteMac, remoteMac, MV_MAC_ADDR_SIZE);
pppIf->sid = MV_16BIT_BE(sid);
pppIf->flags |= NFP_F_MAP_PPPOE;
return MV_OK;
}
MV_STATUS mvNfpPppDel(int ifIndex)
{
NFP_IF_MAP *pppIf = mvNfpIfMapGet(ifIndex);
if (pppIf == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, ifIndex);
return MV_NOT_FOUND;
}
pppIf->flags &= ~NFP_F_MAP_PPPOE;
pppIf->sid = 0;
mvOsMemset(pppIf->remoteMac, 0, MV_MAC_ADDR_SIZE);
return MV_OK;
}
MV_STATUS mvNfpPppRx(int port, NETA_RX_DESC *pRxDesc, MV_U8 *pData, MV_ETH_PKT *pPkt ,
NFP_IF_MAP **ppIfMap, MV_IP_HEADER_INFO *pIpHdrInfo)
{
unsigned char *pIpHdr;
PPPoE_HEADER *pPppHdr;
NFP_IF_MAP *ifMap = *ppIfMap;
NFP_IF_MAP *ifPppMap = NULL;
if (NETA_RX_IS_PPPOE(pRxDesc)) {
pIpHdr = (unsigned char *)pIpHdrInfo->ip_hdr.ip4;
pPppHdr = (PPPoE_HEADER *)(pIpHdr - MV_PPPOE_HDR_SIZE);
ifPppMap = mvNfpPppIfFind(ifMap, pPppHdr->session);
if (ifPppMap == NULL) {
NFP_WARN("%s: PPPoE sid=%d not found; ifMap->name=%s\n",
__func__, MV_16BIT_BE(pPppHdr->session), ifMap->name);
NFP_INC(port, pppoe_rx_not_found);
return MV_TERMINATE;
}
NFP_INC(port, pppoe_rx_found);
}
return MV_CONTINUE;
}
#endif /* NFP_PPP */
#ifdef NFP_BRIDGE
/* Do bridging: MV_OK - bridging, MV_TERMINATE - slow path, MV_CONTINUE - Routing */
static INLINE MV_STATUS mvNfpBridgeRx(int port, NETA_RX_DESC *pRxDesc, NFP_IF_MAP *inIfMap, MV_ETH_PKT *pPkt,
MV_NFP_RESULT *pRes)
{
int shift = 0;
MV_U8 *pData;
MV_U8 *da, *sa;
NFP_IF_MAP *outIfMap;
#ifdef NFP_FDB_MODE
NFP_RULE_FDB *fdbRule;
#else
NFP_RULE_BRIDGE *bridgeRule;
#endif
#if defined(NFP_CLASSIFY) && !defined(NFP_FDB_MODE)
int prio;
NFP_CLASSIFY_INFO *classifyInfo = (NFP_CLASSIFY_INFO *)(pRes->privateData);
#endif /* NFP_CLASSIFY */
pData = pPkt->pBuf + pPkt->offset;
da = pData + MV_ETH_MH_SIZE;
sa = da + MV_MAC_ADDR_SIZE;
#ifdef NFP_FDB_MODE
/* BridgeIf + SA lookup */
fdbRule = mvNfpFdbLookup(inIfMap->bridgeIf, pData + MV_ETH_MH_SIZE + MV_MAC_ADDR_SIZE);
if (fdbRule == NULL) {
NFP_INC(port, fdb_sa_miss);
return MV_TERMINATE;
}
/* Check if FDB entry move to other port of the bridge */
if (fdbRule->if_index != inIfMap->ifIdx) {
NFP_INC(port, fdb_port_miss);
return MV_TERMINATE;
}
/* BridgeIf + DA lookup */
fdbRule = mvNfpFdbLookup(inIfMap->bridgeIf, pData + MV_ETH_MH_SIZE);
if (fdbRule == NULL) {
NFP_INC(port, fdb_da_miss);
return MV_TERMINATE;
}
fdbRule->age++;
if (fdbRule->status == NFP_BRIDGE_LOCAL) {
NFP_INC(port, fdb_local);
return MV_CONTINUE;
}
outIfMap = mvNfpIfMapGet(fdbRule->if_index);
if (outIfMap == NULL) {
mvOsPrintf("%s: bridge rule interface %d is not valid\n", __func__, fdbRule->if_index);
NFP_INC(port, oif_err);
return MV_TERMINATE;
}
NFP_INC(port, fdb_hit);
#else
bridgeRule = mvNfpBridgeLookup(da, sa, inIfMap->ifIdx);
if (bridgeRule == NULL) {
NFP_INC(port, bridge_miss);
return MV_TERMINATE;
}
bridgeRule->age++;
#if defined(NFP_CLASSIFY) && !defined(NFP_FDB_MODE)
if (bridgeRule->flags & NFP_F_BR_SET_VLAN_PRIO)
mvNfpVpriBridgeClassifySave(pData, bridgeRule, classifyInfo);
if (bridgeRule->flags & NFP_F_BR_SET_TXQ)
mvNfpTxqClassifySave(bridgeRule->txq, classifyInfo);
if (bridgeRule->flags & NFP_F_BR_SET_TXP)
mvNfpTxpClassifySave(bridgeRule->txp, classifyInfo);
if (bridgeRule->flags & NFP_F_BR_SET_MH)
mvNfpMhClassifySave(bridgeRule->mh, classifyInfo);
#endif /* NFP_CLASSIFY */
/* Check if this is a local bridge rule (DA is "to me") */
if (inIfMap->bridgeIf == bridgeRule->oif) {
NFP_INC(port, bridge_local);
return MV_CONTINUE;
}
outIfMap = mvNfpIfMapGet(bridgeRule->oif);
if (outIfMap == NULL) {
mvOsPrintf("%s: bridge rule out interface %d is not valid\n", __func__, bridgeRule->oif);
NFP_INC(port, oif_err);
return MV_TERMINATE;
}
#if defined(NFP_CLASSIFY) && !defined(NFP_FDB_MODE)
prio = mvNfpClassifyPrioGet(classifyInfo);
if (prio != NFP_PRIO_INVALID)
mvNfpClassifyPrioSave(outIfMap, classifyInfo, prio);
#endif /* NFP_CLASSIFY */
NFP_INC(port, bridge_hit);
#endif /* NFP_FDB_MODE */
#ifdef NFP_VLAN
/* Process VLAN tag */
shift += mvNfpVlanTxUpdate(port, pRxDesc, outIfMap, pData + shift, pPkt, MV_TRUE, pRes);
#endif /* NFP_VLAN */
while (outIfMap->parentIf)
outIfMap = outIfMap->parentIf;
/* Update pPkt for bridging TX */
pRes->dev = outIfMap->dev;
if (outIfMap->flags & NFP_F_MAP_EXT)
pRes->flags |= MV_NFP_RES_NETDEV_EXT;
/* Process 2B of MH */
if (outIfMap->flags & NFP_F_MAP_TX_MH) {
/* Transmit with MH */
*(MV_U16 *)(pData + shift) = outIfMap->txMh;
#if defined(NFP_CLASSIFY) && !defined(NFP_FDB_MODE)
/* allow setting MH only for PON ports */
if (MV_PON_PORT(outIfMap->port))
mvNfpMhClassifyUpdate(pData + shift, classifyInfo);
#endif /* NFP_CLASSIFY */
} else {
/* Transmit without MH */
shift += MV_ETH_MH_SIZE;
pPkt->bytes -= MV_ETH_MH_SIZE;
}
pRes->shift = shift;
#if defined(NFP_CLASSIFY) && !defined(NFP_FDB_MODE)
mvNfpTxqClassifyUpdate(pRes, classifyInfo);
/* allow setting txp only for PON ports */
if (MV_PON_PORT(outIfMap->port))
mvNfpTxpClassifyUpdate(pRes, classifyInfo);
#endif /* NFP_CLASSIFY */
pRes->tx_cmd = NETA_TX_L4_CSUM_NOT;
if ((pRes->flags & MV_NFP_RES_NETDEV_EXT) == 0)
mvOsCacheLineFlush(NULL, pData);
return MV_OK;
}
#endif /* NFP_BRIDGE */
#ifdef NFP_NAT
static INLINE void mvNfpNatUpdate(MV_IP_HEADER_INFO *pIpInfo, NFP_RULE_CT *pCt, MV_NFP_RESULT *pRes, NFP_IF_MAP *pOutIf)
{
MV_IP_HEADER *pIpHdr = pIpInfo->ip_hdr.ip4;
char *l4Hdr = ((char *)pIpHdr + pIpInfo->ipHdrLen);
MV_U16 *pPort;
MV_U32 old_val = 0, new_val = 0;
int csum;
if ((pIpHdr->protocol == MV_IP_PROTO_UDP) && (((MV_UDP_HEADER *)l4Hdr)->check == 0)) {
/* skip L4 csum */
csum = 0;
} else if ((pOutIf->flags & NFP_F_MAP_EXT) ||
needFragment(pIpInfo, pOutIf) ||
(pIpInfo->ipLen > MV_ETH_TX_CSUM_MAX_SIZE)) {
/* L4 checksum must be calculated by SW */
csum = 1;
} else {
/* L4 checksum can be calculated by HW */
csum = 2;
}
if (pCt->flags & NFP_F_CT_SNAT) {
pPort = (MV_U16 *)l4Hdr;
if (csum == 1) {
old_val = pIpHdr->srcIP + *pPort;
new_val = pCt->new_sip + pCt->new_sport;
}
pIpHdr->srcIP = pCt->new_sip;
*pPort = pCt->new_sport;
}
if (pCt->flags & NFP_F_CT_DNAT) {
pPort = (MV_U16 *)(l4Hdr + 2);
if (csum == 1) {
old_val += pIpHdr->dstIP + *pPort;
new_val += pCt->new_dip + pCt->new_dport;
}
pIpHdr->dstIP = pCt->new_dip;
*pPort = pCt->new_dport;
}
switch (csum) {
case 0:
pRes->pWrite = l4Hdr + sizeof(MV_UDP_HEADER);
break;
case 1:
pRes->diffL4[0] = ~old_val;
pRes->diffL4[1] = new_val;
pRes->flags |= MV_NFP_RES_L4_CSUM_NEEDED;
break;
case 2:
pRes->tx_cmd &= ~NETA_TX_L4_CSUM_MASK;
if (pIpHdr->protocol == MV_IP_PROTO_TCP) {
pRes->pWrite = l4Hdr + 4;
pRes->tx_cmd |= NETA_TX_L4_TCP | NETA_TX_L4_CSUM_FULL;
} else if (pIpHdr->protocol == MV_IP_PROTO_UDP) {
pRes->pWrite = l4Hdr + sizeof(MV_UDP_HEADER);
pRes->tx_cmd |= NETA_TX_L4_UDP | NETA_TX_L4_CSUM_FULL;
}
break;
}
}
#endif /* NFP_NAT */
#ifdef NFP_PPP
static INLINE int removePppoeHeader(MV_IP_HEADER_INFO *pIpHdrInfo)
{
unsigned char *pIpHdr;
/* writing IP ethertype to the new location of ether header */
if (pIpHdrInfo->family == MV_INET) {
pIpHdr = (unsigned char *)(pIpHdrInfo->ip_hdr.ip4);
*(pIpHdr - 1) = 0x00;
*(pIpHdr - 2) = 0x08;
} else {
pIpHdr = (unsigned char *)(pIpHdrInfo->ip_hdr.ip6);
*(pIpHdr - 1) = 0xDD;
*(pIpHdr - 2) = 0x86;
}
return MV_PPPOE_HDR_SIZE;
}
static INLINE int addPppoeHeader(NFP_IF_MAP *pOutIf, MV_IP_HEADER_INFO *pIpHdrInfo)
{
unsigned char *pIpHdr;
PPPoE_HEADER *pPPPNew;
if (pIpHdrInfo->family == MV_INET)
pIpHdr = (unsigned char *)pIpHdrInfo->ip_hdr.ip4;
else
pIpHdr = (unsigned char *)pIpHdrInfo->ip_hdr.ip6;
/* Keep VLAN fields*/
*(pIpHdr - MV_PPPOE_HDR_SIZE - 3) = *(pIpHdr - 3);
*(pIpHdr - MV_PPPOE_HDR_SIZE - 4) = *(pIpHdr - 4);
*(pIpHdr - MV_PPPOE_HDR_SIZE - 5) = *(pIpHdr - 5);
*(pIpHdr - MV_PPPOE_HDR_SIZE - 6) = *(pIpHdr - 6);
*(pIpHdr - MV_PPPOE_HDR_SIZE - 1) = 0x64;
*(pIpHdr - MV_PPPOE_HDR_SIZE - 2) = 0x88;
pPPPNew = (PPPoE_HEADER *)(pIpHdr - MV_PPPOE_HDR_SIZE);
pPPPNew->version = 0x11;
pPPPNew->code = 0x0;
pPPPNew->session = pOutIf->sid;
/* calculate PPPoE payload len considering padding for short packets */
if (pIpHdrInfo->family == MV_INET) {
pPPPNew->proto = MV_16BIT_BE(MV_IP_PPP);
pPPPNew->len = MV_16BIT_BE(pIpHdrInfo->ipLen + MV_PPP_HDR_SIZE);
} else {
pPPPNew->proto = MV_16BIT_BE(MV_IP6_PPP);
pPPPNew->len = MV_16BIT_BE(pIpHdrInfo->ipLen + MV_PPP_HDR_SIZE + pIpHdrInfo->ipHdrLen);
}
return -MV_PPPOE_HDR_SIZE;
}
static INLINE void replacePppoeHeader(NFP_IF_MAP *pOutIf, MV_IP_HEADER_INFO *pIpHdrInfo)
{
PPPoE_HEADER *pPPPHdr;
unsigned char *pIpHdr;
pIpHdr = (unsigned char *)pIpHdrInfo->ip_hdr.ip4;
pPPPHdr = (PPPoE_HEADER *)(pIpHdr - MV_PPPOE_HDR_SIZE);
if (pPPPHdr)
pPPPHdr->session = pOutIf->sid;
}
static INLINE int mvNfpPppTxUpdate(MV_U32 port, NETA_RX_DESC *pRxDesc,
NFP_IF_MAP *pOutIf, MV_ETH_PKT *pPkt,
MV_IP_HEADER_INFO *pIpHdrInfo)
{
int pppShift = 0;
if (NETA_RX_IS_PPPOE(pRxDesc)) {
/* Ingress packet has PPPoE header */
if (pOutIf->flags & NFP_F_MAP_PPPOE) {
replacePppoeHeader(pOutIf, pIpHdrInfo);
NFP_INC(port, pppoe_tx_replace);
} else {
/* remove pppoe header */
pppShift = removePppoeHeader(pIpHdrInfo);
pPkt->bytes -= pppShift;
NFP_INC(port, pppoe_tx_remove);
}
} else {
/* Ingress packet doesn't have PPPoE header */
if (pOutIf->flags & NFP_F_MAP_PPPOE) {
/* add pppoe header */
pppShift = addPppoeHeader(pOutIf, pIpHdrInfo);
pPkt->bytes -= pppShift;
NFP_INC(port, pppoe_tx_add);
}
}
return pppShift;
}
#endif /* NFP_PPP */
static INLINE MV_STATUS mvNfpStatusCheck(MV_U32 port, const NETA_RX_DESC *pRxDesc)
{
#ifndef CONFIG_MV_ETH_PNC
if ((pRxDesc->status & ETH_RX_NOT_LLC_SNAP_FORMAT_MASK) == 0) {
NFP_INC(port, non_ip);
return MV_TERMINATE;
}
#endif /* !CONFIG_MV_ETH_PNC */
if (NETA_RX_L3_IS_UN(pRxDesc->status)) {
NFP_INC(port, non_ip);
return MV_TERMINATE;
}
if (NETA_RX_L3_IS_IP4_ERR(pRxDesc->status)) {
NFP_INC(port, ipv4_csum_err);
return MV_TERMINATE;
}
if ((NETA_RX_L4_IS_TCP(pRxDesc->status) ||
NETA_RX_L4_IS_UDP(pRxDesc->status)) &&
(!NETA_RX_L4_CSUM_IS_OK(pRxDesc->status))) {
NFP_INC(port, l4_csum_err);
return MV_TERMINATE;
}
if (nfpMode == MV_NFP_5_TUPLE) {
/* Only UDP or TCP packets with correct checksum are processed in 5 tuple mode */
if (!NETA_RX_L4_CSUM_IS_OK(pRxDesc->status)) {
NFP_INC(port, l4_unknown);
return MV_TERMINATE;
}
}
return MV_CONTINUE;
}
static INLINE MV_STATUS mvNfpParseIpHeader(MV_U32 port, const NETA_RX_DESC *pRxDesc, MV_U8 *pData,
MV_IP_HEADER_INFO *pIpHdr)
{
MV_U8 *pEth;
pEth = pData + MV_ETH_MH_SIZE;
if (pEth[0] & 0x01) { /* Check multicast and broadcast */
NFP_INC(port, mac_mcast);
return MV_TERMINATE;
}
pIpHdr->ipOffset = NETA_RX_GET_IPHDR_OFFSET(pRxDesc);
pIpHdr->ipHdrLen = NETA_RX_GET_IPHDR_HDRLEN(pRxDesc) << 2;
if (NETA_RX_L3_IS_IP6(pRxDesc->status)) {
pIpHdr->family = MV_INET6;
pIpHdr->ip_hdr.ip6 = (MV_IP6_HEADER *) (pData + pIpHdr->ipOffset);
if ((pIpHdr->ip_hdr.ip6)->hoplimit <= 1) {
NFP_INC(port, ttl_exp);
return MV_TERMINATE;
}
pIpHdr->ipLen = MV_16BIT_BE(pIpHdr->ip_hdr.ip6->payloadLength);
pIpHdr->ipProto = pIpHdr->ip_hdr.ip6->protocol;
NFP_INC(port, ipv6);
} else {
pIpHdr->family = MV_INET;
pIpHdr->ip_hdr.ip4 = (MV_IP_HEADER *) (pData + pIpHdr->ipOffset);
pIpHdr->ipLen = MV_16BIT_BE(pIpHdr->ip_hdr.ip4->totalLength);
pIpHdr->ipProto = pIpHdr->ip_hdr.ip4->protocol;
#ifdef NFP_CT
if (nfpMode == MV_NFP_5_TUPLE) {
if (NETA_RX_IP_IS_FRAG(pRxDesc->status)) {
NFP_INC(port, ipv4_rx_frag);
return MV_TERMINATE;
}
}
#endif /* NFP_CT */
if ((pIpHdr->ip_hdr.ip4)->ttl <= 1) {
NFP_INC(port, ttl_exp);
return MV_TERMINATE;
}
NFP_INC(port, ipv4);
}
return MV_CONTINUE;
}
static INLINE MV_STATUS mvNfpFragmentCheck(int port, MV_IP_HEADER_INFO *pIpInfo, NFP_IF_MAP *pOutIf)
{
if (needFragment(pIpInfo, pOutIf)) {
if ((pIpInfo->family == MV_INET) &&
(pIpInfo->ip_hdr.ip4->fragmentCtrl & MV_16BIT_BE(MV_IP4_DF_FLAG_MASK))) {
NFP_INC(port, ip_tx_frag_err);
return MV_TERMINATE;
}
NFP_INC(port, ip_tx_frag);
}
return MV_CONTINUE;
}
#ifdef NFP_CLASSIFY
MV_STATUS mvNfpClassifyModeSet(MV_NFP_CLASSIFY_FEATURE feature, MV_NFP_CLASSIFY_MODE mode)
{
if ((feature < MV_NFP_CLASSIFY_FEATURE_DSCP) || (feature > MV_NFP_CLASSIFY_FEATURE_MH)) {
mvOsPrintf("%s: Illegal feature value %d\n", __func__, feature);
return MV_BAD_PARAM;
}
if ((mode < MV_NFP_CLASSIFY_MODE_DISABLED) || (mode > MV_NFP_CLASSIFY_MODE_LOWEST)) {
mvOsPrintf("%s: Illegal mode value %d\n", __func__, mode);
return MV_BAD_PARAM;
}
classifyMode[feature] = mode;
return MV_OK;
}
MV_NFP_CLASSIFY_MODE mvNfpClassifyModeGet(MV_NFP_CLASSIFY_FEATURE feature)
{
if ((feature < MV_NFP_CLASSIFY_FEATURE_DSCP) || (feature >= MV_NFP_CLASSIFY_FEATURE_INVALID)) {
mvOsPrintf("%s: Illegal feature value %d\n", __func__, feature);
return MV_NFP_CLASSIFY_MODE_INVALID;
}
return classifyMode[feature];
}
MV_STATUS mvNfpExactPolicySet(MV_NFP_CLASSIFY_FEATURE feature, MV_NFP_CLASSIFY_POLICY policy)
{
if ((feature < MV_NFP_CLASSIFY_FEATURE_DSCP) || (feature > MV_NFP_CLASSIFY_FEATURE_MH)) {
mvOsPrintf("%s: Illegal feature value %d\n", __func__, feature);
return MV_BAD_PARAM;
}
if ((policy < MV_NFP_CLASSIFY_POLICY_HIGHEST) || (policy > MV_NFP_CLASSIFY_POLICY_LAST)) {
mvOsPrintf("%s: Illegal policy value %d\n", __func__, policy);
return MV_BAD_PARAM;
}
exactPolicy[feature] = policy;
return MV_OK;
}
MV_NFP_CLASSIFY_POLICY mvNfpExactPolicyGet(MV_NFP_CLASSIFY_FEATURE feature)
{
if ((feature < MV_NFP_CLASSIFY_FEATURE_DSCP) || (feature > MV_NFP_CLASSIFY_FEATURE_MH)) {
mvOsPrintf("%s: Illegal feature value %d\n", __func__, feature);
return MV_NFP_CLASSIFY_POLICY_INVALID;
}
return exactPolicy[feature];
}
MV_STATUS mvNfpPrioPolicySet(MV_NFP_CLASSIFY_POLICY policy)
{
if ((policy < MV_NFP_CLASSIFY_POLICY_HIGHEST) || (policy > MV_NFP_CLASSIFY_POLICY_LOWEST)) {
mvOsPrintf("%s: Illegal policy value %d\n", __func__, policy);
return MV_NFP_CLASSIFY_POLICY_INVALID;
}
prioPolicy = policy;
return MV_OK;
}
MV_NFP_CLASSIFY_POLICY mvNfpPrioPolicyGet(MV_VOID)
{
return prioPolicy;
}
/* Priority classification API */
MV_STATUS mvNfpIifToPrioSet(int iif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio < NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->prio = prio;
return MV_OK;
}
MV_STATUS mvNfpIifVlanToPrioSet(int iif, MV_U8 vlan_prio, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio < NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
if (vlan_prio < NFP_VPRI_MIN || vlan_prio > NFP_VPRI_MAX) {
NFP_WARN("%s: vlan_prio #%d is invalid.\n", __func__, vlan_prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->vpri_to_prio[vlan_prio].prio = prio;
ifMap->vpri_to_prio[vlan_prio].valid = 1;
return MV_OK;
}
MV_STATUS mvNfpIifDscpToPrioSet(int iif, MV_U8 dscp, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio < NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
if (dscp < NFP_DSCP_MIN || dscp > NFP_DSCP_MAX) {
NFP_WARN("%s: dscp #%d is invalid.\n", __func__, dscp);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->dscp_to_prio[dscp].prio = prio;
ifMap->dscp_to_prio[dscp].valid = 1;
return MV_OK;
}
MV_STATUS mvNfpIifToPrioDel(int iif)
{
NFP_IF_MAP *ifMap = NULL;
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->prio = NFP_PRIO_INVALID;
return MV_OK;
}
MV_STATUS mvNfpIifVlanToPrioDel(int iif, MV_U8 vlan_prio)
{
NFP_IF_MAP *ifMap = NULL;
if (vlan_prio < NFP_VPRI_MIN || vlan_prio > NFP_VPRI_MAX) {
NFP_WARN("%s: vlan_prio #%d is invalid.\n", __func__, vlan_prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->vpri_to_prio[vlan_prio].prio = NFP_PRIO_INVALID;
ifMap->vpri_to_prio[vlan_prio].valid = 0;
return MV_OK;
}
MV_STATUS mvNfpIifDscpToPrioDel(int iif, MV_U8 dscp)
{
NFP_IF_MAP *ifMap = NULL;
if (dscp < NFP_DSCP_MIN || dscp > NFP_DSCP_MAX) {
NFP_WARN("%s: dscp #%d is invalid.\n", __func__, dscp);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(iif);
if (!ifMap) {
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
return MV_BAD_PARAM;
}
ifMap->dscp_to_prio[dscp].prio = NFP_PRIO_INVALID;
ifMap->dscp_to_prio[dscp].valid = 0;
return MV_OK;
}
MV_STATUS mvNfpPrioToDscpSet(int oif, MV_U8 prio, MV_U8 dscp)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
if (dscp < NFP_DSCP_MIN || dscp > NFP_DSCP_MAX) {
NFP_WARN("%s: dscp #%d is invalid.\n", __func__, dscp);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].dscp = dscp;
ifMap->prio_to_classify[prio].flags |= NFP_F_PRIO_DSCP;
return MV_OK;
}
MV_STATUS mvNfpPrioToVprioSet(int oif, MV_U8 prio, MV_U8 vlan_prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
if (vlan_prio < NFP_VPRI_MIN || vlan_prio > NFP_VPRI_MAX) {
NFP_WARN("%s: vlan_prio #%d is invalid.\n", __func__, vlan_prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].vprio = vlan_prio;
ifMap->prio_to_classify[prio].flags |= NFP_F_PRIO_VPRIO;
return MV_OK;
}
MV_STATUS mvNfpPrioToTxpSet(int oif, MV_U8 prio, MV_U8 txp)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].txp = txp;
ifMap->prio_to_classify[prio].flags |= NFP_F_PRIO_TXP;
return MV_OK;
}
MV_STATUS mvNfpPrioToTxqSet(int oif, MV_U8 prio, MV_U8 txq)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
if (txq >= CONFIG_MV_ETH_TXQ) {
NFP_WARN("%s: txq #%d is invalid.\n", __func__, txq);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].txq = txq;
ifMap->prio_to_classify[prio].flags |= NFP_F_PRIO_TXQ;
return MV_OK;
}
MV_STATUS mvNfpPrioToMhSet(int oif, MV_U8 prio, MV_U16 mh)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].mh = mh;
ifMap->prio_to_classify[prio].flags |= NFP_F_PRIO_MH;
return MV_OK;
}
MV_STATUS mvNfpPrioToDscpDel(int oif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].flags &= ~NFP_F_PRIO_DSCP;
return MV_OK;
}
MV_STATUS mvNfpPrioToVprioDel(int oif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].flags &= ~NFP_F_PRIO_VPRIO;
return MV_OK;
}
MV_STATUS mvNfpPrioToTxpDel(int oif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].flags &= ~NFP_F_PRIO_TXP;
return MV_OK;
}
MV_STATUS mvNfpPrioToTxqDel(int oif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].flags &= ~NFP_F_PRIO_TXQ;
return MV_OK;
}
MV_STATUS mvNfpPrioToMhDel(int oif, MV_U8 prio)
{
NFP_IF_MAP *ifMap = NULL;
if (prio <= NFP_PRIO_INVALID || prio > NFP_PRIO_MAX) {
NFP_WARN("%s: prio #%d is invalid.\n", __func__, prio);
return MV_BAD_PARAM;
}
ifMap = mvNfpIfMapGet(oif);
if (!ifMap) {
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
return MV_BAD_PARAM;
}
ifMap->prio_to_classify[prio].flags &= ~NFP_F_PRIO_MH;
return MV_OK;
}
MV_VOID mvNfpIngressPrioDump(int iif)
{
int i;
NFP_IF_MAP *ifMap = NULL;
ifMap = mvNfpIfMapGet(iif);
if (!ifMap)
NFP_WARN("%s: iif #%d is invalid\n", __func__, iif);
mvOsPrintf("ingress interface #%d prio dump\n\n", iif);
if (ifMap->prio != NFP_PRIO_INVALID)
mvOsPrintf("interface priority = %d\n\n", ifMap->prio);
else
mvOsPrintf("interface priority = invalid (no priority)\n\n");
mvOsPrintf("interface + DSCP to priority Map: \n");
mvOsPrintf(" DSCP Priority\n");
for (i = 0; i <= NFP_DSCP_MAP_GLOBAL; i++) {
if (ifMap->dscp_to_prio[i].valid) {
if (i == NFP_DSCP_MAP_GLOBAL)
mvOsPrintf(" Global %2d\n", ifMap->dscp_to_prio[i].prio);
else
mvOsPrintf(" %2d %2d\n", i, ifMap->dscp_to_prio[i].prio);
}
}
mvOsPrintf("\ninterface + Vpri to priority Map: \n");
mvOsPrintf(" Vpri Priority\n");
for (i = 0; i <= NFP_VPRI_MAP_GLOBAL; i++) {
if (ifMap->vpri_to_prio[i].valid) {
if (i == NFP_VPRI_MAP_GLOBAL)
mvOsPrintf(" Global %2d\n", ifMap->vpri_to_prio[i].prio);
else
mvOsPrintf(" %2d %2d\n", i, ifMap->vpri_to_prio[i].prio);
}
}
}
MV_VOID mvNfpEgressPrioDump(int oif)
{
int i;
NFP_IF_MAP *ifMap = NULL;
ifMap = mvNfpIfMapGet(oif);
if (!ifMap)
NFP_WARN("%s: oif #%d is invalid\n", __func__, oif);
mvOsPrintf("egress interface #%d prio dump\n\n", oif);
mvOsPrintf("interface + prio to classification data Map: \n");
mvOsPrintf(" Prio DSCP Vpri TXP TXQ MH\n");
for (i = 0; i < NFP_PRIO_MAP_SIZE; i++) {
if (ifMap->prio_to_classify[i].flags) {
mvOsPrintf(" %2d", i);
if (ifMap->prio_to_classify[i].flags & NFP_F_PRIO_DSCP)
mvOsPrintf(" %2d", ifMap->prio_to_classify[i].dscp);
else
mvOsPrintf(" ");
if (ifMap->prio_to_classify[i].flags & NFP_F_PRIO_VPRIO)
mvOsPrintf(" %2d", ifMap->prio_to_classify[i].vprio);
else
mvOsPrintf(" ");
if (ifMap->prio_to_classify[i].flags & NFP_F_PRIO_TXP)
mvOsPrintf(" %2d", ifMap->prio_to_classify[i].txp);
else
mvOsPrintf(" ");
if (ifMap->prio_to_classify[i].flags & NFP_F_PRIO_TXQ)
mvOsPrintf(" %2d", ifMap->prio_to_classify[i].txq);
else
mvOsPrintf(" ");
if (ifMap->prio_to_classify[i].flags & NFP_F_PRIO_MH)
mvOsPrintf(" %2d", ifMap->prio_to_classify[i].mh);
mvOsPrintf("\n");
}
}
}
static INLINE MV_VOID mvNfpClassifyIifToPrioSave(NFP_IF_MAP *pInIf, NFP_CLASSIFY_INFO *info)
{
info->iif_prio = pInIf->prio;
}
static INLINE MV_VOID mvNfpClassifyIifVprioToPrioSave(NFP_IF_MAP *pInIf, NFP_CLASSIFY_INFO *info)
{
MV_U8 vprio = info->pkt_vlan_prio;
MV_U8 valid = pInIf->vpri_to_prio[vprio].valid;
info->iif_vlan_prio = (valid) ? pInIf->vpri_to_prio[vprio].prio : NFP_PRIO_INVALID;
}
static INLINE MV_VOID mvNfpClassifyIifDscpToPrioSave(NFP_IF_MAP *pInIf, NFP_CLASSIFY_INFO *info)
{
MV_U8 dscp = info->pkt_dscp;
MV_U8 valid = pInIf->dscp_to_prio[dscp].valid;
info->iif_dscp_prio = (valid) ? pInIf->dscp_to_prio[dscp].prio : NFP_PRIO_INVALID;
}
#endif /* NFP_CLASSIFY */
static INLINE MV_STATUS mvNfpTwoTupleProcess(MV_U32 port, MV_IP_HEADER_INFO *pIpHdr,
MV_ETH_PKT *pPkt, NFP_RULE_FIB **pFib)
{
MV_U8 *srcL3, *dstL3;
if (pIpHdr->family == MV_INET) {
/* Remove padding */
pPkt->bytes = (pIpHdr->ipLen + pIpHdr->ipOffset);
dstL3 = (MV_U8 *)&(pIpHdr->ip_hdr.ip4->dstIP);
srcL3 = (MV_U8 *)&(pIpHdr->ip_hdr.ip4->srcIP);
} else {
dstL3 = pIpHdr->ip_hdr.ip6->dstAddr;
srcL3 = pIpHdr->ip_hdr.ip6->srcAddr;
}
*pFib = mvNfpFibLookup(pIpHdr->family, srcL3, dstL3);
if (!(*pFib)) {
NFP_WARN("%s failed: ", __func__);
mvNfp2TupleInfoPrint(NFP_WARN_PRINT, pIpHdr->family, srcL3, dstL3);
NFP_INC(port, fib_miss);
return MV_TERMINATE;
}
(*pFib)->age++;
NFP_INC(port, fib_hit);
return MV_CONTINUE;
}
#ifdef NFP_CT
#ifdef NFP_CT_LEARN
/* Check for FIN/RST flags in TCP header */
static INLINE MV_U8 mvNfpTcpClose(MV_IP_HEADER_INFO *pIpHdr)
{
MV_TCP_HEADER *pTcpHdr;
if (pIpHdr->ipProto != MV_IP_PROTO_TCP)
return 0;
pTcpHdr = (MV_TCP_HEADER *)((unsigned)(pIpHdr->ip_hdr.l3) + pIpHdr->ipHdrLen);
return (MV_16BIT_BE(pTcpHdr->flags) & (MV_TCP_FLAG_RST | MV_TCP_FLAG_FIN));
}
#endif /* NFP_CT_LEARN */
static INLINE MV_STATUS mvNfpFiveTupleProcess(MV_U32 port, MV_IP_HEADER_INFO *pIpHdr,
MV_ETH_PKT *pPkt, NFP_RULE_CT **ppCt,
MV_NFP_RESULT *pRes)
{
NFP_RULE_CT *pCt = NULL;
MV_U8 *srcL3, *dstL3;
MV_U16 proto = 0;
MV_U32 ports = 0;
if (pIpHdr->family == MV_INET) {
MV_IP_HEADER *pIph = pIpHdr->ip_hdr.ip4;
/* Remove padding */
pPkt->bytes = (pIpHdr->ipLen + pIpHdr->ipOffset);
dstL3 = (MV_U8 *)&(pIph->dstIP);
srcL3 = (MV_U8 *)&(pIph->srcIP);
proto = pIph->protocol;
ports = *(MV_U32 *)((char *)pIph + pIpHdr->ipHdrLen);
} else {
MV_IP6_HEADER *pIp6Hdr = pIpHdr->ip_hdr.ip6;
srcL3 = pIp6Hdr->srcAddr;
dstL3 = pIp6Hdr->dstAddr;
proto = pIp6Hdr->protocol;
ports = *(MV_U32 *)((char *)pIp6Hdr + pIpHdr->ipHdrLen);
}
pCt = mvNfpCtLookupByTuple(pIpHdr->family, srcL3, dstL3, ports, proto);
if (!pCt) {
NFP_WARN("%s failed: ", __func__);
mvNfp5TupleInfoPrint(NFP_WARN_PRINT, pIpHdr->family, srcL3, dstL3,
MV_16BIT_BE(ports & 0xFFFF), MV_16BIT_BE((ports >> 16) & 0xFFFF), proto);
NFP_INC(port, ct_miss);
return MV_TERMINATE;
}
pCt->age++;
pCt->hit_cntr++;
NFP_INC(port, ct_hit);
#ifdef NFP_CT_LEARN
if (mvNfpTcpClose(pIpHdr)) {
NFP_INC(port, ct_tcp_fin_rst);
return MV_TERMINATE;
}
#endif /* NFP_CT_LEARN */
if (pCt->flags & NFP_F_CT_DROP)
return MV_DROPPED;
*ppCt = pCt;
#ifdef NFP_CLASSIFY
{
int txq = 0;
NFP_CLASSIFY_INFO *classifyInfo = (NFP_CLASSIFY_INFO *)(pRes->privateData);
if (pCt->flags & NFP_F_CT_SET_DSCP)
mvNfpDscpClassifySave(pCt, classifyInfo);
if (pCt->flags & NFP_F_CT_SET_VLAN_PRIO)
mvNfpVpriCtClassifySave(pCt, classifyInfo);
/* classifyInfo->pkt_dscp is updated in mvNfpDscpClassifySave so it is valid here */
if (pCt->txq_map[classifyInfo->pkt_dscp].valid)
txq = pCt->txq_map[classifyInfo->pkt_dscp].txq;
else if (pCt->txq_map[NFP_DSCP_MAP_GLOBAL].valid)
txq = pCt->txq_map[NFP_DSCP_MAP_GLOBAL].txq;
if (pCt->flags & NFP_F_CT_SET_TXQ)
mvNfpTxqClassifySave(txq, classifyInfo);
if (pCt->flags & NFP_F_CT_SET_TXP)
mvNfpTxpClassifySave(pCt->txp, classifyInfo);
if (pCt->flags & NFP_F_CT_SET_MH)
mvNfpMhClassifySave(pCt->mh, classifyInfo);
}
#endif /* NFP_CLASSIFY */
#ifdef NFP_LIMIT
if (pCt->tbfInfo)
return mvNfpTbfProcess(pCt->tbfInfo, pPkt->bytes);
#endif /* NFP_LIMIT */
return MV_CONTINUE;
}
#endif /* NFP_CT */
/* NFP Process */
MV_STATUS mvNfpRx(MV_U32 port, NETA_RX_DESC *pRxDesc, MV_ETH_PKT *pPkt, MV_NFP_RESULT *pRes)
{
NFP_RULE_FIB *pFib;
MV_U8 *pData;
MV_IP_HEADER_INFO *ipHdrInfo = &pRes->ipInfo;
int shift = 0;
MV_STATUS status;
NFP_IF_MAP *pInIf, *pOutIf;
#ifdef NFP_CT
NFP_RULE_CT *pCt = NULL;
#endif /* NFP_CT */
#ifdef NFP_CLASSIFY
int prio;
NFP_CLASSIFY_INFO classifyInfo;
mvOsMemset(&classifyInfo, 0, sizeof(NFP_CLASSIFY_INFO));
mvNfpClassifyInit(&classifyInfo);
pRes->privateData = &classifyInfo;
#endif /* NFP_CLASSIFY */
NFP_INC(port, rx);
pData = pPkt->pBuf + pPkt->offset;
pRes->flags = 0;
pRes->shift = 0;
pRes->tx_cmd = NETA_TX_L4_CSUM_NOT;
/* Lookup incoming interface (port + switchGroup) */
pInIf = mvNfpIfMapRealGet(port, pData);
if (pInIf == NULL) {
NFP_INC(port, iif_err);
return MV_TERMINATE;
}
#ifdef NFP_CLASSIFY
/* map iif to prio */
mvNfpClassifyIifToPrioSave(pInIf, &classifyInfo);
#endif /* NFP_CLASSIFY */
#ifdef NFP_VLAN
status = mvNfpVlanRx(port, pRxDesc, pData, pPkt, &pInIf, pRes);
if (status != MV_CONTINUE)
return status;
#endif /* NFP_VLAN */
#ifdef NFP_CLASSIFY
/* map iif + vlan to prio */
mvNfpClassifyIifVprioToPrioSave(pInIf, &classifyInfo);
#endif /* NFP_CLASSIFY */
#ifdef NFP_BRIDGE
if (pInIf->flags & NFP_F_MAP_BRIDGE_PORT) {
/* Do bridging: OK - bridging, TERMINATE - slow path, CONTINUE - Routing */
status = mvNfpBridgeRx(port, pRxDesc, pInIf, pPkt, pRes);
if (status != MV_CONTINUE)
return status;
}
#endif /* NFP_BRIDGE */
status = mvNfpStatusCheck(port, pRxDesc);
if (status != MV_CONTINUE)
return status;
status = mvNfpParseIpHeader(port, pRxDesc, pData, ipHdrInfo);
if (status != MV_CONTINUE)
return status;
pRes->flags |= MV_NFP_RES_IP_INFO_VALID;
#ifdef NFP_PPP
status = mvNfpPppRx(port, pRxDesc, pData, pPkt, &pInIf, ipHdrInfo);
if (status != MV_CONTINUE)
return status;
#endif /* NFP_PPP */
#ifdef NFP_CLASSIFY
mvNfpPktDscpClassifySave(ipHdrInfo, &classifyInfo);
#endif /* NFP_CLASSIFY */
if (nfpMode == MV_NFP_2_TUPLE) {
status = mvNfpTwoTupleProcess(port, ipHdrInfo, pPkt, &pFib);
if (status != MV_CONTINUE)
return status;
} else {
#ifdef NFP_CT
status = mvNfpFiveTupleProcess(port, ipHdrInfo, pPkt, &pCt, pRes);
if (status != MV_CONTINUE)
return status;
pFib = pCt->fib;
pFib->age++;
#else
return MV_TERMINATE;
#endif /* NFP_CT */
}
#ifdef NFP_CLASSIFY
/* map iif + dscp to prio */
mvNfpClassifyIifDscpToPrioSave(pInIf, &classifyInfo);
#endif /* NFP_CLASSIFY */
/* At this point pFib is valid */
pOutIf = mvNfpIfMapGet(pFib->oif);
if (pOutIf == NULL) {
mvOsPrintf("%s: fib out interface %d is not valid\n", __func__, pFib->oif);
NFP_INC(port, oif_err);
return MV_TERMINATE;
}
/* Check if fragmentation needed but don't fragment bit is set */
status = mvNfpFragmentCheck(port, ipHdrInfo, pOutIf);
if (status != MV_CONTINUE)
return status;
pRes->mtu = pOutIf->mtu;
pRes->pWrite = ((MV_U8 *)ipHdrInfo->ip_hdr.l3) + ipHdrInfo->ipHdrLen;
#ifdef NFP_NAT
if (pCt && (pCt->flags & (NFP_F_CT_SNAT | NFP_F_CT_DNAT)))
mvNfpNatUpdate(ipHdrInfo, pCt, pRes, pOutIf);
#endif /* NFP_NAT */
mvNfpFibIpUpdate(ipHdrInfo);
#ifdef NFP_PPP
shift = mvNfpPppTxUpdate(port, pRxDesc, pOutIf, pPkt, ipHdrInfo);
if (pOutIf->flags & NFP_F_MAP_PPPOE)
pOutIf = pOutIf->parentIf;
#endif /* NFP_PPP */
#ifdef NFP_CLASSIFY
prio = mvNfpClassifyPrioGet(&classifyInfo);
if (prio != NFP_PRIO_INVALID)
mvNfpClassifyPrioSave(pOutIf, &classifyInfo, prio);
#endif /* NFP_CLASSIFY */
#ifdef NFP_VLAN
shift += mvNfpVlanTxUpdate(port, pRxDesc, pOutIf, pData + shift, pPkt, MV_FALSE, pRes);
#endif /* NFP_VLAN */
mvNfpFibMacUpdate(pData + shift, pFib);
while (pOutIf->parentIf)
pOutIf = pOutIf->parentIf;
pRes->dev = pOutIf->dev;
if (pOutIf->flags & NFP_F_MAP_EXT)
pRes->flags |= MV_NFP_RES_NETDEV_EXT;
#ifdef NFP_CLASSIFY
/* Update packet according to classification results */
#ifdef NFP_CT
mvNfpDscpClassifyUpdate(ipHdrInfo, &classifyInfo);
#endif /* NFP_CT */
/* allow setting MH only for PON ports */
if (MV_PON_PORT(pOutIf->port))
mvNfpMhClassifyUpdate(pData + shift, &classifyInfo);
if (classifyInfo.flags & NFP_F_SET_TXQ)
mvNfpTxqClassifyUpdate(pRes, &classifyInfo);
/* allow setting txp only for PON ports */
if (MV_PON_PORT(pOutIf->port))
mvNfpTxpClassifyUpdate(pRes, &classifyInfo);
#endif /* NFP_CLASSIFY */
/* Process 2B of MH */
if (!(pOutIf->flags & NFP_F_MAP_TX_MH)) {
shift += MV_ETH_MH_SIZE;
pPkt->bytes -= MV_ETH_MH_SIZE;
}
pRes->shift = shift;
if ((pRes->flags & (MV_NFP_RES_L4_CSUM_NEEDED | MV_NFP_RES_NETDEV_EXT)) == 0) {
/* Flush maximum accessed data before TX */
if (shift < 0)
pData += shift;
mvOsCacheMultiLineFlushInv(NULL, pData, (pRes->pWrite - pData));
}
return MV_OK;
}
MV_STATUS mvNfpIfMapCreate(NFP_IF_MAP *ifMap2)
{
MV_U32 flags;
NFP_IF_MAP *newMap, *ifMap;
newMap = mvOsMalloc(sizeof(NFP_IF_MAP));
if (newMap == NULL) {
mvOsPrintf("%s: can't allocate NFP_IF_MAP\n", __func__);
return MV_NO_RESOURCE;
}
memcpy(newMap, ifMap2, sizeof(NFP_IF_MAP));
flags = newMap->flags;
if (!(flags & NFP_F_MAP_INT))
newMap->port = NFP_INVALID_PORT;
if (flags & NFP_F_MAP_EXT) {
if (nfpFreeExtPort >= NFP_MAX_PORTS) {
mvOsPrintf("%s: No free place for external interface. nfpFreeExtPort=%d\n",
__func__, nfpFreeExtPort);
mvOsFree(newMap);
return MV_BUSY;
}
newMap->port = nfpFreeExtPort;
nfpFreeExtPort++;
}
if (flags & NFP_F_MAP_SWITCH_PORT) {
/* Set MH flag for port */
nfp_ports[newMap->port] |= NFP_F_PORT_MH;
} else
newMap->switchGroup = NFP_INVALID_SWITCH_GROUP;
if (!(flags & NFP_F_MAP_TX_MH))
newMap->txMh = 0;
newMap->vlanId = NFP_INVALID_VLAN;
#ifdef NFP_CLASSIFY
newMap->prio = NFP_PRIO_INVALID;
#endif /* NFP_CLASSIFY */
/* Check if such entry already exist */
ifMap = nfp_if_map[newMap->ifIdx & NFP_DEV_HASH_MASK];
while (ifMap) {
if (ifMap->ifIdx == newMap->ifIdx) {
mvOsPrintf("%s: ifMap for ifIdx=%d already exist\n", __func__, newMap->ifIdx);
mvOsFree(newMap);
return MV_BUSY;
}
if (mvNfpIfMapCmp(newMap->port, newMap->switchGroup, ifMap)) {
mvOsPrintf("%s: ifMap with port=%d, switchGroup=%d already exist\n",
__func__, newMap->port, newMap->switchGroup);
mvOsFree(newMap);
return MV_BUSY;
}
ifMap = ifMap->nextMap;
}
/* Add to nfp_if_map */
newMap->nextMap = nfp_if_map[newMap->ifIdx & NFP_DEV_HASH_MASK];
nfp_if_map[newMap->ifIdx & NFP_DEV_HASH_MASK] = newMap;
/* Add to nfp_if_real_map */
if (newMap->port != NFP_INVALID_PORT) {
if (newMap->switchGroup == NFP_INVALID_SWITCH_GROUP)
nfp_if_real_map[newMap->port][0] = newMap;
else
nfp_if_real_map[newMap->port][newMap->switchGroup] = newMap;
}
return MV_OK;
}
MV_STATUS mvNfpIfVirtMap(int ifIdx, int virtIf)
{
NFP_IF_MAP *ifMap = mvNfpIfMapGet(ifIdx);
NFP_IF_MAP *ifVirt = mvNfpIfMapGet(virtIf);
NFP_IF_MAP *ifTemp;
/* parentIf and virtIf must be created */
if ((ifMap == NULL) || (ifVirt == NULL)) {
mvOsPrintf("%s: interface not valid - parent=%d (%p), virt=%d (%p)\n",
__func__, ifIdx, ifMap, virtIf, ifVirt);
return MV_NOT_FOUND;
}
/* Check validity - TBD */
/* Set MH as in parent interface */
ifVirt->txMh = ifMap->txMh;
/* Set external flag if parent is external */
if (ifMap->flags & NFP_F_MAP_EXT)
ifVirt->flags |= NFP_F_MAP_EXT;
/* Bind */
ifTemp = ifMap->virtIf;
ifMap->virtIf = ifVirt;
ifVirt->virtNext = ifTemp;
/* Remember parent interface */
ifVirt->parentIf = ifMap;
return MV_OK;
}
MV_STATUS mvNfpIfVirtUnmap(int virtIf)
{
NFP_IF_MAP *ifVirt = mvNfpIfMapGet(virtIf);
NFP_IF_MAP *ifUp, *ifTemp;
if (ifVirt == NULL) {
mvOsPrintf("%s: virtual interface is not valid - virt=%d\n",
__func__, virtIf);
return MV_NOT_FOUND;
}
if (ifVirt->virtIf != NULL) {
mvOsPrintf("%s: Can't unmap (%s), virtual interface %s was created\n",
__func__, ifVirt->name, ifVirt->virtIf->name);
return MV_NOT_FOUND;
}
ifUp = ifVirt->parentIf;
if (ifUp == NULL) {
mvOsPrintf("%s: Can't unmap (%s), parentIf is NULL\n", __func__, ifVirt->name);
return MV_NOT_FOUND;
}
ifTemp = ifUp->virtIf;
if (ifTemp == ifVirt) {
ifUp->virtIf = ifVirt->virtNext;
/* FIXME: PPPoE over VLAN */
return MV_OK;
}
while (ifTemp->virtNext != NULL) {
if (ifTemp->virtNext == ifVirt) {
ifTemp->virtNext = ifVirt->virtNext;
/* FIXME: PPPoE over VLAN */
return MV_OK;
}
ifTemp = ifTemp->virtNext;
}
mvOsPrintf("%s: virtual interface %d is not mapped to interface %d\n",
__func__, virtIf, ifUp->ifIdx);
return MV_NOT_FOUND;
}
MV_STATUS mvNfpIfFlagsSet(int ifIdx, MV_U32 flags)
{
NFP_IF_MAP *ifMap = mvNfpIfMapGet(ifIdx);
if (ifMap == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, ifIdx);
return MV_NOT_FOUND;
}
ifMap->flags |= flags;
return MV_OK;
}
MV_STATUS mvNfpIfFlagsClear(int ifIdx, MV_U32 flags)
{
NFP_IF_MAP *ifMap = mvNfpIfMapGet(ifIdx);
if (ifMap == NULL) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, ifIdx);
return MV_NOT_FOUND;
}
ifMap->flags &= ~flags;
return MV_OK;
}
MV_STATUS mvNfpIfMapMacUpdate(int ifIdx, const MV_U8 *mac)
{
NFP_IF_MAP *map = mvNfpIfMapGet(ifIdx);
if (map != NULL) {
mvOsMemcpy(map->mac, mac, MV_MAC_ADDR_SIZE);
return MV_OK;
}
return MV_NOT_FOUND;
}
MV_STATUS mvNfpIfMapMtuUpdate(int ifIdx, int mtu)
{
NFP_IF_MAP *map = mvNfpIfMapGet(ifIdx);
if (map != NULL) {
map->mtu = mtu;
return MV_OK;
}
return MV_NOT_FOUND;
}
MV_STATUS mvNfpIfMapPortGet(int ifIdx, int *port)
{
NFP_IF_MAP *ifMap = mvNfpIfMapGet(ifIdx);
if (ifMap && (ifMap->port != NFP_INVALID_PORT)) {
*port = ifMap->port;
return MV_OK;
}
return MV_NOT_FOUND;
}
MV_STATUS mvNfpIfMapDelete(int ifIdx)
{
MV_U32 hash = 0;
NFP_IF_MAP *currMap = NULL, *prevMap = NULL;
if ((ifIdx <= 0) || (mvNfpIfMapGet(ifIdx) == NULL)) {
mvOsPrintf("%s: interface %d is not valid\n", __func__, ifIdx);
return MV_BAD_PARAM;
}
hash = (ifIdx & NFP_DEV_HASH_MASK);
/* remove from nfp_if_map */
for (currMap = nfp_if_map[hash]; currMap != NULL; prevMap = currMap, currMap = currMap->nextMap) {
if (currMap->ifIdx == ifIdx) {
if (prevMap == NULL)
nfp_if_map[hash] = currMap->nextMap;
else
prevMap->nextMap = currMap->nextMap;
/* do not delete element yet, need to remove it from nfp_if_real_map */
break;
}
}
if (currMap) {
if (currMap->port != NFP_INVALID_PORT) {
/* remove from nfp_if_real_map */
if (currMap->switchGroup == NFP_INVALID_SWITCH_GROUP)
nfp_if_real_map[currMap->port][0] = NULL;
else
nfp_if_real_map[currMap->port][currMap->switchGroup] = NULL;
}
/* delete element */
mvOsFree(currMap);
return MV_OK;
}
return MV_NOT_FOUND;
}
#ifdef NFP_BRIDGE
/* There are functions common for mvNfpBridge.c and for mvNfpFdb.c */
MV_STATUS mvNfpIfToBridgeAdd(int bridgeIf, int portIf)
{
NFP_IF_MAP *portIfMap = mvNfpIfMapGet(portIf);
NFP_IF_MAP *bridgeIfMap = mvNfpIfMapGet(bridgeIf);
if (bridgeIfMap == NULL) {
mvOsPrintf("%s: trying to add interface (%d) to non-registered bridge (%d)\n",
__func__, portIf, bridgeIf);
return MV_NOT_FOUND;
}
if (!(bridgeIfMap->flags & NFP_F_MAP_BRIDGE) || (bridgeIfMap->ifIdx != bridgeIf)) {
mvOsPrintf("%s: Wrong bridgeIf=%d\n", __func__, bridgeIf);
return MV_FAIL;
}
if (portIfMap != NULL) {
/* Check that port_if isn't already connected to an other bridge */
if ((portIfMap->flags & NFP_F_MAP_BRIDGE_PORT) && (portIfMap->bridgeIf != bridgeIf))
return MV_BUSY;
portIfMap->flags |= NFP_F_MAP_BRIDGE_PORT;
portIfMap->bridgeIf = bridgeIf;
return MV_OK;
}
return MV_NOT_FOUND;
}
MV_STATUS mvNfpIfToBridgeDel(int bridge_if, int port_if)
{
NFP_IF_MAP *portIfMap = mvNfpIfMapGet(port_if);
if (portIfMap != NULL) {
/* Check that port_if is connected to this bridge */
if (!(portIfMap->flags & NFP_F_MAP_BRIDGE_PORT) || (portIfMap->bridgeIf != bridge_if))
return MV_BAD_PARAM;
portIfMap->flags &= ~NFP_F_MAP_BRIDGE_PORT;
portIfMap->bridgeIf = 0;
return MV_OK;
}
return MV_NOT_FOUND;
}
MV_BOOL mvNfpIfOnSameBridge(NFP_IF_MAP *ifMap1, NFP_IF_MAP *ifMap2)
{
if ((ifMap1 != NULL) && (ifMap2 != NULL)) {
/* first interface is bridge and second is port on the same bridge */
if ((ifMap1->flags & NFP_F_MAP_BRIDGE) &&
(ifMap2->flags & NFP_F_MAP_BRIDGE_PORT) &&
(ifMap1->ifIdx == ifMap2->bridgeIf))
return MV_TRUE;
/* second interface is bridge and first is port on the same bridge */
if ((ifMap1->flags & NFP_F_MAP_BRIDGE_PORT) &&
(ifMap2->flags & NFP_F_MAP_BRIDGE) &&
(ifMap1->bridgeIf == ifMap2->ifIdx))
return MV_TRUE;
/* two interfaces are ports of the same bridge */
if ((ifMap1->flags & NFP_F_MAP_BRIDGE_PORT) &&
(ifMap2->flags & NFP_F_MAP_BRIDGE_PORT) &&
(ifMap1->bridgeIf == ifMap2->bridgeIf))
return MV_TRUE;
}
return MV_FALSE;
}
#endif /* NFP_BRIDGE */
MV_VOID mvNfpIpInfoPrint(u32 dbgLevel, int family, u8 *ipAddr)
{
if (nfpDebugLevel & dbgLevel) {
if (family == MV_INET)
mvOsPrintf("IPv4: " MV_IPQUAD_FMT "\n", MV_IPQUAD(ipAddr));
else
mvOsPrintf("IPv6: " MV_IP6_FMT "\n", MV_IP6_ARG(ipAddr));
}
}
MV_VOID mvNfp2TupleInfoPrint(u32 dbgLevel, int family, u8 *srcL3, u8 *dstL3)
{
if (nfpDebugLevel & dbgLevel) {
if (family == MV_INET)
mvOsPrintf("IPv4: " MV_IPQUAD_FMT "->" MV_IPQUAD_FMT"\n",
MV_IPQUAD(srcL3), MV_IPQUAD(dstL3));
else
mvOsPrintf("IPv6: " MV_IP6_FMT "->" MV_IP6_FMT"\n",
MV_IP6_ARG(srcL3), MV_IP6_ARG(dstL3));
}
}
MV_VOID mvNfp5TupleInfoPrint(u32 dbgLevel, int family, u8 *srcL3, u8 *dstL3, u16 sport, u16 dport, u8 proto)
{
if (nfpDebugLevel & dbgLevel) {
if (family == MV_INET)
mvOsPrintf("IPv4: " MV_IPQUAD_FMT ":%d->" MV_IPQUAD_FMT":%d",
MV_IPQUAD(srcL3), sport, MV_IPQUAD(dstL3), dport);
else
mvOsPrintf("IPv6: " MV_IP6_FMT ":%d->" MV_IP6_FMT":%d",
MV_IP6_ARG(srcL3), sport, MV_IP6_ARG(dstL3), dport);
if (proto == MV_IP_PROTO_TCP)
mvOsPrintf(", proto = TCP\n");
else if (proto == MV_IP_PROTO_UDP)
mvOsPrintf(", proto = UDP\n");
else
mvOsPrintf(", proto = Unknown (%d)\n", proto);
}
}
static void mvNfpIfMapPrint(NFP_IF_MAP *ifMap)
{
mvOsPrintf(" %8s %3d %3d %3d %4d 0x%04x "MV_MACQUAD_FMT" %4d %3d %3d 0x%04x\n",
ifMap->name, ifMap->ifIdx, ifMap->port, ifMap->switchGroup, ifMap->vlanId,
ifMap->txMh, MV_MACQUAD(ifMap->mac), ifMap->mtu,
ifMap->bridgeIf, ifMap->parentIf ? ifMap->parentIf->ifIdx : ifMap->ifIdx, ifMap->flags);
if (ifMap->virtIf) {
NFP_IF_MAP *ifVirt = ifMap->virtIf;
mvOsPrintf("\t Virtual list: ");
while (ifVirt) {
mvOsPrintf(" %d,", ifVirt->ifIdx);
ifVirt = ifVirt->virtNext;
}
mvOsPrintf("\n");
}
}
MV_VOID mvNfpIfMapDump(void)
{
int i;
NFP_IF_MAP *ifMap;
mvOsPrintf("\n(ifMap - direct)\n");
mvOsPrintf("[No]: name idx port swGr vid txMh mac mtu brIf upIf flags\n");
for (i = 0; i < NFP_DEV_HASH_SZ; i++) {
ifMap = nfp_if_map[i];
while (ifMap != NULL) {
mvOsPrintf("[%2d]: ", i);
mvNfpIfMapPrint(ifMap);
ifMap = ifMap->nextMap;
}
}
mvOsPrintf("\n");
mvOsPrintf("(ifMap - Real)\n");
mvOsPrintf("[Port][Group]: name idx\n");
for (i = 0; i < NFP_MAX_PORTS; i++) {
int j;
for (j = 0; j < NFP_MAX_SWITCH_GROUPS; j++) {
ifMap = nfp_if_real_map[i][j];
if (ifMap != NULL)
mvOsPrintf("[%4d][%5d]: %8s %3d\n", i, j, ifMap->name, ifMap->ifIdx);
}
}
}
MV_VOID mvNfpStats(MV_U32 port)
{
if ((port < 0) || (port >= NFP_MAX_PORTS)) {
mvOsPrintf("Invalid port number %d\n", port);
return;
}
mvOsPrintf("\n====================================================\n");
mvOsPrintf(" NFP statistics");
mvOsPrintf("\n----------------------------------------------------\n");
#ifdef NFP_STAT
mvOsPrintf("nfp_rx........................%10u\n", nfp_stats[port].rx);
mvOsPrintf("nfp_iif_err...................%10u\n", nfp_stats[port].iif_err);
mvOsPrintf("nfp_oif_err...................%10u\n", nfp_stats[port].oif_err);
#ifdef NFP_VLAN
mvOsPrintf("nfp_vlan_rx_tag_drop..........%10u\n", nfp_stats[port].vlan_rx_tag_drop);
mvOsPrintf("nfp_vlan_rx_untag_drop........%10u\n", nfp_stats[port].vlan_rx_untag_drop);
mvOsPrintf("nfp_vlan_rx_unknown_drop......%10u\n", nfp_stats[port].vlan_rx_unknown_drop);
mvOsPrintf("nfp_vlan_rx_found.............%10u\n", nfp_stats[port].vlan_rx_found);
mvOsPrintf("nfp_vlan_rx_trans.............%10u\n", nfp_stats[port].vlan_rx_trans);
mvOsPrintf("nfp_vlan_tx_add...............%10u\n", nfp_stats[port].vlan_tx_add);
mvOsPrintf("nfp_vlan_tx_remove............%10u\n", nfp_stats[port].vlan_tx_remove);
mvOsPrintf("nfp_vlan_tx_replace...........%10u\n", nfp_stats[port].vlan_tx_replace);
#endif /* NFP_VLAN */
#ifdef NFP_BRIDGE
#ifdef NFP_FDB_MODE
mvOsPrintf("nfp_fdb_local.................%10u\n", nfp_stats[port].fdb_local);
mvOsPrintf("nfp_fdb_sa_miss...............%10u\n", nfp_stats[port].fdb_sa_miss);
mvOsPrintf("nfp_fdb_da_miss...............%10u\n", nfp_stats[port].fdb_da_miss);
mvOsPrintf("nfp_fdb_port_miss.............%10u\n", nfp_stats[port].fdb_port_miss);
mvOsPrintf("nfp_fdb_hit...................%10u\n", nfp_stats[port].fdb_hit);
#else
mvOsPrintf("nfp_bridge_miss...............%10u\n", nfp_stats[port].bridge_miss);
mvOsPrintf("nfp_bridge_hit................%10u\n", nfp_stats[port].bridge_hit);
mvOsPrintf("nfp_bridge_local..............%10u\n", nfp_stats[port].bridge_local);
#endif /* NFP_FDB_MODE */
#endif /* NFP_BRIDGE */
mvOsPrintf("nfp_non_ip....................%10u\n", nfp_stats[port].non_ip);
mvOsPrintf("nfp_ipv4_csum_err.............%10u\n", nfp_stats[port].ipv4_csum_err);
mvOsPrintf("nfp_mac_mcast.................%10u\n", nfp_stats[port].mac_mcast);
mvOsPrintf("nfp_ttl_exp...................%10u\n", nfp_stats[port].ttl_exp);
mvOsPrintf("nfp_l4_unknown................%10u\n", nfp_stats[port].l4_unknown);
mvOsPrintf("nfp_l4_csum_err...............%10u\n", nfp_stats[port].l4_csum_err);
mvOsPrintf("nfp_ipv4......................%10u\n", nfp_stats[port].ipv4);
mvOsPrintf("nfp_ipv6......................%10u\n", nfp_stats[port].ipv6);
mvOsPrintf("nfp_ip_rx_frag................%10u\n", nfp_stats[port].ipv4_rx_frag);
mvOsPrintf("nfp_ip_tx_frag................%10u\n", nfp_stats[port].ip_tx_frag);
mvOsPrintf("nfp_ip_tx_frag_err............%10u\n", nfp_stats[port].ip_tx_frag_err);
#ifdef NFP_PPP
mvOsPrintf("pppoe_rx_not_found............%10u\n", nfp_stats[port].pppoe_rx_not_found);
mvOsPrintf("pppoe_rx_found................%10u\n", nfp_stats[port].pppoe_rx_found);
mvOsPrintf("pppoe_tx_add..................%10u\n", nfp_stats[port].pppoe_tx_add);
mvOsPrintf("pppoe_tx_remove...............%10u\n", nfp_stats[port].pppoe_tx_remove);
mvOsPrintf("pppoe_tx_replace..............%10u\n", nfp_stats[port].pppoe_tx_replace);
#endif /* NFP_PPP */
#ifdef NFP_FIB
mvOsPrintf("nfp_fib_hit...................%10u\n", nfp_stats[port].fib_hit);
mvOsPrintf("nfp_fib_miss..................%10u\n", nfp_stats[port].fib_miss);
#endif /* NFP_FIB */
#ifdef NFP_CT
mvOsPrintf("nfp_ct_hit....................%10u\n", nfp_stats[port].ct_hit);
mvOsPrintf("nfp_ct_miss...................%10u\n", nfp_stats[port].ct_miss);
mvOsPrintf("nfp_ct_tcp_fin_rst............%10u\n", nfp_stats[port].ct_tcp_fin_rst);
#ifdef NFP_NAT
mvOsPrintf("nfp_dnat_hit..................%10u\n", nfp_stats[port].dnat_hit);
mvOsPrintf("nfp_dnat_miss.................%10u\n", nfp_stats[port].dnat_miss);
mvOsPrintf("nfp_dnat_inv..................%10u\n", nfp_stats[port].dnat_inv);
mvOsPrintf("nfp_snat_hit..................%10u\n", nfp_stats[port].snat_hit);
mvOsPrintf("nfp_snat_miss.................%10u\n", nfp_stats[port].snat_miss);
mvOsPrintf("nfp_snat_inv..................%10u\n", nfp_stats[port].snat_inv);
#endif /* NFP_NAT */
#endif /* NFP_CT */
mvOsMemset(&nfp_stats[port], 0, sizeof(NFP_STATS));
#endif /* NFP_STAT */
}