5702b7bf1c
rte_lpm_lookupx4 could return wrong next hop when more than 256 tbl8 groups are created. This is caused by incorrect type casting of tbl8 group index that been stored in tbl24 entry. The casting caused group index truncation and hence wrong tbl8 group been searched. Issue fixed by applying proper mask to tbl24 entry to get tbl8 group index. Fixes:dc81ebbaca
("lpm: extend IPv4 next hop field") Fixes:cbc2f1dccf
("lpm/arm: support NEON") Fixes:d2cc795934
("lpm: add AltiVec for ppc64") Cc: stable@dpdk.org Signed-off-by: Ruifeng Wang <ruifeng.wang@arm.com> Tested-by: David Christensen <drc@linux.vnet.ibm.com> Acked-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
121 lines
3.3 KiB
C
121 lines
3.3 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2015 Cavium, Inc.
|
|
* Copyright(c) 2010-2014 Intel Corporation.
|
|
*/
|
|
|
|
#ifndef _RTE_LPM_NEON_H_
|
|
#define _RTE_LPM_NEON_H_
|
|
|
|
#include <rte_branch_prediction.h>
|
|
#include <rte_byteorder.h>
|
|
#include <rte_common.h>
|
|
#include <rte_vect.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
static inline void
|
|
rte_lpm_lookupx4(const struct rte_lpm *lpm, xmm_t ip, uint32_t hop[4],
|
|
uint32_t defv)
|
|
{
|
|
uint32x4_t i24;
|
|
rte_xmm_t i8;
|
|
uint32_t tbl[4];
|
|
uint64_t idx, pt, pt2;
|
|
const uint32_t *ptbl;
|
|
|
|
const uint32_t mask = UINT8_MAX;
|
|
const int32x4_t mask8 = vdupq_n_s32(mask);
|
|
|
|
/*
|
|
* RTE_LPM_VALID_EXT_ENTRY_BITMASK for 2 LPM entries
|
|
* as one 64-bit value (0x0300000003000000).
|
|
*/
|
|
const uint64_t mask_xv =
|
|
((uint64_t)RTE_LPM_VALID_EXT_ENTRY_BITMASK |
|
|
(uint64_t)RTE_LPM_VALID_EXT_ENTRY_BITMASK << 32);
|
|
|
|
/*
|
|
* RTE_LPM_LOOKUP_SUCCESS for 2 LPM entries
|
|
* as one 64-bit value (0x0100000001000000).
|
|
*/
|
|
const uint64_t mask_v =
|
|
((uint64_t)RTE_LPM_LOOKUP_SUCCESS |
|
|
(uint64_t)RTE_LPM_LOOKUP_SUCCESS << 32);
|
|
|
|
/* get 4 indexes for tbl24[]. */
|
|
i24 = vshrq_n_u32((uint32x4_t)ip, CHAR_BIT);
|
|
|
|
/* extract values from tbl24[] */
|
|
idx = vgetq_lane_u64((uint64x2_t)i24, 0);
|
|
|
|
ptbl = (const uint32_t *)&lpm->tbl24[(uint32_t)idx];
|
|
tbl[0] = *ptbl;
|
|
ptbl = (const uint32_t *)&lpm->tbl24[idx >> 32];
|
|
tbl[1] = *ptbl;
|
|
|
|
idx = vgetq_lane_u64((uint64x2_t)i24, 1);
|
|
|
|
ptbl = (const uint32_t *)&lpm->tbl24[(uint32_t)idx];
|
|
tbl[2] = *ptbl;
|
|
ptbl = (const uint32_t *)&lpm->tbl24[idx >> 32];
|
|
tbl[3] = *ptbl;
|
|
|
|
/* get 4 indexes for tbl8[]. */
|
|
i8.x = vandq_s32(ip, mask8);
|
|
|
|
pt = (uint64_t)tbl[0] |
|
|
(uint64_t)tbl[1] << 32;
|
|
pt2 = (uint64_t)tbl[2] |
|
|
(uint64_t)tbl[3] << 32;
|
|
|
|
/* search successfully finished for all 4 IP addresses. */
|
|
if (likely((pt & mask_xv) == mask_v) &&
|
|
likely((pt2 & mask_xv) == mask_v)) {
|
|
*(uint64_t *)hop = pt & RTE_LPM_MASKX4_RES;
|
|
*(uint64_t *)(hop + 2) = pt2 & RTE_LPM_MASKX4_RES;
|
|
return;
|
|
}
|
|
|
|
if (unlikely((pt & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
|
|
RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
|
|
i8.u32[0] = i8.u32[0] +
|
|
(tbl[0] & 0x00FFFFFF) * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
|
|
ptbl = (const uint32_t *)&lpm->tbl8[i8.u32[0]];
|
|
tbl[0] = *ptbl;
|
|
}
|
|
if (unlikely((pt >> 32 & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
|
|
RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
|
|
i8.u32[1] = i8.u32[1] +
|
|
(tbl[1] & 0x00FFFFFF) * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
|
|
ptbl = (const uint32_t *)&lpm->tbl8[i8.u32[1]];
|
|
tbl[1] = *ptbl;
|
|
}
|
|
if (unlikely((pt2 & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
|
|
RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
|
|
i8.u32[2] = i8.u32[2] +
|
|
(tbl[2] & 0x00FFFFFF) * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
|
|
ptbl = (const uint32_t *)&lpm->tbl8[i8.u32[2]];
|
|
tbl[2] = *ptbl;
|
|
}
|
|
if (unlikely((pt2 >> 32 & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
|
|
RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
|
|
i8.u32[3] = i8.u32[3] +
|
|
(tbl[3] & 0x00FFFFFF) * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
|
|
ptbl = (const uint32_t *)&lpm->tbl8[i8.u32[3]];
|
|
tbl[3] = *ptbl;
|
|
}
|
|
|
|
hop[0] = (tbl[0] & RTE_LPM_LOOKUP_SUCCESS) ? tbl[0] & 0x00FFFFFF : defv;
|
|
hop[1] = (tbl[1] & RTE_LPM_LOOKUP_SUCCESS) ? tbl[1] & 0x00FFFFFF : defv;
|
|
hop[2] = (tbl[2] & RTE_LPM_LOOKUP_SUCCESS) ? tbl[2] & 0x00FFFFFF : defv;
|
|
hop[3] = (tbl[3] & RTE_LPM_LOOKUP_SUCCESS) ? tbl[3] & 0x00FFFFFF : defv;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _RTE_LPM_NEON_H_ */
|