Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>
3 : : * Copyright(c) 2019 Intel Corporation
4 : : */
5 : :
6 : : #include <stdint.h>
7 : : #include <stdio.h>
8 : :
9 : : #include <rte_debug.h>
10 : : #include <rte_malloc.h>
11 : : #include <rte_errno.h>
12 : : #include <rte_vect.h>
13 : :
14 : : #include <rte_rib.h>
15 : : #include <rte_fib.h>
16 : : #include "dir24_8.h"
17 : : #include "fib_log.h"
18 : :
19 : : #ifdef CC_DIR24_8_AVX512_SUPPORT
20 : :
21 : : #include "dir24_8_avx512.h"
22 : :
23 : : #endif /* CC_DIR24_8_AVX512_SUPPORT */
24 : :
25 : : #define DIR24_8_NAMESIZE 64
26 : :
27 : : #define ROUNDUP(x, y) RTE_ALIGN_CEIL(x, (1 << (32 - y)))
28 : :
29 : : static inline rte_fib_lookup_fn_t
30 : : get_scalar_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
31 : : {
32 [ + + + + : 6 : switch (nh_sz) {
- ]
33 : 1 : case RTE_FIB_DIR24_8_1B:
34 [ - - + - ]: 1 : return be_addr ? dir24_8_lookup_bulk_1b_be : dir24_8_lookup_bulk_1b;
35 : 1 : case RTE_FIB_DIR24_8_2B:
36 [ - - + - ]: 1 : return be_addr ? dir24_8_lookup_bulk_2b_be : dir24_8_lookup_bulk_2b;
37 : 3 : case RTE_FIB_DIR24_8_4B:
38 [ - - + - ]: 3 : return be_addr ? dir24_8_lookup_bulk_4b_be : dir24_8_lookup_bulk_4b;
39 : 1 : case RTE_FIB_DIR24_8_8B:
40 [ - - + - ]: 1 : return be_addr ? dir24_8_lookup_bulk_8b_be : dir24_8_lookup_bulk_8b;
41 : : default:
42 : : return NULL;
43 : : }
44 : : }
45 : :
46 : : static inline rte_fib_lookup_fn_t
47 : : get_scalar_fn_inlined(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
48 : : {
49 : 0 : switch (nh_sz) {
50 : 0 : case RTE_FIB_DIR24_8_1B:
51 [ # # ]: 0 : return be_addr ? dir24_8_lookup_bulk_0_be : dir24_8_lookup_bulk_0;
52 : 0 : case RTE_FIB_DIR24_8_2B:
53 [ # # ]: 0 : return be_addr ? dir24_8_lookup_bulk_1_be : dir24_8_lookup_bulk_1;
54 : 0 : case RTE_FIB_DIR24_8_4B:
55 [ # # ]: 0 : return be_addr ? dir24_8_lookup_bulk_2_be : dir24_8_lookup_bulk_2;
56 : 0 : case RTE_FIB_DIR24_8_8B:
57 [ # # ]: 0 : return be_addr ? dir24_8_lookup_bulk_3_be : dir24_8_lookup_bulk_3;
58 : : default:
59 : : return NULL;
60 : : }
61 : : }
62 : :
63 : : static inline rte_fib_lookup_fn_t
64 : 6 : get_vector_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
65 : : {
66 : : #ifdef CC_DIR24_8_AVX512_SUPPORT
67 [ + - + - ]: 12 : if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) <= 0 ||
68 [ + - ]: 12 : rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512DQ) <= 0 ||
69 : 6 : rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_512)
70 : 6 : return NULL;
71 : :
72 [ # # # # ]: 0 : if (be_addr && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) <= 0)
73 : : return NULL;
74 : :
75 [ # # # # : 0 : switch (nh_sz) {
# ]
76 : 0 : case RTE_FIB_DIR24_8_1B:
77 [ # # ]: 0 : return be_addr ? rte_dir24_8_vec_lookup_bulk_1b_be :
78 : : rte_dir24_8_vec_lookup_bulk_1b;
79 : 0 : case RTE_FIB_DIR24_8_2B:
80 [ # # ]: 0 : return be_addr ? rte_dir24_8_vec_lookup_bulk_2b_be :
81 : : rte_dir24_8_vec_lookup_bulk_2b;
82 : 0 : case RTE_FIB_DIR24_8_4B:
83 [ # # ]: 0 : return be_addr ? rte_dir24_8_vec_lookup_bulk_4b_be :
84 : : rte_dir24_8_vec_lookup_bulk_4b;
85 : 0 : case RTE_FIB_DIR24_8_8B:
86 [ # # ]: 0 : return be_addr ? rte_dir24_8_vec_lookup_bulk_8b_be :
87 : : rte_dir24_8_vec_lookup_bulk_8b;
88 : : default:
89 : : return NULL;
90 : : }
91 : : #else
92 : : RTE_SET_USED(nh_sz);
93 : : RTE_SET_USED(be_addr);
94 : : #endif
95 : : return NULL;
96 : : }
97 : :
98 : : rte_fib_lookup_fn_t
99 : 6 : dir24_8_get_lookup_fn(void *p, enum rte_fib_lookup_type type, bool be_addr)
100 : : {
101 : : enum rte_fib_dir24_8_nh_sz nh_sz;
102 : : rte_fib_lookup_fn_t ret_fn;
103 : : struct dir24_8_tbl *dp = p;
104 : :
105 [ + - ]: 6 : if (dp == NULL)
106 : : return NULL;
107 : :
108 : 6 : nh_sz = dp->nh_sz;
109 : :
110 [ - - - - : 6 : switch (type) {
+ - ]
111 [ # # # # : 0 : case RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO:
# ]
112 : : return get_scalar_fn(nh_sz, be_addr);
113 [ # # # # : 0 : case RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE:
# ]
114 : : return get_scalar_fn_inlined(nh_sz, be_addr);
115 : 0 : case RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI:
116 [ # # ]: 0 : return be_addr ? dir24_8_lookup_bulk_uni_be : dir24_8_lookup_bulk_uni;
117 : 0 : case RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512:
118 : 0 : return get_vector_fn(nh_sz, be_addr);
119 : 6 : case RTE_FIB_LOOKUP_DEFAULT:
120 : 6 : ret_fn = get_vector_fn(nh_sz, be_addr);
121 [ + - ]: 6 : return ret_fn != NULL ? ret_fn : get_scalar_fn(nh_sz, be_addr);
122 : : default:
123 : : return NULL;
124 : : }
125 : :
126 : : return NULL;
127 : : }
128 : :
129 : : static void
130 : 2593 : write_to_fib(void *ptr, uint64_t val, enum rte_fib_dir24_8_nh_sz size, int n)
131 : : {
132 : : int i;
133 : : uint8_t *ptr8 = (uint8_t *)ptr;
134 : : uint16_t *ptr16 = (uint16_t *)ptr;
135 : : uint32_t *ptr32 = (uint32_t *)ptr;
136 : : uint64_t *ptr64 = (uint64_t *)ptr;
137 : :
138 [ + + + + : 2593 : switch (size) {
- ]
139 : : case RTE_FIB_DIR24_8_1B:
140 [ + + ]: 67110531 : for (i = 0; i < n; i++)
141 : 67110396 : ptr8[i] = (uint8_t)val;
142 : : break;
143 : : case RTE_FIB_DIR24_8_2B:
144 [ + + ]: 67110531 : for (i = 0; i < n; i++)
145 : 67110396 : ptr16[i] = (uint16_t)val;
146 : : break;
147 : : case RTE_FIB_DIR24_8_4B:
148 [ + + ]: 100815257 : for (i = 0; i < n; i++)
149 : 100813069 : ptr32[i] = (uint32_t)val;
150 : : break;
151 : : case RTE_FIB_DIR24_8_8B:
152 [ + + ]: 67110531 : for (i = 0; i < n; i++)
153 : 67110396 : ptr64[i] = (uint64_t)val;
154 : : break;
155 : : }
156 : 2593 : }
157 : :
158 : : static int
159 : 521 : tbl8_get_idx(struct dir24_8_tbl *dp)
160 : : {
161 : : uint32_t i;
162 : : int bit_idx;
163 : :
164 [ + - ]: 521 : for (i = 0; (i < (dp->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) &&
165 [ - + ]: 521 : (dp->tbl8_idxes[i] == UINT64_MAX); i++)
166 : : ;
167 [ + - ]: 521 : if (i < (dp->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) {
168 : 521 : bit_idx = rte_ctz64(~dp->tbl8_idxes[i]);
169 : 521 : dp->tbl8_idxes[i] |= (1ULL << bit_idx);
170 : 521 : return (i << BITMAP_SLAB_BIT_SIZE_LOG2) + bit_idx;
171 : : }
172 : : return -ENOSPC;
173 : : }
174 : :
175 : : static inline void
176 : : tbl8_free_idx(struct dir24_8_tbl *dp, int idx)
177 : : {
178 : 520 : dp->tbl8_idxes[idx >> BITMAP_SLAB_BIT_SIZE_LOG2] &=
179 : 520 : ~(1ULL << (idx & BITMAP_SLAB_BITMASK));
180 : : }
181 : :
182 : : static int
183 : 521 : tbl8_alloc(struct dir24_8_tbl *dp, uint64_t nh)
184 : : {
185 : : int64_t tbl8_idx;
186 : : uint8_t *tbl8_ptr;
187 : :
188 : 521 : tbl8_idx = tbl8_get_idx(dp);
189 : :
190 : : /* If there are no tbl8 groups try to reclaim one. */
191 [ - + - - : 521 : if (unlikely(tbl8_idx == -ENOSPC && dp->dq &&
- - ]
192 : : !rte_rcu_qsbr_dq_reclaim(dp->dq, 1, NULL, NULL, NULL)))
193 : 0 : tbl8_idx = tbl8_get_idx(dp);
194 : :
195 [ - + ]: 521 : if (tbl8_idx < 0)
196 : 0 : return tbl8_idx;
197 : 521 : tbl8_ptr = (uint8_t *)dp->tbl8 +
198 : 521 : ((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) <<
199 : 521 : dp->nh_sz);
200 : : /*Init tbl8 entries with nexthop from tbl24*/
201 : 521 : write_to_fib((void *)tbl8_ptr, nh|
202 : : DIR24_8_EXT_ENT, dp->nh_sz,
203 : : DIR24_8_TBL8_GRP_NUM_ENT);
204 : 521 : dp->cur_tbl8s++;
205 : 521 : return tbl8_idx;
206 : : }
207 : :
208 : : static void
209 : 520 : tbl8_cleanup_and_free(struct dir24_8_tbl *dp, uint64_t tbl8_idx)
210 : : {
211 : 520 : uint8_t *ptr = (uint8_t *)dp->tbl8 + (tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT << dp->nh_sz);
212 : :
213 : 520 : memset(ptr, 0, DIR24_8_TBL8_GRP_NUM_ENT << dp->nh_sz);
214 : 520 : tbl8_free_idx(dp, tbl8_idx);
215 : 520 : dp->cur_tbl8s--;
216 : 520 : }
217 : :
218 : : static void
219 : 0 : __rcu_qsbr_free_resource(void *p, void *data, unsigned int n __rte_unused)
220 : : {
221 : : struct dir24_8_tbl *dp = p;
222 : 0 : uint64_t tbl8_idx = *(uint64_t *)data;
223 : :
224 : 0 : tbl8_cleanup_and_free(dp, tbl8_idx);
225 : 0 : }
226 : :
227 : : static void
228 : 1161 : tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t tbl8_idx)
229 : : {
230 : : uint32_t i;
231 : : uint64_t nh;
232 : : uint8_t *ptr8;
233 : : uint16_t *ptr16;
234 : : uint32_t *ptr32;
235 : : uint64_t *ptr64;
236 : :
237 [ + + + + : 1161 : switch (dp->nh_sz) {
- ]
238 : 34 : case RTE_FIB_DIR24_8_1B:
239 : 34 : ptr8 = &((uint8_t *)dp->tbl8)[tbl8_idx *
240 : : DIR24_8_TBL8_GRP_NUM_ENT];
241 : 34 : nh = *ptr8;
242 [ + + ]: 1038 : for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) {
243 [ + + ]: 1036 : if (nh != ptr8[i])
244 : : return;
245 : : }
246 : 2 : ((uint8_t *)dp->tbl24)[ip >> 8] =
247 : 2 : nh & ~DIR24_8_EXT_ENT;
248 : 2 : break;
249 : 34 : case RTE_FIB_DIR24_8_2B:
250 : 34 : ptr16 = &((uint16_t *)dp->tbl8)[tbl8_idx *
251 : : DIR24_8_TBL8_GRP_NUM_ENT];
252 : 34 : nh = *ptr16;
253 [ + + ]: 1038 : for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) {
254 [ + + ]: 1036 : if (nh != ptr16[i])
255 : : return;
256 : : }
257 : 2 : ((uint16_t *)dp->tbl24)[ip >> 8] =
258 : 2 : nh & ~DIR24_8_EXT_ENT;
259 : 2 : break;
260 : 1059 : case RTE_FIB_DIR24_8_4B:
261 : 1059 : ptr32 = &((uint32_t *)dp->tbl8)[tbl8_idx *
262 : : DIR24_8_TBL8_GRP_NUM_ENT];
263 : 1059 : nh = *ptr32;
264 [ + + ]: 181358 : for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) {
265 [ + + ]: 180844 : if (nh != ptr32[i])
266 : : return;
267 : : }
268 : 514 : ((uint32_t *)dp->tbl24)[ip >> 8] =
269 : 514 : nh & ~DIR24_8_EXT_ENT;
270 : 514 : break;
271 : 34 : case RTE_FIB_DIR24_8_8B:
272 : 34 : ptr64 = &((uint64_t *)dp->tbl8)[tbl8_idx *
273 : : DIR24_8_TBL8_GRP_NUM_ENT];
274 : 34 : nh = *ptr64;
275 [ + + ]: 1038 : for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) {
276 [ + + ]: 1036 : if (nh != ptr64[i])
277 : : return;
278 : : }
279 : 2 : ((uint64_t *)dp->tbl24)[ip >> 8] =
280 : 2 : nh & ~DIR24_8_EXT_ENT;
281 : 2 : break;
282 : : }
283 : :
284 [ + + ]: 520 : if (dp->v == NULL) {
285 : 8 : tbl8_cleanup_and_free(dp, tbl8_idx);
286 [ + - ]: 512 : } else if (dp->rcu_mode == RTE_FIB_QSBR_MODE_SYNC) {
287 : 512 : rte_rcu_qsbr_synchronize(dp->v, RTE_QSBR_THRID_INVALID);
288 : 512 : tbl8_cleanup_and_free(dp, tbl8_idx);
289 : : } else { /* RTE_FIB_QSBR_MODE_DQ */
290 [ # # ]: 0 : if (rte_rcu_qsbr_dq_enqueue(dp->dq, &tbl8_idx))
291 : 0 : FIB_LOG(ERR, "Failed to push QSBR FIFO");
292 : : }
293 : : }
294 : :
295 : : static int
296 : 1537 : install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge, uint32_t redge,
297 : : uint64_t next_hop)
298 : : {
299 : : uint64_t tbl24_tmp;
300 : : int tbl8_idx;
301 : : int tmp_tbl8_idx;
302 : : uint8_t *tbl8_ptr;
303 : : uint32_t len;
304 : :
305 [ + - ]: 1537 : len = ((ledge == 0) && (redge == 0)) ? 1 << 24 :
306 : 1537 : ((redge & DIR24_8_TBL24_MASK) - ROUNDUP(ledge, 24)) >> 8;
307 : :
308 [ + + - + ]: 1537 : if (((ledge >> 8) != (redge >> 8)) || (len == 1 << 24)) {
309 [ + + ]: 384 : if ((ROUNDUP(ledge, 24) - ledge) != 0) {
310 [ - + ]: 8 : tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz);
311 [ - + ]: 8 : if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
312 : : DIR24_8_EXT_ENT) {
313 : : /**
314 : : * Make sure there is space for two TBL8.
315 : : * This is necessary when installing range that
316 : : * needs tbl8 for ledge and redge.
317 : : */
318 : 0 : tbl8_idx = tbl8_alloc(dp, tbl24_tmp);
319 : 0 : tmp_tbl8_idx = tbl8_get_idx(dp);
320 [ # # ]: 0 : if (tbl8_idx < 0)
321 : : return -ENOSPC;
322 [ # # ]: 0 : else if (tmp_tbl8_idx < 0) {
323 : : tbl8_free_idx(dp, tbl8_idx);
324 : 0 : return -ENOSPC;
325 : : }
326 : : tbl8_free_idx(dp, tmp_tbl8_idx);
327 : : /*update dir24 entry with tbl8 index*/
328 : 0 : write_to_fib(get_tbl24_p(dp, ledge,
329 : 0 : dp->nh_sz), (tbl8_idx << 1)|
330 : : DIR24_8_EXT_ENT,
331 : : dp->nh_sz, 1);
332 : : } else
333 : 8 : tbl8_idx = tbl24_tmp >> 1;
334 : 8 : tbl8_ptr = (uint8_t *)dp->tbl8 +
335 : 8 : (((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) +
336 : 8 : (ledge & ~DIR24_8_TBL24_MASK)) <<
337 : 8 : dp->nh_sz);
338 : : /*update tbl8 with new next hop*/
339 : 8 : write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
340 : : DIR24_8_EXT_ENT,
341 : 8 : dp->nh_sz, ROUNDUP(ledge, 24) - ledge);
342 : 8 : tbl8_recycle(dp, ledge, tbl8_idx);
343 : : }
344 : 384 : write_to_fib(get_tbl24_p(dp, ROUNDUP(ledge, 24), dp->nh_sz),
345 : : next_hop << 1, dp->nh_sz, len);
346 [ - + ]: 384 : if (redge & ~DIR24_8_TBL24_MASK) {
347 [ # # ]: 0 : tbl24_tmp = get_tbl24(dp, redge, dp->nh_sz);
348 [ # # ]: 0 : if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
349 : : DIR24_8_EXT_ENT) {
350 : 0 : tbl8_idx = tbl8_alloc(dp, tbl24_tmp);
351 [ # # ]: 0 : if (tbl8_idx < 0)
352 : : return -ENOSPC;
353 : : /*update dir24 entry with tbl8 index*/
354 : 0 : write_to_fib(get_tbl24_p(dp, redge,
355 : 0 : dp->nh_sz), (tbl8_idx << 1)|
356 : : DIR24_8_EXT_ENT,
357 : : dp->nh_sz, 1);
358 : : } else
359 : 0 : tbl8_idx = tbl24_tmp >> 1;
360 : 0 : tbl8_ptr = (uint8_t *)dp->tbl8 +
361 : 0 : ((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) <<
362 : 0 : dp->nh_sz);
363 : : /*update tbl8 with new next hop*/
364 : 0 : write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
365 : : DIR24_8_EXT_ENT,
366 : 0 : dp->nh_sz, redge & ~DIR24_8_TBL24_MASK);
367 : 0 : tbl8_recycle(dp, redge, tbl8_idx);
368 : : }
369 [ + - ]: 1153 : } else if ((redge - ledge) != 0) {
370 [ + + ]: 1153 : tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz);
371 [ + + ]: 1153 : if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
372 : : DIR24_8_EXT_ENT) {
373 : 521 : tbl8_idx = tbl8_alloc(dp, tbl24_tmp);
374 [ + - ]: 521 : if (tbl8_idx < 0)
375 : : return -ENOSPC;
376 : : /*update dir24 entry with tbl8 index*/
377 : 521 : write_to_fib(get_tbl24_p(dp, ledge, dp->nh_sz),
378 : 521 : (tbl8_idx << 1)|
379 : : DIR24_8_EXT_ENT,
380 : : dp->nh_sz, 1);
381 : : } else
382 : 632 : tbl8_idx = tbl24_tmp >> 1;
383 : 1153 : tbl8_ptr = (uint8_t *)dp->tbl8 +
384 : 1153 : (((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) +
385 : 1153 : (ledge & ~DIR24_8_TBL24_MASK)) <<
386 : 1153 : dp->nh_sz);
387 : : /*update tbl8 with new next hop*/
388 : 1153 : write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
389 : : DIR24_8_EXT_ENT,
390 : 1153 : dp->nh_sz, redge - ledge);
391 : 1153 : tbl8_recycle(dp, ledge, tbl8_idx);
392 : : }
393 : : return 0;
394 : : }
395 : :
396 : : static int
397 : 1537 : modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib, uint32_t ip,
398 : : uint8_t depth, uint64_t next_hop)
399 : : {
400 : : struct rte_rib_node *tmp = NULL;
401 : : uint32_t ledge, redge, tmp_ip;
402 : : int ret;
403 : : uint8_t tmp_depth;
404 : :
405 : : ledge = ip;
406 : : do {
407 : 1785 : tmp = rte_rib_get_nxt(rib, ip, depth, tmp,
408 : : RTE_RIB_GET_NXT_COVER);
409 [ + + ]: 1785 : if (tmp != NULL) {
410 : 248 : rte_rib_get_depth(tmp, &tmp_depth);
411 [ - + ]: 248 : if (tmp_depth == depth)
412 : 0 : continue;
413 : 248 : rte_rib_get_ip(tmp, &tmp_ip);
414 [ + - ]: 248 : redge = tmp_ip & rte_rib_depth_to_mask(tmp_depth);
415 [ + - ]: 248 : if (ledge == redge) {
416 : 248 : ledge = redge +
417 : 248 : (uint32_t)(1ULL << (32 - tmp_depth));
418 : 248 : continue;
419 : : }
420 : 0 : ret = install_to_fib(dp, ledge, redge,
421 : : next_hop);
422 [ # # ]: 0 : if (ret != 0)
423 : 0 : return ret;
424 : 0 : ledge = redge +
425 : 0 : (uint32_t)(1ULL << (32 - tmp_depth));
426 : : /*
427 : : * we got to the end of address space
428 : : * and wrapped around
429 : : */
430 [ # # ]: 0 : if (ledge == 0)
431 : : break;
432 : : } else {
433 : 1537 : redge = ip + (uint32_t)(1ULL << (32 - depth));
434 [ + - ]: 1537 : if (ledge == redge && ledge != 0)
435 : : break;
436 : 1537 : ret = install_to_fib(dp, ledge, redge,
437 : : next_hop);
438 [ - + ]: 1537 : if (ret != 0)
439 : 0 : return ret;
440 : : }
441 [ + + ]: 1785 : } while (tmp);
442 : :
443 : : return 0;
444 : : }
445 : :
446 : : int
447 : 1537 : dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth,
448 : : uint64_t next_hop, int op)
449 : : {
450 : : struct dir24_8_tbl *dp;
451 : : struct rte_rib *rib;
452 : : struct rte_rib_node *tmp = NULL;
453 : : struct rte_rib_node *node;
454 : : struct rte_rib_node *parent;
455 : : int ret = 0;
456 : : uint64_t par_nh, node_nh;
457 : :
458 [ + - ]: 1537 : if ((fib == NULL) || (depth > RTE_FIB_MAXDEPTH))
459 : : return -EINVAL;
460 : :
461 : 1537 : dp = rte_fib_get_dp(fib);
462 : 1537 : rib = rte_fib_get_rib(fib);
463 : : RTE_ASSERT((dp != NULL) && (rib != NULL));
464 : :
465 [ + - ]: 1537 : if (next_hop > get_max_nh(dp->nh_sz))
466 : : return -EINVAL;
467 : :
468 : 1537 : ip &= rte_rib_depth_to_mask(depth);
469 : :
470 : 1537 : node = rte_rib_lookup_exact(rib, ip, depth);
471 [ + + - ]: 1537 : switch (op) {
472 : 769 : case RTE_FIB_ADD:
473 [ - + ]: 769 : if (node != NULL) {
474 : 0 : rte_rib_get_nh(node, &node_nh);
475 [ # # ]: 0 : if (node_nh == next_hop)
476 : : return 0;
477 : 0 : ret = modify_fib(dp, rib, ip, depth, next_hop);
478 [ # # ]: 0 : if (ret == 0)
479 : 0 : rte_rib_set_nh(node, next_hop);
480 : 0 : return 0;
481 : : }
482 [ + + ]: 769 : if (depth > 24) {
483 : 577 : tmp = rte_rib_get_nxt(rib, ip, 24, NULL,
484 : : RTE_RIB_GET_NXT_COVER);
485 [ + + ]: 577 : if ((tmp == NULL) &&
486 [ + - ]: 521 : (dp->rsvd_tbl8s >= dp->number_tbl8s))
487 : : return -ENOSPC;
488 : :
489 : : }
490 : 769 : node = rte_rib_insert(rib, ip, depth);
491 [ - + ]: 769 : if (node == NULL)
492 : 0 : return -rte_errno;
493 : 769 : rte_rib_set_nh(node, next_hop);
494 : 769 : parent = rte_rib_lookup_parent(node);
495 [ + + ]: 769 : if (parent != NULL) {
496 : 124 : rte_rib_get_nh(parent, &par_nh);
497 [ + - ]: 124 : if (par_nh == next_hop)
498 : : return 0;
499 : : }
500 : 769 : ret = modify_fib(dp, rib, ip, depth, next_hop);
501 [ - + ]: 769 : if (ret != 0) {
502 : 0 : rte_rib_remove(rib, ip, depth);
503 : 0 : return ret;
504 : : }
505 [ + + ]: 769 : if ((depth > 24) && (tmp == NULL))
506 : 521 : dp->rsvd_tbl8s++;
507 : : return 0;
508 : 768 : case RTE_FIB_DEL:
509 [ + - ]: 768 : if (node == NULL)
510 : : return -ENOENT;
511 : :
512 : 768 : parent = rte_rib_lookup_parent(node);
513 [ + + ]: 768 : if (parent != NULL) {
514 : 124 : rte_rib_get_nh(parent, &par_nh);
515 : 124 : rte_rib_get_nh(node, &node_nh);
516 [ + - ]: 124 : if (par_nh != node_nh)
517 : 124 : ret = modify_fib(dp, rib, ip, depth, par_nh);
518 : : } else
519 : 644 : ret = modify_fib(dp, rib, ip, depth, dp->def_nh);
520 [ + - ]: 768 : if (ret == 0) {
521 : 768 : rte_rib_remove(rib, ip, depth);
522 [ + + ]: 768 : if (depth > 24) {
523 : 576 : tmp = rte_rib_get_nxt(rib, ip, 24, NULL,
524 : : RTE_RIB_GET_NXT_COVER);
525 [ + + ]: 576 : if (tmp == NULL)
526 : 520 : dp->rsvd_tbl8s--;
527 : : }
528 : : }
529 : : return ret;
530 : : default:
531 : : break;
532 : : }
533 : : return -EINVAL;
534 : : }
535 : :
536 : : void *
537 : 8 : dir24_8_create(const char *name, int socket_id, struct rte_fib_conf *fib_conf)
538 : : {
539 : : char mem_name[DIR24_8_NAMESIZE];
540 : : struct dir24_8_tbl *dp;
541 : : uint64_t def_nh;
542 : : uint32_t num_tbl8;
543 : : enum rte_fib_dir24_8_nh_sz nh_sz;
544 : :
545 [ + - ]: 8 : if ((name == NULL) || (fib_conf == NULL) ||
546 : 8 : (fib_conf->dir24_8.nh_sz < RTE_FIB_DIR24_8_1B) ||
547 [ + + + - ]: 8 : (fib_conf->dir24_8.nh_sz > RTE_FIB_DIR24_8_8B) ||
548 : 7 : (fib_conf->dir24_8.num_tbl8 >
549 [ + - + + ]: 7 : get_max_nh(fib_conf->dir24_8.nh_sz)) ||
550 : 6 : (fib_conf->dir24_8.num_tbl8 == 0) ||
551 [ - + ]: 6 : (fib_conf->default_nh >
552 : : get_max_nh(fib_conf->dir24_8.nh_sz))) {
553 : 2 : rte_errno = EINVAL;
554 : 2 : return NULL;
555 : : }
556 : :
557 : : def_nh = fib_conf->default_nh;
558 : : nh_sz = fib_conf->dir24_8.nh_sz;
559 : 6 : num_tbl8 = RTE_ALIGN_CEIL(fib_conf->dir24_8.num_tbl8,
560 : : BITMAP_SLAB_BIT_SIZE);
561 : :
562 : : snprintf(mem_name, sizeof(mem_name), "DP_%s", name);
563 : 6 : dp = rte_zmalloc_socket(name, sizeof(struct dir24_8_tbl) +
564 : 6 : DIR24_8_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t),
565 : : RTE_CACHE_LINE_SIZE, socket_id);
566 [ - + ]: 6 : if (dp == NULL) {
567 : 0 : rte_errno = ENOMEM;
568 : 0 : return NULL;
569 : : }
570 : :
571 : : /* Init table with default value */
572 : 6 : write_to_fib(dp->tbl24, (def_nh << 1), nh_sz, 1 << 24);
573 : :
574 : : snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp);
575 : 6 : uint64_t tbl8_sz = DIR24_8_TBL8_GRP_NUM_ENT * (1ULL << nh_sz) *
576 : 6 : (num_tbl8 + 1);
577 : 6 : dp->tbl8 = rte_zmalloc_socket(mem_name, tbl8_sz,
578 : : RTE_CACHE_LINE_SIZE, socket_id);
579 [ - + ]: 6 : if (dp->tbl8 == NULL) {
580 : 0 : rte_errno = ENOMEM;
581 : 0 : rte_free(dp);
582 : 0 : return NULL;
583 : : }
584 : 6 : dp->def_nh = def_nh;
585 : 6 : dp->nh_sz = nh_sz;
586 : 6 : dp->number_tbl8s = num_tbl8;
587 : :
588 : : snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp);
589 : 12 : dp->tbl8_idxes = rte_zmalloc_socket(mem_name,
590 : 6 : RTE_ALIGN_CEIL(dp->number_tbl8s, 64) >> 3,
591 : : RTE_CACHE_LINE_SIZE, socket_id);
592 [ - + ]: 6 : if (dp->tbl8_idxes == NULL) {
593 : 0 : rte_errno = ENOMEM;
594 : 0 : rte_free(dp->tbl8);
595 : 0 : rte_free(dp);
596 : 0 : return NULL;
597 : : }
598 : :
599 : : return dp;
600 : : }
601 : :
602 : : void
603 : 6 : dir24_8_free(void *p)
604 : : {
605 : : struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
606 : :
607 : 6 : rte_rcu_qsbr_dq_delete(dp->dq);
608 : 6 : rte_free(dp->tbl8_idxes);
609 : 6 : rte_free(dp->tbl8);
610 : 6 : rte_free(dp);
611 : 6 : }
612 : :
613 : : int
614 : 5 : dir24_8_rcu_qsbr_add(struct dir24_8_tbl *dp, struct rte_fib_rcu_config *cfg,
615 : : const char *name)
616 : : {
617 : 5 : struct rte_rcu_qsbr_dq_parameters params = {0};
618 : : char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
619 : :
620 [ + + ]: 5 : if (dp == NULL || cfg == NULL)
621 : : return -EINVAL;
622 : :
623 [ + + ]: 4 : if (dp->v != NULL)
624 : : return -EEXIST;
625 : :
626 [ + + ]: 3 : if (cfg->mode == RTE_FIB_QSBR_MODE_SYNC) {
627 : : /* No other things to do. */
628 [ + + ]: 2 : } else if (cfg->mode == RTE_FIB_QSBR_MODE_DQ) {
629 : : /* Init QSBR defer queue. */
630 : : snprintf(rcu_dq_name, sizeof(rcu_dq_name),
631 : : "FIB_RCU_%s", name);
632 : 1 : params.name = rcu_dq_name;
633 : 1 : params.size = cfg->dq_size;
634 [ + - ]: 1 : if (params.size == 0)
635 : 1 : params.size = RTE_FIB_RCU_DQ_RECLAIM_SZ;
636 : 1 : params.trigger_reclaim_limit = cfg->reclaim_thd;
637 : 1 : params.max_reclaim_size = cfg->reclaim_max;
638 [ + - ]: 1 : if (params.max_reclaim_size == 0)
639 : 1 : params.max_reclaim_size = RTE_FIB_RCU_DQ_RECLAIM_MAX;
640 : 1 : params.esize = sizeof(uint64_t);
641 : 1 : params.free_fn = __rcu_qsbr_free_resource;
642 : 1 : params.p = dp;
643 : 1 : params.v = cfg->v;
644 : 1 : dp->dq = rte_rcu_qsbr_dq_create(¶ms);
645 [ - + ]: 1 : if (dp->dq == NULL) {
646 : 0 : FIB_LOG(ERR, "LPM defer queue creation failed");
647 : 0 : return -rte_errno;
648 : : }
649 : : } else {
650 : : return -EINVAL;
651 : : }
652 : :
653 : 2 : dp->rcu_mode = cfg->mode;
654 : 2 : dp->v = cfg->v;
655 : :
656 : 2 : return 0;
657 : : }
|