199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com> 399a2dd95SBruce Richardson * Copyright(c) 2019 Intel Corporation 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <stdint.h> 799a2dd95SBruce Richardson #include <stdio.h> 899a2dd95SBruce Richardson 999a2dd95SBruce Richardson #include <rte_debug.h> 1099a2dd95SBruce Richardson #include <rte_malloc.h> 1199a2dd95SBruce Richardson #include <rte_errno.h> 1299a2dd95SBruce Richardson 1399a2dd95SBruce Richardson #include <rte_rib6.h> 1499a2dd95SBruce Richardson #include <rte_fib6.h> 1599a2dd95SBruce Richardson #include "trie.h" 1699a2dd95SBruce Richardson 1799a2dd95SBruce Richardson #ifdef CC_TRIE_AVX512_SUPPORT 1899a2dd95SBruce Richardson 1999a2dd95SBruce Richardson #include "trie_avx512.h" 2099a2dd95SBruce Richardson 2199a2dd95SBruce Richardson #endif /* CC_TRIE_AVX512_SUPPORT */ 2299a2dd95SBruce Richardson 2399a2dd95SBruce Richardson #define TRIE_NAMESIZE 64 2499a2dd95SBruce Richardson 2599a2dd95SBruce Richardson enum edge { 2699a2dd95SBruce Richardson LEDGE, 2799a2dd95SBruce Richardson REDGE 2899a2dd95SBruce Richardson }; 2999a2dd95SBruce Richardson 3099a2dd95SBruce Richardson static inline rte_fib6_lookup_fn_t 3199a2dd95SBruce Richardson get_scalar_fn(enum rte_fib_trie_nh_sz nh_sz) 3299a2dd95SBruce Richardson { 3399a2dd95SBruce Richardson switch (nh_sz) { 3499a2dd95SBruce Richardson case RTE_FIB6_TRIE_2B: 3599a2dd95SBruce Richardson return rte_trie_lookup_bulk_2b; 3699a2dd95SBruce Richardson case RTE_FIB6_TRIE_4B: 3799a2dd95SBruce Richardson return rte_trie_lookup_bulk_4b; 3899a2dd95SBruce Richardson case RTE_FIB6_TRIE_8B: 3999a2dd95SBruce Richardson return rte_trie_lookup_bulk_8b; 4099a2dd95SBruce Richardson default: 4199a2dd95SBruce Richardson return NULL; 4299a2dd95SBruce Richardson } 4399a2dd95SBruce Richardson } 4499a2dd95SBruce Richardson 4599a2dd95SBruce Richardson static inline rte_fib6_lookup_fn_t 4699a2dd95SBruce Richardson get_vector_fn(enum rte_fib_trie_nh_sz nh_sz) 4799a2dd95SBruce Richardson { 4899a2dd95SBruce Richardson #ifdef CC_TRIE_AVX512_SUPPORT 4945ddc566SVladimir Medvedkin if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) <= 0 || 5045ddc566SVladimir Medvedkin rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512DQ) <= 0 || 5145ddc566SVladimir Medvedkin rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) <= 0 || 5245ddc566SVladimir Medvedkin rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_512) 5399a2dd95SBruce Richardson return NULL; 5499a2dd95SBruce Richardson switch (nh_sz) { 5599a2dd95SBruce Richardson case RTE_FIB6_TRIE_2B: 5699a2dd95SBruce Richardson return rte_trie_vec_lookup_bulk_2b; 5799a2dd95SBruce Richardson case RTE_FIB6_TRIE_4B: 5899a2dd95SBruce Richardson return rte_trie_vec_lookup_bulk_4b; 5999a2dd95SBruce Richardson case RTE_FIB6_TRIE_8B: 6099a2dd95SBruce Richardson return rte_trie_vec_lookup_bulk_8b; 6199a2dd95SBruce Richardson default: 6299a2dd95SBruce Richardson return NULL; 6399a2dd95SBruce Richardson } 6499a2dd95SBruce Richardson #else 6599a2dd95SBruce Richardson RTE_SET_USED(nh_sz); 6699a2dd95SBruce Richardson #endif 6799a2dd95SBruce Richardson return NULL; 6899a2dd95SBruce Richardson } 6999a2dd95SBruce Richardson 7099a2dd95SBruce Richardson rte_fib6_lookup_fn_t 7199a2dd95SBruce Richardson trie_get_lookup_fn(void *p, enum rte_fib6_lookup_type type) 7299a2dd95SBruce Richardson { 7399a2dd95SBruce Richardson enum rte_fib_trie_nh_sz nh_sz; 7499a2dd95SBruce Richardson rte_fib6_lookup_fn_t ret_fn; 7599a2dd95SBruce Richardson struct rte_trie_tbl *dp = p; 7699a2dd95SBruce Richardson 7799a2dd95SBruce Richardson if (dp == NULL) 7899a2dd95SBruce Richardson return NULL; 7999a2dd95SBruce Richardson 8099a2dd95SBruce Richardson nh_sz = dp->nh_sz; 8199a2dd95SBruce Richardson 8299a2dd95SBruce Richardson switch (type) { 8399a2dd95SBruce Richardson case RTE_FIB6_LOOKUP_TRIE_SCALAR: 8499a2dd95SBruce Richardson return get_scalar_fn(nh_sz); 8599a2dd95SBruce Richardson case RTE_FIB6_LOOKUP_TRIE_VECTOR_AVX512: 8699a2dd95SBruce Richardson return get_vector_fn(nh_sz); 8799a2dd95SBruce Richardson case RTE_FIB6_LOOKUP_DEFAULT: 8899a2dd95SBruce Richardson ret_fn = get_vector_fn(nh_sz); 8999a2dd95SBruce Richardson return (ret_fn != NULL) ? ret_fn : get_scalar_fn(nh_sz); 9099a2dd95SBruce Richardson default: 9199a2dd95SBruce Richardson return NULL; 9299a2dd95SBruce Richardson } 9399a2dd95SBruce Richardson return NULL; 9499a2dd95SBruce Richardson } 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson static void 9799a2dd95SBruce Richardson write_to_dp(void *ptr, uint64_t val, enum rte_fib_trie_nh_sz size, int n) 9899a2dd95SBruce Richardson { 9999a2dd95SBruce Richardson int i; 10099a2dd95SBruce Richardson uint16_t *ptr16 = (uint16_t *)ptr; 10199a2dd95SBruce Richardson uint32_t *ptr32 = (uint32_t *)ptr; 10299a2dd95SBruce Richardson uint64_t *ptr64 = (uint64_t *)ptr; 10399a2dd95SBruce Richardson 10499a2dd95SBruce Richardson switch (size) { 10599a2dd95SBruce Richardson case RTE_FIB6_TRIE_2B: 10699a2dd95SBruce Richardson for (i = 0; i < n; i++) 10799a2dd95SBruce Richardson ptr16[i] = (uint16_t)val; 10899a2dd95SBruce Richardson break; 10999a2dd95SBruce Richardson case RTE_FIB6_TRIE_4B: 11099a2dd95SBruce Richardson for (i = 0; i < n; i++) 11199a2dd95SBruce Richardson ptr32[i] = (uint32_t)val; 11299a2dd95SBruce Richardson break; 11399a2dd95SBruce Richardson case RTE_FIB6_TRIE_8B: 11499a2dd95SBruce Richardson for (i = 0; i < n; i++) 11599a2dd95SBruce Richardson ptr64[i] = (uint64_t)val; 11699a2dd95SBruce Richardson break; 11799a2dd95SBruce Richardson } 11899a2dd95SBruce Richardson } 11999a2dd95SBruce Richardson 12099a2dd95SBruce Richardson static void 12199a2dd95SBruce Richardson tbl8_pool_init(struct rte_trie_tbl *dp) 12299a2dd95SBruce Richardson { 12399a2dd95SBruce Richardson uint32_t i; 12499a2dd95SBruce Richardson 12599a2dd95SBruce Richardson /* put entire range of indexes to the tbl8 pool */ 12699a2dd95SBruce Richardson for (i = 0; i < dp->number_tbl8s; i++) 12799a2dd95SBruce Richardson dp->tbl8_pool[i] = i; 12899a2dd95SBruce Richardson 12999a2dd95SBruce Richardson dp->tbl8_pool_pos = 0; 13099a2dd95SBruce Richardson } 13199a2dd95SBruce Richardson 13299a2dd95SBruce Richardson /* 13399a2dd95SBruce Richardson * Get an index of a free tbl8 from the pool 13499a2dd95SBruce Richardson */ 13599a2dd95SBruce Richardson static inline int32_t 13699a2dd95SBruce Richardson tbl8_get(struct rte_trie_tbl *dp) 13799a2dd95SBruce Richardson { 13899a2dd95SBruce Richardson if (dp->tbl8_pool_pos == dp->number_tbl8s) 13999a2dd95SBruce Richardson /* no more free tbl8 */ 14099a2dd95SBruce Richardson return -ENOSPC; 14199a2dd95SBruce Richardson 14299a2dd95SBruce Richardson /* next index */ 14399a2dd95SBruce Richardson return dp->tbl8_pool[dp->tbl8_pool_pos++]; 14499a2dd95SBruce Richardson } 14599a2dd95SBruce Richardson 14699a2dd95SBruce Richardson /* 14799a2dd95SBruce Richardson * Put an index of a free tbl8 back to the pool 14899a2dd95SBruce Richardson */ 14999a2dd95SBruce Richardson static inline void 15099a2dd95SBruce Richardson tbl8_put(struct rte_trie_tbl *dp, uint32_t tbl8_ind) 15199a2dd95SBruce Richardson { 15299a2dd95SBruce Richardson dp->tbl8_pool[--dp->tbl8_pool_pos] = tbl8_ind; 15399a2dd95SBruce Richardson } 15499a2dd95SBruce Richardson 15599a2dd95SBruce Richardson static int 15699a2dd95SBruce Richardson tbl8_alloc(struct rte_trie_tbl *dp, uint64_t nh) 15799a2dd95SBruce Richardson { 15899a2dd95SBruce Richardson int64_t tbl8_idx; 15999a2dd95SBruce Richardson uint8_t *tbl8_ptr; 16099a2dd95SBruce Richardson 16199a2dd95SBruce Richardson tbl8_idx = tbl8_get(dp); 16299a2dd95SBruce Richardson if (tbl8_idx < 0) 16399a2dd95SBruce Richardson return tbl8_idx; 16499a2dd95SBruce Richardson tbl8_ptr = get_tbl_p_by_idx(dp->tbl8, 16599a2dd95SBruce Richardson tbl8_idx * TRIE_TBL8_GRP_NUM_ENT, dp->nh_sz); 16699a2dd95SBruce Richardson /*Init tbl8 entries with nexthop from tbl24*/ 16799a2dd95SBruce Richardson write_to_dp((void *)tbl8_ptr, nh, dp->nh_sz, 16899a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT); 16999a2dd95SBruce Richardson return tbl8_idx; 17099a2dd95SBruce Richardson } 17199a2dd95SBruce Richardson 17299a2dd95SBruce Richardson static void 17399a2dd95SBruce Richardson tbl8_recycle(struct rte_trie_tbl *dp, void *par, uint64_t tbl8_idx) 17499a2dd95SBruce Richardson { 17599a2dd95SBruce Richardson uint32_t i; 17699a2dd95SBruce Richardson uint64_t nh; 17799a2dd95SBruce Richardson uint16_t *ptr16; 17899a2dd95SBruce Richardson uint32_t *ptr32; 17999a2dd95SBruce Richardson uint64_t *ptr64; 18099a2dd95SBruce Richardson 18199a2dd95SBruce Richardson switch (dp->nh_sz) { 18299a2dd95SBruce Richardson case RTE_FIB6_TRIE_2B: 18399a2dd95SBruce Richardson ptr16 = &((uint16_t *)dp->tbl8)[tbl8_idx * 18499a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT]; 18599a2dd95SBruce Richardson nh = *ptr16; 18699a2dd95SBruce Richardson if (nh & TRIE_EXT_ENT) 18799a2dd95SBruce Richardson return; 18899a2dd95SBruce Richardson for (i = 1; i < TRIE_TBL8_GRP_NUM_ENT; i++) { 18999a2dd95SBruce Richardson if (nh != ptr16[i]) 19099a2dd95SBruce Richardson return; 19199a2dd95SBruce Richardson } 19299a2dd95SBruce Richardson write_to_dp(par, nh, dp->nh_sz, 1); 19399a2dd95SBruce Richardson for (i = 0; i < TRIE_TBL8_GRP_NUM_ENT; i++) 19499a2dd95SBruce Richardson ptr16[i] = 0; 19599a2dd95SBruce Richardson break; 19699a2dd95SBruce Richardson case RTE_FIB6_TRIE_4B: 19799a2dd95SBruce Richardson ptr32 = &((uint32_t *)dp->tbl8)[tbl8_idx * 19899a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT]; 19999a2dd95SBruce Richardson nh = *ptr32; 20099a2dd95SBruce Richardson if (nh & TRIE_EXT_ENT) 20199a2dd95SBruce Richardson return; 20299a2dd95SBruce Richardson for (i = 1; i < TRIE_TBL8_GRP_NUM_ENT; i++) { 20399a2dd95SBruce Richardson if (nh != ptr32[i]) 20499a2dd95SBruce Richardson return; 20599a2dd95SBruce Richardson } 20699a2dd95SBruce Richardson write_to_dp(par, nh, dp->nh_sz, 1); 20799a2dd95SBruce Richardson for (i = 0; i < TRIE_TBL8_GRP_NUM_ENT; i++) 20899a2dd95SBruce Richardson ptr32[i] = 0; 20999a2dd95SBruce Richardson break; 21099a2dd95SBruce Richardson case RTE_FIB6_TRIE_8B: 21199a2dd95SBruce Richardson ptr64 = &((uint64_t *)dp->tbl8)[tbl8_idx * 21299a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT]; 21399a2dd95SBruce Richardson nh = *ptr64; 21499a2dd95SBruce Richardson if (nh & TRIE_EXT_ENT) 21599a2dd95SBruce Richardson return; 21699a2dd95SBruce Richardson for (i = 1; i < TRIE_TBL8_GRP_NUM_ENT; i++) { 21799a2dd95SBruce Richardson if (nh != ptr64[i]) 21899a2dd95SBruce Richardson return; 21999a2dd95SBruce Richardson } 22099a2dd95SBruce Richardson write_to_dp(par, nh, dp->nh_sz, 1); 22199a2dd95SBruce Richardson for (i = 0; i < TRIE_TBL8_GRP_NUM_ENT; i++) 22299a2dd95SBruce Richardson ptr64[i] = 0; 22399a2dd95SBruce Richardson break; 22499a2dd95SBruce Richardson } 22599a2dd95SBruce Richardson tbl8_put(dp, tbl8_idx); 22699a2dd95SBruce Richardson } 22799a2dd95SBruce Richardson 22899a2dd95SBruce Richardson #define BYTE_SIZE 8 22999a2dd95SBruce Richardson static inline uint32_t 2306cb10a9bSRobin Jarry get_idx(const struct rte_ipv6_addr *ip, uint32_t prev_idx, int bytes, int first_byte) 23199a2dd95SBruce Richardson { 23299a2dd95SBruce Richardson int i; 23399a2dd95SBruce Richardson uint32_t idx = 0; 23499a2dd95SBruce Richardson uint8_t bitshift; 23599a2dd95SBruce Richardson 23699a2dd95SBruce Richardson for (i = first_byte; i < (first_byte + bytes); i++) { 23799a2dd95SBruce Richardson bitshift = (int8_t)(((first_byte + bytes - 1) - i)*BYTE_SIZE); 2386cb10a9bSRobin Jarry idx |= ip->a[i] << bitshift; 23999a2dd95SBruce Richardson } 24099a2dd95SBruce Richardson return (prev_idx * TRIE_TBL8_GRP_NUM_ENT) + idx; 24199a2dd95SBruce Richardson } 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson static inline uint64_t 24499a2dd95SBruce Richardson get_val_by_p(void *p, uint8_t nh_sz) 24599a2dd95SBruce Richardson { 24699a2dd95SBruce Richardson uint64_t val = 0; 24799a2dd95SBruce Richardson 24899a2dd95SBruce Richardson switch (nh_sz) { 24999a2dd95SBruce Richardson case RTE_FIB6_TRIE_2B: 25099a2dd95SBruce Richardson val = *(uint16_t *)p; 25199a2dd95SBruce Richardson break; 25299a2dd95SBruce Richardson case RTE_FIB6_TRIE_4B: 25399a2dd95SBruce Richardson val = *(uint32_t *)p; 25499a2dd95SBruce Richardson break; 25599a2dd95SBruce Richardson case RTE_FIB6_TRIE_8B: 25699a2dd95SBruce Richardson val = *(uint64_t *)p; 25799a2dd95SBruce Richardson break; 25899a2dd95SBruce Richardson } 25999a2dd95SBruce Richardson return val; 26099a2dd95SBruce Richardson } 26199a2dd95SBruce Richardson 26299a2dd95SBruce Richardson /* 26399a2dd95SBruce Richardson * recursively recycle tbl8's 26499a2dd95SBruce Richardson */ 26599a2dd95SBruce Richardson static void 26699a2dd95SBruce Richardson recycle_root_path(struct rte_trie_tbl *dp, const uint8_t *ip_part, 26799a2dd95SBruce Richardson uint8_t common_tbl8, void *prev) 26899a2dd95SBruce Richardson { 26999a2dd95SBruce Richardson void *p; 27099a2dd95SBruce Richardson uint64_t val; 27199a2dd95SBruce Richardson 27299a2dd95SBruce Richardson val = get_val_by_p(prev, dp->nh_sz); 27399a2dd95SBruce Richardson if (unlikely((val & TRIE_EXT_ENT) != TRIE_EXT_ENT)) 27499a2dd95SBruce Richardson return; 27599a2dd95SBruce Richardson 27699a2dd95SBruce Richardson if (common_tbl8 != 0) { 27799a2dd95SBruce Richardson p = get_tbl_p_by_idx(dp->tbl8, (val >> 1) * 27899a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT + *ip_part, dp->nh_sz); 27999a2dd95SBruce Richardson recycle_root_path(dp, ip_part + 1, common_tbl8 - 1, p); 28099a2dd95SBruce Richardson } 28199a2dd95SBruce Richardson tbl8_recycle(dp, prev, val >> 1); 28299a2dd95SBruce Richardson } 28399a2dd95SBruce Richardson 28499a2dd95SBruce Richardson static inline int 2856cb10a9bSRobin Jarry build_common_root(struct rte_trie_tbl *dp, const struct rte_ipv6_addr *ip, 28699a2dd95SBruce Richardson int common_bytes, void **tbl) 28799a2dd95SBruce Richardson { 28899a2dd95SBruce Richardson void *tbl_ptr = NULL; 28999a2dd95SBruce Richardson uint64_t *cur_tbl; 29099a2dd95SBruce Richardson uint64_t val; 29199a2dd95SBruce Richardson int i, j, idx, prev_idx = 0; 29299a2dd95SBruce Richardson 29399a2dd95SBruce Richardson cur_tbl = dp->tbl24; 29499a2dd95SBruce Richardson for (i = 3, j = 0; i <= common_bytes; i++) { 29599a2dd95SBruce Richardson idx = get_idx(ip, prev_idx, i - j, j); 29699a2dd95SBruce Richardson val = get_tbl_val_by_idx(cur_tbl, idx, dp->nh_sz); 29799a2dd95SBruce Richardson tbl_ptr = get_tbl_p_by_idx(cur_tbl, idx, dp->nh_sz); 29899a2dd95SBruce Richardson if ((val & TRIE_EXT_ENT) != TRIE_EXT_ENT) { 29999a2dd95SBruce Richardson idx = tbl8_alloc(dp, val); 30099a2dd95SBruce Richardson if (unlikely(idx < 0)) 30199a2dd95SBruce Richardson return idx; 30299a2dd95SBruce Richardson write_to_dp(tbl_ptr, (idx << 1) | 30399a2dd95SBruce Richardson TRIE_EXT_ENT, dp->nh_sz, 1); 30499a2dd95SBruce Richardson prev_idx = idx; 30599a2dd95SBruce Richardson } else 30699a2dd95SBruce Richardson prev_idx = val >> 1; 30799a2dd95SBruce Richardson 30899a2dd95SBruce Richardson j = i; 30999a2dd95SBruce Richardson cur_tbl = dp->tbl8; 31099a2dd95SBruce Richardson } 31199a2dd95SBruce Richardson *tbl = get_tbl_p_by_idx(cur_tbl, prev_idx * TRIE_TBL8_GRP_NUM_ENT, 31299a2dd95SBruce Richardson dp->nh_sz); 31399a2dd95SBruce Richardson return 0; 31499a2dd95SBruce Richardson } 31599a2dd95SBruce Richardson 31699a2dd95SBruce Richardson static int 31799a2dd95SBruce Richardson write_edge(struct rte_trie_tbl *dp, const uint8_t *ip_part, uint64_t next_hop, 31899a2dd95SBruce Richardson int len, enum edge edge, void *ent) 31999a2dd95SBruce Richardson { 32099a2dd95SBruce Richardson uint64_t val = next_hop << 1; 32199a2dd95SBruce Richardson int tbl8_idx; 32299a2dd95SBruce Richardson int ret = 0; 32399a2dd95SBruce Richardson void *p; 32499a2dd95SBruce Richardson 32599a2dd95SBruce Richardson if (len != 0) { 32699a2dd95SBruce Richardson val = get_val_by_p(ent, dp->nh_sz); 32799a2dd95SBruce Richardson if ((val & TRIE_EXT_ENT) == TRIE_EXT_ENT) 32899a2dd95SBruce Richardson tbl8_idx = val >> 1; 32999a2dd95SBruce Richardson else { 33099a2dd95SBruce Richardson tbl8_idx = tbl8_alloc(dp, val); 33199a2dd95SBruce Richardson if (tbl8_idx < 0) 33299a2dd95SBruce Richardson return tbl8_idx; 33399a2dd95SBruce Richardson val = (tbl8_idx << 1)|TRIE_EXT_ENT; 33499a2dd95SBruce Richardson } 33599a2dd95SBruce Richardson p = get_tbl_p_by_idx(dp->tbl8, (tbl8_idx * 33699a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT) + *ip_part, dp->nh_sz); 33799a2dd95SBruce Richardson ret = write_edge(dp, ip_part + 1, next_hop, len - 1, edge, p); 33899a2dd95SBruce Richardson if (ret < 0) 33999a2dd95SBruce Richardson return ret; 34099a2dd95SBruce Richardson if (edge == LEDGE) { 34199a2dd95SBruce Richardson write_to_dp((uint8_t *)p + (1 << dp->nh_sz), 34299a2dd95SBruce Richardson next_hop << 1, dp->nh_sz, UINT8_MAX - *ip_part); 34399a2dd95SBruce Richardson } else { 34499a2dd95SBruce Richardson write_to_dp(get_tbl_p_by_idx(dp->tbl8, tbl8_idx * 34599a2dd95SBruce Richardson TRIE_TBL8_GRP_NUM_ENT, dp->nh_sz), 34699a2dd95SBruce Richardson next_hop << 1, dp->nh_sz, *ip_part); 34799a2dd95SBruce Richardson } 34899a2dd95SBruce Richardson tbl8_recycle(dp, &val, tbl8_idx); 34999a2dd95SBruce Richardson } 35099a2dd95SBruce Richardson 35199a2dd95SBruce Richardson write_to_dp(ent, val, dp->nh_sz, 1); 35299a2dd95SBruce Richardson return ret; 35399a2dd95SBruce Richardson } 35499a2dd95SBruce Richardson 3556cb10a9bSRobin Jarry #define IPV6_MAX_IDX (RTE_IPV6_ADDR_SIZE - 1) 35699a2dd95SBruce Richardson #define TBL24_BYTES 3 3576cb10a9bSRobin Jarry #define TBL8_LEN (RTE_IPV6_ADDR_SIZE - TBL24_BYTES) 35899a2dd95SBruce Richardson 35999a2dd95SBruce Richardson static int 3606cb10a9bSRobin Jarry install_to_dp(struct rte_trie_tbl *dp, const struct rte_ipv6_addr *ledge, 3616cb10a9bSRobin Jarry const struct rte_ipv6_addr *r, uint64_t next_hop) 36299a2dd95SBruce Richardson { 36399a2dd95SBruce Richardson void *common_root_tbl; 36499a2dd95SBruce Richardson void *ent; 36599a2dd95SBruce Richardson int ret; 36699a2dd95SBruce Richardson int i; 36799a2dd95SBruce Richardson int common_bytes; 36899a2dd95SBruce Richardson int llen, rlen; 3696cb10a9bSRobin Jarry struct rte_ipv6_addr redge; 37099a2dd95SBruce Richardson 37199a2dd95SBruce Richardson /* decrement redge by 1*/ 3726cb10a9bSRobin Jarry redge = *r; 37399a2dd95SBruce Richardson for (i = 15; i >= 0; i--) { 3746cb10a9bSRobin Jarry redge.a[i]--; 3756cb10a9bSRobin Jarry if (redge.a[i] != 0xff) 37699a2dd95SBruce Richardson break; 37799a2dd95SBruce Richardson } 37899a2dd95SBruce Richardson 37999a2dd95SBruce Richardson for (common_bytes = 0; common_bytes < 15; common_bytes++) { 3806cb10a9bSRobin Jarry if (ledge->a[common_bytes] != redge.a[common_bytes]) 38199a2dd95SBruce Richardson break; 38299a2dd95SBruce Richardson } 38399a2dd95SBruce Richardson 38499a2dd95SBruce Richardson ret = build_common_root(dp, ledge, common_bytes, &common_root_tbl); 38599a2dd95SBruce Richardson if (unlikely(ret != 0)) 38699a2dd95SBruce Richardson return ret; 38799a2dd95SBruce Richardson /*first uncommon tbl8 byte idx*/ 38899a2dd95SBruce Richardson uint8_t first_tbl8_byte = RTE_MAX(common_bytes, TBL24_BYTES); 38999a2dd95SBruce Richardson 39099a2dd95SBruce Richardson for (i = IPV6_MAX_IDX; i > first_tbl8_byte; i--) { 3916cb10a9bSRobin Jarry if (ledge->a[i] != 0) 39299a2dd95SBruce Richardson break; 39399a2dd95SBruce Richardson } 39499a2dd95SBruce Richardson 39599a2dd95SBruce Richardson llen = i - first_tbl8_byte + (common_bytes < 3); 39699a2dd95SBruce Richardson 39799a2dd95SBruce Richardson for (i = IPV6_MAX_IDX; i > first_tbl8_byte; i--) { 3986cb10a9bSRobin Jarry if (redge.a[i] != UINT8_MAX) 39999a2dd95SBruce Richardson break; 40099a2dd95SBruce Richardson } 40199a2dd95SBruce Richardson rlen = i - first_tbl8_byte + (common_bytes < 3); 40299a2dd95SBruce Richardson 40399a2dd95SBruce Richardson /*first noncommon byte*/ 40499a2dd95SBruce Richardson uint8_t first_byte_idx = (common_bytes < 3) ? 0 : common_bytes; 40599a2dd95SBruce Richardson uint8_t first_idx_len = (common_bytes < 3) ? 3 : 1; 40699a2dd95SBruce Richardson 40799a2dd95SBruce Richardson uint32_t left_idx = get_idx(ledge, 0, first_idx_len, first_byte_idx); 4086cb10a9bSRobin Jarry uint32_t right_idx = get_idx(&redge, 0, first_idx_len, first_byte_idx); 40999a2dd95SBruce Richardson 41099a2dd95SBruce Richardson ent = get_tbl_p_by_idx(common_root_tbl, left_idx, dp->nh_sz); 4116cb10a9bSRobin Jarry ret = write_edge(dp, &ledge->a[first_tbl8_byte + !(common_bytes < 3)], 41299a2dd95SBruce Richardson next_hop, llen, LEDGE, ent); 41399a2dd95SBruce Richardson if (ret < 0) 41499a2dd95SBruce Richardson return ret; 41599a2dd95SBruce Richardson 41699a2dd95SBruce Richardson if (right_idx > left_idx + 1) { 41799a2dd95SBruce Richardson ent = get_tbl_p_by_idx(common_root_tbl, left_idx + 1, 41899a2dd95SBruce Richardson dp->nh_sz); 41999a2dd95SBruce Richardson write_to_dp(ent, next_hop << 1, dp->nh_sz, 42099a2dd95SBruce Richardson right_idx - (left_idx + 1)); 42199a2dd95SBruce Richardson } 42299a2dd95SBruce Richardson ent = get_tbl_p_by_idx(common_root_tbl, right_idx, dp->nh_sz); 4236cb10a9bSRobin Jarry ret = write_edge(dp, &redge.a[first_tbl8_byte + !((common_bytes < 3))], 42499a2dd95SBruce Richardson next_hop, rlen, REDGE, ent); 42599a2dd95SBruce Richardson if (ret < 0) 42699a2dd95SBruce Richardson return ret; 42799a2dd95SBruce Richardson 42899a2dd95SBruce Richardson uint8_t common_tbl8 = (common_bytes < TBL24_BYTES) ? 42999a2dd95SBruce Richardson 0 : common_bytes - (TBL24_BYTES - 1); 43099a2dd95SBruce Richardson ent = get_tbl24_p(dp, ledge, dp->nh_sz); 4316cb10a9bSRobin Jarry recycle_root_path(dp, ledge->a + TBL24_BYTES, common_tbl8, ent); 43299a2dd95SBruce Richardson return 0; 43399a2dd95SBruce Richardson } 43499a2dd95SBruce Richardson 43599a2dd95SBruce Richardson static void 4366cb10a9bSRobin Jarry get_nxt_net(struct rte_ipv6_addr *ip, uint8_t depth) 43799a2dd95SBruce Richardson { 43899a2dd95SBruce Richardson int i; 43999a2dd95SBruce Richardson uint8_t part_depth; 44099a2dd95SBruce Richardson uint8_t prev_byte; 44199a2dd95SBruce Richardson 44299a2dd95SBruce Richardson for (i = 0, part_depth = depth; part_depth > 8; part_depth -= 8, i++) 44399a2dd95SBruce Richardson ; 44499a2dd95SBruce Richardson 4456cb10a9bSRobin Jarry prev_byte = ip->a[i]; 4466cb10a9bSRobin Jarry ip->a[i] += 1 << (8 - part_depth); 4476cb10a9bSRobin Jarry if (ip->a[i] < prev_byte) { 44899a2dd95SBruce Richardson while (i > 0) { 4496cb10a9bSRobin Jarry ip->a[--i] += 1; 4506cb10a9bSRobin Jarry if (ip->a[i] != 0) 45199a2dd95SBruce Richardson break; 45299a2dd95SBruce Richardson } 45399a2dd95SBruce Richardson } 45499a2dd95SBruce Richardson } 45599a2dd95SBruce Richardson 45699a2dd95SBruce Richardson static int 45799a2dd95SBruce Richardson modify_dp(struct rte_trie_tbl *dp, struct rte_rib6 *rib, 4586cb10a9bSRobin Jarry const struct rte_ipv6_addr *ip, 45999a2dd95SBruce Richardson uint8_t depth, uint64_t next_hop) 46099a2dd95SBruce Richardson { 46199a2dd95SBruce Richardson struct rte_rib6_node *tmp = NULL; 4626cb10a9bSRobin Jarry struct rte_ipv6_addr ledge, redge; 46399a2dd95SBruce Richardson int ret; 46499a2dd95SBruce Richardson uint8_t tmp_depth; 46599a2dd95SBruce Richardson 46699a2dd95SBruce Richardson if (next_hop > get_max_nh(dp->nh_sz)) 46799a2dd95SBruce Richardson return -EINVAL; 46899a2dd95SBruce Richardson 4696cb10a9bSRobin Jarry ledge = *ip; 47099a2dd95SBruce Richardson do { 471*59b99315SRobin Jarry tmp = rte_rib6_get_nxt(rib, ip, depth, tmp, 47299a2dd95SBruce Richardson RTE_RIB6_GET_NXT_COVER); 47399a2dd95SBruce Richardson if (tmp != NULL) { 47499a2dd95SBruce Richardson rte_rib6_get_depth(tmp, &tmp_depth); 47599a2dd95SBruce Richardson if (tmp_depth == depth) 47699a2dd95SBruce Richardson continue; 477*59b99315SRobin Jarry rte_rib6_get_ip(tmp, &redge); 4786cb10a9bSRobin Jarry if (rte_ipv6_addr_eq(&ledge, &redge)) { 4796cb10a9bSRobin Jarry get_nxt_net(&ledge, tmp_depth); 48099a2dd95SBruce Richardson continue; 48199a2dd95SBruce Richardson } 4826cb10a9bSRobin Jarry ret = install_to_dp(dp, &ledge, &redge, next_hop); 48399a2dd95SBruce Richardson if (ret != 0) 48499a2dd95SBruce Richardson return ret; 4856cb10a9bSRobin Jarry get_nxt_net(&redge, tmp_depth); 4866cb10a9bSRobin Jarry ledge = redge; 487fd66617cSVladimir Medvedkin /* 488fd66617cSVladimir Medvedkin * we got to the end of address space 489fd66617cSVladimir Medvedkin * and wrapped around 490fd66617cSVladimir Medvedkin */ 4916cb10a9bSRobin Jarry if (rte_ipv6_addr_is_unspec(&ledge)) 492fd66617cSVladimir Medvedkin break; 49399a2dd95SBruce Richardson } else { 4946cb10a9bSRobin Jarry redge = *ip; 4956cb10a9bSRobin Jarry get_nxt_net(&redge, depth); 4966cb10a9bSRobin Jarry if (rte_ipv6_addr_eq(&ledge, &redge) && 4976cb10a9bSRobin Jarry !rte_ipv6_addr_is_unspec(&ledge)) 49899a2dd95SBruce Richardson break; 499fd66617cSVladimir Medvedkin 5006cb10a9bSRobin Jarry ret = install_to_dp(dp, &ledge, &redge, next_hop); 50199a2dd95SBruce Richardson if (ret != 0) 50299a2dd95SBruce Richardson return ret; 50399a2dd95SBruce Richardson } 50499a2dd95SBruce Richardson } while (tmp); 50599a2dd95SBruce Richardson 50699a2dd95SBruce Richardson return 0; 50799a2dd95SBruce Richardson } 50899a2dd95SBruce Richardson 50999a2dd95SBruce Richardson int 5106cb10a9bSRobin Jarry trie_modify(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, 51199a2dd95SBruce Richardson uint8_t depth, uint64_t next_hop, int op) 51299a2dd95SBruce Richardson { 51399a2dd95SBruce Richardson struct rte_trie_tbl *dp; 51499a2dd95SBruce Richardson struct rte_rib6 *rib; 51599a2dd95SBruce Richardson struct rte_rib6_node *tmp = NULL; 51699a2dd95SBruce Richardson struct rte_rib6_node *node; 51799a2dd95SBruce Richardson struct rte_rib6_node *parent; 5186cb10a9bSRobin Jarry struct rte_ipv6_addr ip_masked; 5196cb10a9bSRobin Jarry int ret = 0; 52099a2dd95SBruce Richardson uint64_t par_nh, node_nh; 52199a2dd95SBruce Richardson uint8_t tmp_depth, depth_diff = 0, parent_depth = 24; 52299a2dd95SBruce Richardson 5236cb10a9bSRobin Jarry if ((fib == NULL) || (ip == NULL) || (depth > RTE_IPV6_MAX_DEPTH)) 52499a2dd95SBruce Richardson return -EINVAL; 52599a2dd95SBruce Richardson 52699a2dd95SBruce Richardson dp = rte_fib6_get_dp(fib); 52799a2dd95SBruce Richardson RTE_ASSERT(dp); 52899a2dd95SBruce Richardson rib = rte_fib6_get_rib(fib); 52999a2dd95SBruce Richardson RTE_ASSERT(rib); 53099a2dd95SBruce Richardson 5316cb10a9bSRobin Jarry ip_masked = *ip; 5326cb10a9bSRobin Jarry rte_ipv6_addr_mask(&ip_masked, depth); 53399a2dd95SBruce Richardson 53499a2dd95SBruce Richardson if (depth > 24) { 535*59b99315SRobin Jarry tmp = rte_rib6_get_nxt(rib, &ip_masked, 53699a2dd95SBruce Richardson RTE_ALIGN_FLOOR(depth, 8), NULL, 53799a2dd95SBruce Richardson RTE_RIB6_GET_NXT_COVER); 53899a2dd95SBruce Richardson if (tmp == NULL) { 539*59b99315SRobin Jarry tmp = rte_rib6_lookup(rib, ip); 54099a2dd95SBruce Richardson if (tmp != NULL) { 54199a2dd95SBruce Richardson rte_rib6_get_depth(tmp, &tmp_depth); 54299a2dd95SBruce Richardson parent_depth = RTE_MAX(tmp_depth, 24); 54399a2dd95SBruce Richardson } 54499a2dd95SBruce Richardson depth_diff = RTE_ALIGN_CEIL(depth, 8) - 54599a2dd95SBruce Richardson RTE_ALIGN_CEIL(parent_depth, 8); 54699a2dd95SBruce Richardson depth_diff = depth_diff >> 3; 54799a2dd95SBruce Richardson } 54899a2dd95SBruce Richardson } 549*59b99315SRobin Jarry node = rte_rib6_lookup_exact(rib, &ip_masked, depth); 55099a2dd95SBruce Richardson switch (op) { 55199a2dd95SBruce Richardson case RTE_FIB6_ADD: 55299a2dd95SBruce Richardson if (node != NULL) { 55399a2dd95SBruce Richardson rte_rib6_get_nh(node, &node_nh); 55499a2dd95SBruce Richardson if (node_nh == next_hop) 55599a2dd95SBruce Richardson return 0; 5566cb10a9bSRobin Jarry ret = modify_dp(dp, rib, &ip_masked, depth, next_hop); 55799a2dd95SBruce Richardson if (ret == 0) 55899a2dd95SBruce Richardson rte_rib6_set_nh(node, next_hop); 55999a2dd95SBruce Richardson return 0; 56099a2dd95SBruce Richardson } 56199a2dd95SBruce Richardson 56299a2dd95SBruce Richardson if ((depth > 24) && (dp->rsvd_tbl8s >= 56399a2dd95SBruce Richardson dp->number_tbl8s - depth_diff)) 56499a2dd95SBruce Richardson return -ENOSPC; 56599a2dd95SBruce Richardson 566*59b99315SRobin Jarry node = rte_rib6_insert(rib, &ip_masked, depth); 56799a2dd95SBruce Richardson if (node == NULL) 56899a2dd95SBruce Richardson return -rte_errno; 56999a2dd95SBruce Richardson rte_rib6_set_nh(node, next_hop); 57099a2dd95SBruce Richardson parent = rte_rib6_lookup_parent(node); 57199a2dd95SBruce Richardson if (parent != NULL) { 57299a2dd95SBruce Richardson rte_rib6_get_nh(parent, &par_nh); 57399a2dd95SBruce Richardson if (par_nh == next_hop) 57499a2dd95SBruce Richardson return 0; 57599a2dd95SBruce Richardson } 5766cb10a9bSRobin Jarry ret = modify_dp(dp, rib, &ip_masked, depth, next_hop); 57799a2dd95SBruce Richardson if (ret != 0) { 578*59b99315SRobin Jarry rte_rib6_remove(rib, &ip_masked, depth); 57999a2dd95SBruce Richardson return ret; 58099a2dd95SBruce Richardson } 58199a2dd95SBruce Richardson 58299a2dd95SBruce Richardson dp->rsvd_tbl8s += depth_diff; 58399a2dd95SBruce Richardson return 0; 58499a2dd95SBruce Richardson case RTE_FIB6_DEL: 58599a2dd95SBruce Richardson if (node == NULL) 58699a2dd95SBruce Richardson return -ENOENT; 58799a2dd95SBruce Richardson 58899a2dd95SBruce Richardson parent = rte_rib6_lookup_parent(node); 58999a2dd95SBruce Richardson if (parent != NULL) { 59099a2dd95SBruce Richardson rte_rib6_get_nh(parent, &par_nh); 59199a2dd95SBruce Richardson rte_rib6_get_nh(node, &node_nh); 59299a2dd95SBruce Richardson if (par_nh != node_nh) 5936cb10a9bSRobin Jarry ret = modify_dp(dp, rib, &ip_masked, depth, 59499a2dd95SBruce Richardson par_nh); 59599a2dd95SBruce Richardson } else 5966cb10a9bSRobin Jarry ret = modify_dp(dp, rib, &ip_masked, depth, dp->def_nh); 59799a2dd95SBruce Richardson 59899a2dd95SBruce Richardson if (ret != 0) 59999a2dd95SBruce Richardson return ret; 600*59b99315SRobin Jarry rte_rib6_remove(rib, ip, depth); 60199a2dd95SBruce Richardson 60299a2dd95SBruce Richardson dp->rsvd_tbl8s -= depth_diff; 60399a2dd95SBruce Richardson return 0; 60499a2dd95SBruce Richardson default: 60599a2dd95SBruce Richardson break; 60699a2dd95SBruce Richardson } 60799a2dd95SBruce Richardson return -EINVAL; 60899a2dd95SBruce Richardson } 60999a2dd95SBruce Richardson 61099a2dd95SBruce Richardson void * 61199a2dd95SBruce Richardson trie_create(const char *name, int socket_id, 61299a2dd95SBruce Richardson struct rte_fib6_conf *conf) 61399a2dd95SBruce Richardson { 61499a2dd95SBruce Richardson char mem_name[TRIE_NAMESIZE]; 61599a2dd95SBruce Richardson struct rte_trie_tbl *dp = NULL; 61699a2dd95SBruce Richardson uint64_t def_nh; 61799a2dd95SBruce Richardson uint32_t num_tbl8; 61899a2dd95SBruce Richardson enum rte_fib_trie_nh_sz nh_sz; 61999a2dd95SBruce Richardson 62099a2dd95SBruce Richardson if ((name == NULL) || (conf == NULL) || 62199a2dd95SBruce Richardson (conf->trie.nh_sz < RTE_FIB6_TRIE_2B) || 62299a2dd95SBruce Richardson (conf->trie.nh_sz > RTE_FIB6_TRIE_8B) || 62399a2dd95SBruce Richardson (conf->trie.num_tbl8 > 62499a2dd95SBruce Richardson get_max_nh(conf->trie.nh_sz)) || 62599a2dd95SBruce Richardson (conf->trie.num_tbl8 == 0) || 62699a2dd95SBruce Richardson (conf->default_nh > 62799a2dd95SBruce Richardson get_max_nh(conf->trie.nh_sz))) { 62899a2dd95SBruce Richardson 62999a2dd95SBruce Richardson rte_errno = EINVAL; 63099a2dd95SBruce Richardson return NULL; 63199a2dd95SBruce Richardson } 63299a2dd95SBruce Richardson 63399a2dd95SBruce Richardson def_nh = conf->default_nh; 63499a2dd95SBruce Richardson nh_sz = conf->trie.nh_sz; 63599a2dd95SBruce Richardson num_tbl8 = conf->trie.num_tbl8; 63699a2dd95SBruce Richardson 63799a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "DP_%s", name); 63899a2dd95SBruce Richardson dp = rte_zmalloc_socket(name, sizeof(struct rte_trie_tbl) + 63966ed1786SVladimir Medvedkin TRIE_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t), 64066ed1786SVladimir Medvedkin RTE_CACHE_LINE_SIZE, socket_id); 64199a2dd95SBruce Richardson if (dp == NULL) { 64299a2dd95SBruce Richardson rte_errno = ENOMEM; 64399a2dd95SBruce Richardson return dp; 64499a2dd95SBruce Richardson } 64599a2dd95SBruce Richardson 64699a2dd95SBruce Richardson write_to_dp(&dp->tbl24, (def_nh << 1), nh_sz, 1 << 24); 64799a2dd95SBruce Richardson 64899a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp); 64999a2dd95SBruce Richardson dp->tbl8 = rte_zmalloc_socket(mem_name, TRIE_TBL8_GRP_NUM_ENT * 65099a2dd95SBruce Richardson (1ll << nh_sz) * (num_tbl8 + 1), 65199a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, socket_id); 65299a2dd95SBruce Richardson if (dp->tbl8 == NULL) { 65399a2dd95SBruce Richardson rte_errno = ENOMEM; 65499a2dd95SBruce Richardson rte_free(dp); 65599a2dd95SBruce Richardson return NULL; 65699a2dd95SBruce Richardson } 65799a2dd95SBruce Richardson dp->def_nh = def_nh; 65899a2dd95SBruce Richardson dp->nh_sz = nh_sz; 65999a2dd95SBruce Richardson dp->number_tbl8s = num_tbl8; 66099a2dd95SBruce Richardson 66199a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp); 66299a2dd95SBruce Richardson dp->tbl8_pool = rte_zmalloc_socket(mem_name, 66399a2dd95SBruce Richardson sizeof(uint32_t) * dp->number_tbl8s, 66499a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, socket_id); 66599a2dd95SBruce Richardson if (dp->tbl8_pool == NULL) { 66699a2dd95SBruce Richardson rte_errno = ENOMEM; 66799a2dd95SBruce Richardson rte_free(dp->tbl8); 66899a2dd95SBruce Richardson rte_free(dp); 66999a2dd95SBruce Richardson return NULL; 67099a2dd95SBruce Richardson } 67199a2dd95SBruce Richardson 67299a2dd95SBruce Richardson tbl8_pool_init(dp); 67399a2dd95SBruce Richardson 67499a2dd95SBruce Richardson return dp; 67599a2dd95SBruce Richardson } 67699a2dd95SBruce Richardson 67799a2dd95SBruce Richardson void 67899a2dd95SBruce Richardson trie_free(void *p) 67999a2dd95SBruce Richardson { 68099a2dd95SBruce Richardson struct rte_trie_tbl *dp = (struct rte_trie_tbl *)p; 68199a2dd95SBruce Richardson 68299a2dd95SBruce Richardson rte_free(dp->tbl8_pool); 68399a2dd95SBruce Richardson rte_free(dp->tbl8); 68499a2dd95SBruce Richardson rte_free(dp); 68599a2dd95SBruce Richardson } 686