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 #ifndef _DIR24_8_H_ 799a2dd95SBruce Richardson #define _DIR24_8_H_ 899a2dd95SBruce Richardson 9e9fd1ebfSTyler Retzlaff #include <stdalign.h> 10e194f3cdSVladimir Medvedkin #include <stdbool.h> 11e9fd1ebfSTyler Retzlaff 12e194f3cdSVladimir Medvedkin #include <rte_byteorder.h> 1399a2dd95SBruce Richardson #include <rte_prefetch.h> 1499a2dd95SBruce Richardson #include <rte_branch_prediction.h> 15*96c3d06aSVladimir Medvedkin #include <rte_rcu_qsbr.h> 1699a2dd95SBruce Richardson 1799a2dd95SBruce Richardson /** 1899a2dd95SBruce Richardson * @file 1999a2dd95SBruce Richardson * DIR24_8 algorithm 2099a2dd95SBruce Richardson */ 2199a2dd95SBruce Richardson 2299a2dd95SBruce Richardson #define DIR24_8_TBL24_NUM_ENT (1 << 24) 2399a2dd95SBruce Richardson #define DIR24_8_TBL8_GRP_NUM_ENT 256U 2499a2dd95SBruce Richardson #define DIR24_8_EXT_ENT 1 2599a2dd95SBruce Richardson #define DIR24_8_TBL24_MASK 0xffffff00 2699a2dd95SBruce Richardson 2799a2dd95SBruce Richardson #define BITMAP_SLAB_BIT_SIZE_LOG2 6 2899a2dd95SBruce Richardson #define BITMAP_SLAB_BIT_SIZE (1 << BITMAP_SLAB_BIT_SIZE_LOG2) 2999a2dd95SBruce Richardson #define BITMAP_SLAB_BITMASK (BITMAP_SLAB_BIT_SIZE - 1) 3099a2dd95SBruce Richardson 3199a2dd95SBruce Richardson struct dir24_8_tbl { 3299a2dd95SBruce Richardson uint32_t number_tbl8s; /**< Total number of tbl8s */ 3399a2dd95SBruce Richardson uint32_t rsvd_tbl8s; /**< Number of reserved tbl8s */ 3499a2dd95SBruce Richardson uint32_t cur_tbl8s; /**< Current number of tbl8s */ 3599a2dd95SBruce Richardson enum rte_fib_dir24_8_nh_sz nh_sz; /**< Size of nexthop entry */ 36*96c3d06aSVladimir Medvedkin /* RCU config. */ 37*96c3d06aSVladimir Medvedkin enum rte_fib_qsbr_mode rcu_mode;/* Blocking, defer queue. */ 38*96c3d06aSVladimir Medvedkin struct rte_rcu_qsbr *v; /* RCU QSBR variable. */ 39*96c3d06aSVladimir Medvedkin struct rte_rcu_qsbr_dq *dq; /* RCU QSBR defer queue. */ 4099a2dd95SBruce Richardson uint64_t def_nh; /**< Default next hop */ 4199a2dd95SBruce Richardson uint64_t *tbl8; /**< tbl8 table. */ 4299a2dd95SBruce Richardson uint64_t *tbl8_idxes; /**< bitmap containing free tbl8 idxes*/ 4399a2dd95SBruce Richardson /* tbl24 table. */ 4496f25531STyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint64_t tbl24[]; 4599a2dd95SBruce Richardson }; 4699a2dd95SBruce Richardson 4799a2dd95SBruce Richardson static inline void * 4899a2dd95SBruce Richardson get_tbl24_p(struct dir24_8_tbl *dp, uint32_t ip, uint8_t nh_sz) 4999a2dd95SBruce Richardson { 5099a2dd95SBruce Richardson return (void *)&((uint8_t *)dp->tbl24)[(ip & 5199a2dd95SBruce Richardson DIR24_8_TBL24_MASK) >> (8 - nh_sz)]; 5299a2dd95SBruce Richardson } 5399a2dd95SBruce Richardson 5499a2dd95SBruce Richardson static inline uint8_t 5599a2dd95SBruce Richardson bits_in_nh(uint8_t nh_sz) 5699a2dd95SBruce Richardson { 5799a2dd95SBruce Richardson return 8 * (1 << nh_sz); 5899a2dd95SBruce Richardson } 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson static inline uint64_t 6199a2dd95SBruce Richardson get_max_nh(uint8_t nh_sz) 6299a2dd95SBruce Richardson { 6399a2dd95SBruce Richardson return ((1ULL << (bits_in_nh(nh_sz) - 1)) - 1); 6499a2dd95SBruce Richardson } 6599a2dd95SBruce Richardson 6699a2dd95SBruce Richardson static inline uint32_t 6799a2dd95SBruce Richardson get_tbl24_idx(uint32_t ip) 6899a2dd95SBruce Richardson { 6999a2dd95SBruce Richardson return ip >> 8; 7099a2dd95SBruce Richardson } 7199a2dd95SBruce Richardson 7299a2dd95SBruce Richardson static inline uint32_t 7399a2dd95SBruce Richardson get_tbl8_idx(uint32_t res, uint32_t ip) 7499a2dd95SBruce Richardson { 7599a2dd95SBruce Richardson return (res >> 1) * DIR24_8_TBL8_GRP_NUM_ENT + (uint8_t)ip; 7699a2dd95SBruce Richardson } 7799a2dd95SBruce Richardson 7899a2dd95SBruce Richardson static inline uint64_t 7999a2dd95SBruce Richardson lookup_msk(uint8_t nh_sz) 8099a2dd95SBruce Richardson { 8199a2dd95SBruce Richardson return ((1ULL << ((1 << (nh_sz + 3)) - 1)) << 1) - 1; 8299a2dd95SBruce Richardson } 8399a2dd95SBruce Richardson 8499a2dd95SBruce Richardson static inline uint8_t 8599a2dd95SBruce Richardson get_psd_idx(uint32_t val, uint8_t nh_sz) 8699a2dd95SBruce Richardson { 8799a2dd95SBruce Richardson return val & ((1 << (3 - nh_sz)) - 1); 8899a2dd95SBruce Richardson } 8999a2dd95SBruce Richardson 9099a2dd95SBruce Richardson static inline uint32_t 9199a2dd95SBruce Richardson get_tbl_idx(uint32_t val, uint8_t nh_sz) 9299a2dd95SBruce Richardson { 9399a2dd95SBruce Richardson return val >> (3 - nh_sz); 9499a2dd95SBruce Richardson } 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson static inline uint64_t 9799a2dd95SBruce Richardson get_tbl24(struct dir24_8_tbl *dp, uint32_t ip, uint8_t nh_sz) 9899a2dd95SBruce Richardson { 9999a2dd95SBruce Richardson return ((dp->tbl24[get_tbl_idx(get_tbl24_idx(ip), nh_sz)] >> 10099a2dd95SBruce Richardson (get_psd_idx(get_tbl24_idx(ip), nh_sz) * 10199a2dd95SBruce Richardson bits_in_nh(nh_sz))) & lookup_msk(nh_sz)); 10299a2dd95SBruce Richardson } 10399a2dd95SBruce Richardson 10499a2dd95SBruce Richardson static inline uint64_t 10599a2dd95SBruce Richardson get_tbl8(struct dir24_8_tbl *dp, uint32_t res, uint32_t ip, uint8_t nh_sz) 10699a2dd95SBruce Richardson { 10799a2dd95SBruce Richardson return ((dp->tbl8[get_tbl_idx(get_tbl8_idx(res, ip), nh_sz)] >> 10899a2dd95SBruce Richardson (get_psd_idx(get_tbl8_idx(res, ip), nh_sz) * 10999a2dd95SBruce Richardson bits_in_nh(nh_sz))) & lookup_msk(nh_sz)); 11099a2dd95SBruce Richardson } 11199a2dd95SBruce Richardson 11299a2dd95SBruce Richardson static inline int 11399a2dd95SBruce Richardson is_entry_extended(uint64_t ent) 11499a2dd95SBruce Richardson { 11599a2dd95SBruce Richardson return (ent & DIR24_8_EXT_ENT) == DIR24_8_EXT_ENT; 11699a2dd95SBruce Richardson } 11799a2dd95SBruce Richardson 11899a2dd95SBruce Richardson #define LOOKUP_FUNC(suffix, type, bulk_prefetch, nh_sz) \ 11999a2dd95SBruce Richardson static inline void dir24_8_lookup_bulk_##suffix(void *p, const uint32_t *ips, \ 12099a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) \ 12199a2dd95SBruce Richardson { \ 12299a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; \ 12399a2dd95SBruce Richardson uint64_t tmp; \ 12499a2dd95SBruce Richardson uint32_t i; \ 12599a2dd95SBruce Richardson uint32_t prefetch_offset = \ 12699a2dd95SBruce Richardson RTE_MIN((unsigned int)bulk_prefetch, n); \ 12799a2dd95SBruce Richardson \ 12899a2dd95SBruce Richardson for (i = 0; i < prefetch_offset; i++) \ 12999a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz)); \ 13099a2dd95SBruce Richardson for (i = 0; i < (n - prefetch_offset); i++) { \ 13199a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, \ 13299a2dd95SBruce Richardson ips[i + prefetch_offset], nh_sz)); \ 13399a2dd95SBruce Richardson tmp = ((type *)dp->tbl24)[ips[i] >> 8]; \ 13499a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) \ 13599a2dd95SBruce Richardson tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] + \ 13699a2dd95SBruce Richardson ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)]; \ 13799a2dd95SBruce Richardson next_hops[i] = tmp >> 1; \ 13899a2dd95SBruce Richardson } \ 13999a2dd95SBruce Richardson for (; i < n; i++) { \ 14099a2dd95SBruce Richardson tmp = ((type *)dp->tbl24)[ips[i] >> 8]; \ 14199a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) \ 14299a2dd95SBruce Richardson tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] + \ 14399a2dd95SBruce Richardson ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)]; \ 14499a2dd95SBruce Richardson next_hops[i] = tmp >> 1; \ 14599a2dd95SBruce Richardson } \ 14699a2dd95SBruce Richardson } \ 14799a2dd95SBruce Richardson 14899a2dd95SBruce Richardson LOOKUP_FUNC(1b, uint8_t, 5, 0) 14999a2dd95SBruce Richardson LOOKUP_FUNC(2b, uint16_t, 6, 1) 15099a2dd95SBruce Richardson LOOKUP_FUNC(4b, uint32_t, 15, 2) 15199a2dd95SBruce Richardson LOOKUP_FUNC(8b, uint64_t, 12, 3) 15299a2dd95SBruce Richardson 15399a2dd95SBruce Richardson static inline void 15499a2dd95SBruce Richardson dir24_8_lookup_bulk(struct dir24_8_tbl *dp, const uint32_t *ips, 15599a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n, uint8_t nh_sz) 15699a2dd95SBruce Richardson { 15799a2dd95SBruce Richardson uint64_t tmp; 15899a2dd95SBruce Richardson uint32_t i; 15999a2dd95SBruce Richardson uint32_t prefetch_offset = RTE_MIN(15U, n); 16099a2dd95SBruce Richardson 16199a2dd95SBruce Richardson for (i = 0; i < prefetch_offset; i++) 16299a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz)); 16399a2dd95SBruce Richardson for (i = 0; i < (n - prefetch_offset); i++) { 16499a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, ips[i + prefetch_offset], 16599a2dd95SBruce Richardson nh_sz)); 16699a2dd95SBruce Richardson tmp = get_tbl24(dp, ips[i], nh_sz); 16799a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) 16899a2dd95SBruce Richardson tmp = get_tbl8(dp, tmp, ips[i], nh_sz); 16999a2dd95SBruce Richardson 17099a2dd95SBruce Richardson next_hops[i] = tmp >> 1; 17199a2dd95SBruce Richardson } 17299a2dd95SBruce Richardson for (; i < n; i++) { 17399a2dd95SBruce Richardson tmp = get_tbl24(dp, ips[i], nh_sz); 17499a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) 17599a2dd95SBruce Richardson tmp = get_tbl8(dp, tmp, ips[i], nh_sz); 17699a2dd95SBruce Richardson 17799a2dd95SBruce Richardson next_hops[i] = tmp >> 1; 17899a2dd95SBruce Richardson } 17999a2dd95SBruce Richardson } 18099a2dd95SBruce Richardson 18199a2dd95SBruce Richardson static inline void 18299a2dd95SBruce Richardson dir24_8_lookup_bulk_0(void *p, const uint32_t *ips, 18399a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 18499a2dd95SBruce Richardson { 18599a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 18699a2dd95SBruce Richardson 18799a2dd95SBruce Richardson dir24_8_lookup_bulk(dp, ips, next_hops, n, 0); 18899a2dd95SBruce Richardson } 18999a2dd95SBruce Richardson 19099a2dd95SBruce Richardson static inline void 19199a2dd95SBruce Richardson dir24_8_lookup_bulk_1(void *p, const uint32_t *ips, 19299a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 19399a2dd95SBruce Richardson { 19499a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 19599a2dd95SBruce Richardson 19699a2dd95SBruce Richardson dir24_8_lookup_bulk(dp, ips, next_hops, n, 1); 19799a2dd95SBruce Richardson } 19899a2dd95SBruce Richardson 19999a2dd95SBruce Richardson static inline void 20099a2dd95SBruce Richardson dir24_8_lookup_bulk_2(void *p, const uint32_t *ips, 20199a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 20299a2dd95SBruce Richardson { 20399a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 20499a2dd95SBruce Richardson 20599a2dd95SBruce Richardson dir24_8_lookup_bulk(dp, ips, next_hops, n, 2); 20699a2dd95SBruce Richardson } 20799a2dd95SBruce Richardson 20899a2dd95SBruce Richardson static inline void 20999a2dd95SBruce Richardson dir24_8_lookup_bulk_3(void *p, const uint32_t *ips, 21099a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 21199a2dd95SBruce Richardson { 21299a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 21399a2dd95SBruce Richardson 21499a2dd95SBruce Richardson dir24_8_lookup_bulk(dp, ips, next_hops, n, 3); 21599a2dd95SBruce Richardson } 21699a2dd95SBruce Richardson 21799a2dd95SBruce Richardson static inline void 21899a2dd95SBruce Richardson dir24_8_lookup_bulk_uni(void *p, const uint32_t *ips, 21999a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 22099a2dd95SBruce Richardson { 22199a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 22299a2dd95SBruce Richardson uint64_t tmp; 22399a2dd95SBruce Richardson uint32_t i; 22499a2dd95SBruce Richardson uint32_t prefetch_offset = RTE_MIN(15U, n); 22599a2dd95SBruce Richardson uint8_t nh_sz = dp->nh_sz; 22699a2dd95SBruce Richardson 22799a2dd95SBruce Richardson for (i = 0; i < prefetch_offset; i++) 22899a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz)); 22999a2dd95SBruce Richardson for (i = 0; i < (n - prefetch_offset); i++) { 23099a2dd95SBruce Richardson rte_prefetch0(get_tbl24_p(dp, ips[i + prefetch_offset], 23199a2dd95SBruce Richardson nh_sz)); 23299a2dd95SBruce Richardson tmp = get_tbl24(dp, ips[i], nh_sz); 23399a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) 23499a2dd95SBruce Richardson tmp = get_tbl8(dp, tmp, ips[i], nh_sz); 23599a2dd95SBruce Richardson 23699a2dd95SBruce Richardson next_hops[i] = tmp >> 1; 23799a2dd95SBruce Richardson } 23899a2dd95SBruce Richardson for (; i < n; i++) { 23999a2dd95SBruce Richardson tmp = get_tbl24(dp, ips[i], nh_sz); 24099a2dd95SBruce Richardson if (unlikely(is_entry_extended(tmp))) 24199a2dd95SBruce Richardson tmp = get_tbl8(dp, tmp, ips[i], nh_sz); 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson next_hops[i] = tmp >> 1; 24499a2dd95SBruce Richardson } 24599a2dd95SBruce Richardson } 24699a2dd95SBruce Richardson 247e194f3cdSVladimir Medvedkin #define BSWAP_MAX_LENGTH 64 248e194f3cdSVladimir Medvedkin 249e194f3cdSVladimir Medvedkin typedef void (*dir24_8_lookup_bulk_be_cb)(void *p, const uint32_t *ips, uint64_t *next_hops, 250e194f3cdSVladimir Medvedkin const unsigned int n); 251e194f3cdSVladimir Medvedkin 252e194f3cdSVladimir Medvedkin static inline void 253e194f3cdSVladimir Medvedkin dir24_8_lookup_bulk_be(void *p, const uint32_t *ips, uint64_t *next_hops, const unsigned int n, 254e194f3cdSVladimir Medvedkin dir24_8_lookup_bulk_be_cb cb) 255e194f3cdSVladimir Medvedkin { 256e194f3cdSVladimir Medvedkin uint32_t le_ips[BSWAP_MAX_LENGTH]; 257e194f3cdSVladimir Medvedkin unsigned int i; 258e194f3cdSVladimir Medvedkin 259e194f3cdSVladimir Medvedkin #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN 260e194f3cdSVladimir Medvedkin cb(p, ips, next_hops, n); 261e194f3cdSVladimir Medvedkin #else 262e194f3cdSVladimir Medvedkin for (i = 0; i < n; i += BSWAP_MAX_LENGTH) { 263e194f3cdSVladimir Medvedkin int j; 264e194f3cdSVladimir Medvedkin for (j = 0; j < BSWAP_MAX_LENGTH && i + j < n; j++) 265e194f3cdSVladimir Medvedkin le_ips[j] = rte_be_to_cpu_32(ips[i + j]); 266e194f3cdSVladimir Medvedkin 267e194f3cdSVladimir Medvedkin cb(p, le_ips, next_hops + i, j); 268e194f3cdSVladimir Medvedkin } 269e194f3cdSVladimir Medvedkin #endif 270e194f3cdSVladimir Medvedkin } 271e194f3cdSVladimir Medvedkin 272e194f3cdSVladimir Medvedkin #define DECLARE_BE_LOOKUP_FN(name) \ 273e194f3cdSVladimir Medvedkin static inline void \ 274e194f3cdSVladimir Medvedkin name##_be(void *p, const uint32_t *ips, uint64_t *next_hops, const unsigned int n) \ 275e194f3cdSVladimir Medvedkin { \ 276e194f3cdSVladimir Medvedkin dir24_8_lookup_bulk_be(p, ips, next_hops, n, name); \ 277e194f3cdSVladimir Medvedkin } 278e194f3cdSVladimir Medvedkin 279e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_1b) 280e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_2b) 281e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_4b) 282e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_8b) 283e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_0) 284e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_1) 285e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_2) 286e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_3) 287e194f3cdSVladimir Medvedkin DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_uni) 288e194f3cdSVladimir Medvedkin 28999a2dd95SBruce Richardson void * 29099a2dd95SBruce Richardson dir24_8_create(const char *name, int socket_id, struct rte_fib_conf *conf); 29199a2dd95SBruce Richardson 29299a2dd95SBruce Richardson void 29399a2dd95SBruce Richardson dir24_8_free(void *p); 29499a2dd95SBruce Richardson 29599a2dd95SBruce Richardson rte_fib_lookup_fn_t 296e194f3cdSVladimir Medvedkin dir24_8_get_lookup_fn(void *p, enum rte_fib_lookup_type type, bool be_addr); 29799a2dd95SBruce Richardson 29899a2dd95SBruce Richardson int 29999a2dd95SBruce Richardson dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth, 30099a2dd95SBruce Richardson uint64_t next_hop, int op); 30199a2dd95SBruce Richardson 302*96c3d06aSVladimir Medvedkin int 303*96c3d06aSVladimir Medvedkin dir24_8_rcu_qsbr_add(struct dir24_8_tbl *dp, struct rte_fib_rcu_config *cfg, 304*96c3d06aSVladimir Medvedkin const char *name); 305*96c3d06aSVladimir Medvedkin 30699a2dd95SBruce Richardson #endif /* _DIR24_8_H_ */ 307