Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vnet/fib/fib_test.h>
17 : #include <vnet/fib/ip6_fib.h>
18 : #include <vnet/fib/ip4_fib.h>
19 : #include <vnet/fib/mpls_fib.h>
20 : #include <vnet/adj/adj.h>
21 : #include <vnet/dpo/load_balance.h>
22 : #include <vnet/dpo/load_balance_map.h>
23 : #include <vnet/dpo/mpls_label_dpo.h>
24 : #include <vnet/dpo/lookup_dpo.h>
25 : #include <vnet/dpo/drop_dpo.h>
26 : #include <vnet/dpo/receive_dpo.h>
27 : #include <vnet/dpo/ip_null_dpo.h>
28 : #include <vnet/bfd/bfd_main.h>
29 : #include <vnet/dpo/interface_rx_dpo.h>
30 : #include <vnet/dpo/replicate_dpo.h>
31 : #include <vnet/dpo/dvr_dpo.h>
32 : #include <vnet/dpo/mpls_disposition.h>
33 : #include <vnet/dpo/punt_dpo.h>
34 :
35 : #include <vnet/mpls/mpls.h>
36 :
37 : #include <vnet/fib/fib_test.h>
38 : #include <vnet/fib/fib_path_list.h>
39 : #include <vnet/fib/fib_entry_src.h>
40 : #include <vnet/fib/fib_walk.h>
41 : #include <vnet/fib/fib_node_list.h>
42 : #include <vnet/fib/fib_urpf_list.h>
43 :
44 : #include <vlib/unix/plugin.h>
45 :
46 : // clang-format off
47 :
48 : /*
49 : * Add debugs for passing tests
50 : */
51 : static int fib_test_do_debug;
52 :
53 : #define FIB_TEST_I(_cond, _comment, _args...) \
54 : ({ \
55 : int _evald = (_cond); \
56 : if (!(_evald)) { \
57 : fformat(stderr, "FAIL:%d: " _comment "\n", \
58 : __LINE__, ##_args); \
59 : res = 1; \
60 : } else { \
61 : if (fib_test_do_debug) \
62 : fformat(stderr, "PASS:%d: " _comment "\n", \
63 : __LINE__, ##_args); \
64 : } \
65 : res; \
66 : })
67 : #define FIB_TEST(_cond, _comment, _args...) \
68 : { \
69 : if (FIB_TEST_I(_cond, _comment, ##_args)) { \
70 : return 1; \
71 : ASSERT(!("FAIL: " _comment)); \
72 : } \
73 : }
74 :
75 : /**
76 : * A 'i'm not fussed is this is not efficient' store of test data
77 : */
78 : typedef struct test_main_t_ {
79 : /**
80 : * HW if indicies
81 : */
82 : u32 hw_if_indicies[4];
83 : /**
84 : * HW interfaces
85 : */
86 : vnet_hw_interface_t * hw[4];
87 :
88 : } test_main_t;
89 : static test_main_t test_main;
90 :
91 : /* fake ethernet device class, distinct from "fake-ethX" */
92 9 : static u8 * format_test_interface_name (u8 * s, va_list * args)
93 : {
94 9 : u32 dev_instance = va_arg (*args, u32);
95 9 : return format (s, "test-eth%d", dev_instance);
96 : }
97 :
98 4 : static uword placeholder_interface_tx (vlib_main_t * vm,
99 : vlib_node_runtime_t * node,
100 : vlib_frame_t * frame)
101 : {
102 4 : clib_warning ("you shouldn't be here, leaking buffers...");
103 4 : return frame->n_vectors;
104 : }
105 :
106 : static clib_error_t *
107 16 : test_interface_admin_up_down (vnet_main_t * vnm,
108 : u32 hw_if_index,
109 : u32 flags)
110 : {
111 16 : u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
112 : VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
113 16 : vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
114 16 : return 0;
115 : }
116 :
117 2799 : VNET_DEVICE_CLASS (test_interface_device_class,static) = {
118 : .name = "Test interface",
119 : .format_device_name = format_test_interface_name,
120 : .tx_function = placeholder_interface_tx,
121 : .admin_up_down_function = test_interface_admin_up_down,
122 : };
123 :
124 : static u8 *hw_address;
125 :
126 : static int
127 1 : fib_test_mk_intf (u32 ninterfaces)
128 : {
129 1 : clib_error_t * error = NULL;
130 1 : test_main_t *tm = &test_main;
131 : u32 i, res;
132 : u8 byte;
133 :
134 1 : res = 0;
135 1 : ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
136 :
137 7 : for (i=0; i<6; i++)
138 : {
139 6 : byte = 0xd0+i;
140 6 : vec_add1(hw_address, byte);
141 : }
142 :
143 5 : for (i = 0; i < ninterfaces; i++)
144 : {
145 4 : vnet_eth_interface_registration_t eir = {};
146 4 : vnet_main_t *vnm = vnet_get_main();
147 :
148 4 : hw_address[5] = i;
149 :
150 4 : eir.dev_class_index = test_interface_device_class.index;
151 4 : eir.dev_instance = i;
152 4 : eir.address = hw_address;
153 4 : tm->hw_if_indicies[i] = vnet_eth_register_interface (vnm, &eir);
154 :
155 4 : error = vnet_hw_interface_set_flags(vnet_get_main(),
156 : tm->hw_if_indicies[i],
157 : VNET_HW_INTERFACE_FLAG_LINK_UP);
158 4 : tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
159 : tm->hw_if_indicies[i]);
160 :
161 4 : error = vnet_sw_interface_set_flags(vnet_get_main(),
162 4 : tm->hw[i]->sw_if_index,
163 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
164 4 : FIB_TEST((NULL == error), "UP interface %d", i);
165 : }
166 : /*
167 : * re-eval after the inevitable realloc
168 : */
169 5 : for (i = 0; i < ninterfaces; i++)
170 : {
171 4 : tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
172 : tm->hw_if_indicies[i]);
173 : }
174 :
175 1 : return (res);
176 : }
177 :
178 : #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
179 : { \
180 : const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
181 : fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
182 : const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
183 : fib_table_lookup(fib_index, (_via_prefix))); \
184 : FIB_TEST(!dpo_cmp(_via_dpo, \
185 : load_balance_get_bucket(_rec_dpo->dpoi_index, \
186 : _bucket)), \
187 : "%U is recursive via %U", \
188 : format_fib_prefix, (_rec_prefix), \
189 : format_fib_prefix, _via_prefix); \
190 : }
191 :
192 : #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
193 : { \
194 : const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
195 : fib_table_lookup_exact_match(fib_index, (_prefix))); \
196 : const dpo_id_t *_dpo1 = \
197 : load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
198 : FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
199 : format_dpo_type, _dpo1->dpoi_type); \
200 : FIB_TEST((_ai == _dpo1->dpoi_index), \
201 : "%U bucket %d resolves via %U", \
202 : format_fib_prefix, (_prefix), \
203 : _bucket, \
204 : format_dpo_id, _dpo1, 0); \
205 : }
206 :
207 : #define FIB_TEST_RPF(_cond, _comment, _args...) \
208 : { \
209 : if (FIB_TEST_I(_cond, _comment, ##_args)) { \
210 : res = 1; \
211 : goto cleanup; \
212 : } \
213 : }
214 :
215 : static int
216 14 : fib_test_urpf_is_equal (fib_node_index_t fei,
217 : fib_forward_chain_type_t fct,
218 : u32 num, ...)
219 : {
220 14 : dpo_id_t dpo = DPO_INVALID;
221 : fib_urpf_list_t *urpf;
222 : int ii, res;
223 : index_t ui;
224 : va_list ap;
225 :
226 14 : va_start(ap, num);
227 :
228 14 : res = 0;
229 14 : fib_entry_contribute_forwarding(fei, fct, &dpo);
230 14 : ui = load_balance_get_urpf(dpo.dpoi_index);
231 :
232 14 : urpf = fib_urpf_list_get(ui);
233 :
234 14 : FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
235 : "RPF:%U len %d == %d",
236 : format_fib_urpf_list, ui,
237 : num, vec_len(urpf->furpf_itfs));
238 14 : FIB_TEST_RPF(num == fib_urpf_check_size(ui),
239 : "RPF:%U check-size %d == %d",
240 : format_fib_urpf_list, ui,
241 : num, vec_len(urpf->furpf_itfs));
242 :
243 27 : for (ii = 0; ii < num; ii++)
244 : {
245 13 : adj_index_t ai = va_arg(ap, adj_index_t);
246 :
247 13 : FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
248 : "RPF:%d item:%d - %d == %d",
249 : ui, ii, ai, urpf->furpf_itfs[ii]);
250 13 : FIB_TEST_RPF(fib_urpf_check(ui, ai),
251 : "RPF:%d %d found",
252 : ui, ai);
253 : }
254 :
255 14 : dpo_reset(&dpo);
256 :
257 14 : cleanup:
258 14 : va_end(ap);
259 :
260 14 : return (res);
261 : }
262 :
263 : static u8*
264 5 : fib_test_build_rewrite (u8 *eth_addr)
265 : {
266 5 : u8* rewrite = NULL;
267 :
268 5 : vec_validate(rewrite, 13);
269 :
270 5 : memcpy(rewrite, eth_addr, 6);
271 5 : memcpy(rewrite+6, eth_addr, 6);
272 :
273 5 : return (rewrite);
274 : }
275 :
276 : #define FIB_TEST_LB(_cond, _comment, _args...) \
277 : { \
278 : if (FIB_TEST_I(_cond, _comment, ##_args)) { \
279 : return (1); \
280 : } \
281 : }
282 :
283 : int
284 5 : fib_test_validate_rep_v (const replicate_t *rep,
285 : u16 n_buckets,
286 : va_list *ap)
287 : {
288 : const fib_test_rep_bucket_t *exp;
289 : const dpo_id_t *dpo;
290 : int bucket, res;
291 :
292 5 : res = 0;
293 5 : FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
294 : "n_buckets = %d", rep->rep_n_buckets);
295 :
296 13 : for (bucket = 0; bucket < n_buckets; bucket++)
297 : {
298 8 : exp = va_arg(*ap, fib_test_rep_bucket_t*);
299 :
300 8 : dpo = replicate_get_bucket_i(rep, bucket);
301 :
302 8 : switch (exp->type)
303 : {
304 5 : case FT_REP_LABEL_O_ADJ:
305 : {
306 : const mpls_label_dpo_t *mld;
307 : mpls_label_t hdr;
308 :
309 5 : FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
310 : == dpo->dpoi_type),
311 : "bucket %d stacks on %U",
312 : bucket,
313 : format_dpo_type, dpo->dpoi_type);
314 :
315 5 : mld = mpls_label_dpo_get(dpo->dpoi_index);
316 5 : hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
317 :
318 5 : FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
319 : exp->label_o_adj.label),
320 : "bucket %d stacks on label %d",
321 : bucket,
322 : exp->label_o_adj.label);
323 :
324 5 : FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
325 : exp->label_o_adj.eos),
326 : "bucket %d stacks on label %d %U",
327 : bucket,
328 : exp->label_o_adj.label,
329 : format_mpls_eos_bit, exp->label_o_adj.eos);
330 :
331 5 : FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
332 : "bucket %d label stacks on %U",
333 : bucket,
334 : format_dpo_type, mld->mld_dpo.dpoi_type);
335 :
336 5 : FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
337 : "bucket %d label stacks on adj %d",
338 : bucket,
339 : exp->label_o_adj.adj);
340 : }
341 5 : break;
342 2 : case FT_REP_INTF:
343 2 : FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
344 : "bucket %d stacks on %U",
345 : bucket,
346 : format_dpo_type, dpo->dpoi_type);
347 :
348 2 : FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
349 : "bucket %d stacks on adj %d",
350 : bucket,
351 : exp->adj.adj);
352 2 : break;
353 1 : case FT_REP_DISP_MFIB_LOOKUP:
354 : // ASSERT(0);
355 1 : break;
356 : }
357 8 : }
358 :
359 5 : return (res);
360 : }
361 :
362 : int
363 458 : fib_test_validate_lb_v (const load_balance_t *lb,
364 : int n_buckets,
365 : va_list *ap)
366 : {
367 : const dpo_id_t *dpo;
368 : int bucket, res;
369 :
370 458 : res = 0;
371 458 : FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
372 :
373 1271 : for (bucket = 0; bucket < n_buckets; bucket++)
374 : {
375 : const fib_test_lb_bucket_t *exp;
376 :
377 813 : exp = va_arg(*ap, fib_test_lb_bucket_t*);
378 813 : dpo = load_balance_get_bucket_i(lb, bucket);
379 :
380 813 : switch (exp->type)
381 : {
382 2 : case FT_LB_LABEL_STACK_O_ADJ:
383 : {
384 : const mpls_label_dpo_t *mld;
385 : mpls_label_dpo_flags_t mf;
386 : mpls_label_t hdr;
387 : u32 ii;
388 :
389 4 : mf = ((exp->label_stack_o_adj.mode ==
390 : FIB_MPLS_LSP_MODE_UNIFORM) ?
391 2 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
392 : MPLS_LABEL_DPO_FLAG_NONE);
393 2 : FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
394 : "bucket %d stacks on %U",
395 : bucket,
396 : format_dpo_type, dpo->dpoi_type);
397 :
398 2 : mld = mpls_label_dpo_get(dpo->dpoi_index);
399 :
400 2 : FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
401 : "label stack size",
402 : mld->mld_n_labels);
403 :
404 14 : for (ii = 0; ii < mld->mld_n_labels; ii++)
405 : {
406 12 : hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
407 12 : FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
408 : exp->label_stack_o_adj.label_stack[ii]),
409 : "bucket %d stacks on label %d",
410 : bucket,
411 : exp->label_stack_o_adj.label_stack[ii]);
412 :
413 12 : if (ii == mld->mld_n_labels-1)
414 : {
415 2 : FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
416 : exp->label_o_adj.eos),
417 : "bucket %d stacks on label %d %U!=%U",
418 : bucket,
419 : exp->label_stack_o_adj.label_stack[ii],
420 : format_mpls_eos_bit, exp->label_o_adj.eos,
421 : format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
422 : }
423 : else
424 : {
425 10 : FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
426 : "bucket %d stacks on label %d %U",
427 : bucket,
428 : exp->label_stack_o_adj.label_stack[ii],
429 : format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
430 : }
431 : }
432 :
433 2 : FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
434 : "bucket %d label stacks on %U",
435 : bucket,
436 : format_dpo_type, mld->mld_dpo.dpoi_type);
437 :
438 2 : FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
439 : "bucket %d label stacks on adj %d",
440 : bucket,
441 : exp->label_stack_o_adj.adj);
442 : }
443 2 : break;
444 3 : case FT_LB_LABEL_CHAIN_O_ADJ:
445 : {
446 3 : const mpls_label_dpo_t *mld = NULL;
447 : mpls_label_dpo_flags_t mf;
448 : mpls_label_t hdr;
449 : u32 ii;
450 :
451 6 : mf = ((exp->label_chain_o_adj.mode ==
452 : FIB_MPLS_LSP_MODE_UNIFORM) ?
453 3 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
454 : MPLS_LABEL_DPO_FLAG_NONE);
455 :
456 9 : for (ii = 0; ii < exp->label_chain_o_adj.label_chain_size; ii++)
457 : {
458 6 : FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
459 : "bucket %d stacks on %U",
460 : bucket,
461 : format_dpo_type, dpo->dpoi_type);
462 6 : mld = mpls_label_dpo_get(dpo->dpoi_index);
463 :
464 6 : hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
465 6 : FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
466 : exp->label_chain_o_adj.label_chain[ii]),
467 : "bucket %d stacks on label %d",
468 : bucket,
469 : exp->label_chain_o_adj.label_chain[ii]);
470 6 : dpo = &mld->mld_dpo;
471 : }
472 :
473 3 : FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
474 : "bucket %d label stacks on %U",
475 : bucket,
476 : format_dpo_type, mld->mld_dpo.dpoi_type);
477 :
478 3 : FIB_TEST_LB((exp->label_chain_o_adj.adj == mld->mld_dpo.dpoi_index),
479 : "bucket %d label stacks on adj %d",
480 : bucket,
481 : exp->label_chain_o_adj.adj);
482 : }
483 3 : break;
484 44 : case FT_LB_LABEL_O_ADJ:
485 : {
486 : const mpls_label_dpo_t *mld;
487 : mpls_label_t hdr;
488 44 : FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
489 : == dpo->dpoi_type),
490 : "bucket %d stacks on %U",
491 : bucket,
492 : format_dpo_type, dpo->dpoi_type);
493 :
494 44 : mld = mpls_label_dpo_get(dpo->dpoi_index);
495 44 : hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
496 :
497 44 : FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
498 : exp->label_o_adj.label),
499 : "bucket %d stacks on label %d not %d",
500 : bucket,
501 : vnet_mpls_uc_get_label(hdr),
502 : exp->label_o_adj.label);
503 :
504 44 : FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
505 : exp->label_o_adj.eos),
506 : "bucket %d stacks on label %d %U",
507 : bucket,
508 : exp->label_o_adj.label,
509 : format_mpls_eos_bit, exp->label_o_adj.eos);
510 :
511 44 : FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
512 : "bucket %d label stacks on %U",
513 : bucket,
514 : format_dpo_type, mld->mld_dpo.dpoi_type);
515 :
516 44 : FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
517 : "bucket %d label stacks on adj %d",
518 : bucket,
519 : exp->label_o_adj.adj);
520 : }
521 44 : break;
522 8 : case FT_LB_LABEL_O_LB:
523 : {
524 : const mpls_label_dpo_t *mld;
525 : mpls_label_dpo_flags_t mf;
526 : mpls_label_t hdr;
527 :
528 16 : mf = ((exp->label_o_lb.mode ==
529 : FIB_MPLS_LSP_MODE_UNIFORM) ?
530 8 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
531 : MPLS_LABEL_DPO_FLAG_NONE);
532 8 : FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
533 : "bucket %d stacks on %U",
534 : bucket,
535 : format_dpo_type, dpo->dpoi_type);
536 :
537 8 : mld = mpls_label_dpo_get(dpo->dpoi_index);
538 8 : hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
539 :
540 8 : FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
541 : mld->mld_n_labels);
542 8 : FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
543 : exp->label_o_lb.label),
544 : "bucket %d stacks on label %d",
545 : bucket,
546 : exp->label_o_lb.label);
547 :
548 8 : FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
549 : exp->label_o_lb.eos),
550 : "bucket %d stacks on label %d %U",
551 : bucket,
552 : exp->label_o_lb.label,
553 : format_mpls_eos_bit, exp->label_o_lb.eos);
554 :
555 8 : FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
556 : "bucket %d label stacks on %U",
557 : bucket,
558 : format_dpo_type, mld->mld_dpo.dpoi_type);
559 :
560 8 : FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
561 : "bucket %d label stacks on LB %d",
562 : bucket,
563 : exp->label_o_lb.lb);
564 : }
565 8 : break;
566 360 : case FT_LB_ADJ:
567 360 : res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
568 : (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
569 : "bucket %d stacks on %U",
570 : bucket,
571 : format_dpo_type, dpo->dpoi_type);
572 360 : FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
573 : "bucket %d stacks on adj %d",
574 : bucket,
575 : exp->adj.adj);
576 360 : break;
577 18 : case FT_LB_MPLS_DISP_PIPE_O_ADJ:
578 : {
579 : const mpls_disp_dpo_t *mdd;
580 :
581 18 : res = FIB_TEST_I((DPO_MPLS_DISPOSITION_PIPE == dpo->dpoi_type),
582 : "bucket %d stacks on %U",
583 : bucket,
584 : format_dpo_type, dpo->dpoi_type);
585 :
586 18 : mdd = mpls_disp_dpo_get(dpo->dpoi_index);
587 :
588 18 : dpo = &mdd->mdd_dpo;
589 :
590 18 : res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
591 : (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
592 : "bucket %d stacks on %U",
593 : bucket,
594 : format_dpo_type, dpo->dpoi_type);
595 18 : FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
596 : "bucket %d stacks on adj %d",
597 : bucket,
598 : exp->adj.adj);
599 18 : break;
600 : }
601 1 : case FT_LB_INTF:
602 1 : res = FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
603 : "bucket %d stacks on %U",
604 : bucket,
605 : format_dpo_type, dpo->dpoi_type);
606 1 : FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
607 : "bucket %d stacks on adj %d",
608 : bucket,
609 : exp->adj.adj);
610 1 : break;
611 1 : case FT_LB_L2:
612 1 : res = FIB_TEST_I((DPO_DVR == dpo->dpoi_type),
613 : "bucket %d stacks on %U",
614 : bucket,
615 : format_dpo_type, dpo->dpoi_type);
616 1 : FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
617 : "bucket %d stacks on adj %d",
618 : bucket,
619 : exp->adj.adj);
620 1 : break;
621 331 : case FT_LB_O_LB:
622 331 : res = FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
623 : "bucket %d stacks on %U",
624 : bucket,
625 : format_dpo_type, dpo->dpoi_type);
626 331 : FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
627 : "bucket %d stacks on lb %d not %d",
628 : bucket,
629 : dpo->dpoi_index,
630 : exp->lb.lb);
631 331 : break;
632 32 : case FT_LB_BIER_TABLE:
633 32 : FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
634 : "bucket %d stacks on %U",
635 : bucket,
636 : format_dpo_type, dpo->dpoi_type);
637 32 : FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
638 : "bucket %d stacks on lb %d",
639 : bucket,
640 : exp->bier.table);
641 32 : break;
642 4 : case FT_LB_BIER_FMASK:
643 4 : FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
644 : "bucket %d stacks on %U",
645 : bucket,
646 : format_dpo_type, dpo->dpoi_type);
647 4 : FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
648 : "bucket %d stacks on lb %d",
649 : bucket,
650 : exp->bier.fmask);
651 4 : break;
652 9 : case FT_LB_DROP:
653 9 : FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
654 : "bucket %d stacks on %U",
655 : bucket,
656 : format_dpo_type, dpo->dpoi_type);
657 9 : break;
658 0 : case FT_LB_PUNT:
659 0 : FIB_TEST_LB((DPO_PUNT == dpo->dpoi_type),
660 : "bucket %d stacks on %U",
661 : bucket,
662 : format_dpo_type, dpo->dpoi_type);
663 0 : break;
664 : }
665 813 : }
666 458 : return (res);
667 : }
668 :
669 : int
670 2 : fib_test_validate_lb (const dpo_id_t *dpo,
671 : int n_buckets,
672 : ...)
673 : {
674 : const load_balance_t *lb;
675 : va_list ap;
676 : int res;
677 :
678 2 : res = 0;
679 2 : va_start(ap, n_buckets);
680 :
681 2 : if (!FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
682 : "Entry links to %U",
683 : format_dpo_type, dpo->dpoi_type))
684 : {
685 2 : lb = load_balance_get(dpo->dpoi_index);
686 :
687 2 : res = fib_test_validate_lb_v(lb, n_buckets, &ap);
688 : }
689 : else
690 : {
691 0 : res = 1;
692 : }
693 :
694 2 : va_end(ap);
695 :
696 2 : return (res);
697 : }
698 :
699 : int
700 459 : fib_test_validate_entry (fib_node_index_t fei,
701 : fib_forward_chain_type_t fct,
702 : int n_buckets,
703 : ...)
704 : {
705 459 : dpo_id_t dpo = DPO_INVALID;
706 : const fib_prefix_t *pfx;
707 : index_t fw_lbi;
708 : u32 fib_index;
709 : va_list ap;
710 : int res;
711 :
712 :
713 459 : res = 0;
714 459 : pfx = fib_entry_get_prefix(fei);
715 459 : fib_index = fib_entry_get_fib_index(fei);
716 459 : fib_entry_contribute_forwarding(fei, fct, &dpo);
717 :
718 459 : if (DPO_REPLICATE == dpo.dpoi_type)
719 : {
720 : const replicate_t *rep;
721 :
722 5 : va_start(ap, n_buckets);
723 5 : rep = replicate_get(dpo.dpoi_index);
724 5 : res = fib_test_validate_rep_v(rep, n_buckets, &ap);
725 5 : va_end (ap);
726 : }
727 : else
728 : {
729 : const load_balance_t *lb;
730 :
731 454 : FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
732 : "%U Entry links to %U",
733 : format_fib_prefix, pfx,
734 : format_dpo_type, dpo.dpoi_type);
735 :
736 454 : va_start(ap, n_buckets);
737 454 : lb = load_balance_get(dpo.dpoi_index);
738 454 : res = fib_test_validate_lb_v(lb, n_buckets, &ap);
739 454 : va_end(ap);
740 :
741 : /*
742 : * ensure that the LB contributed by the entry is the
743 : * same as the LB in the forwarding tables
744 : */
745 454 : if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
746 : {
747 453 : switch (pfx->fp_proto)
748 : {
749 427 : case FIB_PROTOCOL_IP4:
750 427 : fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx->fp_addr.ip4);
751 427 : break;
752 6 : case FIB_PROTOCOL_IP6:
753 6 : fw_lbi = ip6_fib_table_fwding_lookup(fib_index, &pfx->fp_addr.ip6);
754 6 : break;
755 20 : case FIB_PROTOCOL_MPLS:
756 : {
757 20 : mpls_unicast_header_t hdr = {
758 : .label_exp_s_ttl = 0,
759 : };
760 :
761 20 : vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx->fp_label);
762 20 : vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx->fp_eos);
763 20 : hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
764 :
765 20 : fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
766 20 : break;
767 : }
768 0 : default:
769 0 : fw_lbi = 0;
770 : }
771 453 : FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
772 : "Contributed LB = FW LB:\n fwd:%U\n cont:%U",
773 : format_load_balance, fw_lbi, 0,
774 : format_load_balance, dpo.dpoi_index, 0);
775 : }
776 : }
777 :
778 459 : dpo_reset(&dpo);
779 :
780 459 : return (res);
781 : }
782 :
783 : static int
784 3 : fib_test_multipath_v4 (const test_main_t *tm, const u32 fib_index,
785 : const fib_prefix_t *pfx, const int n_paths,
786 : const int expected_n_buckets)
787 : {
788 3 : const int path_list_pool_size = fib_path_list_pool_size();
789 3 : const int path_list_db_size = fib_path_list_db_size();
790 3 : const int entry_pool_size = fib_entry_pool_size();
791 3 : fib_route_path_t *r_paths = NULL;
792 : const load_balance_t *lb;
793 : const dpo_id_t *dpo;
794 : u32 fei;
795 3 : int res = 0;
796 : int i;
797 :
798 12331 : for (i = 0; i < n_paths; i++)
799 : {
800 24656 : fib_route_path_t r_path = {
801 : .frp_proto = DPO_PROTO_IP4,
802 : .frp_addr = {
803 12328 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + i),
804 : },
805 12328 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
806 : .frp_weight = 1,
807 : .frp_fib_index = ~0,
808 : .frp_flags = FIB_ROUTE_PATH_ATTACHED,
809 : };
810 12328 : vec_add1(r_paths, r_path);
811 : }
812 :
813 3 : fib_table_entry_update(fib_index,
814 : pfx,
815 : FIB_SOURCE_API,
816 : FIB_ENTRY_FLAG_NONE,
817 : r_paths);
818 :
819 3 : fei = fib_table_lookup_exact_match(fib_index, pfx);
820 3 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "prefix present");
821 3 : dpo = fib_entry_contribute_ip_forwarding(fei);
822 :
823 3 : lb = load_balance_get(dpo->dpoi_index);
824 3 : FIB_TEST((lb->lb_n_buckets == expected_n_buckets),
825 : "prefix lb over %d paths", lb->lb_n_buckets);
826 :
827 3 : fib_table_entry_delete(fib_index,
828 : pfx,
829 : FIB_SOURCE_API);
830 3 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
831 : fib_table_lookup_exact_match(fib_index, pfx), "prefix removed");
832 3 : vec_free(r_paths);
833 :
834 : /*
835 : * add-remove test. no change.
836 : */
837 3 : FIB_TEST((path_list_db_size == fib_path_list_db_size()),
838 : "path list DB population:%d", fib_path_list_db_size());
839 3 : FIB_TEST((path_list_pool_size == fib_path_list_pool_size()),
840 : "path list pool size is %d", fib_path_list_pool_size());
841 3 : FIB_TEST((entry_pool_size == fib_entry_pool_size()),
842 : "entry pool size is %d", fib_entry_pool_size());
843 3 : return res;
844 : }
845 :
846 : static int
847 1 : fib_test_v4 (void)
848 : {
849 : /*
850 : * In the default table check for the presence and correct forwarding
851 : * of the special entries
852 : */
853 : fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
854 : const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
855 : const ip_adjacency_t *adj;
856 : const load_balance_t *lb;
857 : test_main_t *tm;
858 : u32 fib_index;
859 : int lb_count;
860 : int ii, res;
861 :
862 1 : res = 0;
863 : /* via 10.10.10.1 */
864 2 : ip46_address_t nh_10_10_10_1 = {
865 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
866 : };
867 : /* via 10.10.10.2 */
868 2 : ip46_address_t nh_10_10_10_2 = {
869 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
870 : };
871 :
872 1 : FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
873 : pool_elts(load_balance_map_pool));
874 :
875 1 : tm = &test_main;
876 :
877 : /* record the nubmer of load-balances in use before we start */
878 1 : lb_count = pool_elts(load_balance_pool);
879 :
880 : /* Find or create FIB table 11 */
881 1 : fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
882 : FIB_SOURCE_API);
883 :
884 5 : for (ii = 0; ii < 4; ii++)
885 4 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[ii]->sw_if_index, fib_index);
886 :
887 1 : fib_prefix_t pfx_0_0_0_0_s_0 = {
888 : .fp_len = 0,
889 : .fp_proto = FIB_PROTOCOL_IP4,
890 : .fp_addr = {
891 : .ip4 = {
892 : {0}
893 : },
894 : },
895 : };
896 :
897 1 : fib_prefix_t pfx = {
898 : .fp_len = 0,
899 : .fp_proto = FIB_PROTOCOL_IP4,
900 : .fp_addr = {
901 : .ip4 = {
902 : {0}
903 : },
904 : },
905 : };
906 :
907 1 : dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
908 :
909 1 : dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
910 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
911 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
912 : "Default route is DROP");
913 :
914 1 : pfx.fp_len = 32;
915 1 : fei = fib_table_lookup(fib_index, &pfx);
916 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
917 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
918 : "all 0s route is DROP");
919 :
920 1 : pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
921 1 : pfx.fp_len = 32;
922 1 : fei = fib_table_lookup(fib_index, &pfx);
923 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
924 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
925 : "all 1s route is DROP");
926 :
927 1 : pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
928 1 : pfx.fp_len = 8;
929 1 : fei = fib_table_lookup(fib_index, &pfx);
930 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
931 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
932 : "all-mcast route is DROP");
933 :
934 1 : pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
935 1 : pfx.fp_len = 8;
936 1 : fei = fib_table_lookup(fib_index, &pfx);
937 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
938 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
939 : "class-e route is DROP");
940 :
941 : /*
942 : * at this stage there are 5 entries in the test FIB (plus 5 in the default),
943 : * all of which are special sourced and so none of which share path-lists.
944 : * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
945 : * table, and 4 path-lists in the v6 MFIB table and 2 in v4.
946 : */
947 : #define ENBR (5+5+2)
948 :
949 1 : u32 PNBR = 5+5+2+4+2;
950 :
951 : /*
952 : * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
953 : */
954 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
955 1 : FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
956 : fib_path_list_pool_size());
957 1 : FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
958 : fib_entry_pool_size());
959 :
960 : /*
961 : * add interface routes.
962 : * validate presence of /24 attached and /32 recieve.
963 : * test for the presence of the receive address in the glean and local adj
964 : */
965 2 : fib_prefix_t local_pfx = {
966 : .fp_len = 24,
967 : .fp_proto = FIB_PROTOCOL_IP4,
968 : .fp_addr = {
969 : .ip4 = {
970 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
971 : },
972 : },
973 : };
974 :
975 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
976 : FIB_SOURCE_INTERFACE,
977 : (FIB_ENTRY_FLAG_CONNECTED |
978 : FIB_ENTRY_FLAG_ATTACHED),
979 : DPO_PROTO_IP4,
980 : NULL,
981 1 : tm->hw[0]->sw_if_index,
982 : ~0, // invalid fib index
983 : 1, // weight
984 : NULL,
985 : FIB_ROUTE_PATH_FLAG_NONE);
986 1 : fei = fib_table_lookup(fib_index, &local_pfx);
987 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
988 1 : FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
989 : fib_entry_get_flags(fei)),
990 : "Flags set on attached interface");
991 :
992 1 : ai = fib_entry_get_adj(fei);
993 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
994 : "attached interface route adj present %d", ai);
995 1 : adj = adj_get(ai);
996 1 : FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
997 : "attached interface adj is glean");
998 :
999 1 : local_pfx.fp_len = 32;
1000 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
1001 : FIB_SOURCE_INTERFACE,
1002 : (FIB_ENTRY_FLAG_CONNECTED |
1003 : FIB_ENTRY_FLAG_LOCAL),
1004 : DPO_PROTO_IP4,
1005 : NULL,
1006 1 : tm->hw[0]->sw_if_index,
1007 : ~0, // invalid fib index
1008 : 1, // weight
1009 : NULL,
1010 : FIB_ROUTE_PATH_FLAG_NONE);
1011 1 : fei = fib_table_lookup(fib_index, &local_pfx);
1012 1 : FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
1013 : fib_entry_get_flags(fei)),
1014 : "Flags set on local interface");
1015 :
1016 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
1017 :
1018 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1019 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1020 : "RPF list for local length 0");
1021 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1022 1 : FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1023 : "local interface adj is local");
1024 1 : receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
1025 :
1026 1 : FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
1027 : &rd->rd_addr)),
1028 : "local interface adj is receive ok");
1029 :
1030 1 : FIB_TEST((2 == fib_table_get_num_entries(fib_index,
1031 : FIB_PROTOCOL_IP4,
1032 : FIB_SOURCE_INTERFACE)),
1033 : "2 Interface Source'd prefixes");
1034 1 : FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
1035 : &adj->sub_type.glean.rx_pfx.fp_addr)),
1036 : "attached interface adj is receive ok");
1037 :
1038 : /*
1039 : * +2 interface routes +2 non-shared path-lists
1040 : */
1041 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1042 1 : FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
1043 : fib_path_list_pool_size());
1044 1 : FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
1045 : fib_entry_pool_size());
1046 :
1047 : /*
1048 : * Modify the default route to be via an adj not yet known.
1049 : * this sources the defalut route with the API source, which is
1050 : * a higher preference to the DEFAULT_ROUTE source
1051 : */
1052 1 : pfx.fp_addr.ip4.as_u32 = 0;
1053 1 : pfx.fp_len = 0;
1054 1 : fib_table_entry_path_add(fib_index, &pfx,
1055 : FIB_SOURCE_API,
1056 : FIB_ENTRY_FLAG_NONE,
1057 : DPO_PROTO_IP4,
1058 : &nh_10_10_10_1,
1059 1 : tm->hw[0]->sw_if_index,
1060 : ~0, // invalid fib index
1061 : 1,
1062 : NULL,
1063 : FIB_ROUTE_PATH_FLAG_NONE);
1064 1 : fei = fib_table_lookup(fib_index, &pfx);
1065 1 : FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1066 : "Flags set on API route");
1067 :
1068 1 : FIB_TEST((fei == dfrt), "default route same index");
1069 1 : ai = fib_entry_get_adj(fei);
1070 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
1071 1 : adj = adj_get(ai);
1072 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1073 : "adj is incomplete");
1074 1 : FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
1075 : "adj nbr next-hop ok");
1076 1 : FIB_TEST((1 == fib_table_get_num_entries(fib_index,
1077 : FIB_PROTOCOL_IP4,
1078 : FIB_SOURCE_API)),
1079 : "1 API Source'd prefixes");
1080 :
1081 : /*
1082 : * find the adj in the shared db
1083 : */
1084 1 : locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1085 : VNET_LINK_IP4,
1086 : &nh_10_10_10_1,
1087 1 : tm->hw[0]->sw_if_index);
1088 1 : FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
1089 1 : adj_unlock(locked_ai);
1090 :
1091 : /*
1092 : * +1 shared path-list
1093 : */
1094 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1095 : fib_path_list_db_size());
1096 1 : FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
1097 : fib_path_list_pool_size());
1098 1 : FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
1099 : fib_entry_pool_size());
1100 :
1101 : /*
1102 : * remove the API source from the default route. We expected
1103 : * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
1104 : */
1105 1 : pfx.fp_addr.ip4.as_u32 = 0;
1106 1 : pfx.fp_len = 0;
1107 1 : fib_table_entry_path_remove(fib_index, &pfx,
1108 : FIB_SOURCE_API,
1109 : DPO_PROTO_IP4,
1110 : &nh_10_10_10_1,
1111 1 : tm->hw[0]->sw_if_index,
1112 : ~0, // non-recursive path, so no FIB index
1113 : 1,
1114 : FIB_ROUTE_PATH_FLAG_NONE);
1115 :
1116 1 : fei = fib_table_lookup(fib_index, &pfx);
1117 :
1118 1 : FIB_TEST((fei == dfrt), "default route same index");
1119 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1120 : "Default route is DROP");
1121 :
1122 : /*
1123 : * -1 shared-path-list
1124 : */
1125 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1126 1 : FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
1127 : fib_path_list_pool_size());
1128 1 : FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
1129 : fib_entry_pool_size());
1130 :
1131 : /*
1132 : * Add an 2 ARP entry => a complete ADJ plus adj-fib.
1133 : */
1134 2 : fib_prefix_t pfx_10_10_10_1_s_32 = {
1135 : .fp_len = 32,
1136 : .fp_proto = FIB_PROTOCOL_IP4,
1137 : .fp_addr = {
1138 : /* 10.10.10.1 */
1139 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1140 : },
1141 : };
1142 2 : fib_prefix_t pfx_10_10_10_2_s_32 = {
1143 : .fp_len = 32,
1144 : .fp_proto = FIB_PROTOCOL_IP4,
1145 : .fp_addr = {
1146 : /* 10.10.10.2 */
1147 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1148 : },
1149 : };
1150 2 : fib_prefix_t pfx_11_11_11_11_s_32 = {
1151 : .fp_len = 32,
1152 : .fp_proto = FIB_PROTOCOL_IP4,
1153 : .fp_addr = {
1154 : /* 11.11.11.11 */
1155 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1156 : },
1157 : };
1158 1 : u8 eth_addr[] = {
1159 : 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1160 : };
1161 :
1162 2 : ip46_address_t nh_12_12_12_12 = {
1163 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1164 : };
1165 : adj_index_t ai_12_12_12_12;
1166 :
1167 : /*
1168 : * Add a route via an incomplete ADJ. then complete the ADJ
1169 : * Expect the route LB is updated to use complete adj type.
1170 : */
1171 1 : fei = fib_table_entry_update_one_path(fib_index,
1172 : &pfx_11_11_11_11_s_32,
1173 : FIB_SOURCE_API,
1174 : FIB_ENTRY_FLAG_ATTACHED,
1175 : DPO_PROTO_IP4,
1176 : &pfx_10_10_10_1_s_32.fp_addr,
1177 1 : tm->hw[0]->sw_if_index,
1178 : ~0, // invalid fib index
1179 : 1,
1180 : NULL,
1181 : FIB_ROUTE_PATH_FLAG_NONE);
1182 :
1183 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1184 1 : dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1185 1 : FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1186 : "11.11.11.11/32 via incomplete adj");
1187 :
1188 1 : ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1189 : VNET_LINK_IP4,
1190 : &pfx_10_10_10_1_s_32.fp_addr,
1191 1 : tm->hw[0]->sw_if_index);
1192 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1193 1 : adj = adj_get(ai_01);
1194 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1195 : "adj is incomplete");
1196 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1197 : &adj->sub_type.nbr.next_hop)),
1198 : "adj nbr next-hop ok");
1199 :
1200 1 : adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1201 : fib_test_build_rewrite(eth_addr));
1202 1 : FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1203 : "adj is complete");
1204 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1205 : &adj->sub_type.nbr.next_hop)),
1206 : "adj nbr next-hop ok");
1207 1 : ai = fib_entry_get_adj(fei);
1208 1 : FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1209 :
1210 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1211 1 : dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1212 1 : FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1213 : "11.11.11.11/32 via complete adj");
1214 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1215 : tm->hw[0]->sw_if_index),
1216 : "RPF list for adj-fib contains adj");
1217 :
1218 1 : ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1219 : VNET_LINK_IP4,
1220 : &nh_12_12_12_12,
1221 1 : tm->hw[1]->sw_if_index);
1222 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1223 1 : adj = adj_get(ai_12_12_12_12);
1224 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1225 : "adj is incomplete");
1226 1 : FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1227 : &adj->sub_type.nbr.next_hop)),
1228 : "adj nbr next-hop ok");
1229 1 : adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1230 : fib_test_build_rewrite(eth_addr));
1231 1 : FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1232 : "adj is complete");
1233 :
1234 : /*
1235 : * add the adj fib
1236 : */
1237 1 : fei = fib_table_entry_path_add(fib_index,
1238 : &pfx_10_10_10_1_s_32,
1239 : FIB_SOURCE_ADJ,
1240 : FIB_ENTRY_FLAG_ATTACHED,
1241 : DPO_PROTO_IP4,
1242 : &pfx_10_10_10_1_s_32.fp_addr,
1243 1 : tm->hw[0]->sw_if_index,
1244 : ~0, // invalid fib index
1245 : 1,
1246 : NULL,
1247 : FIB_ROUTE_PATH_FLAG_NONE);
1248 1 : FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1249 : "Flags set on adj-fib");
1250 1 : ai = fib_entry_get_adj(fei);
1251 1 : FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1252 :
1253 1 : fib_table_entry_path_remove(fib_index,
1254 : &pfx_11_11_11_11_s_32,
1255 : FIB_SOURCE_API,
1256 : DPO_PROTO_IP4,
1257 : &pfx_10_10_10_1_s_32.fp_addr,
1258 1 : tm->hw[0]->sw_if_index,
1259 : ~0, // invalid fib index
1260 : 1,
1261 : FIB_ROUTE_PATH_FLAG_NONE);
1262 :
1263 1 : eth_addr[5] = 0xb2;
1264 :
1265 1 : ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1266 : VNET_LINK_IP4,
1267 : &pfx_10_10_10_2_s_32.fp_addr,
1268 1 : tm->hw[0]->sw_if_index);
1269 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1270 1 : adj = adj_get(ai_02);
1271 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1272 : "adj is incomplete");
1273 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1274 : &adj->sub_type.nbr.next_hop)),
1275 : "adj nbr next-hop ok");
1276 :
1277 1 : adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1278 : fib_test_build_rewrite(eth_addr));
1279 1 : FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1280 : "adj is complete");
1281 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1282 : &adj->sub_type.nbr.next_hop)),
1283 : "adj nbr next-hop ok");
1284 1 : FIB_TEST((ai_01 != ai_02), "ADJs are different");
1285 :
1286 1 : fib_table_entry_path_add(fib_index,
1287 : &pfx_10_10_10_2_s_32,
1288 : FIB_SOURCE_ADJ,
1289 : FIB_ENTRY_FLAG_ATTACHED,
1290 : DPO_PROTO_IP4,
1291 : &pfx_10_10_10_2_s_32.fp_addr,
1292 1 : tm->hw[0]->sw_if_index,
1293 : ~0, // invalid fib index
1294 : 1,
1295 : NULL,
1296 : FIB_ROUTE_PATH_FLAG_NONE);
1297 :
1298 1 : fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1299 1 : ai = fib_entry_get_adj(fei);
1300 1 : FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1301 :
1302 : /*
1303 : * +2 adj-fibs, and their non-shared path-lists
1304 : */
1305 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1306 1 : FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1307 : fib_path_list_pool_size());
1308 1 : FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1309 : fib_entry_pool_size());
1310 :
1311 : /*
1312 : * Add 2 routes via the first ADJ. ensure path-list sharing
1313 : */
1314 2 : fib_prefix_t pfx_1_1_1_1_s_32 = {
1315 : .fp_len = 32,
1316 : .fp_proto = FIB_PROTOCOL_IP4,
1317 : .fp_addr = {
1318 : /* 1.1.1.1/32 */
1319 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1320 : },
1321 : };
1322 :
1323 1 : fib_table_entry_path_add(fib_index,
1324 : &pfx_1_1_1_1_s_32,
1325 : FIB_SOURCE_API,
1326 : FIB_ENTRY_FLAG_NONE,
1327 : DPO_PROTO_IP4,
1328 : &nh_10_10_10_1,
1329 1 : tm->hw[0]->sw_if_index,
1330 : ~0, // invalid fib index
1331 : 1,
1332 : NULL,
1333 : FIB_ROUTE_PATH_FLAG_NONE);
1334 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1335 1 : ai = fib_entry_get_adj(fei);
1336 1 : FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1337 :
1338 : /*
1339 : * +1 entry and a shared path-list
1340 : */
1341 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1342 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1343 : fib_path_list_pool_size());
1344 1 : FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1345 : fib_entry_pool_size());
1346 :
1347 : /* 1.1.2.0/24 */
1348 2 : fib_prefix_t pfx_1_1_2_0_s_24 = {
1349 : .fp_len = 24,
1350 : .fp_proto = FIB_PROTOCOL_IP4,
1351 : .fp_addr = {
1352 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1353 : }
1354 : };
1355 :
1356 1 : fib_table_entry_path_add(fib_index,
1357 : &pfx_1_1_2_0_s_24,
1358 : FIB_SOURCE_API,
1359 : FIB_ENTRY_FLAG_NONE,
1360 : DPO_PROTO_IP4,
1361 : &nh_10_10_10_1,
1362 1 : tm->hw[0]->sw_if_index,
1363 : ~0, // invalid fib index
1364 : 1,
1365 : NULL,
1366 : FIB_ROUTE_PATH_FLAG_NONE);
1367 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1368 1 : ai = fib_entry_get_adj(fei);
1369 1 : FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1370 :
1371 : /*
1372 : * +1 entry only
1373 : */
1374 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1375 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1376 : fib_path_list_pool_size());
1377 1 : FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1378 : fib_entry_pool_size());
1379 :
1380 : /*
1381 : * modify 1.1.2.0/24 to use multipath.
1382 : */
1383 1 : fib_table_entry_path_add(fib_index,
1384 : &pfx_1_1_2_0_s_24,
1385 : FIB_SOURCE_API,
1386 : FIB_ENTRY_FLAG_NONE,
1387 : DPO_PROTO_IP4,
1388 : &nh_10_10_10_2,
1389 1 : tm->hw[0]->sw_if_index,
1390 : ~0, // invalid fib index
1391 : 1,
1392 : NULL,
1393 : FIB_ROUTE_PATH_FLAG_NONE);
1394 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1395 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1396 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1397 : 1, tm->hw[0]->sw_if_index),
1398 : "RPF list for 1.1.2.0/24 contains both adjs");
1399 :
1400 1 : dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1401 1 : FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1402 1 : FIB_TEST((ai_01 == dpo1->dpoi_index),
1403 : "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1404 : ai_01, dpo1->dpoi_index);
1405 :
1406 1 : dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1407 1 : FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1408 1 : FIB_TEST((ai_02 == dpo1->dpoi_index),
1409 : "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1410 :
1411 : /*
1412 : * +1 shared-pathlist
1413 : */
1414 1 : FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1415 1 : FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1416 : fib_path_list_pool_size());
1417 1 : FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1418 : fib_entry_pool_size());
1419 :
1420 : /*
1421 : * revert the modify
1422 : */
1423 1 : fib_table_entry_path_remove(fib_index,
1424 : &pfx_1_1_2_0_s_24,
1425 : FIB_SOURCE_API,
1426 : DPO_PROTO_IP4,
1427 : &nh_10_10_10_2,
1428 1 : tm->hw[0]->sw_if_index,
1429 : ~0,
1430 : 1,
1431 : FIB_ROUTE_PATH_FLAG_NONE);
1432 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1433 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1434 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1435 : 1, tm->hw[0]->sw_if_index),
1436 : "RPF list for 1.1.2.0/24 contains one adj");
1437 :
1438 1 : ai = fib_entry_get_adj(fei);
1439 1 : FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1440 :
1441 : /*
1442 : * +1 shared-pathlist
1443 : */
1444 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1445 : fib_path_list_db_size());
1446 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1447 : fib_path_list_pool_size());
1448 1 : FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1449 : fib_entry_pool_size());
1450 :
1451 : /*
1452 : * Add 2 recursive routes:
1453 : * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1454 : * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1455 : */
1456 2 : fib_prefix_t bgp_100_pfx = {
1457 : .fp_len = 32,
1458 : .fp_proto = FIB_PROTOCOL_IP4,
1459 : .fp_addr = {
1460 : /* 100.100.100.100/32 */
1461 1 : .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1462 : },
1463 : };
1464 : /* via 1.1.1.1 */
1465 2 : ip46_address_t nh_1_1_1_1 = {
1466 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1467 : };
1468 :
1469 1 : fei = fib_table_entry_path_add(fib_index,
1470 : &bgp_100_pfx,
1471 : FIB_SOURCE_API,
1472 : FIB_ENTRY_FLAG_NONE,
1473 : DPO_PROTO_IP4,
1474 : &nh_1_1_1_1,
1475 : ~0, // no index provided.
1476 : fib_index, // nexthop in same fib as route
1477 : 1,
1478 : NULL,
1479 : FIB_ROUTE_PATH_FLAG_NONE);
1480 :
1481 1 : FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1482 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1483 : tm->hw[0]->sw_if_index),
1484 : "RPF list for adj-fib contains adj");
1485 :
1486 : /*
1487 : * +1 entry and +1 shared-path-list
1488 : */
1489 1 : FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1490 : fib_path_list_db_size());
1491 1 : FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1492 : fib_path_list_pool_size());
1493 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1494 : fib_entry_pool_size());
1495 :
1496 2 : fib_prefix_t bgp_101_pfx = {
1497 : .fp_len = 32,
1498 : .fp_proto = FIB_PROTOCOL_IP4,
1499 : .fp_addr = {
1500 : /* 100.100.100.101/32 */
1501 1 : .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1502 : },
1503 : };
1504 :
1505 1 : fib_table_entry_path_add(fib_index,
1506 : &bgp_101_pfx,
1507 : FIB_SOURCE_API,
1508 : FIB_ENTRY_FLAG_NONE,
1509 : DPO_PROTO_IP4,
1510 : &nh_1_1_1_1,
1511 : ~0, // no index provided.
1512 : fib_index, // nexthop in same fib as route
1513 : 1,
1514 : NULL,
1515 : FIB_ROUTE_PATH_FLAG_NONE);
1516 :
1517 1 : FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1518 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1519 : tm->hw[0]->sw_if_index),
1520 : "RPF list for adj-fib contains adj");
1521 :
1522 : /*
1523 : * +1 entry, but the recursive path-list is shared.
1524 : */
1525 1 : FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1526 : fib_path_list_db_size());
1527 1 : FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1528 : fib_path_list_pool_size());
1529 1 : FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1530 : fib_entry_pool_size());
1531 :
1532 : /*
1533 : * An special route; one where the user (me) provides the
1534 : * adjacency through which the route will resovle by setting the flags
1535 : */
1536 2 : fib_prefix_t ex_pfx = {
1537 : .fp_len = 32,
1538 : .fp_proto = FIB_PROTOCOL_IP4,
1539 : .fp_addr = {
1540 : /* 4.4.4.4/32 */
1541 1 : .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1542 : },
1543 : };
1544 :
1545 1 : fib_table_entry_special_add(fib_index,
1546 : &ex_pfx,
1547 : FIB_SOURCE_SPECIAL,
1548 : FIB_ENTRY_FLAG_LOCAL);
1549 1 : fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1550 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1551 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1552 1 : FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1553 : "local interface adj is local");
1554 :
1555 1 : fib_table_entry_special_remove(fib_index,
1556 : &ex_pfx,
1557 : FIB_SOURCE_SPECIAL);
1558 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
1559 : fib_table_lookup_exact_match(fib_index, &ex_pfx),
1560 : "Exclusive reoute removed");
1561 :
1562 : /*
1563 : * An EXCLUSIVE route; one where the user (me) provides the exclusive
1564 : * adjacency through which the route will resovle
1565 : */
1566 1 : dpo_id_t ex_dpo = DPO_INVALID;
1567 :
1568 1 : lookup_dpo_add_or_lock_w_fib_index(fib_index,
1569 : DPO_PROTO_IP4,
1570 : LOOKUP_UNICAST,
1571 : LOOKUP_INPUT_DST_ADDR,
1572 : LOOKUP_TABLE_FROM_CONFIG,
1573 : &ex_dpo);
1574 :
1575 1 : fib_table_entry_special_dpo_add(fib_index,
1576 : &ex_pfx,
1577 : FIB_SOURCE_SPECIAL,
1578 : FIB_ENTRY_FLAG_EXCLUSIVE,
1579 : &ex_dpo);
1580 1 : fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1581 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1582 1 : FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1583 : "exclusive remote uses lookup DPO");
1584 :
1585 : /*
1586 : * update the exclusive to use a different DPO
1587 : */
1588 1 : ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1589 : IP_NULL_ACTION_SEND_ICMP_UNREACH,
1590 : &ex_dpo);
1591 1 : fib_table_entry_special_dpo_update(fib_index,
1592 : &ex_pfx,
1593 : FIB_SOURCE_SPECIAL,
1594 : FIB_ENTRY_FLAG_EXCLUSIVE,
1595 : &ex_dpo);
1596 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1597 1 : FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1598 : "exclusive remote uses now uses NULL DPO");
1599 :
1600 1 : fib_table_entry_special_remove(fib_index,
1601 : &ex_pfx,
1602 : FIB_SOURCE_SPECIAL);
1603 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
1604 : fib_table_lookup_exact_match(fib_index, &ex_pfx),
1605 : "Exclusive reoute removed");
1606 1 : dpo_reset(&ex_dpo);
1607 :
1608 : /*
1609 : * Add a recursive route:
1610 : * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1611 : */
1612 2 : fib_prefix_t bgp_200_pfx = {
1613 : .fp_len = 32,
1614 : .fp_proto = FIB_PROTOCOL_IP4,
1615 : .fp_addr = {
1616 : /* 200.200.200.200/32 */
1617 1 : .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1618 : },
1619 : };
1620 : /* via 1.1.1.2 */
1621 2 : fib_prefix_t pfx_1_1_1_2_s_32 = {
1622 : .fp_len = 32,
1623 : .fp_proto = FIB_PROTOCOL_IP4,
1624 : .fp_addr = {
1625 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1626 : },
1627 : };
1628 :
1629 1 : fei = fib_table_entry_path_add(fib_index,
1630 : &bgp_200_pfx,
1631 : FIB_SOURCE_API,
1632 : FIB_ENTRY_FLAG_NONE,
1633 : DPO_PROTO_IP4,
1634 : &pfx_1_1_1_2_s_32.fp_addr,
1635 : ~0, // no index provided.
1636 : fib_index, // nexthop in same fib as route
1637 : 1,
1638 : NULL,
1639 : FIB_ROUTE_PATH_FLAG_NONE);
1640 :
1641 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1642 : "Recursive via unresolved is drop");
1643 :
1644 : /*
1645 : * the adj should be recursive via drop, since the route resolves via
1646 : * the default route, which is itself a DROP
1647 : */
1648 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1649 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
1650 1 : FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1651 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1652 : "RPF list for 1.1.1.2/32 contains 0 adjs");
1653 :
1654 : /*
1655 : * +2 entry and +1 shared-path-list
1656 : */
1657 1 : FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1658 : fib_path_list_db_size());
1659 1 : FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1660 : fib_path_list_pool_size());
1661 1 : FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1662 : fib_entry_pool_size());
1663 :
1664 : /*
1665 : * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1666 : * The paths are sort by NH first. in this case the the path with greater
1667 : * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1668 : */
1669 2 : fib_prefix_t pfx_1_2_3_4_s_32 = {
1670 : .fp_len = 32,
1671 : .fp_proto = FIB_PROTOCOL_IP4,
1672 : .fp_addr = {
1673 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1674 : },
1675 : };
1676 1 : fib_table_entry_path_add(fib_index,
1677 : &pfx_1_2_3_4_s_32,
1678 : FIB_SOURCE_API,
1679 : FIB_ENTRY_FLAG_NONE,
1680 : DPO_PROTO_IP4,
1681 : &nh_10_10_10_1,
1682 1 : tm->hw[0]->sw_if_index,
1683 : ~0,
1684 : 1,
1685 : NULL,
1686 : FIB_ROUTE_PATH_FLAG_NONE);
1687 1 : fei = fib_table_entry_path_add(fib_index,
1688 : &pfx_1_2_3_4_s_32,
1689 : FIB_SOURCE_API,
1690 : FIB_ENTRY_FLAG_NONE,
1691 : DPO_PROTO_IP4,
1692 : &nh_12_12_12_12,
1693 1 : tm->hw[1]->sw_if_index,
1694 : ~0,
1695 : 3,
1696 : NULL,
1697 : FIB_ROUTE_PATH_FLAG_NONE);
1698 :
1699 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1700 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1701 1 : lb = load_balance_get(dpo->dpoi_index);
1702 1 : FIB_TEST((lb->lb_n_buckets == 4),
1703 : "1.2.3.4/32 LB has %d bucket",
1704 : lb->lb_n_buckets);
1705 :
1706 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1707 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1708 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1709 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1710 :
1711 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1712 : tm->hw[0]->sw_if_index,
1713 : tm->hw[1]->sw_if_index),
1714 : "RPF list for 1.2.3.4/32 contains both adjs");
1715 :
1716 :
1717 : /*
1718 : * Unequal Cost load-balance. 4:1 ratio.
1719 : * fits in a 16 bucket LB with ratio 13:3
1720 : */
1721 2 : fib_prefix_t pfx_1_2_3_5_s_32 = {
1722 : .fp_len = 32,
1723 : .fp_proto = FIB_PROTOCOL_IP4,
1724 : .fp_addr = {
1725 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1726 : },
1727 : };
1728 1 : fib_table_entry_path_add(fib_index,
1729 : &pfx_1_2_3_5_s_32,
1730 : FIB_SOURCE_API,
1731 : FIB_ENTRY_FLAG_NONE,
1732 : DPO_PROTO_IP4,
1733 : &nh_12_12_12_12,
1734 1 : tm->hw[1]->sw_if_index,
1735 : ~0,
1736 : 1,
1737 : NULL,
1738 : FIB_ROUTE_PATH_FLAG_NONE);
1739 1 : fei = fib_table_entry_path_add(fib_index,
1740 : &pfx_1_2_3_5_s_32,
1741 : FIB_SOURCE_API,
1742 : FIB_ENTRY_FLAG_NONE,
1743 : DPO_PROTO_IP4,
1744 : &nh_10_10_10_1,
1745 1 : tm->hw[0]->sw_if_index,
1746 : ~0,
1747 : 4,
1748 : NULL,
1749 : FIB_ROUTE_PATH_FLAG_NONE);
1750 :
1751 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1752 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
1753 1 : lb = load_balance_get(dpo->dpoi_index);
1754 1 : FIB_TEST((lb->lb_n_buckets == 16),
1755 : "1.2.3.5/32 LB has %d bucket",
1756 : lb->lb_n_buckets);
1757 :
1758 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1759 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1760 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1761 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1762 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1763 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1764 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1765 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1766 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1767 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1768 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1769 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1770 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1771 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1772 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1773 1 : FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1774 :
1775 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1776 : tm->hw[0]->sw_if_index,
1777 : tm->hw[1]->sw_if_index),
1778 : "RPF list for 1.2.3.4/32 contains both adjs");
1779 :
1780 : /*
1781 : * Test UCMP with a large weight skew - this produces load-balance objects with large
1782 : * numbers of buckets to accommodate the skew. By updating said load-balances we are
1783 : * laso testing the LB in placce modify code when number of buckets is large.
1784 : */
1785 2 : fib_prefix_t pfx_6_6_6_6_s_32 = {
1786 : .fp_len = 32,
1787 : .fp_proto = FIB_PROTOCOL_IP4,
1788 : .fp_addr = {
1789 : /* 1.1.1.1/32 */
1790 1 : .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1791 : },
1792 : };
1793 1 : fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1794 : .type = FT_LB_ADJ,
1795 : .adj = {
1796 : .adj = ai_01,
1797 : },
1798 : };
1799 1 : fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1800 : .type = FT_LB_ADJ,
1801 : .adj = {
1802 : .adj = ai_02,
1803 : },
1804 : };
1805 1 : fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1806 : .type = FT_LB_ADJ,
1807 : .adj = {
1808 : .adj = ai_12_12_12_12,
1809 : },
1810 : };
1811 1 : fib_table_entry_update_one_path(fib_index,
1812 : &pfx_6_6_6_6_s_32,
1813 : FIB_SOURCE_API,
1814 : FIB_ENTRY_FLAG_NONE,
1815 : DPO_PROTO_IP4,
1816 : &nh_10_10_10_1,
1817 1 : tm->hw[0]->sw_if_index,
1818 : ~0, // invalid fib index
1819 : 0, // zero weigth
1820 : NULL,
1821 : FIB_ROUTE_PATH_FLAG_NONE);
1822 :
1823 1 : fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1824 1 : FIB_TEST(!fib_test_validate_entry(fei,
1825 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1826 : 1,
1827 : &ip_o_10_10_10_1),
1828 : "6.6.6.6/32 via 10.10.10.1");
1829 :
1830 1 : fib_table_entry_path_add(fib_index,
1831 : &pfx_6_6_6_6_s_32,
1832 : FIB_SOURCE_API,
1833 : FIB_ENTRY_FLAG_NONE,
1834 : DPO_PROTO_IP4,
1835 : &nh_10_10_10_2,
1836 1 : tm->hw[0]->sw_if_index,
1837 : ~0, // invalid fib index
1838 : 100,
1839 : NULL,
1840 : FIB_ROUTE_PATH_FLAG_NONE);
1841 :
1842 1 : fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1843 1 : FIB_TEST(!fib_test_validate_entry(fei,
1844 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1845 : 64,
1846 : &ip_o_10_10_10_2,
1847 : &ip_o_10_10_10_2,
1848 : &ip_o_10_10_10_2,
1849 : &ip_o_10_10_10_2,
1850 : &ip_o_10_10_10_2,
1851 : &ip_o_10_10_10_2,
1852 : &ip_o_10_10_10_2,
1853 : &ip_o_10_10_10_2,
1854 : &ip_o_10_10_10_2,
1855 : &ip_o_10_10_10_2,
1856 : &ip_o_10_10_10_2,
1857 : &ip_o_10_10_10_2,
1858 : &ip_o_10_10_10_2,
1859 : &ip_o_10_10_10_2,
1860 : &ip_o_10_10_10_2,
1861 : &ip_o_10_10_10_2,
1862 : &ip_o_10_10_10_2,
1863 : &ip_o_10_10_10_2,
1864 : &ip_o_10_10_10_2,
1865 : &ip_o_10_10_10_2,
1866 : &ip_o_10_10_10_2,
1867 : &ip_o_10_10_10_2,
1868 : &ip_o_10_10_10_2,
1869 : &ip_o_10_10_10_2,
1870 : &ip_o_10_10_10_2,
1871 : &ip_o_10_10_10_2,
1872 : &ip_o_10_10_10_2,
1873 : &ip_o_10_10_10_2,
1874 : &ip_o_10_10_10_2,
1875 : &ip_o_10_10_10_2,
1876 : &ip_o_10_10_10_2,
1877 : &ip_o_10_10_10_2,
1878 : &ip_o_10_10_10_2,
1879 : &ip_o_10_10_10_2,
1880 : &ip_o_10_10_10_2,
1881 : &ip_o_10_10_10_2,
1882 : &ip_o_10_10_10_2,
1883 : &ip_o_10_10_10_2,
1884 : &ip_o_10_10_10_2,
1885 : &ip_o_10_10_10_2,
1886 : &ip_o_10_10_10_2,
1887 : &ip_o_10_10_10_2,
1888 : &ip_o_10_10_10_2,
1889 : &ip_o_10_10_10_2,
1890 : &ip_o_10_10_10_2,
1891 : &ip_o_10_10_10_2,
1892 : &ip_o_10_10_10_2,
1893 : &ip_o_10_10_10_2,
1894 : &ip_o_10_10_10_2,
1895 : &ip_o_10_10_10_2,
1896 : &ip_o_10_10_10_2,
1897 : &ip_o_10_10_10_2,
1898 : &ip_o_10_10_10_2,
1899 : &ip_o_10_10_10_2,
1900 : &ip_o_10_10_10_2,
1901 : &ip_o_10_10_10_2,
1902 : &ip_o_10_10_10_2,
1903 : &ip_o_10_10_10_2,
1904 : &ip_o_10_10_10_2,
1905 : &ip_o_10_10_10_2,
1906 : &ip_o_10_10_10_2,
1907 : &ip_o_10_10_10_2,
1908 : &ip_o_10_10_10_2,
1909 : &ip_o_10_10_10_1),
1910 : "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1911 :
1912 1 : fib_table_entry_path_add(fib_index,
1913 : &pfx_6_6_6_6_s_32,
1914 : FIB_SOURCE_API,
1915 : FIB_ENTRY_FLAG_NONE,
1916 : DPO_PROTO_IP4,
1917 : &nh_12_12_12_12,
1918 1 : tm->hw[1]->sw_if_index,
1919 : ~0, // invalid fib index
1920 : 100,
1921 : NULL,
1922 : FIB_ROUTE_PATH_FLAG_NONE);
1923 :
1924 1 : fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1925 1 : FIB_TEST(!fib_test_validate_entry(fei,
1926 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1927 : 128,
1928 : &ip_o_10_10_10_1,
1929 : &ip_o_10_10_10_2,
1930 : &ip_o_10_10_10_2,
1931 : &ip_o_10_10_10_2,
1932 : &ip_o_10_10_10_2,
1933 : &ip_o_10_10_10_2,
1934 : &ip_o_10_10_10_2,
1935 : &ip_o_10_10_10_2,
1936 : &ip_o_10_10_10_2,
1937 : &ip_o_10_10_10_2,
1938 : &ip_o_10_10_10_2,
1939 : &ip_o_10_10_10_2,
1940 : &ip_o_10_10_10_2,
1941 : &ip_o_10_10_10_2,
1942 : &ip_o_10_10_10_2,
1943 : &ip_o_10_10_10_2,
1944 : &ip_o_10_10_10_2,
1945 : &ip_o_10_10_10_2,
1946 : &ip_o_10_10_10_2,
1947 : &ip_o_10_10_10_2,
1948 : &ip_o_10_10_10_2,
1949 : &ip_o_10_10_10_2,
1950 : &ip_o_10_10_10_2,
1951 : &ip_o_10_10_10_2,
1952 : &ip_o_10_10_10_2,
1953 : &ip_o_10_10_10_2,
1954 : &ip_o_10_10_10_2,
1955 : &ip_o_10_10_10_2,
1956 : &ip_o_10_10_10_2,
1957 : &ip_o_10_10_10_2,
1958 : &ip_o_10_10_10_2,
1959 : &ip_o_10_10_10_2,
1960 : &ip_o_10_10_10_2,
1961 : &ip_o_10_10_10_2,
1962 : &ip_o_10_10_10_2,
1963 : &ip_o_10_10_10_2,
1964 : &ip_o_10_10_10_2,
1965 : &ip_o_10_10_10_2,
1966 : &ip_o_10_10_10_2,
1967 : &ip_o_10_10_10_2,
1968 : &ip_o_10_10_10_2,
1969 : &ip_o_10_10_10_2,
1970 : &ip_o_10_10_10_2,
1971 : &ip_o_10_10_10_2,
1972 : &ip_o_10_10_10_2,
1973 : &ip_o_10_10_10_2,
1974 : &ip_o_10_10_10_2,
1975 : &ip_o_10_10_10_2,
1976 : &ip_o_10_10_10_2,
1977 : &ip_o_10_10_10_2,
1978 : &ip_o_10_10_10_2,
1979 : &ip_o_10_10_10_2,
1980 : &ip_o_10_10_10_2,
1981 : &ip_o_10_10_10_2,
1982 : &ip_o_10_10_10_2,
1983 : &ip_o_10_10_10_2,
1984 : &ip_o_10_10_10_2,
1985 : &ip_o_10_10_10_2,
1986 : &ip_o_10_10_10_2,
1987 : &ip_o_10_10_10_2,
1988 : &ip_o_10_10_10_2,
1989 : &ip_o_10_10_10_2,
1990 : &ip_o_10_10_10_2,
1991 : &ip_o_10_10_10_2,
1992 : &ip_o_10_10_10_2,
1993 : &ip_6_6_6_6_o_12_12_12_12,
1994 : &ip_6_6_6_6_o_12_12_12_12,
1995 : &ip_6_6_6_6_o_12_12_12_12,
1996 : &ip_6_6_6_6_o_12_12_12_12,
1997 : &ip_6_6_6_6_o_12_12_12_12,
1998 : &ip_6_6_6_6_o_12_12_12_12,
1999 : &ip_6_6_6_6_o_12_12_12_12,
2000 : &ip_6_6_6_6_o_12_12_12_12,
2001 : &ip_6_6_6_6_o_12_12_12_12,
2002 : &ip_6_6_6_6_o_12_12_12_12,
2003 : &ip_6_6_6_6_o_12_12_12_12,
2004 : &ip_6_6_6_6_o_12_12_12_12,
2005 : &ip_6_6_6_6_o_12_12_12_12,
2006 : &ip_6_6_6_6_o_12_12_12_12,
2007 : &ip_6_6_6_6_o_12_12_12_12,
2008 : &ip_6_6_6_6_o_12_12_12_12,
2009 : &ip_6_6_6_6_o_12_12_12_12,
2010 : &ip_6_6_6_6_o_12_12_12_12,
2011 : &ip_6_6_6_6_o_12_12_12_12,
2012 : &ip_6_6_6_6_o_12_12_12_12,
2013 : &ip_6_6_6_6_o_12_12_12_12,
2014 : &ip_6_6_6_6_o_12_12_12_12,
2015 : &ip_6_6_6_6_o_12_12_12_12,
2016 : &ip_6_6_6_6_o_12_12_12_12,
2017 : &ip_6_6_6_6_o_12_12_12_12,
2018 : &ip_6_6_6_6_o_12_12_12_12,
2019 : &ip_6_6_6_6_o_12_12_12_12,
2020 : &ip_6_6_6_6_o_12_12_12_12,
2021 : &ip_6_6_6_6_o_12_12_12_12,
2022 : &ip_6_6_6_6_o_12_12_12_12,
2023 : &ip_6_6_6_6_o_12_12_12_12,
2024 : &ip_6_6_6_6_o_12_12_12_12,
2025 : &ip_6_6_6_6_o_12_12_12_12,
2026 : &ip_6_6_6_6_o_12_12_12_12,
2027 : &ip_6_6_6_6_o_12_12_12_12,
2028 : &ip_6_6_6_6_o_12_12_12_12,
2029 : &ip_6_6_6_6_o_12_12_12_12,
2030 : &ip_6_6_6_6_o_12_12_12_12,
2031 : &ip_6_6_6_6_o_12_12_12_12,
2032 : &ip_6_6_6_6_o_12_12_12_12,
2033 : &ip_6_6_6_6_o_12_12_12_12,
2034 : &ip_6_6_6_6_o_12_12_12_12,
2035 : &ip_6_6_6_6_o_12_12_12_12,
2036 : &ip_6_6_6_6_o_12_12_12_12,
2037 : &ip_6_6_6_6_o_12_12_12_12,
2038 : &ip_6_6_6_6_o_12_12_12_12,
2039 : &ip_6_6_6_6_o_12_12_12_12,
2040 : &ip_6_6_6_6_o_12_12_12_12,
2041 : &ip_6_6_6_6_o_12_12_12_12,
2042 : &ip_6_6_6_6_o_12_12_12_12,
2043 : &ip_6_6_6_6_o_12_12_12_12,
2044 : &ip_6_6_6_6_o_12_12_12_12,
2045 : &ip_6_6_6_6_o_12_12_12_12,
2046 : &ip_6_6_6_6_o_12_12_12_12,
2047 : &ip_6_6_6_6_o_12_12_12_12,
2048 : &ip_6_6_6_6_o_12_12_12_12,
2049 : &ip_6_6_6_6_o_12_12_12_12,
2050 : &ip_6_6_6_6_o_12_12_12_12,
2051 : &ip_6_6_6_6_o_12_12_12_12,
2052 : &ip_6_6_6_6_o_12_12_12_12,
2053 : &ip_6_6_6_6_o_12_12_12_12,
2054 : &ip_6_6_6_6_o_12_12_12_12,
2055 : &ip_6_6_6_6_o_12_12_12_12),
2056 : "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
2057 :
2058 1 : fib_table_entry_path_remove(fib_index,
2059 : &pfx_6_6_6_6_s_32,
2060 : FIB_SOURCE_API,
2061 : DPO_PROTO_IP4,
2062 : &nh_12_12_12_12,
2063 1 : tm->hw[1]->sw_if_index,
2064 : ~0, // invalid fib index
2065 : 100,
2066 : FIB_ROUTE_PATH_FLAG_NONE);
2067 :
2068 1 : fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2069 1 : FIB_TEST(!fib_test_validate_entry(fei,
2070 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2071 : 64,
2072 : &ip_o_10_10_10_2,
2073 : &ip_o_10_10_10_2,
2074 : &ip_o_10_10_10_2,
2075 : &ip_o_10_10_10_2,
2076 : &ip_o_10_10_10_2,
2077 : &ip_o_10_10_10_2,
2078 : &ip_o_10_10_10_2,
2079 : &ip_o_10_10_10_2,
2080 : &ip_o_10_10_10_2,
2081 : &ip_o_10_10_10_2,
2082 : &ip_o_10_10_10_2,
2083 : &ip_o_10_10_10_2,
2084 : &ip_o_10_10_10_2,
2085 : &ip_o_10_10_10_2,
2086 : &ip_o_10_10_10_2,
2087 : &ip_o_10_10_10_2,
2088 : &ip_o_10_10_10_2,
2089 : &ip_o_10_10_10_2,
2090 : &ip_o_10_10_10_2,
2091 : &ip_o_10_10_10_2,
2092 : &ip_o_10_10_10_2,
2093 : &ip_o_10_10_10_2,
2094 : &ip_o_10_10_10_2,
2095 : &ip_o_10_10_10_2,
2096 : &ip_o_10_10_10_2,
2097 : &ip_o_10_10_10_2,
2098 : &ip_o_10_10_10_2,
2099 : &ip_o_10_10_10_2,
2100 : &ip_o_10_10_10_2,
2101 : &ip_o_10_10_10_2,
2102 : &ip_o_10_10_10_2,
2103 : &ip_o_10_10_10_2,
2104 : &ip_o_10_10_10_2,
2105 : &ip_o_10_10_10_2,
2106 : &ip_o_10_10_10_2,
2107 : &ip_o_10_10_10_2,
2108 : &ip_o_10_10_10_2,
2109 : &ip_o_10_10_10_2,
2110 : &ip_o_10_10_10_2,
2111 : &ip_o_10_10_10_2,
2112 : &ip_o_10_10_10_2,
2113 : &ip_o_10_10_10_2,
2114 : &ip_o_10_10_10_2,
2115 : &ip_o_10_10_10_2,
2116 : &ip_o_10_10_10_2,
2117 : &ip_o_10_10_10_2,
2118 : &ip_o_10_10_10_2,
2119 : &ip_o_10_10_10_2,
2120 : &ip_o_10_10_10_2,
2121 : &ip_o_10_10_10_2,
2122 : &ip_o_10_10_10_2,
2123 : &ip_o_10_10_10_2,
2124 : &ip_o_10_10_10_2,
2125 : &ip_o_10_10_10_2,
2126 : &ip_o_10_10_10_2,
2127 : &ip_o_10_10_10_2,
2128 : &ip_o_10_10_10_2,
2129 : &ip_o_10_10_10_2,
2130 : &ip_o_10_10_10_2,
2131 : &ip_o_10_10_10_2,
2132 : &ip_o_10_10_10_2,
2133 : &ip_o_10_10_10_2,
2134 : &ip_o_10_10_10_2,
2135 : &ip_o_10_10_10_1),
2136 : "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
2137 :
2138 1 : fib_table_entry_path_remove(fib_index,
2139 : &pfx_6_6_6_6_s_32,
2140 : FIB_SOURCE_API,
2141 : DPO_PROTO_IP4,
2142 : &nh_10_10_10_2,
2143 1 : tm->hw[0]->sw_if_index,
2144 : ~0, // invalid fib index
2145 : 100,
2146 : FIB_ROUTE_PATH_FLAG_NONE);
2147 :
2148 1 : fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2149 1 : FIB_TEST(!fib_test_validate_entry(fei,
2150 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2151 : 1,
2152 : &ip_o_10_10_10_1),
2153 : "6.6.6.6/32 via 10.10.10.1");
2154 :
2155 1 : fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2156 :
2157 : /*
2158 : * A recursive via the two unequal cost entries
2159 : */
2160 2 : fib_prefix_t bgp_44_s_32 = {
2161 : .fp_len = 32,
2162 : .fp_proto = FIB_PROTOCOL_IP4,
2163 : .fp_addr = {
2164 : /* 200.200.200.201/32 */
2165 1 : .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2166 : },
2167 : };
2168 1 : fei = fib_table_entry_path_add(fib_index,
2169 : &bgp_44_s_32,
2170 : FIB_SOURCE_API,
2171 : FIB_ENTRY_FLAG_NONE,
2172 : DPO_PROTO_IP4,
2173 : &pfx_1_2_3_4_s_32.fp_addr,
2174 : ~0,
2175 : fib_index,
2176 : 1,
2177 : NULL,
2178 : FIB_ROUTE_PATH_FLAG_NONE);
2179 1 : fei = fib_table_entry_path_add(fib_index,
2180 : &bgp_44_s_32,
2181 : FIB_SOURCE_API,
2182 : FIB_ENTRY_FLAG_NONE,
2183 : DPO_PROTO_IP4,
2184 : &pfx_1_2_3_5_s_32.fp_addr,
2185 : ~0,
2186 : fib_index,
2187 : 1,
2188 : NULL,
2189 : FIB_ROUTE_PATH_FLAG_NONE);
2190 :
2191 1 : FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2192 1 : FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2193 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2194 : tm->hw[0]->sw_if_index,
2195 : tm->hw[1]->sw_if_index),
2196 : "RPF list for 1.2.3.4/32 contains both adjs");
2197 :
2198 : /*
2199 : * test the uRPF check functions
2200 : */
2201 1 : dpo_id_t dpo_44 = DPO_INVALID;
2202 : index_t urpfi;
2203 :
2204 1 : fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2205 1 : urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2206 :
2207 1 : FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2208 : "uRPF check for 68.68.68.68/32 on %d OK",
2209 : tm->hw[0]->sw_if_index);
2210 1 : FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2211 : "uRPF check for 68.68.68.68/32 on %d OK",
2212 : tm->hw[1]->sw_if_index);
2213 1 : FIB_TEST(!fib_urpf_check(urpfi, 99),
2214 : "uRPF check for 68.68.68.68/32 on 99 not-OK",
2215 : 99);
2216 1 : dpo_reset(&dpo_44);
2217 :
2218 1 : fib_table_entry_delete(fib_index,
2219 : &bgp_44_s_32,
2220 : FIB_SOURCE_API);
2221 1 : fib_table_entry_delete(fib_index,
2222 : &pfx_1_2_3_5_s_32,
2223 : FIB_SOURCE_API);
2224 1 : fib_table_entry_delete(fib_index,
2225 : &pfx_1_2_3_4_s_32,
2226 : FIB_SOURCE_API);
2227 :
2228 : /*
2229 : * Add a recursive route:
2230 : * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2231 : */
2232 2 : fib_prefix_t bgp_201_pfx = {
2233 : .fp_len = 32,
2234 : .fp_proto = FIB_PROTOCOL_IP4,
2235 : .fp_addr = {
2236 : /* 200.200.200.201/32 */
2237 1 : .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2238 : },
2239 : };
2240 : /* via 1.1.1.200 */
2241 2 : fib_prefix_t pfx_1_1_1_200_s_32 = {
2242 : .fp_len = 32,
2243 : .fp_proto = FIB_PROTOCOL_IP4,
2244 : .fp_addr = {
2245 1 : .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2246 : },
2247 : };
2248 :
2249 1 : fei = fib_table_entry_path_add(fib_index,
2250 : &bgp_201_pfx,
2251 : FIB_SOURCE_API,
2252 : FIB_ENTRY_FLAG_NONE,
2253 : DPO_PROTO_IP4,
2254 : &pfx_1_1_1_200_s_32.fp_addr,
2255 : ~0, // no index provided.
2256 : fib_index, // nexthop in same fib as route
2257 : 1,
2258 : NULL,
2259 : FIB_ROUTE_PATH_FLAG_NONE);
2260 :
2261 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2262 : "Recursive via unresolved is drop");
2263 :
2264 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2265 1 : FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2266 : "Flags set on RR via non-attached");
2267 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2268 : "RPF list for BGP route empty");
2269 :
2270 : /*
2271 : * +2 entry (BGP & RR) and +1 shared-path-list
2272 : */
2273 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2274 : fib_path_list_db_size());
2275 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2276 : fib_path_list_pool_size());
2277 1 : FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2278 : fib_entry_pool_size());
2279 :
2280 : /*
2281 : * insert a route that covers the missing 1.1.1.2/32. we epxect
2282 : * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2283 : */
2284 2 : fib_prefix_t pfx_1_1_1_0_s_24 = {
2285 : .fp_len = 24,
2286 : .fp_proto = FIB_PROTOCOL_IP4,
2287 : .fp_addr = {
2288 : /* 1.1.1.0/24 */
2289 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2290 : },
2291 : };
2292 :
2293 1 : fib_table_entry_path_add(fib_index,
2294 : &pfx_1_1_1_0_s_24,
2295 : FIB_SOURCE_API,
2296 : FIB_ENTRY_FLAG_NONE,
2297 : DPO_PROTO_IP4,
2298 : &nh_10_10_10_1,
2299 1 : tm->hw[0]->sw_if_index,
2300 : ~0, // invalid fib index
2301 : 1,
2302 : NULL,
2303 : FIB_ROUTE_PATH_FLAG_NONE);
2304 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2305 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2306 1 : ai = fib_entry_get_adj(fei);
2307 1 : FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2308 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2309 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2310 1 : ai = fib_entry_get_adj(fei);
2311 1 : FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2312 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2313 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2314 1 : ai = fib_entry_get_adj(fei);
2315 1 : FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2316 :
2317 : /*
2318 : * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2319 : */
2320 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2321 : fib_path_list_db_size());
2322 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2323 : fib_path_list_pool_size());
2324 1 : FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2325 : fib_entry_pool_size());
2326 :
2327 : /*
2328 : * the recursive adj for 200.200.200.200 should be updated.
2329 : */
2330 1 : FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2331 1 : FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2332 1 : fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2333 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2334 : tm->hw[0]->sw_if_index),
2335 : "RPF list for BGP route has itf index 0");
2336 :
2337 : /*
2338 : * insert a more specific route than 1.1.1.0/24 that also covers the
2339 : * missing 1.1.1.2/32, but not 1.1.1.200/32. we expect
2340 : * 200.200.200.200 to resolve through it.
2341 : */
2342 2 : fib_prefix_t pfx_1_1_1_0_s_28 = {
2343 : .fp_len = 28,
2344 : .fp_proto = FIB_PROTOCOL_IP4,
2345 : .fp_addr = {
2346 : /* 1.1.1.0/24 */
2347 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2348 : },
2349 : };
2350 :
2351 1 : fib_table_entry_path_add(fib_index,
2352 : &pfx_1_1_1_0_s_28,
2353 : FIB_SOURCE_API,
2354 : FIB_ENTRY_FLAG_NONE,
2355 : DPO_PROTO_IP4,
2356 : &nh_10_10_10_2,
2357 1 : tm->hw[0]->sw_if_index,
2358 : ~0, // invalid fib index
2359 : 1,
2360 : NULL,
2361 : FIB_ROUTE_PATH_FLAG_NONE);
2362 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2363 1 : dpo2 = fib_entry_contribute_ip_forwarding(fei);
2364 1 : ai = fib_entry_get_adj(fei);
2365 1 : FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2366 :
2367 : /*
2368 : * +1 entry. +1 shared path-list
2369 : */
2370 1 : FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2371 : fib_path_list_db_size());
2372 1 : FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2373 : fib_path_list_pool_size());
2374 1 : FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2375 : fib_entry_pool_size());
2376 :
2377 : /*
2378 : * the recursive adj for 200.200.200.200 should be updated.
2379 : * 200.200.200.201 remains unchanged.
2380 : */
2381 1 : FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2382 1 : FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2383 :
2384 : /*
2385 : * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2386 : */
2387 1 : fib_table_entry_path_remove(fib_index,
2388 : &pfx_1_1_1_0_s_28,
2389 : FIB_SOURCE_API,
2390 : DPO_PROTO_IP4,
2391 : &nh_10_10_10_2,
2392 1 : tm->hw[0]->sw_if_index,
2393 : ~0,
2394 : 1,
2395 : FIB_ROUTE_PATH_FLAG_NONE);
2396 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2397 : FIB_NODE_INDEX_INVALID),
2398 : "1.1.1.0/28 removed");
2399 1 : FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2400 : fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2401 : "1.1.1.0/28 lookup via /24");
2402 1 : FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2403 1 : FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2404 :
2405 : /*
2406 : * -1 entry. -1 shared path-list
2407 : */
2408 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2409 : fib_path_list_db_size());
2410 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2411 : fib_path_list_pool_size());
2412 1 : FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2413 : fib_entry_pool_size());
2414 :
2415 : /*
2416 : * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2417 : */
2418 1 : fib_table_entry_path_remove(fib_index,
2419 : &pfx_1_1_1_0_s_24,
2420 : FIB_SOURCE_API,
2421 : DPO_PROTO_IP4,
2422 : &nh_10_10_10_1,
2423 1 : tm->hw[0]->sw_if_index,
2424 : ~0,
2425 : 1,
2426 : FIB_ROUTE_PATH_FLAG_NONE);
2427 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2428 : FIB_NODE_INDEX_INVALID),
2429 : "1.1.1.0/24 removed");
2430 :
2431 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2432 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2433 : "1.1.1.2/32 route is DROP");
2434 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2435 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2436 : "1.1.1.200/32 route is DROP");
2437 :
2438 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2439 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2440 : "201 is drop");
2441 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2442 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2443 : "200 is drop");
2444 :
2445 : /*
2446 : * -1 entry
2447 : */
2448 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2449 : fib_path_list_db_size());
2450 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2451 : fib_path_list_pool_size());
2452 1 : FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2453 : fib_entry_pool_size());
2454 :
2455 : /*
2456 : * insert the missing 1.1.1.2/32
2457 : */
2458 1 : fei = fib_table_entry_path_add(fib_index,
2459 : &pfx_1_1_1_2_s_32,
2460 : FIB_SOURCE_API,
2461 : FIB_ENTRY_FLAG_NONE,
2462 : DPO_PROTO_IP4,
2463 : &nh_10_10_10_1,
2464 1 : tm->hw[0]->sw_if_index,
2465 : ~0, // invalid fib index
2466 : 1,
2467 : NULL,
2468 : FIB_ROUTE_PATH_FLAG_NONE);
2469 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2470 1 : ai = fib_entry_get_adj(fei);
2471 1 : FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2472 :
2473 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2474 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2475 : "201 is drop");
2476 1 : FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2477 :
2478 : /*
2479 : * no change. 1.1.1.2/32 was already there RR sourced.
2480 : */
2481 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2482 : fib_path_list_db_size());
2483 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2484 : fib_path_list_pool_size());
2485 1 : FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2486 : fib_entry_pool_size());
2487 :
2488 : /*
2489 : * give 201 a resolved path.
2490 : * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2491 : * only the latter contributes forwarding.
2492 : */
2493 1 : fei = fib_table_entry_path_add(fib_index,
2494 : &bgp_201_pfx,
2495 : FIB_SOURCE_API,
2496 : FIB_ENTRY_FLAG_NONE,
2497 : DPO_PROTO_IP4,
2498 : &pfx_1_1_1_2_s_32.fp_addr,
2499 : ~0,
2500 : fib_index,
2501 : 1,
2502 : NULL,
2503 : FIB_ROUTE_PATH_FLAG_NONE);
2504 1 : FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2505 1 : fib_table_entry_path_remove(fib_index,
2506 : &bgp_201_pfx,
2507 : FIB_SOURCE_API,
2508 : DPO_PROTO_IP4,
2509 : &pfx_1_1_1_2_s_32.fp_addr,
2510 : ~0,
2511 : fib_index,
2512 : 1,
2513 : FIB_ROUTE_PATH_FLAG_NONE);
2514 :
2515 : /*
2516 : * remove 200.200.200.201/32 which does not have a valid via FIB
2517 : */
2518 1 : fib_table_entry_path_remove(fib_index,
2519 : &bgp_201_pfx,
2520 : FIB_SOURCE_API,
2521 : DPO_PROTO_IP4,
2522 : &pfx_1_1_1_200_s_32.fp_addr,
2523 : ~0, // no index provided.
2524 : fib_index,
2525 : 1,
2526 : FIB_ROUTE_PATH_FLAG_NONE);
2527 :
2528 : /*
2529 : * -2 entries (BGP and RR). -1 shared path-list;
2530 : */
2531 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2532 : FIB_NODE_INDEX_INVALID),
2533 : "200.200.200.201/32 removed");
2534 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2535 : FIB_NODE_INDEX_INVALID),
2536 : "1.1.1.200/32 removed");
2537 :
2538 1 : FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2539 : fib_path_list_db_size());
2540 1 : FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2541 : fib_path_list_pool_size());
2542 1 : FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2543 : fib_entry_pool_size());
2544 :
2545 : /*
2546 : * remove 200.200.200.200/32 which does have a valid via FIB
2547 : */
2548 1 : fib_table_entry_path_remove(fib_index,
2549 : &bgp_200_pfx,
2550 : FIB_SOURCE_API,
2551 : DPO_PROTO_IP4,
2552 : &pfx_1_1_1_2_s_32.fp_addr,
2553 : ~0, // no index provided.
2554 : fib_index,
2555 : 1,
2556 : FIB_ROUTE_PATH_FLAG_NONE);
2557 :
2558 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2559 : FIB_NODE_INDEX_INVALID),
2560 : "200.200.200.200/32 removed");
2561 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2562 : FIB_NODE_INDEX_INVALID),
2563 : "1.1.1.2/32 still present");
2564 :
2565 : /*
2566 : * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2567 : */
2568 1 : FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2569 : fib_path_list_db_size());
2570 1 : FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2571 : fib_path_list_pool_size());
2572 1 : FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2573 : fib_entry_pool_size());
2574 :
2575 : /*
2576 : * A recursive prefix that has a 2 path load-balance.
2577 : * It also shares a next-hop with other BGP prefixes and hence
2578 : * test the ref counting of RR sourced prefixes and 2 level LB.
2579 : */
2580 2 : const fib_prefix_t bgp_102 = {
2581 : .fp_len = 32,
2582 : .fp_proto = FIB_PROTOCOL_IP4,
2583 : .fp_addr = {
2584 : /* 100.100.100.101/32 */
2585 1 : .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2586 : },
2587 : };
2588 1 : fib_table_entry_path_add(fib_index,
2589 : &bgp_102,
2590 : FIB_SOURCE_API,
2591 : FIB_ENTRY_FLAG_NONE,
2592 : DPO_PROTO_IP4,
2593 : &pfx_1_1_1_1_s_32.fp_addr,
2594 : ~0, // no index provided.
2595 : fib_index, // same as route
2596 : 1,
2597 : NULL,
2598 : FIB_ROUTE_PATH_FLAG_NONE);
2599 1 : fib_table_entry_path_add(fib_index,
2600 : &bgp_102,
2601 : FIB_SOURCE_API,
2602 : FIB_ENTRY_FLAG_NONE,
2603 : DPO_PROTO_IP4,
2604 : &pfx_1_1_1_2_s_32.fp_addr,
2605 : ~0, // no index provided.
2606 : fib_index, // same as route's FIB
2607 : 1,
2608 : NULL,
2609 : FIB_ROUTE_PATH_FLAG_NONE);
2610 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2611 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2612 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
2613 :
2614 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2615 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2616 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2617 1 : dpo2 = fib_entry_contribute_ip_forwarding(fei);
2618 :
2619 1 : lb = load_balance_get(dpo->dpoi_index);
2620 1 : FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2621 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2622 : "First via 10.10.10.1");
2623 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2624 : "Second via 10.10.10.1");
2625 :
2626 1 : fib_table_entry_path_remove(fib_index,
2627 : &bgp_102,
2628 : FIB_SOURCE_API,
2629 : DPO_PROTO_IP4,
2630 : &pfx_1_1_1_1_s_32.fp_addr,
2631 : ~0, // no index provided.
2632 : fib_index, // same as route's FIB
2633 : 1,
2634 : FIB_ROUTE_PATH_FLAG_NONE);
2635 1 : fib_table_entry_path_remove(fib_index,
2636 : &bgp_102,
2637 : FIB_SOURCE_API,
2638 : DPO_PROTO_IP4,
2639 : &pfx_1_1_1_2_s_32.fp_addr,
2640 : ~0, // no index provided.
2641 : fib_index, // same as route's FIB
2642 : 1,
2643 : FIB_ROUTE_PATH_FLAG_NONE);
2644 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2645 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2646 :
2647 : /*
2648 : * remove the remaining recursives
2649 : */
2650 1 : fib_table_entry_path_remove(fib_index,
2651 : &bgp_100_pfx,
2652 : FIB_SOURCE_API,
2653 : DPO_PROTO_IP4,
2654 : &pfx_1_1_1_1_s_32.fp_addr,
2655 : ~0, // no index provided.
2656 : fib_index, // same as route's FIB
2657 : 1,
2658 : FIB_ROUTE_PATH_FLAG_NONE);
2659 1 : fib_table_entry_path_remove(fib_index,
2660 : &bgp_101_pfx,
2661 : FIB_SOURCE_API,
2662 : DPO_PROTO_IP4,
2663 : &pfx_1_1_1_1_s_32.fp_addr,
2664 : ~0, // no index provided.
2665 : fib_index, // same as route's FIB
2666 : 1,
2667 : FIB_ROUTE_PATH_FLAG_NONE);
2668 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2669 : FIB_NODE_INDEX_INVALID),
2670 : "100.100.100.100/32 removed");
2671 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2672 : FIB_NODE_INDEX_INVALID),
2673 : "100.100.100.101/32 removed");
2674 :
2675 : /*
2676 : * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2677 : */
2678 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2679 : fib_path_list_db_size());
2680 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2681 : fib_path_list_pool_size());
2682 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2683 : fib_entry_pool_size());
2684 :
2685 : /*
2686 : * Add a recursive route via a connected cover, using an adj-fib that does exist
2687 : */
2688 1 : fib_table_entry_path_add(fib_index,
2689 : &bgp_200_pfx,
2690 : FIB_SOURCE_API,
2691 : FIB_ENTRY_FLAG_NONE,
2692 : DPO_PROTO_IP4,
2693 : &nh_10_10_10_1,
2694 : ~0, // no index provided.
2695 : fib_index, // Same as route's FIB
2696 : 1,
2697 : NULL,
2698 : FIB_ROUTE_PATH_FLAG_NONE);
2699 :
2700 : /*
2701 : * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2702 : */
2703 1 : FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2704 : fib_path_list_db_size());
2705 1 : FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2706 : fib_path_list_pool_size());
2707 1 : FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2708 : fib_entry_pool_size());
2709 :
2710 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2711 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
2712 :
2713 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2714 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2715 :
2716 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2717 : "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2718 :
2719 1 : FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2720 : "Flags set on RR via existing attached");
2721 :
2722 : /*
2723 : * Add a recursive route via a connected cover, using and adj-fib that does
2724 : * not exist
2725 : */
2726 2 : ip46_address_t nh_10_10_10_3 = {
2727 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2728 : };
2729 1 : fib_prefix_t pfx_10_10_10_3 = {
2730 : .fp_len = 32,
2731 : .fp_proto = FIB_PROTOCOL_IP4,
2732 : .fp_addr = nh_10_10_10_3,
2733 : };
2734 :
2735 1 : fib_table_entry_path_add(fib_index,
2736 : &bgp_201_pfx,
2737 : FIB_SOURCE_API,
2738 : FIB_ENTRY_FLAG_NONE,
2739 : DPO_PROTO_IP4,
2740 : &nh_10_10_10_3,
2741 : ~0, // no index provided.
2742 : fib_index,
2743 : 1,
2744 : NULL,
2745 : FIB_ROUTE_PATH_FLAG_NONE);
2746 :
2747 : /*
2748 : * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2749 : * one unshared non-recursive via 10.10.10.3
2750 : */
2751 1 : FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2752 : fib_path_list_db_size());
2753 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2754 : fib_path_list_pool_size());
2755 1 : FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2756 : fib_entry_pool_size());
2757 :
2758 1 : ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2759 : VNET_LINK_IP4,
2760 : &nh_10_10_10_3,
2761 1 : tm->hw[0]->sw_if_index);
2762 :
2763 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2764 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
2765 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2766 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2767 :
2768 1 : ai = fib_entry_get_adj(fei);
2769 1 : FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2770 1 : FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2771 : fib_entry_get_flags(fei)),
2772 : "Flags set on RR via non-existing attached");
2773 :
2774 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2775 : "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2776 :
2777 1 : adj_unlock(ai_03);
2778 :
2779 : /*
2780 : * remove the recursives
2781 : */
2782 1 : fib_table_entry_path_remove(fib_index,
2783 : &bgp_200_pfx,
2784 : FIB_SOURCE_API,
2785 : DPO_PROTO_IP4,
2786 : &nh_10_10_10_1,
2787 : ~0, // no index provided.
2788 : fib_index, // same as route's FIB
2789 : 1,
2790 : FIB_ROUTE_PATH_FLAG_NONE);
2791 1 : fib_table_entry_path_remove(fib_index,
2792 : &bgp_201_pfx,
2793 : FIB_SOURCE_API,
2794 : DPO_PROTO_IP4,
2795 : &nh_10_10_10_3,
2796 : ~0, // no index provided.
2797 : fib_index, // same as route's FIB
2798 : 1,
2799 : FIB_ROUTE_PATH_FLAG_NONE);
2800 :
2801 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2802 : FIB_NODE_INDEX_INVALID),
2803 : "200.200.200.201/32 removed");
2804 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2805 : FIB_NODE_INDEX_INVALID),
2806 : "200.200.200.200/32 removed");
2807 1 : FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2808 : FIB_NODE_INDEX_INVALID),
2809 : "10.10.10.3/32 removed");
2810 :
2811 : /*
2812 : * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2813 : * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2814 : */
2815 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2816 : fib_path_list_db_size());
2817 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2818 : fib_path_list_pool_size());
2819 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2820 : fib_entry_pool_size());
2821 :
2822 :
2823 : /*
2824 : * RECURSION LOOPS
2825 : * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2826 : */
2827 2 : fib_prefix_t pfx_5_5_5_5_s_32 = {
2828 : .fp_len = 32,
2829 : .fp_proto = FIB_PROTOCOL_IP4,
2830 : .fp_addr = {
2831 1 : .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2832 : },
2833 : };
2834 2 : fib_prefix_t pfx_5_5_5_6_s_32 = {
2835 : .fp_len = 32,
2836 : .fp_proto = FIB_PROTOCOL_IP4,
2837 : .fp_addr = {
2838 1 : .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2839 : },
2840 : };
2841 2 : fib_prefix_t pfx_5_5_5_7_s_32 = {
2842 : .fp_len = 32,
2843 : .fp_proto = FIB_PROTOCOL_IP4,
2844 : .fp_addr = {
2845 1 : .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2846 : },
2847 : };
2848 :
2849 1 : fib_table_entry_path_add(fib_index,
2850 : &pfx_5_5_5_5_s_32,
2851 : FIB_SOURCE_API,
2852 : FIB_ENTRY_FLAG_NONE,
2853 : DPO_PROTO_IP4,
2854 : &pfx_5_5_5_6_s_32.fp_addr,
2855 : ~0, // no index provided.
2856 : fib_index,
2857 : 1,
2858 : NULL,
2859 : FIB_ROUTE_PATH_FLAG_NONE);
2860 1 : fib_table_entry_path_add(fib_index,
2861 : &pfx_5_5_5_6_s_32,
2862 : FIB_SOURCE_API,
2863 : FIB_ENTRY_FLAG_NONE,
2864 : DPO_PROTO_IP4,
2865 : &pfx_5_5_5_7_s_32.fp_addr,
2866 : ~0, // no index provided.
2867 : fib_index,
2868 : 1,
2869 : NULL,
2870 : FIB_ROUTE_PATH_FLAG_NONE);
2871 1 : fib_table_entry_path_add(fib_index,
2872 : &pfx_5_5_5_7_s_32,
2873 : FIB_SOURCE_API,
2874 : FIB_ENTRY_FLAG_NONE,
2875 : DPO_PROTO_IP4,
2876 : &pfx_5_5_5_5_s_32.fp_addr,
2877 : ~0, // no index provided.
2878 : fib_index,
2879 : 1,
2880 : NULL,
2881 : FIB_ROUTE_PATH_FLAG_NONE);
2882 : /*
2883 : * +3 entries, +3 shared path-list
2884 : */
2885 1 : FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2886 : fib_path_list_db_size());
2887 1 : FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2888 : fib_path_list_pool_size());
2889 1 : FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2890 : fib_entry_pool_size());
2891 :
2892 : /*
2893 : * All the entries have only looped paths, so they are all drop
2894 : */
2895 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2896 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2897 : "LB for 5.5.5.7/32 is via adj for DROP");
2898 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2899 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2900 : "LB for 5.5.5.5/32 is via adj for DROP");
2901 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2902 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2903 : "LB for 5.5.5.6/32 is via adj for DROP");
2904 :
2905 : /*
2906 : * provide 5.5.5.6/32 with alternate path.
2907 : * this will allow only 5.5.5.6/32 to forward with this path, the others
2908 : * are still drop since the loop is still present.
2909 : */
2910 1 : fib_table_entry_path_add(fib_index,
2911 : &pfx_5_5_5_6_s_32,
2912 : FIB_SOURCE_API,
2913 : FIB_ENTRY_FLAG_NONE,
2914 : DPO_PROTO_IP4,
2915 : &nh_10_10_10_1,
2916 1 : tm->hw[0]->sw_if_index,
2917 : ~0,
2918 : 1,
2919 : NULL,
2920 : FIB_ROUTE_PATH_FLAG_NONE);
2921 :
2922 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2923 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2924 :
2925 1 : lb = load_balance_get(dpo1->dpoi_index);
2926 1 : FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2927 :
2928 1 : dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2929 1 : FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2930 1 : FIB_TEST((ai_01 == dpo2->dpoi_index),
2931 : "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2932 :
2933 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2934 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2935 : "LB for 5.5.5.7/32 is via adj for DROP");
2936 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2937 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2938 : "LB for 5.5.5.5/32 is via adj for DROP");
2939 :
2940 : /*
2941 : * remove the alternate path for 5.5.5.6/32
2942 : * back to all drop
2943 : */
2944 1 : fib_table_entry_path_remove(fib_index,
2945 : &pfx_5_5_5_6_s_32,
2946 : FIB_SOURCE_API,
2947 : DPO_PROTO_IP4,
2948 : &nh_10_10_10_1,
2949 1 : tm->hw[0]->sw_if_index,
2950 : ~0,
2951 : 1,
2952 : FIB_ROUTE_PATH_FLAG_NONE);
2953 :
2954 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2955 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2956 : "LB for 5.5.5.7/32 is via adj for DROP");
2957 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2958 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2959 : "LB for 5.5.5.5/32 is via adj for DROP");
2960 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2961 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2962 : "LB for 5.5.5.6/32 is via adj for DROP");
2963 :
2964 : /*
2965 : * break the loop by giving 5.5.5.5/32 a new set of paths
2966 : * expect all to forward via this new path.
2967 : */
2968 1 : fib_table_entry_update_one_path(fib_index,
2969 : &pfx_5_5_5_5_s_32,
2970 : FIB_SOURCE_API,
2971 : FIB_ENTRY_FLAG_NONE,
2972 : DPO_PROTO_IP4,
2973 : &nh_10_10_10_1,
2974 1 : tm->hw[0]->sw_if_index,
2975 : ~0, // invalid fib index
2976 : 1,
2977 : NULL,
2978 : FIB_ROUTE_PATH_FLAG_NONE);
2979 :
2980 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2981 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
2982 1 : lb = load_balance_get(dpo1->dpoi_index);
2983 1 : FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2984 :
2985 1 : dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2986 1 : FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2987 1 : FIB_TEST((ai_01 == dpo2->dpoi_index),
2988 : "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2989 :
2990 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2991 1 : dpo2 = fib_entry_contribute_ip_forwarding(fei);
2992 :
2993 1 : lb = load_balance_get(dpo2->dpoi_index);
2994 1 : FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2995 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2996 : "5.5.5.5.7 via 5.5.5.5");
2997 :
2998 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2999 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
3000 :
3001 1 : lb = load_balance_get(dpo1->dpoi_index);
3002 1 : FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
3003 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3004 : "5.5.5.5.6 via 5.5.5.7");
3005 :
3006 : /*
3007 : * revert back to the loop. so we can remove the prefixes with
3008 : * the loop intact
3009 : */
3010 1 : fib_table_entry_update_one_path(fib_index,
3011 : &pfx_5_5_5_5_s_32,
3012 : FIB_SOURCE_API,
3013 : FIB_ENTRY_FLAG_NONE,
3014 : DPO_PROTO_IP4,
3015 : &pfx_5_5_5_6_s_32.fp_addr,
3016 : ~0, // no index provided.
3017 : fib_index,
3018 : 1,
3019 : NULL,
3020 : FIB_ROUTE_PATH_FLAG_NONE);
3021 :
3022 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
3023 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3024 : "LB for 5.5.5.7/32 is via adj for DROP");
3025 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
3026 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3027 : "LB for 5.5.5.5/32 is via adj for DROP");
3028 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
3029 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3030 : "LB for 5.5.5.6/32 is via adj for DROP");
3031 :
3032 : /*
3033 : * remove all the 5.5.5.x/32 prefixes
3034 : */
3035 1 : fib_table_entry_path_remove(fib_index,
3036 : &pfx_5_5_5_5_s_32,
3037 : FIB_SOURCE_API,
3038 : DPO_PROTO_IP4,
3039 : &pfx_5_5_5_6_s_32.fp_addr,
3040 : ~0, // no index provided.
3041 : fib_index, // same as route's FIB
3042 : 1,
3043 : FIB_ROUTE_PATH_FLAG_NONE);
3044 1 : fib_table_entry_path_remove(fib_index,
3045 : &pfx_5_5_5_6_s_32,
3046 : FIB_SOURCE_API,
3047 : DPO_PROTO_IP4,
3048 : &pfx_5_5_5_7_s_32.fp_addr,
3049 : ~0, // no index provided.
3050 : fib_index, // same as route's FIB
3051 : 1,
3052 : FIB_ROUTE_PATH_FLAG_NONE);
3053 1 : fib_table_entry_path_remove(fib_index,
3054 : &pfx_5_5_5_7_s_32,
3055 : FIB_SOURCE_API,
3056 : DPO_PROTO_IP4,
3057 : &pfx_5_5_5_5_s_32.fp_addr,
3058 : ~0, // no index provided.
3059 : fib_index, // same as route's FIB
3060 : 1,
3061 : FIB_ROUTE_PATH_FLAG_NONE);
3062 1 : fib_table_entry_path_remove(fib_index,
3063 : &pfx_5_5_5_6_s_32,
3064 : FIB_SOURCE_API,
3065 : DPO_PROTO_IP4,
3066 : &nh_10_10_10_2,
3067 : ~0, // no index provided.
3068 : fib_index, // same as route's FIB
3069 : 1,
3070 : FIB_ROUTE_PATH_FLAG_NONE);
3071 :
3072 : /*
3073 : * -3 entries, -3 shared path-list
3074 : */
3075 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3076 : fib_path_list_db_size());
3077 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3078 : fib_path_list_pool_size());
3079 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3080 : fib_entry_pool_size());
3081 :
3082 : /*
3083 : * Single level loop 5.5.5.5/32 via 5.5.5.5/32
3084 : */
3085 1 : fib_table_entry_path_add(fib_index,
3086 : &pfx_5_5_5_6_s_32,
3087 : FIB_SOURCE_API,
3088 : FIB_ENTRY_FLAG_NONE,
3089 : DPO_PROTO_IP4,
3090 : &pfx_5_5_5_6_s_32.fp_addr,
3091 : ~0, // no index provided.
3092 : fib_index,
3093 : 1,
3094 : NULL,
3095 : FIB_ROUTE_PATH_FLAG_NONE);
3096 1 : fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
3097 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3098 : "1-level 5.5.5.6/32 loop is via adj for DROP");
3099 :
3100 1 : fib_table_entry_path_remove(fib_index,
3101 : &pfx_5_5_5_6_s_32,
3102 : FIB_SOURCE_API,
3103 : DPO_PROTO_IP4,
3104 : &pfx_5_5_5_6_s_32.fp_addr,
3105 : ~0, // no index provided.
3106 : fib_index, // same as route's FIB
3107 : 1,
3108 : FIB_ROUTE_PATH_FLAG_NONE);
3109 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3110 : fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
3111 : "1-level 5.5.5.6/32 loop is removed");
3112 :
3113 : /*
3114 : * A recursive route whose next-hop is covered by the prefix.
3115 : * This would mean the via-fib, which inherits forwarding from its
3116 : * cover, thus picks up forwarding from the prfix, which is via the
3117 : * via-fib, and we have a loop.
3118 : */
3119 2 : fib_prefix_t pfx_23_23_23_0_s_24 = {
3120 : .fp_len = 24,
3121 : .fp_proto = FIB_PROTOCOL_IP4,
3122 : .fp_addr = {
3123 1 : .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
3124 : },
3125 : };
3126 2 : fib_prefix_t pfx_23_23_23_23_s_32 = {
3127 : .fp_len = 32,
3128 : .fp_proto = FIB_PROTOCOL_IP4,
3129 : .fp_addr = {
3130 1 : .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
3131 : },
3132 : };
3133 1 : fei = fib_table_entry_path_add(fib_index,
3134 : &pfx_23_23_23_0_s_24,
3135 : FIB_SOURCE_API,
3136 : FIB_ENTRY_FLAG_NONE,
3137 : DPO_PROTO_IP4,
3138 : &pfx_23_23_23_23_s_32.fp_addr,
3139 : ~0, // recursive
3140 : fib_index,
3141 : 1,
3142 : NULL,
3143 : FIB_ROUTE_PATH_FLAG_NONE);
3144 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3145 1 : FIB_TEST(load_balance_is_drop(dpo),
3146 : "23.23.23.0/24 via covered is DROP");
3147 1 : fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3148 :
3149 : /*
3150 : * add-remove test. no change.
3151 : */
3152 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3153 : fib_path_list_db_size());
3154 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3155 : fib_path_list_pool_size());
3156 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3157 : fib_entry_pool_size());
3158 :
3159 : /*
3160 : * Make the default route recursive via a unknown next-hop. Thus the
3161 : * next hop's cover would be the default route
3162 : */
3163 1 : fei = fib_table_entry_path_add(fib_index,
3164 : &pfx_0_0_0_0_s_0,
3165 : FIB_SOURCE_API,
3166 : FIB_ENTRY_FLAG_NONE,
3167 : DPO_PROTO_IP4,
3168 : &pfx_23_23_23_23_s_32.fp_addr,
3169 : ~0, // recursive
3170 : fib_index,
3171 : 1,
3172 : NULL,
3173 : FIB_ROUTE_PATH_FLAG_NONE);
3174 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3175 1 : FIB_TEST(load_balance_is_drop(dpo),
3176 : "0.0.0.0.0/0 via is DROP");
3177 1 : FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3178 : "no resolving interface for looped 0.0.0.0/0");
3179 :
3180 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3181 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3182 1 : FIB_TEST(load_balance_is_drop(dpo),
3183 : "23.23.23.23/32 via is DROP");
3184 1 : FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3185 : "no resolving interface for looped 23.23.23.23/32");
3186 :
3187 1 : fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3188 :
3189 : /*
3190 : * A recursive route with recursion constraints.
3191 : * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3192 : */
3193 1 : fib_table_entry_path_add(fib_index,
3194 : &bgp_200_pfx,
3195 : FIB_SOURCE_API,
3196 : FIB_ENTRY_FLAG_NONE,
3197 : DPO_PROTO_IP4,
3198 : &nh_1_1_1_1,
3199 : ~0,
3200 : fib_index,
3201 : 1,
3202 : NULL,
3203 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3204 :
3205 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3206 1 : dpo2 = fib_entry_contribute_ip_forwarding(fei);
3207 :
3208 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3209 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
3210 :
3211 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3212 : "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3213 :
3214 : /*
3215 : * save the load-balance. we expect it to be inplace modified
3216 : */
3217 1 : lb = load_balance_get(dpo1->dpoi_index);
3218 :
3219 : /*
3220 : * add a covering prefix for the via fib that would otherwise serve
3221 : * as the resolving route when the host is removed
3222 : */
3223 1 : fib_table_entry_path_add(fib_index,
3224 : &pfx_1_1_1_0_s_28,
3225 : FIB_SOURCE_API,
3226 : FIB_ENTRY_FLAG_NONE,
3227 : DPO_PROTO_IP4,
3228 : &nh_10_10_10_1,
3229 1 : tm->hw[0]->sw_if_index,
3230 : ~0, // invalid fib index
3231 : 1,
3232 : NULL,
3233 : FIB_ROUTE_PATH_FLAG_NONE);
3234 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3235 1 : ai = fib_entry_get_adj(fei);
3236 1 : FIB_TEST((ai == ai_01),
3237 : "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3238 :
3239 : /*
3240 : * remove the host via FIB - expect the BGP prefix to be drop
3241 : */
3242 1 : fib_table_entry_path_remove(fib_index,
3243 : &pfx_1_1_1_1_s_32,
3244 : FIB_SOURCE_API,
3245 : DPO_PROTO_IP4,
3246 : &nh_10_10_10_1,
3247 1 : tm->hw[0]->sw_if_index,
3248 : ~0, // invalid fib index
3249 : 1,
3250 : FIB_ROUTE_PATH_FLAG_NONE);
3251 :
3252 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3253 : "adj for 200.200.200.200/32 is recursive via adj for DROP");
3254 :
3255 : /*
3256 : * add the via-entry host reoute back. expect to resolve again
3257 : */
3258 1 : fib_table_entry_path_add(fib_index,
3259 : &pfx_1_1_1_1_s_32,
3260 : FIB_SOURCE_API,
3261 : FIB_ENTRY_FLAG_NONE,
3262 : DPO_PROTO_IP4,
3263 : &nh_10_10_10_1,
3264 1 : tm->hw[0]->sw_if_index,
3265 : ~0, // invalid fib index
3266 : 1,
3267 : NULL,
3268 : FIB_ROUTE_PATH_FLAG_NONE);
3269 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3270 : "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3271 :
3272 : /*
3273 : * add another path for the recursive. it will then have 2.
3274 : */
3275 2 : fib_prefix_t pfx_1_1_1_3_s_32 = {
3276 : .fp_len = 32,
3277 : .fp_proto = FIB_PROTOCOL_IP4,
3278 : .fp_addr = {
3279 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3280 : },
3281 : };
3282 1 : fib_table_entry_path_add(fib_index,
3283 : &pfx_1_1_1_3_s_32,
3284 : FIB_SOURCE_API,
3285 : FIB_ENTRY_FLAG_NONE,
3286 : DPO_PROTO_IP4,
3287 : &nh_10_10_10_2,
3288 1 : tm->hw[0]->sw_if_index,
3289 : ~0, // invalid fib index
3290 : 1,
3291 : NULL,
3292 : FIB_ROUTE_PATH_FLAG_NONE);
3293 :
3294 1 : fib_table_entry_path_add(fib_index,
3295 : &bgp_200_pfx,
3296 : FIB_SOURCE_API,
3297 : FIB_ENTRY_FLAG_NONE,
3298 : DPO_PROTO_IP4,
3299 : &pfx_1_1_1_3_s_32.fp_addr,
3300 : ~0,
3301 : fib_index,
3302 : 1,
3303 : NULL,
3304 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3305 :
3306 : /*
3307 : * add a bunch load more entries using this path combo so that we get
3308 : * an LB-map created.
3309 : */
3310 : #define N_P 128
3311 : fib_prefix_t bgp_78s[N_P];
3312 129 : for (ii = 0; ii < N_P; ii++)
3313 : {
3314 128 : bgp_78s[ii].fp_len = 32;
3315 128 : bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3316 128 : bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3317 :
3318 :
3319 128 : fib_table_entry_path_add(fib_index,
3320 128 : &bgp_78s[ii],
3321 : FIB_SOURCE_API,
3322 : FIB_ENTRY_FLAG_NONE,
3323 : DPO_PROTO_IP4,
3324 : &pfx_1_1_1_3_s_32.fp_addr,
3325 : ~0,
3326 : fib_index,
3327 : 1,
3328 : NULL,
3329 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3330 128 : fib_table_entry_path_add(fib_index,
3331 128 : &bgp_78s[ii],
3332 : FIB_SOURCE_API,
3333 : FIB_ENTRY_FLAG_NONE,
3334 : DPO_PROTO_IP4,
3335 : &nh_1_1_1_1,
3336 : ~0,
3337 : fib_index,
3338 : 1,
3339 : NULL,
3340 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3341 : }
3342 :
3343 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3344 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3345 :
3346 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3347 1 : dpo2 = fib_entry_contribute_ip_forwarding(fei);
3348 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3349 : "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3350 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3351 1 : dpo1 = fib_entry_contribute_ip_forwarding(fei);
3352 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3353 : "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3354 :
3355 : /*
3356 : * expect the lb-map used by the recursive's load-balance is using both buckets
3357 : */
3358 : load_balance_map_t *lbm;
3359 : index_t lbmi;
3360 :
3361 1 : lb = load_balance_get(dpo->dpoi_index);
3362 1 : lbmi = lb->lb_map;
3363 1 : load_balance_map_lock(lbmi);
3364 1 : lbm = load_balance_map_get(lbmi);
3365 :
3366 1 : FIB_TEST(lbm->lbm_buckets[0] == 0,
3367 : "LB maps's bucket 0 is %d",
3368 : lbm->lbm_buckets[0]);
3369 1 : FIB_TEST(lbm->lbm_buckets[1] == 1,
3370 : "LB maps's bucket 1 is %d",
3371 : lbm->lbm_buckets[1]);
3372 :
3373 : /*
3374 : * withdraw one of the /32 via-entrys.
3375 : * that ECMP path will be unresolved and forwarding should continue on the
3376 : * other available path. this is an iBGP PIC edge failover.
3377 : * Test the forwarding changes without re-fetching the adj from the
3378 : * recursive entry. this ensures its the same one that is updated; i.e. an
3379 : * inplace-modify.
3380 : */
3381 1 : fib_table_entry_path_remove(fib_index,
3382 : &pfx_1_1_1_1_s_32,
3383 : FIB_SOURCE_API,
3384 : DPO_PROTO_IP4,
3385 : &nh_10_10_10_1,
3386 1 : tm->hw[0]->sw_if_index,
3387 : ~0, // invalid fib index
3388 : 1,
3389 : FIB_ROUTE_PATH_FLAG_NONE);
3390 :
3391 : /* suspend so the update walk kicks int */
3392 1 : vlib_process_suspend(vlib_get_main(), 1e-5);
3393 :
3394 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3395 1 : FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3396 : "post PIC 200.200.200.200/32 was inplace modified");
3397 :
3398 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3399 : "post PIC adj for 200.200.200.200/32 is recursive"
3400 : " via adj for 1.1.1.3");
3401 :
3402 : /*
3403 : * the LB maps that was locked above should have been modified to remove
3404 : * the path that was down, and thus its bucket points to a path that is
3405 : * still up.
3406 : */
3407 1 : FIB_TEST(lbm->lbm_buckets[0] == 1,
3408 : "LB maps's bucket 0 is %d",
3409 : lbm->lbm_buckets[0]);
3410 1 : FIB_TEST(lbm->lbm_buckets[1] == 1,
3411 : "LB maps's bucket 1 is %d",
3412 : lbm->lbm_buckets[1]);
3413 :
3414 1 : load_balance_map_unlock(lbmi);
3415 :
3416 : /*
3417 : * add it back. again
3418 : */
3419 1 : fib_table_entry_path_add(fib_index,
3420 : &pfx_1_1_1_1_s_32,
3421 : FIB_SOURCE_API,
3422 : FIB_ENTRY_FLAG_NONE,
3423 : DPO_PROTO_IP4,
3424 : &nh_10_10_10_1,
3425 1 : tm->hw[0]->sw_if_index,
3426 : ~0, // invalid fib index
3427 : 1,
3428 : NULL,
3429 : FIB_ROUTE_PATH_FLAG_NONE);
3430 :
3431 : /* suspend so the update walk kicks in */
3432 1 : vlib_process_suspend(vlib_get_main(), 1e-5);
3433 :
3434 1 : FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3435 : "post PIC recovery adj for 200.200.200.200/32 is recursive "
3436 : "via adj for 1.1.1.1");
3437 1 : FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3438 : "post PIC recovery adj for 200.200.200.200/32 is recursive "
3439 : "via adj for 1.1.1.3");
3440 :
3441 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3442 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3443 1 : FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3444 : "post PIC 200.200.200.200/32 was inplace modified");
3445 :
3446 : /*
3447 : * add a 3rd path. this makes the LB 16 buckets.
3448 : */
3449 1 : fib_table_entry_path_add(fib_index,
3450 : &bgp_200_pfx,
3451 : FIB_SOURCE_API,
3452 : FIB_ENTRY_FLAG_NONE,
3453 : DPO_PROTO_IP4,
3454 : &pfx_1_1_1_2_s_32.fp_addr,
3455 : ~0,
3456 : fib_index,
3457 : 1,
3458 : NULL,
3459 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3460 129 : for (ii = 0; ii < N_P; ii++)
3461 : {
3462 128 : fib_table_entry_path_add(fib_index,
3463 128 : &bgp_78s[ii],
3464 : FIB_SOURCE_API,
3465 : FIB_ENTRY_FLAG_NONE,
3466 : DPO_PROTO_IP4,
3467 : &pfx_1_1_1_2_s_32.fp_addr,
3468 : ~0,
3469 : fib_index,
3470 : 1,
3471 : NULL,
3472 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3473 : }
3474 :
3475 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3476 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3477 1 : FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3478 : "200.200.200.200/32 was inplace modified for 3rd path");
3479 1 : FIB_TEST(16 == lb->lb_n_buckets,
3480 : "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3481 :
3482 1 : lbmi = lb->lb_map;
3483 1 : load_balance_map_lock(lbmi);
3484 1 : lbm = load_balance_map_get(lbmi);
3485 :
3486 17 : for (ii = 0; ii < 16; ii++)
3487 : {
3488 16 : FIB_TEST(lbm->lbm_buckets[ii] == ii,
3489 : "LB Map for 200.200.200.200/32 at %d is %d",
3490 : ii, lbm->lbm_buckets[ii]);
3491 : }
3492 :
3493 : /*
3494 : * trigger PIC by removing the first via-entry
3495 : * the first 6 buckets of the map should map to the next 6
3496 : */
3497 1 : fib_table_entry_path_remove(fib_index,
3498 : &pfx_1_1_1_1_s_32,
3499 : FIB_SOURCE_API,
3500 : DPO_PROTO_IP4,
3501 : &nh_10_10_10_1,
3502 1 : tm->hw[0]->sw_if_index,
3503 : ~0,
3504 : 1,
3505 : FIB_ROUTE_PATH_FLAG_NONE);
3506 : /* suspend so the update walk kicks int */
3507 1 : vlib_process_suspend(vlib_get_main(), 1e-5);
3508 :
3509 1 : fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3510 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3511 1 : FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3512 : "200.200.200.200/32 was inplace modified for 3rd path");
3513 1 : FIB_TEST(2 == lb->lb_n_buckets,
3514 : "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3515 :
3516 7 : for (ii = 0; ii < 6; ii++)
3517 : {
3518 6 : FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3519 : "LB Map for 200.200.200.200/32 at %d is %d",
3520 : ii, lbm->lbm_buckets[ii]);
3521 : }
3522 11 : for (ii = 6; ii < 16; ii++)
3523 : {
3524 10 : FIB_TEST(lbm->lbm_buckets[ii] == ii,
3525 : "LB Map for 200.200.200.200/32 at %d is %d",
3526 : ii, lbm->lbm_buckets[ii]);
3527 : }
3528 1 : load_balance_map_unlock(lbmi);
3529 :
3530 : /*
3531 : * tidy up
3532 : */
3533 1 : fib_table_entry_path_add(fib_index,
3534 : &pfx_1_1_1_1_s_32,
3535 : FIB_SOURCE_API,
3536 : FIB_ENTRY_FLAG_NONE,
3537 : DPO_PROTO_IP4,
3538 : &nh_10_10_10_1,
3539 1 : tm->hw[0]->sw_if_index,
3540 : ~0,
3541 : 1,
3542 : NULL,
3543 : FIB_ROUTE_PATH_FLAG_NONE);
3544 :
3545 129 : for (ii = 0; ii < N_P; ii++)
3546 : {
3547 128 : fib_table_entry_delete(fib_index,
3548 128 : &bgp_78s[ii],
3549 : FIB_SOURCE_API);
3550 128 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
3551 : fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3552 : "%U removed",
3553 : format_fib_prefix, &bgp_78s[ii]);
3554 : }
3555 1 : fib_table_entry_path_remove(fib_index,
3556 : &bgp_200_pfx,
3557 : FIB_SOURCE_API,
3558 : DPO_PROTO_IP4,
3559 : &pfx_1_1_1_2_s_32.fp_addr,
3560 : ~0,
3561 : fib_index,
3562 : 1,
3563 : MPLS_LABEL_INVALID);
3564 1 : fib_table_entry_path_remove(fib_index,
3565 : &bgp_200_pfx,
3566 : FIB_SOURCE_API,
3567 : DPO_PROTO_IP4,
3568 : &nh_1_1_1_1,
3569 : ~0,
3570 : fib_index,
3571 : 1,
3572 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3573 1 : fib_table_entry_path_remove(fib_index,
3574 : &bgp_200_pfx,
3575 : FIB_SOURCE_API,
3576 : DPO_PROTO_IP4,
3577 : &pfx_1_1_1_3_s_32.fp_addr,
3578 : ~0,
3579 : fib_index,
3580 : 1,
3581 : FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3582 1 : fib_table_entry_delete(fib_index,
3583 : &pfx_1_1_1_3_s_32,
3584 : FIB_SOURCE_API);
3585 1 : fib_table_entry_delete(fib_index,
3586 : &pfx_1_1_1_0_s_28,
3587 : FIB_SOURCE_API);
3588 : /* suspend so the update walk kicks int */
3589 1 : vlib_process_suspend(vlib_get_main(), 1e-5);
3590 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
3591 : fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3592 : "1.1.1.1/28 removed");
3593 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
3594 : fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3595 : "1.1.1.3/32 removed");
3596 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
3597 : fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3598 : "200.200.200.200/32 removed");
3599 :
3600 : /*
3601 : * add-remove test. no change.
3602 : */
3603 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3604 : fib_path_list_db_size());
3605 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3606 : fib_path_list_pool_size());
3607 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3608 : fib_entry_pool_size());
3609 :
3610 : /*
3611 : * A route whose paths are built up iteratively and then removed
3612 : * all at once
3613 : */
3614 2 : fib_prefix_t pfx_4_4_4_4_s_32 = {
3615 : .fp_len = 32,
3616 : .fp_proto = FIB_PROTOCOL_IP4,
3617 : .fp_addr = {
3618 : /* 4.4.4.4/32 */
3619 1 : .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3620 : },
3621 : };
3622 :
3623 1 : fib_table_entry_path_add(fib_index,
3624 : &pfx_4_4_4_4_s_32,
3625 : FIB_SOURCE_API,
3626 : FIB_ENTRY_FLAG_NONE,
3627 : DPO_PROTO_IP4,
3628 : &nh_10_10_10_1,
3629 1 : tm->hw[0]->sw_if_index,
3630 : ~0,
3631 : 1,
3632 : NULL,
3633 : FIB_ROUTE_PATH_FLAG_NONE);
3634 1 : fib_table_entry_path_add(fib_index,
3635 : &pfx_4_4_4_4_s_32,
3636 : FIB_SOURCE_API,
3637 : FIB_ENTRY_FLAG_NONE,
3638 : DPO_PROTO_IP4,
3639 : &nh_10_10_10_2,
3640 1 : tm->hw[0]->sw_if_index,
3641 : ~0,
3642 : 1,
3643 : NULL,
3644 : FIB_ROUTE_PATH_FLAG_NONE);
3645 1 : fib_table_entry_path_add(fib_index,
3646 : &pfx_4_4_4_4_s_32,
3647 : FIB_SOURCE_API,
3648 : FIB_ENTRY_FLAG_NONE,
3649 : DPO_PROTO_IP4,
3650 : &nh_10_10_10_3,
3651 1 : tm->hw[0]->sw_if_index,
3652 : ~0,
3653 : 1,
3654 : NULL,
3655 : FIB_ROUTE_PATH_FLAG_NONE);
3656 1 : FIB_TEST(FIB_NODE_INDEX_INVALID !=
3657 : fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3658 : "4.4.4.4/32 present");
3659 :
3660 1 : fib_table_entry_delete(fib_index,
3661 : &pfx_4_4_4_4_s_32,
3662 : FIB_SOURCE_API);
3663 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3664 : fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3665 : "4.4.4.4/32 removed");
3666 :
3667 : /*
3668 : * add-remove test. no change.
3669 : */
3670 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3671 : fib_path_list_db_size());
3672 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3673 : fib_path_list_pool_size());
3674 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3675 : fib_entry_pool_size());
3676 :
3677 : /*
3678 : * A route with multiple paths at once
3679 : */
3680 1 : FIB_TEST(0 ==
3681 : fib_test_multipath_v4(tm, fib_index, &pfx_4_4_4_4_s_32, 4, 4),
3682 : "multipath with 4 nexthops");
3683 :
3684 : /*
3685 : * A route with lots of multiple paths that will overflow max supported
3686 : * lb buckets because of normalization
3687 : */
3688 1 : FIB_TEST(0 ==
3689 : fib_test_multipath_v4(tm, fib_index, &pfx_4_4_4_4_s_32,
3690 : LB_MAX_BUCKETS / 2 + 23, LB_MAX_BUCKETS),
3691 : "multipath with too many nexthops");
3692 :
3693 : /*
3694 : * A route with more paths than max supported lb buckets
3695 : */
3696 1 : FIB_TEST(0 ==
3697 : fib_test_multipath_v4 (tm, fib_index, &pfx_4_4_4_4_s_32,
3698 : LB_MAX_BUCKETS + 13, LB_MAX_BUCKETS),
3699 : "multipath with too many nexthops");
3700 :
3701 : /*
3702 : * A route deag route
3703 : */
3704 1 : fib_table_entry_path_add(fib_index,
3705 : &pfx_4_4_4_4_s_32,
3706 : FIB_SOURCE_API,
3707 : FIB_ENTRY_FLAG_NONE,
3708 : DPO_PROTO_IP4,
3709 : &zero_addr,
3710 : ~0,
3711 : fib_index,
3712 : 1,
3713 : NULL,
3714 : FIB_ROUTE_PATH_FLAG_NONE);
3715 :
3716 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3717 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3718 :
3719 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3720 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3721 1 : lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3722 :
3723 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
3724 : "4.4.4.4/32 is deag in %d %U",
3725 : lkd->lkd_fib_index,
3726 : format_dpo_id, dpo, 0);
3727 1 : FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3728 : "4.4.4.4/32 is source deag in %d %U",
3729 : lkd->lkd_input,
3730 : format_dpo_id, dpo, 0);
3731 :
3732 1 : fib_table_entry_delete(fib_index,
3733 : &pfx_4_4_4_4_s_32,
3734 : FIB_SOURCE_API);
3735 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3736 : fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3737 : "4.4.4.4/32 removed");
3738 :
3739 : /*
3740 : * A route deag route in a source lookup table
3741 : */
3742 1 : fib_table_entry_path_add(fib_index,
3743 : &pfx_4_4_4_4_s_32,
3744 : FIB_SOURCE_API,
3745 : FIB_ENTRY_FLAG_NONE,
3746 : DPO_PROTO_IP4,
3747 : &zero_addr,
3748 : ~0,
3749 : fib_index,
3750 : 1,
3751 : NULL,
3752 : FIB_ROUTE_PATH_SOURCE_LOOKUP);
3753 :
3754 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3755 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3756 :
3757 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3758 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3759 1 : lkd = lookup_dpo_get(dpo->dpoi_index);
3760 :
3761 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
3762 : "4.4.4.4/32 is deag in %d %U",
3763 : lkd->lkd_fib_index,
3764 : format_dpo_id, dpo, 0);
3765 1 : FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3766 : "4.4.4.4/32 is source deag in %d %U",
3767 : lkd->lkd_input,
3768 : format_dpo_id, dpo, 0);
3769 :
3770 1 : fib_table_entry_delete(fib_index,
3771 : &pfx_4_4_4_4_s_32,
3772 : FIB_SOURCE_API);
3773 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3774 : fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3775 : "4.4.4.4/32 removed");
3776 :
3777 : /*
3778 : * add-remove test. no change.
3779 : */
3780 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3781 : fib_path_list_db_size());
3782 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3783 : fib_path_list_pool_size());
3784 1 : FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3785 : fib_entry_pool_size());
3786 :
3787 : /*
3788 : * Duplicate paths:
3789 : * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3790 : */
3791 2 : fib_prefix_t pfx_34_1_1_1_s_32 = {
3792 : .fp_len = 32,
3793 : .fp_proto = FIB_PROTOCOL_IP4,
3794 : .fp_addr = {
3795 1 : .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3796 : },
3797 : };
3798 2 : fib_prefix_t pfx_34_34_1_1_s_32 = {
3799 : .fp_len = 32,
3800 : .fp_proto = FIB_PROTOCOL_IP4,
3801 : .fp_addr = {
3802 1 : .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3803 : },
3804 : };
3805 1 : fei = fib_table_entry_path_add(fib_index,
3806 : &pfx_34_34_1_1_s_32,
3807 : FIB_SOURCE_API,
3808 : FIB_ENTRY_FLAG_NONE,
3809 : DPO_PROTO_IP4,
3810 : &nh_10_10_10_1,
3811 1 : tm->hw[0]->sw_if_index,
3812 : 0,
3813 : 1,
3814 : NULL,
3815 : FIB_ROUTE_PATH_FLAG_NONE);
3816 1 : fei = fib_table_entry_path_add(fib_index,
3817 : &pfx_34_1_1_1_s_32,
3818 : FIB_SOURCE_API,
3819 : FIB_ENTRY_FLAG_NONE,
3820 : DPO_PROTO_IP4,
3821 : &pfx_34_34_1_1_s_32.fp_addr,
3822 : ~0,
3823 : fib_index,
3824 : 1,
3825 : NULL,
3826 : FIB_ROUTE_PATH_FLAG_NONE);
3827 1 : fei = fib_table_entry_path_add(fib_index,
3828 : &pfx_34_1_1_1_s_32,
3829 : FIB_SOURCE_API,
3830 : FIB_ENTRY_FLAG_NONE,
3831 : DPO_PROTO_IP4,
3832 : &pfx_34_34_1_1_s_32.fp_addr,
3833 : ~0,
3834 : fib_index,
3835 : 1,
3836 : NULL,
3837 : FIB_ROUTE_PATH_FLAG_NONE);
3838 1 : FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3839 1 : fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3840 1 : fib_table_entry_delete(fib_index,
3841 : &pfx_34_34_1_1_s_32,
3842 : FIB_SOURCE_API);
3843 :
3844 : /*
3845 : * CLEANUP
3846 : * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3847 : * all of which are via 10.10.10.1, Itf1
3848 : */
3849 1 : fib_table_entry_path_remove(fib_index,
3850 : &pfx_1_1_1_2_s_32,
3851 : FIB_SOURCE_API,
3852 : DPO_PROTO_IP4,
3853 : &nh_10_10_10_1,
3854 1 : tm->hw[0]->sw_if_index,
3855 : ~0,
3856 : 1,
3857 : FIB_ROUTE_PATH_FLAG_NONE);
3858 1 : fib_table_entry_path_remove(fib_index,
3859 : &pfx_1_1_1_1_s_32,
3860 : FIB_SOURCE_API,
3861 : DPO_PROTO_IP4,
3862 : &nh_10_10_10_1,
3863 1 : tm->hw[0]->sw_if_index,
3864 : ~0,
3865 : 1,
3866 : FIB_ROUTE_PATH_FLAG_NONE);
3867 1 : fib_table_entry_path_remove(fib_index,
3868 : &pfx_1_1_2_0_s_24,
3869 : FIB_SOURCE_API,
3870 : DPO_PROTO_IP4,
3871 : &nh_10_10_10_1,
3872 1 : tm->hw[0]->sw_if_index,
3873 : ~0,
3874 : 1,
3875 : FIB_ROUTE_PATH_FLAG_NONE);
3876 :
3877 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3878 : fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3879 : "1.1.1.1/32 removed");
3880 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3881 : fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3882 : "1.1.1.2/32 removed");
3883 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
3884 : fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3885 : "1.1.2.0/24 removed");
3886 :
3887 : /*
3888 : * -3 entries and -1 shared path-list
3889 : */
3890 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3891 : fib_path_list_db_size());
3892 1 : FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3893 : fib_path_list_pool_size());
3894 1 : FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3895 : fib_entry_pool_size());
3896 :
3897 : /*
3898 : * An attached-host route. Expect to link to the incomplete adj
3899 : */
3900 2 : fib_prefix_t pfx_4_1_1_1_s_32 = {
3901 : .fp_len = 32,
3902 : .fp_proto = FIB_PROTOCOL_IP4,
3903 : .fp_addr = {
3904 : /* 4.1.1.1/32 */
3905 1 : .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3906 : },
3907 : };
3908 1 : fib_table_entry_path_add(fib_index,
3909 : &pfx_4_1_1_1_s_32,
3910 : FIB_SOURCE_API,
3911 : FIB_ENTRY_FLAG_NONE,
3912 : DPO_PROTO_IP4,
3913 : &zero_addr,
3914 1 : tm->hw[0]->sw_if_index,
3915 : fib_index,
3916 : 1,
3917 : NULL,
3918 : FIB_ROUTE_PATH_FLAG_NONE);
3919 :
3920 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3921 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3922 1 : ai = fib_entry_get_adj(fei);
3923 :
3924 1 : ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3925 : VNET_LINK_IP4,
3926 : &pfx_4_1_1_1_s_32.fp_addr,
3927 1 : tm->hw[0]->sw_if_index);
3928 1 : FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3929 1 : adj_unlock(ai2);
3930 :
3931 : /*
3932 : * +1 entry and +1 shared path-list
3933 : */
3934 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3935 : fib_path_list_db_size());
3936 1 : FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3937 : fib_path_list_pool_size());
3938 1 : FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3939 : fib_entry_pool_size());
3940 :
3941 1 : fib_table_entry_delete(fib_index,
3942 : &pfx_4_1_1_1_s_32,
3943 : FIB_SOURCE_API);
3944 :
3945 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3946 : fib_path_list_db_size());
3947 1 : FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3948 : fib_path_list_pool_size());
3949 1 : FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3950 : fib_entry_pool_size());
3951 :
3952 : /*
3953 : * add a v6 prefix via v4 next-hops
3954 : */
3955 2 : fib_prefix_t pfx_2001_s_64 = {
3956 : .fp_len = 64,
3957 : .fp_proto = FIB_PROTOCOL_IP6,
3958 : .fp_addr = {
3959 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3960 : },
3961 : };
3962 1 : fei = fib_table_entry_path_add(0, //default v6 table
3963 : &pfx_2001_s_64,
3964 : FIB_SOURCE_API,
3965 : FIB_ENTRY_FLAG_NONE,
3966 : DPO_PROTO_IP4,
3967 : &nh_10_10_10_1,
3968 1 : tm->hw[0]->sw_if_index,
3969 : fib_index,
3970 : 1,
3971 : NULL,
3972 : FIB_ROUTE_PATH_FLAG_NONE);
3973 :
3974 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3975 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3976 1 : ai = fib_entry_get_adj(fei);
3977 1 : adj = adj_get(ai);
3978 1 : FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3979 : "2001::/64 via ARP-adj");
3980 1 : FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3981 : "2001::/64 is link type v6");
3982 1 : FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3983 : "2001::/64 ADJ-adj is NH proto v4");
3984 1 : fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3985 :
3986 : /*
3987 : * add a uRPF exempt prefix:
3988 : * test:
3989 : * - it's forwarding is drop
3990 : * - it's uRPF list is not empty
3991 : * - the uRPF list for the default route (it's cover) is empty
3992 : */
3993 1 : fei = fib_table_entry_special_add(fib_index,
3994 : &pfx_4_1_1_1_s_32,
3995 : FIB_SOURCE_URPF_EXEMPT,
3996 : FIB_ENTRY_FLAG_DROP);
3997 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
3998 1 : FIB_TEST(load_balance_is_drop(dpo),
3999 : "uRPF exempt 4.1.1.1/32 DROP");
4000 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
4001 : "uRPF list for exempt prefix has itf index 0");
4002 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
4003 1 : FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
4004 : "uRPF list for 0.0.0.0/0 empty");
4005 :
4006 1 : fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
4007 :
4008 : /*
4009 : * An adj-fib that fails the refinement criteria - no connected cover
4010 : */
4011 2 : fib_prefix_t pfx_12_10_10_2_s_32 = {
4012 : .fp_len = 32,
4013 : .fp_proto = FIB_PROTOCOL_IP4,
4014 : .fp_addr = {
4015 : /* 12.10.10.2 */
4016 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
4017 : },
4018 : };
4019 :
4020 1 : fib_table_entry_path_add(fib_index,
4021 : &pfx_12_10_10_2_s_32,
4022 : FIB_SOURCE_ADJ,
4023 : FIB_ENTRY_FLAG_ATTACHED,
4024 : DPO_PROTO_IP4,
4025 : &pfx_12_10_10_2_s_32.fp_addr,
4026 1 : tm->hw[0]->sw_if_index,
4027 : ~0, // invalid fib index
4028 : 1,
4029 : NULL,
4030 : FIB_ROUTE_PATH_FLAG_NONE);
4031 :
4032 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
4033 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4034 1 : FIB_TEST(dpo_is_drop(dpo),
4035 : "no connected cover adj-fib fails refinement: %U",
4036 : format_dpo_id, dpo, 0);
4037 :
4038 1 : fib_table_entry_delete(fib_index,
4039 : &pfx_12_10_10_2_s_32,
4040 : FIB_SOURCE_ADJ);
4041 :
4042 : /*
4043 : * An adj-fib that fails the refinement criteria - cover is connected
4044 : * but on a different interface
4045 : */
4046 2 : fib_prefix_t pfx_10_10_10_127_s_32 = {
4047 : .fp_len = 32,
4048 : .fp_proto = FIB_PROTOCOL_IP4,
4049 : .fp_addr = {
4050 : /* 10.10.10.127 */
4051 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
4052 : },
4053 : };
4054 :
4055 1 : fib_table_entry_path_add(fib_index,
4056 : &pfx_10_10_10_127_s_32,
4057 : FIB_SOURCE_ADJ,
4058 : FIB_ENTRY_FLAG_ATTACHED,
4059 : DPO_PROTO_IP4,
4060 : &pfx_10_10_10_127_s_32.fp_addr,
4061 1 : tm->hw[1]->sw_if_index,
4062 : ~0, // invalid fib index
4063 : 1,
4064 : NULL,
4065 : FIB_ROUTE_PATH_FLAG_NONE);
4066 :
4067 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
4068 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4069 1 : FIB_TEST(dpo_is_drop(dpo),
4070 : "wrong interface adj-fib fails refinement");
4071 :
4072 1 : fib_table_entry_delete(fib_index,
4073 : &pfx_10_10_10_127_s_32,
4074 : FIB_SOURCE_ADJ);
4075 :
4076 : /*
4077 : * add a second path to an adj-fib
4078 : * this is a sumiluation of another ARP entry created
4079 : * on an interface on which the connected prefix does not exist.
4080 : * The second path fails refinement. Expect to forward through the
4081 : * first.
4082 : */
4083 2 : fib_prefix_t pfx_10_10_10_3_s_32 = {
4084 : .fp_len = 32,
4085 : .fp_proto = FIB_PROTOCOL_IP4,
4086 : .fp_addr = {
4087 : /* 10.10.10.3 */
4088 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4089 : },
4090 : };
4091 :
4092 1 : ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4093 : VNET_LINK_IP4,
4094 : &nh_10_10_10_3,
4095 1 : tm->hw[0]->sw_if_index);
4096 :
4097 1 : fib_test_lb_bucket_t ip_o_10_10_10_3 = {
4098 : .type = FT_LB_ADJ,
4099 : .adj = {
4100 : .adj = ai_03,
4101 : },
4102 : };
4103 1 : fei = fib_table_entry_path_add(fib_index,
4104 : &pfx_10_10_10_3_s_32,
4105 : FIB_SOURCE_ADJ,
4106 : FIB_ENTRY_FLAG_NONE,
4107 : DPO_PROTO_IP4,
4108 : &nh_10_10_10_3,
4109 1 : tm->hw[0]->sw_if_index,
4110 : fib_index,
4111 : 1,
4112 : NULL,
4113 : FIB_ROUTE_PATH_FLAG_NONE);
4114 1 : fei = fib_table_entry_path_add(fib_index,
4115 : &pfx_10_10_10_3_s_32,
4116 : FIB_SOURCE_ADJ,
4117 : FIB_ENTRY_FLAG_NONE,
4118 : DPO_PROTO_IP4,
4119 : &nh_12_12_12_12,
4120 1 : tm->hw[1]->sw_if_index,
4121 : fib_index,
4122 : 1,
4123 : NULL,
4124 : FIB_ROUTE_PATH_FLAG_NONE);
4125 1 : FIB_TEST(!fib_test_validate_entry(fei,
4126 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4127 : 1,
4128 : &ip_o_10_10_10_3),
4129 : "10.10.10.3 via 10.10.10.3/Eth0 only");
4130 :
4131 : /*
4132 : * remove the path that refines the cover, should go unresolved
4133 : */
4134 1 : fib_table_entry_path_remove(fib_index,
4135 : &pfx_10_10_10_3_s_32,
4136 : FIB_SOURCE_ADJ,
4137 : DPO_PROTO_IP4,
4138 : &nh_10_10_10_3,
4139 1 : tm->hw[0]->sw_if_index,
4140 : fib_index,
4141 : 1,
4142 : FIB_ROUTE_PATH_FLAG_NONE);
4143 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4144 1 : FIB_TEST(dpo_is_drop(dpo),
4145 : "wrong interface adj-fib fails refinement");
4146 :
4147 : /*
4148 : * add back the path that refines the cover
4149 : */
4150 1 : fei = fib_table_entry_path_add(fib_index,
4151 : &pfx_10_10_10_3_s_32,
4152 : FIB_SOURCE_ADJ,
4153 : FIB_ENTRY_FLAG_NONE,
4154 : DPO_PROTO_IP4,
4155 : &nh_10_10_10_3,
4156 1 : tm->hw[0]->sw_if_index,
4157 : fib_index,
4158 : 1,
4159 : NULL,
4160 : FIB_ROUTE_PATH_FLAG_NONE);
4161 1 : FIB_TEST(!fib_test_validate_entry(fei,
4162 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4163 : 1,
4164 : &ip_o_10_10_10_3),
4165 : "10.10.10.3 via 10.10.10.3/Eth0 only");
4166 :
4167 : /*
4168 : * remove the path that does not refine the cover
4169 : */
4170 1 : fib_table_entry_path_remove(fib_index,
4171 : &pfx_10_10_10_3_s_32,
4172 : FIB_SOURCE_ADJ,
4173 : DPO_PROTO_IP4,
4174 : &nh_12_12_12_12,
4175 1 : tm->hw[1]->sw_if_index,
4176 : fib_index,
4177 : 1,
4178 : FIB_ROUTE_PATH_FLAG_NONE);
4179 1 : FIB_TEST(!fib_test_validate_entry(fei,
4180 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4181 : 1,
4182 : &ip_o_10_10_10_3),
4183 : "10.10.10.3 via 10.10.10.3/Eth0 only");
4184 :
4185 : /*
4186 : * remove the path that does refine, it's the last path, so
4187 : * the entry should be gone
4188 : */
4189 1 : fib_table_entry_path_remove(fib_index,
4190 : &pfx_10_10_10_3_s_32,
4191 : FIB_SOURCE_ADJ,
4192 : DPO_PROTO_IP4,
4193 : &nh_10_10_10_3,
4194 1 : tm->hw[0]->sw_if_index,
4195 : fib_index,
4196 : 1,
4197 : FIB_ROUTE_PATH_FLAG_NONE);
4198 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4199 1 : FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4200 :
4201 1 : adj_unlock(ai_03);
4202 :
4203 : /*
4204 : * change the table's flow-hash config - expect the update to propagete to
4205 : * the entries' load-balance objects
4206 : */
4207 : flow_hash_config_t old_hash_config, new_hash_config;
4208 :
4209 1 : old_hash_config = fib_table_get_flow_hash_config(fib_index,
4210 : FIB_PROTOCOL_IP4);
4211 1 : new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4212 : IP_FLOW_HASH_DST_ADDR);
4213 :
4214 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4215 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4216 1 : lb = load_balance_get(dpo->dpoi_index);
4217 1 : FIB_TEST((lb->lb_hash_config == old_hash_config),
4218 : "Table and LB hash config match: %U",
4219 : format_ip_flow_hash_config, lb->lb_hash_config);
4220 :
4221 1 : fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4222 :
4223 1 : FIB_TEST((lb->lb_hash_config == new_hash_config),
4224 : "Table and LB newhash config match: %U",
4225 : format_ip_flow_hash_config, lb->lb_hash_config);
4226 :
4227 : /*
4228 : * A route via DVR DPO
4229 : */
4230 1 : fei = fib_table_entry_path_add(fib_index,
4231 : &pfx_10_10_10_3_s_32,
4232 : FIB_SOURCE_API,
4233 : FIB_ENTRY_FLAG_NONE,
4234 : DPO_PROTO_IP4,
4235 : &zero_addr,
4236 1 : tm->hw[0]->sw_if_index,
4237 : ~0,
4238 : 1,
4239 : NULL,
4240 : FIB_ROUTE_PATH_DVR);
4241 1 : dpo_id_t dvr_dpo = DPO_INVALID;
4242 1 : dvr_dpo_add_or_lock(tm->hw[0]->sw_if_index, DPO_PROTO_IP4, &dvr_dpo);
4243 1 : fib_test_lb_bucket_t ip_o_l2 = {
4244 : .type = FT_LB_L2,
4245 : .adj = {
4246 1 : .adj = dvr_dpo.dpoi_index,
4247 : },
4248 : };
4249 :
4250 1 : FIB_TEST(!fib_test_validate_entry(fei,
4251 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4252 : 1,
4253 : &ip_o_l2),
4254 : "10.10.10.3 via L2 on Eth0");
4255 1 : fib_table_entry_path_remove(fib_index,
4256 : &pfx_10_10_10_3_s_32,
4257 : FIB_SOURCE_API,
4258 : DPO_PROTO_IP4,
4259 : &zero_addr,
4260 1 : tm->hw[0]->sw_if_index,
4261 : fib_index,
4262 : 1,
4263 : FIB_ROUTE_PATH_DVR);
4264 1 : dpo_reset(&dvr_dpo);
4265 :
4266 : /*
4267 : * add the default route via a next-hop that will form a loop
4268 : */
4269 2 : fib_prefix_t pfx_conn = {
4270 : .fp_len = 24,
4271 : .fp_proto = FIB_PROTOCOL_IP4,
4272 : .fp_addr = {
4273 : /* 30.30.30.30 */
4274 1 : .ip4.as_u32 = clib_host_to_net_u32(0x1e1e1e1e),
4275 : },
4276 : };
4277 :
4278 1 : dfrt = fib_table_entry_path_add(fib_index,
4279 : &pfx_0_0_0_0_s_0,
4280 : FIB_SOURCE_API,
4281 : FIB_ENTRY_FLAG_NONE,
4282 : DPO_PROTO_IP4,
4283 : &pfx_conn.fp_addr,
4284 : ~0,
4285 : fib_index,
4286 : 1,
4287 : NULL,
4288 : FIB_ROUTE_PATH_FLAG_NONE);
4289 : /*
4290 : * the default route is a drop, since it's looped
4291 : */
4292 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4293 : "Default route is DROP");
4294 :
4295 : /*
4296 : * add a connected cover for the next-hop, this breaks the recursion loop
4297 : * for the default route
4298 : */
4299 1 : fib_table_entry_path_add(fib_index,
4300 : &pfx_conn,
4301 : FIB_SOURCE_API,
4302 : (FIB_ENTRY_FLAG_CONNECTED |
4303 : FIB_ENTRY_FLAG_ATTACHED),
4304 : DPO_PROTO_IP4,
4305 : NULL,
4306 1 : tm->hw[0]->sw_if_index,
4307 : ~0,
4308 : 1,
4309 : NULL,
4310 : FIB_ROUTE_PATH_FLAG_NONE);
4311 1 : pfx_conn.fp_len = 32;
4312 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_conn);
4313 :
4314 1 : u32 ai_30 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4315 : VNET_LINK_IP4,
4316 : &pfx_conn.fp_addr,
4317 1 : tm->hw[0]->sw_if_index);
4318 :
4319 1 : fib_test_lb_bucket_t ip_o_30_30_30_30 = {
4320 : .type = FT_LB_ADJ,
4321 : .adj = {
4322 : .adj = ai_30,
4323 : },
4324 : };
4325 1 : FIB_TEST(!fib_test_validate_entry(fei,
4326 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4327 : 1,
4328 : &ip_o_30_30_30_30),
4329 : "30.30.30.30 via adj");
4330 1 : FIB_TEST_REC_FORW(&pfx_0_0_0_0_s_0, &pfx_conn, 0);
4331 :
4332 1 : pfx_conn.fp_len = 24;
4333 1 : fib_table_entry_delete(fib_index,
4334 : &pfx_conn,
4335 : FIB_SOURCE_API);
4336 1 : fib_table_entry_delete(fib_index,
4337 : &pfx_0_0_0_0_s_0,
4338 : FIB_SOURCE_API);
4339 1 : adj_unlock(ai_30);
4340 :
4341 : /*
4342 : * CLEANUP
4343 : * remove adj-fibs:
4344 : */
4345 1 : fib_table_entry_delete(fib_index,
4346 : &pfx_10_10_10_1_s_32,
4347 : FIB_SOURCE_ADJ);
4348 1 : fib_table_entry_delete(fib_index,
4349 : &pfx_10_10_10_2_s_32,
4350 : FIB_SOURCE_ADJ);
4351 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
4352 : fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4353 : "10.10.10.1/32 adj-fib removed");
4354 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
4355 : fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4356 : "10.10.10.2/32 adj-fib removed");
4357 :
4358 : /*
4359 : * -2 entries and -2 non-shared path-list
4360 : */
4361 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4362 : fib_path_list_db_size());
4363 1 : FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4364 : fib_path_list_pool_size());
4365 1 : FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4366 : fib_entry_pool_size());
4367 :
4368 : /*
4369 : * unlock the adjacencies for which this test provided a rewrite.
4370 : * These are the last locks on these adjs. they should thus go away.
4371 : */
4372 1 : adj_unlock(ai_02);
4373 1 : adj_unlock(ai_01);
4374 1 : adj_unlock(ai_12_12_12_12);
4375 :
4376 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4377 : adj_nbr_db_size());
4378 :
4379 : /*
4380 : * CLEANUP
4381 : * remove the interface prefixes
4382 : */
4383 1 : local_pfx.fp_len = 32;
4384 1 : fib_table_entry_special_remove(fib_index, &local_pfx,
4385 : FIB_SOURCE_INTERFACE);
4386 1 : fei = fib_table_lookup(fib_index, &local_pfx);
4387 :
4388 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
4389 : fib_table_lookup_exact_match(fib_index, &local_pfx),
4390 : "10.10.10.10/32 adj-fib removed");
4391 :
4392 1 : local_pfx.fp_len = 24;
4393 1 : fib_table_entry_delete(fib_index, &local_pfx,
4394 : FIB_SOURCE_INTERFACE);
4395 :
4396 1 : FIB_TEST(FIB_NODE_INDEX_INVALID ==
4397 : fib_table_lookup_exact_match(fib_index, &local_pfx),
4398 : "10.10.10.10/24 adj-fib removed");
4399 :
4400 : /*
4401 : * -2 entries and -2 non-shared path-list
4402 : */
4403 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4404 : fib_path_list_db_size());
4405 1 : FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4406 : fib_path_list_pool_size());
4407 1 : FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4408 : fib_entry_pool_size());
4409 :
4410 : /*
4411 : * Last but not least, remove the VRF
4412 : */
4413 1 : FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4414 : FIB_PROTOCOL_IP4,
4415 : FIB_SOURCE_API)),
4416 : "NO API Source'd prefixes");
4417 1 : FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4418 : FIB_PROTOCOL_IP4,
4419 : FIB_SOURCE_RR)),
4420 : "NO RR Source'd prefixes");
4421 1 : FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4422 : FIB_PROTOCOL_IP4,
4423 : FIB_SOURCE_INTERFACE)),
4424 : "NO INterface Source'd prefixes");
4425 :
4426 5 : for (ii = 0; ii < 4; ii++)
4427 4 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[ii]->sw_if_index, 0);
4428 :
4429 1 : fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4430 :
4431 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4432 : fib_path_list_db_size());
4433 1 : FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4434 : fib_path_list_pool_size());
4435 1 : FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4436 : fib_entry_pool_size());
4437 1 : FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4438 : pool_elts(fib_urpf_list_pool));
4439 1 : FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4440 : pool_elts(load_balance_map_pool));
4441 1 : FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4442 : pool_elts(load_balance_pool));
4443 1 : FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
4444 : pool_elts(dvr_dpo_pool));
4445 :
4446 1 : return (res);
4447 : }
4448 :
4449 : static int
4450 1 : fib_test_v6 (void)
4451 : {
4452 : /*
4453 : * In the default table check for the presence and correct forwarding
4454 : * of the special entries
4455 : */
4456 : fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4457 : const dpo_id_t *dpo, *dpo_drop;
4458 : const ip_adjacency_t *adj;
4459 : const receive_dpo_t *rd;
4460 : test_main_t *tm;
4461 : u32 fib_index;
4462 : int ii, res;
4463 :
4464 1 : res = 0;
4465 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4466 : adj_nbr_db_size());
4467 :
4468 : /* via 2001:0:0:1::2 */
4469 2 : ip46_address_t nh_2001_2 = {
4470 : .ip6 = {
4471 : .as_u64 = {
4472 1 : [0] = clib_host_to_net_u64(0x2001000000000001),
4473 1 : [1] = clib_host_to_net_u64(0x0000000000000002),
4474 : },
4475 : },
4476 : };
4477 :
4478 1 : tm = &test_main;
4479 :
4480 1 : dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4481 :
4482 : /* Find or create FIB table 11 */
4483 1 : fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4484 : FIB_SOURCE_API);
4485 :
4486 5 : for (ii = 0; ii < 4; ii++)
4487 4 : fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[ii]->sw_if_index, fib_index);
4488 :
4489 1 : fib_prefix_t pfx_0_0 = {
4490 : .fp_len = 0,
4491 : .fp_proto = FIB_PROTOCOL_IP6,
4492 : .fp_addr = {
4493 : .ip6 = {
4494 : {0, 0},
4495 : },
4496 : },
4497 : };
4498 :
4499 1 : dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4500 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4501 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4502 : "Default route is DROP");
4503 :
4504 1 : dpo = fib_entry_contribute_ip_forwarding(dfrt);
4505 1 : FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4506 : 1,
4507 : &pfx_0_0.fp_addr.ip6)),
4508 : "default-route; fwd and non-fwd tables match");
4509 :
4510 : // FIXME - check specials.
4511 :
4512 : /*
4513 : * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4514 : * each with 2 entries and a v6 mfib with 4 path-lists and v4 mfib with 2.
4515 : * All entries are special so no path-list sharing.
4516 : */
4517 : #define ENPS (5+4)
4518 1 : u32 PNPS = (5+4+4+2);
4519 : /*
4520 : * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
4521 : */
4522 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4523 1 : FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4524 : fib_path_list_pool_size());
4525 1 : FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4526 : fib_entry_pool_size());
4527 :
4528 : /*
4529 : * add interface routes.
4530 : * validate presence of /64 attached and /128 recieve.
4531 : * test for the presence of the receive address in the glean and local adj
4532 : *
4533 : * receive on 2001:0:0:1::1/128
4534 : */
4535 3 : fib_prefix_t local_pfx = {
4536 : .fp_len = 64,
4537 : .fp_proto = FIB_PROTOCOL_IP6,
4538 : .fp_addr = {
4539 : .ip6 = {
4540 : .as_u64 = {
4541 1 : [0] = clib_host_to_net_u64(0x2001000000000001),
4542 1 : [1] = clib_host_to_net_u64(0x0000000000000001),
4543 : },
4544 : },
4545 : }
4546 : };
4547 :
4548 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
4549 : FIB_SOURCE_INTERFACE,
4550 : (FIB_ENTRY_FLAG_CONNECTED |
4551 : FIB_ENTRY_FLAG_ATTACHED),
4552 : DPO_PROTO_IP6,
4553 : NULL,
4554 1 : tm->hw[0]->sw_if_index,
4555 : ~0,
4556 : 1,
4557 : NULL,
4558 : FIB_ROUTE_PATH_FLAG_NONE);
4559 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4560 :
4561 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4562 :
4563 1 : ai = fib_entry_get_adj(fei);
4564 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4565 1 : adj = adj_get(ai);
4566 1 : FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4567 : "attached interface adj is glean");
4568 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4569 1 : FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4570 : 1,
4571 : &local_pfx.fp_addr.ip6)),
4572 : "attached-route; fwd and non-fwd tables match");
4573 :
4574 1 : local_pfx.fp_len = 128;
4575 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
4576 : FIB_SOURCE_INTERFACE,
4577 : (FIB_ENTRY_FLAG_CONNECTED |
4578 : FIB_ENTRY_FLAG_LOCAL),
4579 : DPO_PROTO_IP6,
4580 : NULL,
4581 1 : tm->hw[0]->sw_if_index,
4582 : ~0, // invalid fib index
4583 : 1,
4584 : NULL,
4585 : FIB_ROUTE_PATH_FLAG_NONE);
4586 1 : fei = fib_table_lookup(fib_index, &local_pfx);
4587 :
4588 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4589 :
4590 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4591 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4592 1 : FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4593 : "local interface adj is local");
4594 1 : rd = receive_dpo_get(dpo->dpoi_index);
4595 :
4596 1 : FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4597 : &rd->rd_addr)),
4598 : "local interface adj is receive ok");
4599 :
4600 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4601 1 : FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4602 : 1,
4603 : &local_pfx.fp_addr.ip6)),
4604 : "local-route; fwd and non-fwd tables match");
4605 1 : FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4606 : &adj->sub_type.glean.rx_pfx.fp_addr)),
4607 : "attached interface adj is receive ok");
4608 :
4609 : /*
4610 : * +2 entries. +2 unshared path-lists
4611 : */
4612 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4613 1 : FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4614 : fib_path_list_pool_size());
4615 1 : FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4616 : fib_entry_pool_size());
4617 :
4618 : /*
4619 : * Modify the default route to be via an adj not yet known.
4620 : * this sources the defalut route with the API source, which is
4621 : * a higher preference to the DEFAULT_ROUTE source
4622 : */
4623 1 : fib_table_entry_path_add(fib_index, &pfx_0_0,
4624 : FIB_SOURCE_API,
4625 : FIB_ENTRY_FLAG_NONE,
4626 : DPO_PROTO_IP6,
4627 : &nh_2001_2,
4628 1 : tm->hw[0]->sw_if_index,
4629 : ~0,
4630 : 1,
4631 : NULL,
4632 : FIB_ROUTE_PATH_FLAG_NONE);
4633 1 : fei = fib_table_lookup(fib_index, &pfx_0_0);
4634 :
4635 1 : FIB_TEST((fei == dfrt), "default route same index");
4636 1 : ai = fib_entry_get_adj(fei);
4637 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4638 1 : adj = adj_get(ai);
4639 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4640 : "adj is incomplete");
4641 1 : FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4642 : "adj nbr next-hop ok");
4643 :
4644 : /*
4645 : * find the adj in the shared db
4646 : */
4647 1 : locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4648 : VNET_LINK_IP6,
4649 : &nh_2001_2,
4650 1 : tm->hw[0]->sw_if_index);
4651 1 : FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4652 1 : adj_unlock(locked_ai);
4653 :
4654 : /*
4655 : * no more entries. +1 shared path-list
4656 : */
4657 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4658 : fib_path_list_db_size());
4659 1 : FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4660 : fib_path_list_pool_size());
4661 1 : FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4662 : fib_entry_pool_size());
4663 :
4664 : /*
4665 : * remove the API source from the default route. We expected
4666 : * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4667 : */
4668 1 : fib_table_entry_path_remove(fib_index, &pfx_0_0,
4669 : FIB_SOURCE_API,
4670 : DPO_PROTO_IP6,
4671 : &nh_2001_2,
4672 1 : tm->hw[0]->sw_if_index,
4673 : ~0,
4674 : 1,
4675 : FIB_ROUTE_PATH_FLAG_NONE);
4676 1 : fei = fib_table_lookup(fib_index, &pfx_0_0);
4677 :
4678 1 : FIB_TEST((fei == dfrt), "default route same index");
4679 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4680 : "Default route is DROP");
4681 :
4682 : /*
4683 : * no more entries. -1 shared path-list
4684 : */
4685 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4686 : fib_path_list_db_size());
4687 1 : FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4688 : fib_path_list_pool_size());
4689 1 : FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4690 : fib_entry_pool_size());
4691 :
4692 : /*
4693 : * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4694 : */
4695 3 : fib_prefix_t pfx_2001_1_2_s_128 = {
4696 : .fp_len = 128,
4697 : .fp_proto = FIB_PROTOCOL_IP6,
4698 : .fp_addr = {
4699 : .ip6 = {
4700 : .as_u64 = {
4701 1 : [0] = clib_host_to_net_u64(0x2001000000000001),
4702 1 : [1] = clib_host_to_net_u64(0x0000000000000002),
4703 : },
4704 : },
4705 : }
4706 : };
4707 3 : fib_prefix_t pfx_2001_1_3_s_128 = {
4708 : .fp_len = 128,
4709 : .fp_proto = FIB_PROTOCOL_IP6,
4710 : .fp_addr = {
4711 : .ip6 = {
4712 : .as_u64 = {
4713 1 : [0] = clib_host_to_net_u64(0x2001000000000001),
4714 1 : [1] = clib_host_to_net_u64(0x0000000000000003),
4715 : },
4716 : },
4717 : }
4718 : };
4719 1 : u8 eth_addr[] = {
4720 : 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4721 : };
4722 :
4723 1 : ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4724 : VNET_LINK_IP6,
4725 : &pfx_2001_1_2_s_128.fp_addr,
4726 1 : tm->hw[0]->sw_if_index);
4727 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4728 1 : adj = adj_get(ai_01);
4729 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4730 : "adj is incomplete");
4731 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4732 : &adj->sub_type.nbr.next_hop)),
4733 : "adj nbr next-hop ok");
4734 :
4735 1 : adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4736 : fib_test_build_rewrite(eth_addr));
4737 1 : FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4738 : "adj is complete");
4739 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4740 : &adj->sub_type.nbr.next_hop)),
4741 : "adj nbr next-hop ok");
4742 :
4743 1 : fib_table_entry_path_add(fib_index,
4744 : &pfx_2001_1_2_s_128,
4745 : FIB_SOURCE_ADJ,
4746 : FIB_ENTRY_FLAG_ATTACHED,
4747 : DPO_PROTO_IP6,
4748 : &pfx_2001_1_2_s_128.fp_addr,
4749 1 : tm->hw[0]->sw_if_index,
4750 : ~0,
4751 : 1,
4752 : NULL,
4753 : FIB_ROUTE_PATH_FLAG_NONE);
4754 :
4755 1 : fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4756 1 : ai = fib_entry_get_adj(fei);
4757 1 : FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4758 :
4759 1 : eth_addr[5] = 0xb2;
4760 :
4761 1 : ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4762 : VNET_LINK_IP6,
4763 : &pfx_2001_1_3_s_128.fp_addr,
4764 1 : tm->hw[0]->sw_if_index);
4765 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4766 1 : adj = adj_get(ai_02);
4767 1 : FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4768 : "adj is incomplete");
4769 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4770 : &adj->sub_type.nbr.next_hop)),
4771 : "adj nbr next-hop ok");
4772 :
4773 1 : adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4774 : fib_test_build_rewrite(eth_addr));
4775 1 : FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4776 : "adj is complete");
4777 1 : FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4778 : &adj->sub_type.nbr.next_hop)),
4779 : "adj nbr next-hop ok");
4780 1 : FIB_TEST((ai_01 != ai_02), "ADJs are different");
4781 :
4782 1 : fib_table_entry_path_add(fib_index,
4783 : &pfx_2001_1_3_s_128,
4784 : FIB_SOURCE_ADJ,
4785 : FIB_ENTRY_FLAG_ATTACHED,
4786 : DPO_PROTO_IP6,
4787 : &pfx_2001_1_3_s_128.fp_addr,
4788 1 : tm->hw[0]->sw_if_index,
4789 : ~0,
4790 : 1,
4791 : NULL,
4792 : FIB_ROUTE_PATH_FLAG_NONE);
4793 :
4794 1 : fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4795 1 : ai = fib_entry_get_adj(fei);
4796 1 : FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4797 :
4798 : /*
4799 : * +2 entries, +2 unshread path-lists.
4800 : */
4801 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4802 : fib_path_list_db_size());
4803 1 : FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4804 : fib_path_list_pool_size());
4805 1 : FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4806 : fib_entry_pool_size());
4807 :
4808 : /*
4809 : * Add a 2 routes via the first ADJ. ensure path-list sharing
4810 : */
4811 3 : fib_prefix_t pfx_2001_a_s_64 = {
4812 : .fp_len = 64,
4813 : .fp_proto = FIB_PROTOCOL_IP6,
4814 : .fp_addr = {
4815 : .ip6 = {
4816 : .as_u64 = {
4817 1 : [0] = clib_host_to_net_u64(0x200100000000000a),
4818 1 : [1] = clib_host_to_net_u64(0x0000000000000000),
4819 : },
4820 : },
4821 : }
4822 : };
4823 3 : fib_prefix_t pfx_2001_b_s_64 = {
4824 : .fp_len = 64,
4825 : .fp_proto = FIB_PROTOCOL_IP6,
4826 : .fp_addr = {
4827 : .ip6 = {
4828 : .as_u64 = {
4829 1 : [0] = clib_host_to_net_u64(0x200100000000000b),
4830 1 : [1] = clib_host_to_net_u64(0x0000000000000000),
4831 : },
4832 : },
4833 : }
4834 : };
4835 :
4836 1 : fib_table_entry_path_add(fib_index,
4837 : &pfx_2001_a_s_64,
4838 : FIB_SOURCE_API,
4839 : FIB_ENTRY_FLAG_NONE,
4840 : DPO_PROTO_IP6,
4841 : &nh_2001_2,
4842 1 : tm->hw[0]->sw_if_index,
4843 : ~0,
4844 : 1,
4845 : NULL,
4846 : FIB_ROUTE_PATH_FLAG_NONE);
4847 1 : fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4848 1 : ai = fib_entry_get_adj(fei);
4849 1 : FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4850 1 : fib_table_entry_path_add(fib_index,
4851 : &pfx_2001_b_s_64,
4852 : FIB_SOURCE_API,
4853 : FIB_ENTRY_FLAG_NONE,
4854 : DPO_PROTO_IP6,
4855 : &nh_2001_2,
4856 1 : tm->hw[0]->sw_if_index,
4857 : ~0,
4858 : 1,
4859 : NULL,
4860 : FIB_ROUTE_PATH_FLAG_NONE);
4861 1 : fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4862 1 : ai = fib_entry_get_adj(fei);
4863 1 : FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4864 :
4865 : /*
4866 : * +2 entries, +1 shared path-list.
4867 : */
4868 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4869 : fib_path_list_db_size());
4870 1 : FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4871 : fib_path_list_pool_size());
4872 1 : FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4873 : fib_entry_pool_size());
4874 :
4875 : /*
4876 : * add a v4 prefix via a v6 next-hop
4877 : */
4878 1 : fib_prefix_t pfx_1_1_1_1_s_32 = {
4879 : .fp_len = 32,
4880 : .fp_proto = FIB_PROTOCOL_IP4,
4881 : .fp_addr = {
4882 : .ip4.as_u32 = 0x01010101,
4883 : },
4884 : };
4885 1 : fei = fib_table_entry_path_add(0, // default table
4886 : &pfx_1_1_1_1_s_32,
4887 : FIB_SOURCE_API,
4888 : FIB_ENTRY_FLAG_NONE,
4889 : DPO_PROTO_IP6,
4890 : &nh_2001_2,
4891 1 : tm->hw[0]->sw_if_index,
4892 : ~0,
4893 : 1,
4894 : NULL,
4895 : FIB_ROUTE_PATH_FLAG_NONE);
4896 1 : FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4897 : "1.1.1.1/32 o v6 route present");
4898 1 : ai = fib_entry_get_adj(fei);
4899 1 : adj = adj_get(ai);
4900 1 : FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4901 : "1.1.1.1/32 via ARP-adj");
4902 1 : FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4903 : "1.1.1.1/32 ADJ-adj is link type v4");
4904 1 : FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4905 : "1.1.1.1/32 ADJ-adj is NH proto v6");
4906 1 : fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4907 :
4908 : /*
4909 : * An attached route
4910 : */
4911 3 : fib_prefix_t pfx_2001_c_s_64 = {
4912 : .fp_len = 64,
4913 : .fp_proto = FIB_PROTOCOL_IP6,
4914 : .fp_addr = {
4915 : .ip6 = {
4916 : .as_u64 = {
4917 1 : [0] = clib_host_to_net_u64(0x200100000000000c),
4918 1 : [1] = clib_host_to_net_u64(0x0000000000000000),
4919 : },
4920 : },
4921 : }
4922 : };
4923 1 : fib_table_entry_path_add(fib_index,
4924 : &pfx_2001_c_s_64,
4925 : FIB_SOURCE_CLI,
4926 : FIB_ENTRY_FLAG_ATTACHED,
4927 : DPO_PROTO_IP6,
4928 : NULL,
4929 1 : tm->hw[0]->sw_if_index,
4930 : ~0,
4931 : 1,
4932 : NULL,
4933 : FIB_ROUTE_PATH_FLAG_NONE);
4934 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4935 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4936 1 : ai = fib_entry_get_adj(fei);
4937 1 : adj = adj_get(ai);
4938 1 : FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4939 : "2001:0:0:c/64 attached resolves via glean");
4940 :
4941 1 : fib_table_entry_path_remove(fib_index,
4942 : &pfx_2001_c_s_64,
4943 : FIB_SOURCE_CLI,
4944 : DPO_PROTO_IP6,
4945 : NULL,
4946 1 : tm->hw[0]->sw_if_index,
4947 : ~0,
4948 : 1,
4949 : FIB_ROUTE_PATH_FLAG_NONE);
4950 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4951 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4952 :
4953 : /*
4954 : * Shutdown the interface on which we have a connected and through
4955 : * which the routes are reachable.
4956 : * This will result in the connected, adj-fibs, and routes linking to drop
4957 : * The local/for-us prefix continues to receive.
4958 : */
4959 : clib_error_t * error;
4960 :
4961 1 : error = vnet_sw_interface_set_flags(vnet_get_main(),
4962 1 : tm->hw[0]->sw_if_index,
4963 : ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4964 1 : FIB_TEST((NULL == error), "Interface shutdown OK");
4965 :
4966 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4967 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4968 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4969 : "2001::b/64 resolves via drop");
4970 :
4971 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4972 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4973 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4974 : "2001::a/64 resolves via drop");
4975 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4976 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4977 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4978 : "2001:0:0:1::3/64 resolves via drop");
4979 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4980 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4981 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4982 : "2001:0:0:1::2/64 resolves via drop");
4983 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4984 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4985 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4986 : "2001:0:0:1::1/128 not drop");
4987 1 : local_pfx.fp_len = 64;
4988 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4989 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
4990 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4991 : "2001:0:0:1/64 resolves via drop");
4992 :
4993 : /*
4994 : * no change
4995 : */
4996 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4997 : fib_path_list_db_size());
4998 1 : FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4999 : fib_path_list_pool_size());
5000 1 : FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
5001 : fib_entry_pool_size());
5002 :
5003 : /*
5004 : * shutdown one of the other interfaces, then add a connected.
5005 : * and swap one of the routes to it.
5006 : */
5007 1 : error = vnet_sw_interface_set_flags(vnet_get_main(),
5008 1 : tm->hw[1]->sw_if_index,
5009 : ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5010 1 : FIB_TEST((NULL == error), "Interface 1 shutdown OK");
5011 :
5012 3 : fib_prefix_t connected_pfx = {
5013 : .fp_len = 64,
5014 : .fp_proto = FIB_PROTOCOL_IP6,
5015 : .fp_addr = {
5016 : .ip6 = {
5017 : /* 2001:0:0:2::1/64 */
5018 : .as_u64 = {
5019 1 : [0] = clib_host_to_net_u64(0x2001000000000002),
5020 1 : [1] = clib_host_to_net_u64(0x0000000000000001),
5021 : },
5022 : },
5023 : }
5024 : };
5025 1 : fib_table_entry_update_one_path(fib_index, &connected_pfx,
5026 : FIB_SOURCE_INTERFACE,
5027 : (FIB_ENTRY_FLAG_CONNECTED |
5028 : FIB_ENTRY_FLAG_ATTACHED),
5029 : DPO_PROTO_IP6,
5030 : NULL,
5031 1 : tm->hw[1]->sw_if_index,
5032 : ~0,
5033 : 1,
5034 : NULL,
5035 : FIB_ROUTE_PATH_FLAG_NONE);
5036 1 : fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
5037 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
5038 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5039 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
5040 1 : FIB_TEST(!dpo_cmp(dpo, dpo_drop),
5041 : "2001:0:0:2/64 not resolves via drop");
5042 :
5043 1 : connected_pfx.fp_len = 128;
5044 1 : fib_table_entry_update_one_path(fib_index, &connected_pfx,
5045 : FIB_SOURCE_INTERFACE,
5046 : (FIB_ENTRY_FLAG_CONNECTED |
5047 : FIB_ENTRY_FLAG_LOCAL),
5048 : DPO_PROTO_IP6,
5049 : NULL,
5050 1 : tm->hw[0]->sw_if_index,
5051 : ~0, // invalid fib index
5052 : 1,
5053 : NULL,
5054 : FIB_ROUTE_PATH_FLAG_NONE);
5055 1 : fei = fib_table_lookup(fib_index, &connected_pfx);
5056 :
5057 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
5058 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5059 1 : dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
5060 1 : FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
5061 : "local interface adj is local");
5062 1 : rd = receive_dpo_get(dpo->dpoi_index);
5063 1 : FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
5064 : &rd->rd_addr)),
5065 : "local interface adj is receive ok");
5066 :
5067 : /*
5068 : * +2 entries, +2 unshared path-lists
5069 : */
5070 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5071 : fib_path_list_db_size());
5072 1 : FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5073 : fib_path_list_pool_size());
5074 1 : FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5075 : fib_entry_pool_size());
5076 :
5077 :
5078 : /*
5079 : * bring the interface back up. we expected the routes to return
5080 : * to normal forwarding.
5081 : */
5082 1 : error = vnet_sw_interface_set_flags(vnet_get_main(),
5083 1 : tm->hw[0]->sw_if_index,
5084 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5085 1 : FIB_TEST((NULL == error), "Interface bring-up OK");
5086 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5087 1 : ai = fib_entry_get_adj(fei);
5088 1 : FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5089 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5090 1 : ai = fib_entry_get_adj(fei);
5091 1 : FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5092 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5093 1 : ai = fib_entry_get_adj(fei);
5094 1 : FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5095 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5096 1 : ai = fib_entry_get_adj(fei);
5097 1 : FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5098 1 : local_pfx.fp_len = 64;
5099 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5100 1 : ai = fib_entry_get_adj(fei);
5101 1 : adj = adj_get(ai);
5102 1 : FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5103 : "attached interface adj is glean");
5104 :
5105 : /*
5106 : * Same test as above, but this time the HW interface goes down
5107 : */
5108 1 : error = vnet_hw_interface_set_flags(vnet_get_main(),
5109 : tm->hw_if_indicies[0],
5110 : ~VNET_HW_INTERFACE_FLAG_LINK_UP);
5111 1 : FIB_TEST((NULL == error), "Interface shutdown OK");
5112 :
5113 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5114 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5115 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5116 : "2001::b/64 resolves via drop");
5117 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5118 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5119 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5120 : "2001::a/64 resolves via drop");
5121 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5122 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5123 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5124 : "2001:0:0:1::3/128 resolves via drop");
5125 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5126 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5127 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5128 : "2001:0:0:1::2/128 resolves via drop");
5129 1 : local_pfx.fp_len = 128;
5130 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5131 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5132 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5133 : "2001:0:0:1::1/128 not drop");
5134 1 : local_pfx.fp_len = 64;
5135 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5136 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5137 1 : FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5138 : "2001:0:0:1/64 resolves via drop");
5139 :
5140 1 : error = vnet_hw_interface_set_flags(vnet_get_main(),
5141 : tm->hw_if_indicies[0],
5142 : VNET_HW_INTERFACE_FLAG_LINK_UP);
5143 1 : FIB_TEST((NULL == error), "Interface bring-up OK");
5144 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5145 1 : ai = fib_entry_get_adj(fei);
5146 1 : FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5147 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5148 1 : ai = fib_entry_get_adj(fei);
5149 1 : FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5150 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5151 1 : ai = fib_entry_get_adj(fei);
5152 1 : FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5153 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5154 1 : ai = fib_entry_get_adj(fei);
5155 1 : FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5156 1 : local_pfx.fp_len = 64;
5157 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5158 1 : ai = fib_entry_get_adj(fei);
5159 1 : adj = adj_get(ai);
5160 1 : FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5161 : "attached interface adj is glean");
5162 :
5163 : /*
5164 : * Delete the interface that the routes reolve through.
5165 : * Again no routes are removed. They all point to drop.
5166 : *
5167 : * This is considered an error case. The control plane should
5168 : * not remove interfaces through which routes resolve, but
5169 : * such things can happen. ALL affected routes will drop.
5170 : */
5171 1 : vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
5172 :
5173 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5174 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5175 : "2001::b/64 resolves via drop");
5176 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5177 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5178 : "2001::b/64 resolves via drop");
5179 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5180 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5181 : "2001:0:0:1::3/64 resolves via drop");
5182 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5183 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5184 : "2001:0:0:1::2/64 resolves via drop");
5185 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5186 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5187 : "2001:0:0:1::1/128 is drop");
5188 1 : local_pfx.fp_len = 64;
5189 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5190 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5191 : "2001:0:0:1/64 resolves via drop");
5192 :
5193 : /*
5194 : * no change
5195 : */
5196 1 : FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5197 : fib_path_list_db_size());
5198 1 : FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5199 : fib_path_list_pool_size());
5200 1 : FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5201 : fib_entry_pool_size());
5202 :
5203 : /*
5204 : * Add the interface back. routes stay unresolved.
5205 : */
5206 1 : vnet_eth_interface_registration_t eir = {};
5207 1 : eir.dev_class_index = test_interface_device_class.index;
5208 1 : eir.dev_instance = 0;
5209 1 : eir.address = hw_address;
5210 1 : tm->hw_if_indicies[0] = vnet_eth_register_interface (vnet_get_main(), &eir);
5211 :
5212 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5213 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5214 : "2001::b/64 resolves via drop");
5215 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5216 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5217 : "2001::b/64 resolves via drop");
5218 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5219 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5220 : "2001:0:0:1::3/64 resolves via drop");
5221 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5222 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5223 : "2001:0:0:1::2/64 resolves via drop");
5224 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5225 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5226 : "2001:0:0:1::1/128 is drop");
5227 1 : local_pfx.fp_len = 64;
5228 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5229 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5230 : "2001:0:0:1/64 resolves via drop");
5231 :
5232 : /*
5233 : * CLEANUP ALL the routes
5234 : */
5235 1 : fib_table_entry_delete(fib_index,
5236 : &pfx_2001_c_s_64,
5237 : FIB_SOURCE_API);
5238 1 : fib_table_entry_delete(fib_index,
5239 : &pfx_2001_a_s_64,
5240 : FIB_SOURCE_API);
5241 1 : fib_table_entry_delete(fib_index,
5242 : &pfx_2001_b_s_64,
5243 : FIB_SOURCE_API);
5244 1 : fib_table_entry_delete(fib_index,
5245 : &pfx_2001_1_3_s_128,
5246 : FIB_SOURCE_ADJ);
5247 1 : fib_table_entry_delete(fib_index,
5248 : &pfx_2001_1_2_s_128,
5249 : FIB_SOURCE_ADJ);
5250 1 : local_pfx.fp_len = 64;
5251 1 : fib_table_entry_delete(fib_index, &local_pfx,
5252 : FIB_SOURCE_INTERFACE);
5253 1 : local_pfx.fp_len = 128;
5254 1 : fib_table_entry_special_remove(fib_index, &local_pfx,
5255 : FIB_SOURCE_INTERFACE);
5256 1 : connected_pfx.fp_len = 64;
5257 1 : fib_table_entry_delete(fib_index, &connected_pfx,
5258 : FIB_SOURCE_INTERFACE);
5259 1 : connected_pfx.fp_len = 128;
5260 1 : fib_table_entry_special_remove(fib_index, &connected_pfx,
5261 : FIB_SOURCE_INTERFACE);
5262 :
5263 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5264 : fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5265 : "2001::a/64 removed");
5266 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5267 : fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5268 : "2001::b/64 removed");
5269 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5270 : fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5271 : "2001:0:0:1::3/128 removed");
5272 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5273 : fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5274 : "2001:0:0:1::3/128 removed");
5275 1 : local_pfx.fp_len = 64;
5276 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5277 : fib_table_lookup_exact_match(fib_index, &local_pfx)),
5278 : "2001:0:0:1/64 removed");
5279 1 : local_pfx.fp_len = 128;
5280 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5281 : fib_table_lookup_exact_match(fib_index, &local_pfx)),
5282 : "2001:0:0:1::1/128 removed");
5283 1 : connected_pfx.fp_len = 64;
5284 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5285 : fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5286 : "2001:0:0:2/64 removed");
5287 1 : connected_pfx.fp_len = 128;
5288 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
5289 : fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5290 : "2001:0:0:2::1/128 removed");
5291 :
5292 : /*
5293 : * -8 entries. -7 path-lists (1 was shared).
5294 : */
5295 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5296 : fib_path_list_db_size());
5297 1 : FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5298 : fib_path_list_pool_size());
5299 1 : FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5300 : fib_entry_pool_size());
5301 :
5302 : /*
5303 : * now remove the VRF
5304 : */
5305 :
5306 5 : for (ii = 0; ii < 4; ii++)
5307 4 : fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[ii]->sw_if_index, 0);
5308 :
5309 1 : fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5310 :
5311 1 : FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5312 : fib_path_list_db_size());
5313 1 : FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5314 : fib_path_list_pool_size());
5315 1 : FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5316 : fib_entry_pool_size());
5317 :
5318 1 : adj_unlock(ai_02);
5319 1 : adj_unlock(ai_01);
5320 :
5321 : /*
5322 : * return the interfaces to up state
5323 : */
5324 1 : error = vnet_sw_interface_set_flags(vnet_get_main(),
5325 1 : tm->hw[0]->sw_if_index,
5326 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5327 1 : error = vnet_sw_interface_set_flags(vnet_get_main(),
5328 1 : tm->hw[1]->sw_if_index,
5329 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5330 :
5331 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5332 : adj_nbr_db_size());
5333 1 : FIB_TEST((0 == adj_glean_db_size()), "ADJ DB size is %d",
5334 : adj_glean_db_size());
5335 :
5336 1 : return (res);
5337 : }
5338 :
5339 : /*
5340 : * Test Attached Exports
5341 : */
5342 : static int
5343 1 : fib_test_ae (void)
5344 : {
5345 : const dpo_id_t *dpo, *dpo_drop;
5346 1 : const u32 fib_index = 0;
5347 : fib_node_index_t dfrt, fei;
5348 : test_main_t *tm;
5349 : int res;
5350 :
5351 1 : res = 0;
5352 1 : tm = &test_main;
5353 :
5354 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5355 : adj_nbr_db_size());
5356 :
5357 : /*
5358 : * add interface routes. We'll assume this works. It's more rigorously
5359 : * tested elsewhere.
5360 : */
5361 2 : fib_prefix_t local_pfx = {
5362 : .fp_len = 24,
5363 : .fp_proto = FIB_PROTOCOL_IP4,
5364 : .fp_addr = {
5365 : .ip4 = {
5366 : /* 10.10.10.10 */
5367 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5368 : },
5369 : },
5370 : };
5371 :
5372 1 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[0]->sw_if_index, fib_index);
5373 :
5374 1 : dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5375 :
5376 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
5377 : FIB_SOURCE_INTERFACE,
5378 : (FIB_ENTRY_FLAG_CONNECTED |
5379 : FIB_ENTRY_FLAG_ATTACHED),
5380 : DPO_PROTO_IP4,
5381 : NULL,
5382 1 : tm->hw[0]->sw_if_index,
5383 : ~0,
5384 : 1,
5385 : NULL,
5386 : FIB_ROUTE_PATH_FLAG_NONE);
5387 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5388 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5389 : "attached interface route present");
5390 :
5391 1 : local_pfx.fp_len = 32;
5392 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
5393 : FIB_SOURCE_INTERFACE,
5394 : (FIB_ENTRY_FLAG_CONNECTED |
5395 : FIB_ENTRY_FLAG_LOCAL),
5396 : DPO_PROTO_IP4,
5397 : NULL,
5398 1 : tm->hw[0]->sw_if_index,
5399 : ~0, // invalid fib index
5400 : 1,
5401 : NULL,
5402 : FIB_ROUTE_PATH_FLAG_NONE);
5403 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5404 :
5405 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5406 : "local interface route present");
5407 :
5408 : /*
5409 : * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5410 : */
5411 2 : fib_prefix_t pfx_10_10_10_1_s_32 = {
5412 : .fp_len = 32,
5413 : .fp_proto = FIB_PROTOCOL_IP4,
5414 : .fp_addr = {
5415 : /* 10.10.10.1 */
5416 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5417 : },
5418 : };
5419 : fib_node_index_t ai;
5420 :
5421 1 : fib_table_entry_path_add(fib_index,
5422 : &pfx_10_10_10_1_s_32,
5423 : FIB_SOURCE_ADJ,
5424 : FIB_ENTRY_FLAG_ATTACHED,
5425 : DPO_PROTO_IP4,
5426 : &pfx_10_10_10_1_s_32.fp_addr,
5427 1 : tm->hw[0]->sw_if_index,
5428 : ~0, // invalid fib index
5429 : 1,
5430 : NULL,
5431 : FIB_ROUTE_PATH_FLAG_NONE);
5432 :
5433 1 : fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5434 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5435 1 : ai = fib_entry_get_adj(fei);
5436 :
5437 : /*
5438 : * create another FIB table into which routes will be imported
5439 : */
5440 : u32 import_fib_index1;
5441 :
5442 1 : import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5443 : 11,
5444 : FIB_SOURCE_CLI);
5445 : /*
5446 : * Add default route in the import FIB
5447 : */
5448 1 : fib_prefix_t pfx_0_0_0_0_s_0 = {
5449 : .fp_len = 0,
5450 : .fp_proto = FIB_PROTOCOL_IP4,
5451 : .fp_addr = {
5452 : .ip4 = {
5453 : {0}
5454 : },
5455 : },
5456 : };
5457 :
5458 1 : dfrt = fib_table_lookup(import_fib_index1, &pfx_0_0_0_0_s_0);
5459 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
5460 :
5461 1 : fib_table_entry_path_add(import_fib_index1,
5462 : &pfx_0_0_0_0_s_0,
5463 : FIB_SOURCE_API,
5464 : FIB_ENTRY_FLAG_NONE,
5465 : DPO_PROTO_IP4,
5466 : NULL,
5467 1 : tm->hw[0]->sw_if_index,
5468 : ~0, // invalid fib index
5469 : 1,
5470 : NULL,
5471 : FIB_ROUTE_PATH_FLAG_NONE);
5472 1 : fei = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
5473 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "default route present");
5474 1 : FIB_TEST((fei != dfrt), "default route added");
5475 :
5476 : /*
5477 : * delete default route and check for the presence in the import table
5478 : */
5479 1 : fib_table_entry_delete(import_fib_index1, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
5480 1 : fei = fib_table_lookup(import_fib_index1, &pfx_0_0_0_0_s_0);
5481 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "default route present");
5482 1 : FIB_TEST((fei == dfrt), "default route removed");
5483 :
5484 : /*
5485 : * Add an attached route in the import FIB
5486 : */
5487 1 : local_pfx.fp_len = 24;
5488 1 : fib_table_entry_update_one_path(import_fib_index1,
5489 : &local_pfx,
5490 : FIB_SOURCE_API,
5491 : FIB_ENTRY_FLAG_NONE,
5492 : DPO_PROTO_IP4,
5493 : NULL,
5494 1 : tm->hw[0]->sw_if_index,
5495 : ~0, // invalid fib index
5496 : 1,
5497 : NULL,
5498 : FIB_ROUTE_PATH_FLAG_NONE);
5499 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5500 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5501 :
5502 : /*
5503 : * check for the presence of the adj-fibs in the import table
5504 : */
5505 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5506 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5507 1 : FIB_TEST((ai == fib_entry_get_adj(fei)),
5508 : "adj-fib1 Import uses same adj as export");
5509 :
5510 : /*
5511 : * check for the presence of the local in the import table
5512 : */
5513 1 : local_pfx.fp_len = 32;
5514 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5515 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5516 :
5517 : /*
5518 : * Add another adj-fin in the export table. Expect this
5519 : * to get magically exported;
5520 : */
5521 2 : fib_prefix_t pfx_10_10_10_2_s_32 = {
5522 : .fp_len = 32,
5523 : .fp_proto = FIB_PROTOCOL_IP4,
5524 : .fp_addr = {
5525 : /* 10.10.10.2 */
5526 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5527 : },
5528 : };
5529 :
5530 1 : fib_table_entry_path_add(fib_index,
5531 : &pfx_10_10_10_2_s_32,
5532 : FIB_SOURCE_ADJ,
5533 : FIB_ENTRY_FLAG_ATTACHED,
5534 : DPO_PROTO_IP4,
5535 : &pfx_10_10_10_2_s_32.fp_addr,
5536 1 : tm->hw[0]->sw_if_index,
5537 : ~0, // invalid fib index
5538 : 1,
5539 : NULL,
5540 : FIB_ROUTE_PATH_FLAG_NONE);
5541 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5542 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5543 1 : ai = fib_entry_get_adj(fei);
5544 :
5545 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5546 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5547 1 : FIB_TEST((ai == fib_entry_get_adj(fei)),
5548 : "Import uses same adj as export");
5549 1 : FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5550 : "ADJ-fib2 imported flags %d",
5551 : fib_entry_get_flags(fei));
5552 :
5553 : /*
5554 : * create a 2nd FIB table into which routes will be imported
5555 : */
5556 : u32 import_fib_index2;
5557 :
5558 1 : import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5559 : FIB_SOURCE_CLI);
5560 :
5561 : /*
5562 : * Add an attached route in the import FIB
5563 : */
5564 1 : local_pfx.fp_len = 24;
5565 1 : fib_table_entry_update_one_path(import_fib_index2,
5566 : &local_pfx,
5567 : FIB_SOURCE_API,
5568 : FIB_ENTRY_FLAG_NONE,
5569 : DPO_PROTO_IP4,
5570 : NULL,
5571 1 : tm->hw[0]->sw_if_index,
5572 : ~0, // invalid fib index
5573 : 1,
5574 : NULL,
5575 : FIB_ROUTE_PATH_FLAG_NONE);
5576 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5577 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5578 :
5579 : /*
5580 : * check for the presence of all the adj-fibs and local in the import table
5581 : */
5582 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5583 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5584 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5585 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5586 1 : local_pfx.fp_len = 32;
5587 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5588 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5589 :
5590 : /*
5591 : * add a 3rd adj-fib. expect it to be exported to both tables.
5592 : */
5593 2 : fib_prefix_t pfx_10_10_10_3_s_32 = {
5594 : .fp_len = 32,
5595 : .fp_proto = FIB_PROTOCOL_IP4,
5596 : .fp_addr = {
5597 : /* 10.10.10.3 */
5598 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5599 : },
5600 : };
5601 :
5602 1 : fib_table_entry_path_add(fib_index,
5603 : &pfx_10_10_10_3_s_32,
5604 : FIB_SOURCE_ADJ,
5605 : FIB_ENTRY_FLAG_ATTACHED,
5606 : DPO_PROTO_IP4,
5607 : &pfx_10_10_10_3_s_32.fp_addr,
5608 1 : tm->hw[0]->sw_if_index,
5609 : ~0, // invalid fib index
5610 : 1,
5611 : NULL,
5612 : FIB_ROUTE_PATH_FLAG_NONE);
5613 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5614 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5615 1 : ai = fib_entry_get_adj(fei);
5616 :
5617 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5618 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5619 1 : FIB_TEST((ai == fib_entry_get_adj(fei)),
5620 : "Import uses same adj as export");
5621 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5622 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5623 1 : FIB_TEST((ai == fib_entry_get_adj(fei)),
5624 : "Import uses same adj as export");
5625 :
5626 : /*
5627 : * remove the 3rd adj fib. we expect it to be removed from both FIBs
5628 : */
5629 1 : fib_table_entry_delete(fib_index,
5630 : &pfx_10_10_10_3_s_32,
5631 : FIB_SOURCE_ADJ);
5632 :
5633 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5634 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5635 :
5636 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5637 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5638 :
5639 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5640 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5641 :
5642 : /*
5643 : * remove the attached route from the 2nd FIB. expect the imported
5644 : * entries to be removed
5645 : */
5646 1 : local_pfx.fp_len = 24;
5647 1 : fib_table_entry_delete(import_fib_index2,
5648 : &local_pfx,
5649 : FIB_SOURCE_API);
5650 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5651 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5652 :
5653 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5654 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5655 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5656 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5657 1 : local_pfx.fp_len = 32;
5658 1 : fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5659 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5660 :
5661 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5662 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5663 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5664 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5665 1 : local_pfx.fp_len = 32;
5666 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5667 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5668 :
5669 : /*
5670 : * modify the route in FIB1 so it is no longer attached. expect the imported
5671 : * entries to be removed
5672 : */
5673 1 : local_pfx.fp_len = 24;
5674 1 : fib_table_entry_update_one_path(import_fib_index1,
5675 : &local_pfx,
5676 : FIB_SOURCE_API,
5677 : FIB_ENTRY_FLAG_NONE,
5678 : DPO_PROTO_IP4,
5679 : &pfx_10_10_10_2_s_32.fp_addr,
5680 1 : tm->hw[0]->sw_if_index,
5681 : ~0, // invalid fib index
5682 : 1,
5683 : NULL,
5684 : FIB_ROUTE_PATH_FLAG_NONE);
5685 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5686 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5687 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5688 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5689 1 : local_pfx.fp_len = 32;
5690 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5691 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5692 :
5693 : /*
5694 : * modify it back to attached. expect the adj-fibs back
5695 : */
5696 1 : local_pfx.fp_len = 24;
5697 1 : fib_table_entry_update_one_path(import_fib_index1,
5698 : &local_pfx,
5699 : FIB_SOURCE_API,
5700 : FIB_ENTRY_FLAG_NONE,
5701 : DPO_PROTO_IP4,
5702 : NULL,
5703 1 : tm->hw[0]->sw_if_index,
5704 : ~0, // invalid fib index
5705 : 1,
5706 : NULL,
5707 : FIB_ROUTE_PATH_FLAG_NONE);
5708 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5709 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5710 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5711 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5712 1 : local_pfx.fp_len = 32;
5713 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5714 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5715 :
5716 : /*
5717 : * add a covering attached next-hop for the interface address, so we have
5718 : * a valid adj to find when we check the forwarding tables
5719 : */
5720 2 : fib_prefix_t pfx_10_0_0_0_s_8 = {
5721 : .fp_len = 8,
5722 : .fp_proto = FIB_PROTOCOL_IP4,
5723 : .fp_addr = {
5724 : /* 10.0.0.0 */
5725 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5726 : },
5727 : };
5728 :
5729 1 : fei = fib_table_entry_update_one_path(fib_index,
5730 : &pfx_10_0_0_0_s_8,
5731 : FIB_SOURCE_API,
5732 : FIB_ENTRY_FLAG_NONE,
5733 : DPO_PROTO_IP4,
5734 : &pfx_10_10_10_3_s_32.fp_addr,
5735 1 : tm->hw[0]->sw_if_index,
5736 : ~0, // invalid fib index
5737 : 1,
5738 : NULL,
5739 : FIB_ROUTE_PATH_FLAG_NONE);
5740 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5741 :
5742 : /*
5743 : * remove the route in the export fib. expect the adj-fibs to be removed
5744 : */
5745 1 : local_pfx.fp_len = 24;
5746 1 : fib_table_entry_delete(fib_index,
5747 : &local_pfx,
5748 : FIB_SOURCE_INTERFACE);
5749 :
5750 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5751 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5752 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5753 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5754 1 : local_pfx.fp_len = 32;
5755 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5756 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5757 :
5758 : /*
5759 : * the adj-fibs in the export VRF are present in the FIB table,
5760 : * but not installed in forwarding, since they have no attached cover.
5761 : * Consequently a lookup in the MTRIE gives the adj for the covering
5762 : * route 10.0.0.0/8.
5763 : */
5764 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5765 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5766 :
5767 : index_t lbi;
5768 1 : lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5769 1 : FIB_TEST(lbi == dpo->dpoi_index,
5770 : "10.10.10.1 forwards on \n%U not \n%U",
5771 : format_load_balance, lbi, 0,
5772 : format_dpo_id, dpo, 0);
5773 1 : lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5774 1 : FIB_TEST(lbi == dpo->dpoi_index,
5775 : "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5776 1 : lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5777 1 : FIB_TEST(lbi == dpo->dpoi_index,
5778 : "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5779 :
5780 : /*
5781 : * add the export prefix back, but not as attached.
5782 : * No adj-fibs in export nor import tables
5783 : */
5784 1 : local_pfx.fp_len = 24;
5785 1 : fei = fib_table_entry_update_one_path(fib_index,
5786 : &local_pfx,
5787 : FIB_SOURCE_API,
5788 : FIB_ENTRY_FLAG_NONE,
5789 : DPO_PROTO_IP4,
5790 : &pfx_10_10_10_1_s_32.fp_addr,
5791 1 : tm->hw[0]->sw_if_index,
5792 : ~0, // invalid fib index
5793 : 1,
5794 : NULL,
5795 : FIB_ROUTE_PATH_FLAG_NONE);
5796 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5797 :
5798 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5799 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5800 1 : lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5801 1 : FIB_TEST(lbi == dpo->dpoi_index,
5802 : "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5803 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5804 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5805 1 : lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5806 1 : FIB_TEST(lbi == dpo->dpoi_index,
5807 : "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5808 :
5809 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5810 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5811 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5812 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5813 1 : local_pfx.fp_len = 32;
5814 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5815 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5816 :
5817 : /*
5818 : * modify the export prefix so it is attached. expect all covereds to return
5819 : */
5820 1 : local_pfx.fp_len = 24;
5821 1 : fib_table_entry_update_one_path(fib_index,
5822 : &local_pfx,
5823 : FIB_SOURCE_API,
5824 : FIB_ENTRY_FLAG_NONE,
5825 : DPO_PROTO_IP4,
5826 : NULL,
5827 1 : tm->hw[0]->sw_if_index,
5828 : ~0, // invalid fib index
5829 : 1,
5830 : NULL,
5831 : FIB_ROUTE_PATH_FLAG_NONE);
5832 :
5833 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5834 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5835 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5836 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5837 : "Adj-fib1 is not drop in export");
5838 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5839 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5840 1 : local_pfx.fp_len = 32;
5841 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5842 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5843 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5844 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5845 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5846 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5847 : "Adj-fib1 is not drop in export: %U %U",
5848 : format_dpo_id, dpo, 0,
5849 : format_dpo_id, load_balance_get_bucket(dpo->dpoi_index, 0), 0);
5850 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5851 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5852 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5853 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5854 1 : local_pfx.fp_len = 32;
5855 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5856 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5857 :
5858 : /*
5859 : * modify the export prefix so connected. no change.
5860 : */
5861 1 : local_pfx.fp_len = 24;
5862 1 : fib_table_entry_update_one_path(fib_index, &local_pfx,
5863 : FIB_SOURCE_INTERFACE,
5864 : (FIB_ENTRY_FLAG_CONNECTED |
5865 : FIB_ENTRY_FLAG_ATTACHED),
5866 : DPO_PROTO_IP4,
5867 : NULL,
5868 1 : tm->hw[0]->sw_if_index,
5869 : ~0,
5870 : 1,
5871 : NULL,
5872 : FIB_ROUTE_PATH_FLAG_NONE);
5873 :
5874 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5875 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5876 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5877 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5878 : "Adj-fib1 is not drop in export");
5879 1 : fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5880 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5881 1 : local_pfx.fp_len = 32;
5882 1 : fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5883 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5884 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5885 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5886 1 : dpo = fib_entry_contribute_ip_forwarding(fei);
5887 1 : FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5888 : "Adj-fib1 is not drop in export");
5889 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5890 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5891 1 : local_pfx.fp_len = 32;
5892 1 : fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5893 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5894 :
5895 : /*
5896 : * CLEANUP
5897 : */
5898 1 : fib_table_entry_delete(fib_index,
5899 : &pfx_10_0_0_0_s_8,
5900 : FIB_SOURCE_API);
5901 1 : fib_table_entry_delete(fib_index,
5902 : &pfx_10_10_10_1_s_32,
5903 : FIB_SOURCE_ADJ);
5904 1 : fib_table_entry_delete(fib_index,
5905 : &pfx_10_10_10_2_s_32,
5906 : FIB_SOURCE_ADJ);
5907 1 : local_pfx.fp_len = 32;
5908 1 : fib_table_entry_delete(fib_index,
5909 : &local_pfx,
5910 : FIB_SOURCE_INTERFACE);
5911 1 : local_pfx.fp_len = 24;
5912 1 : fib_table_entry_delete(fib_index,
5913 : &local_pfx,
5914 : FIB_SOURCE_API);
5915 1 : fib_table_entry_delete(fib_index,
5916 : &local_pfx,
5917 : FIB_SOURCE_INTERFACE);
5918 1 : local_pfx.fp_len = 24;
5919 1 : fib_table_entry_delete(import_fib_index1,
5920 : &local_pfx,
5921 : FIB_SOURCE_API);
5922 :
5923 1 : fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5924 1 : fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5925 :
5926 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5927 : adj_nbr_db_size());
5928 :
5929 1 : return (res);
5930 : }
5931 :
5932 : /*
5933 : * Test Path Preference
5934 : */
5935 : static int
5936 1 : fib_test_pref (void)
5937 : {
5938 : test_main_t *tm;
5939 : int res, i;
5940 :
5941 1 : tm = &test_main;
5942 1 : res = 0;
5943 :
5944 2 : const fib_prefix_t pfx_1_1_1_1_s_32 = {
5945 : .fp_len = 32,
5946 : .fp_proto = FIB_PROTOCOL_IP4,
5947 : .fp_addr = {
5948 : .ip4 = {
5949 1 : .as_u32 = clib_host_to_net_u32(0x01010101),
5950 : },
5951 : },
5952 : };
5953 :
5954 4 : for (i = 0; i <= 2; i++)
5955 3 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[i]->sw_if_index, 0);
5956 :
5957 : /*
5958 : * 2 high, 2 medium and 2 low preference non-recursive paths
5959 : */
5960 2 : fib_route_path_t nr_path_hi_1 = {
5961 : .frp_proto = DPO_PROTO_IP4,
5962 1 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
5963 : .frp_fib_index = ~0,
5964 : .frp_weight = 1,
5965 : .frp_preference = 0,
5966 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5967 : .frp_addr = {
5968 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5969 : },
5970 : };
5971 2 : fib_route_path_t nr_path_hi_2 = {
5972 : .frp_proto = DPO_PROTO_IP4,
5973 1 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
5974 : .frp_fib_index = ~0,
5975 : .frp_weight = 1,
5976 : .frp_preference = 0,
5977 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5978 : .frp_addr = {
5979 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5980 : },
5981 : };
5982 2 : fib_route_path_t nr_path_med_1 = {
5983 : .frp_proto = DPO_PROTO_IP4,
5984 1 : .frp_sw_if_index = tm->hw[1]->sw_if_index,
5985 : .frp_fib_index = ~0,
5986 : .frp_weight = 1,
5987 : .frp_preference = 1,
5988 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5989 : .frp_addr = {
5990 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5991 : },
5992 : };
5993 2 : fib_route_path_t nr_path_med_2 = {
5994 : .frp_proto = DPO_PROTO_IP4,
5995 1 : .frp_sw_if_index = tm->hw[1]->sw_if_index,
5996 : .frp_fib_index = ~0,
5997 : .frp_weight = 1,
5998 : .frp_preference = 1,
5999 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6000 : .frp_addr = {
6001 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
6002 : },
6003 : };
6004 2 : fib_route_path_t nr_path_low_1 = {
6005 : .frp_proto = DPO_PROTO_IP4,
6006 1 : .frp_sw_if_index = tm->hw[2]->sw_if_index,
6007 : .frp_fib_index = ~0,
6008 : .frp_weight = 1,
6009 : .frp_preference = 2,
6010 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6011 : .frp_addr = {
6012 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6013 : },
6014 : };
6015 2 : fib_route_path_t nr_path_low_2 = {
6016 : .frp_proto = DPO_PROTO_IP4,
6017 1 : .frp_sw_if_index = tm->hw[2]->sw_if_index,
6018 : .frp_fib_index = ~0,
6019 : .frp_weight = 1,
6020 : .frp_preference = 2,
6021 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6022 : .frp_addr = {
6023 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6024 : },
6025 : };
6026 1 : fib_route_path_t *nr_paths = NULL;
6027 :
6028 1 : vec_add1(nr_paths, nr_path_hi_1);
6029 1 : vec_add1(nr_paths, nr_path_hi_2);
6030 1 : vec_add1(nr_paths, nr_path_med_1);
6031 1 : vec_add1(nr_paths, nr_path_med_2);
6032 1 : vec_add1(nr_paths, nr_path_low_1);
6033 1 : vec_add1(nr_paths, nr_path_low_2);
6034 :
6035 1 : adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6036 : VNET_LINK_IP4,
6037 : &nr_path_hi_1.frp_addr,
6038 : nr_path_hi_1.frp_sw_if_index);
6039 1 : adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6040 : VNET_LINK_IP4,
6041 : &nr_path_hi_2.frp_addr,
6042 : nr_path_hi_2.frp_sw_if_index);
6043 1 : adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6044 : VNET_LINK_IP4,
6045 : &nr_path_med_1.frp_addr,
6046 : nr_path_med_1.frp_sw_if_index);
6047 1 : adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6048 : VNET_LINK_IP4,
6049 : &nr_path_med_2.frp_addr,
6050 : nr_path_med_2.frp_sw_if_index);
6051 1 : adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6052 : VNET_LINK_IP4,
6053 : &nr_path_low_1.frp_addr,
6054 : nr_path_low_1.frp_sw_if_index);
6055 1 : adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6056 : VNET_LINK_IP4,
6057 : &nr_path_low_2.frp_addr,
6058 : nr_path_low_2.frp_sw_if_index);
6059 :
6060 1 : fib_test_lb_bucket_t ip_hi_1 = {
6061 : .type = FT_LB_ADJ,
6062 : .adj = {
6063 : .adj = ai_hi_1,
6064 : },
6065 : };
6066 1 : fib_test_lb_bucket_t ip_hi_2 = {
6067 : .type = FT_LB_ADJ,
6068 : .adj = {
6069 : .adj = ai_hi_2,
6070 : },
6071 : };
6072 1 : fib_test_lb_bucket_t ip_med_1 = {
6073 : .type = FT_LB_ADJ,
6074 : .adj = {
6075 : .adj = ai_med_1,
6076 : },
6077 : };
6078 1 : fib_test_lb_bucket_t ip_med_2 = {
6079 : .type = FT_LB_ADJ,
6080 : .adj = {
6081 : .adj = ai_med_2,
6082 : },
6083 : };
6084 1 : fib_test_lb_bucket_t ip_low_1 = {
6085 : .type = FT_LB_ADJ,
6086 : .adj = {
6087 : .adj = ai_low_1,
6088 : },
6089 : };
6090 1 : fib_test_lb_bucket_t ip_low_2 = {
6091 : .type = FT_LB_ADJ,
6092 : .adj = {
6093 : .adj = ai_low_2,
6094 : },
6095 : };
6096 :
6097 : fib_node_index_t fei;
6098 :
6099 1 : fei = fib_table_entry_path_add2(0,
6100 : &pfx_1_1_1_1_s_32,
6101 : FIB_SOURCE_API,
6102 : FIB_ENTRY_FLAG_NONE,
6103 : nr_paths);
6104 :
6105 1 : FIB_TEST(!fib_test_validate_entry(fei,
6106 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6107 : 2,
6108 : &ip_hi_1,
6109 : &ip_hi_2),
6110 : "1.1.1.1/32 via high preference paths");
6111 :
6112 : /*
6113 : * bring down the interface on which the high preference path lie
6114 : */
6115 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6116 1 : tm->hw[0]->sw_if_index,
6117 : 0);
6118 :
6119 1 : FIB_TEST(!fib_test_validate_entry(fei,
6120 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6121 : 2,
6122 : &ip_med_1,
6123 : &ip_med_2),
6124 : "1.1.1.1/32 via medium preference paths");
6125 :
6126 : /*
6127 : * bring down the interface on which the medium preference path lie
6128 : */
6129 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6130 1 : tm->hw[1]->sw_if_index,
6131 : 0);
6132 :
6133 1 : FIB_TEST(!fib_test_validate_entry(fei,
6134 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6135 : 2,
6136 : &ip_low_1,
6137 : &ip_low_2),
6138 : "1.1.1.1/32 via low preference paths");
6139 :
6140 : /*
6141 : * bring up the interface on which the high preference path lie
6142 : */
6143 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6144 1 : tm->hw[0]->sw_if_index,
6145 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6146 :
6147 1 : FIB_TEST(!fib_test_validate_entry(fei,
6148 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6149 : 2,
6150 : &ip_hi_1,
6151 : &ip_hi_2),
6152 : "1.1.1.1/32 via high preference paths");
6153 :
6154 : /*
6155 : * bring up the interface on which the medium preference path lie
6156 : */
6157 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6158 1 : tm->hw[1]->sw_if_index,
6159 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6160 :
6161 1 : FIB_TEST(!fib_test_validate_entry(fei,
6162 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6163 : 2,
6164 : &ip_hi_1,
6165 : &ip_hi_2),
6166 : "1.1.1.1/32 via high preference paths");
6167 :
6168 1 : dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6169 1 : fib_entry_contribute_forwarding(fei,
6170 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6171 : &ip_1_1_1_1);
6172 :
6173 : /*
6174 : * 3 recursive paths of different preference
6175 : */
6176 2 : const fib_prefix_t pfx_1_1_1_2_s_32 = {
6177 : .fp_len = 32,
6178 : .fp_proto = FIB_PROTOCOL_IP4,
6179 : .fp_addr = {
6180 : .ip4 = {
6181 1 : .as_u32 = clib_host_to_net_u32(0x01010102),
6182 : },
6183 : },
6184 : };
6185 2 : const fib_prefix_t pfx_1_1_1_3_s_32 = {
6186 : .fp_len = 32,
6187 : .fp_proto = FIB_PROTOCOL_IP4,
6188 : .fp_addr = {
6189 : .ip4 = {
6190 1 : .as_u32 = clib_host_to_net_u32(0x01010103),
6191 : },
6192 : },
6193 : };
6194 1 : fei = fib_table_entry_path_add2(0,
6195 : &pfx_1_1_1_2_s_32,
6196 : FIB_SOURCE_API,
6197 : FIB_ENTRY_FLAG_NONE,
6198 : nr_paths);
6199 1 : dpo_id_t ip_1_1_1_2 = DPO_INVALID;
6200 1 : fib_entry_contribute_forwarding(fei,
6201 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6202 : &ip_1_1_1_2);
6203 1 : fei = fib_table_entry_path_add2(0,
6204 : &pfx_1_1_1_3_s_32,
6205 : FIB_SOURCE_API,
6206 : FIB_ENTRY_FLAG_NONE,
6207 : nr_paths);
6208 1 : dpo_id_t ip_1_1_1_3 = DPO_INVALID;
6209 1 : fib_entry_contribute_forwarding(fei,
6210 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6211 : &ip_1_1_1_3);
6212 :
6213 1 : fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6214 : .type = FT_LB_O_LB,
6215 : .lb = {
6216 1 : .lb = ip_1_1_1_1.dpoi_index,
6217 : },
6218 : };
6219 1 : fib_test_lb_bucket_t ip_o_1_1_1_2 = {
6220 : .type = FT_LB_O_LB,
6221 : .lb = {
6222 1 : .lb = ip_1_1_1_2.dpoi_index,
6223 : },
6224 : };
6225 1 : fib_test_lb_bucket_t ip_o_1_1_1_3 = {
6226 : .type = FT_LB_O_LB,
6227 : .lb = {
6228 1 : .lb = ip_1_1_1_3.dpoi_index,
6229 : },
6230 : };
6231 1 : fib_route_path_t r_path_hi = {
6232 : .frp_proto = DPO_PROTO_IP4,
6233 : .frp_sw_if_index = ~0,
6234 : .frp_fib_index = 0,
6235 : .frp_weight = 1,
6236 : .frp_preference = 0,
6237 : .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6238 : .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6239 : };
6240 1 : fib_route_path_t r_path_med = {
6241 : .frp_proto = DPO_PROTO_IP4,
6242 : .frp_sw_if_index = ~0,
6243 : .frp_fib_index = 0,
6244 : .frp_weight = 1,
6245 : .frp_preference = 10,
6246 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6247 : .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6248 : };
6249 1 : fib_route_path_t r_path_low = {
6250 : .frp_proto = DPO_PROTO_IP4,
6251 : .frp_sw_if_index = ~0,
6252 : .frp_fib_index = 0,
6253 : .frp_weight = 1,
6254 : .frp_preference = 255,
6255 : .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6256 : .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6257 : };
6258 1 : fib_route_path_t *r_paths = NULL;
6259 :
6260 1 : vec_add1(r_paths, r_path_hi);
6261 1 : vec_add1(r_paths, r_path_low);
6262 1 : vec_add1(r_paths, r_path_med);
6263 :
6264 : /*
6265 : * add many recursive so we get the LB MAp created
6266 : */
6267 : #define N_PFXS 64
6268 : fib_prefix_t pfx_r[N_PFXS];
6269 : unsigned int n_pfxs;
6270 65 : for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6271 : {
6272 64 : pfx_r[n_pfxs].fp_len = 32;
6273 64 : pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6274 64 : pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6275 64 : clib_host_to_net_u32(0x02000000 + n_pfxs);
6276 :
6277 64 : fei = fib_table_entry_path_add2(0,
6278 64 : &pfx_r[n_pfxs],
6279 : FIB_SOURCE_API,
6280 : FIB_ENTRY_FLAG_NONE,
6281 : r_paths);
6282 :
6283 64 : FIB_TEST(!fib_test_validate_entry(fei,
6284 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6285 : 1,
6286 : &ip_o_1_1_1_1),
6287 : "recursive via high preference paths");
6288 :
6289 : /*
6290 : * withdraw hig pref resolving entry
6291 : */
6292 64 : fib_table_entry_delete(0,
6293 : &pfx_1_1_1_1_s_32,
6294 : FIB_SOURCE_API);
6295 :
6296 : /* suspend so the update walk kicks int */
6297 64 : vlib_process_suspend(vlib_get_main(), 1e-5);
6298 :
6299 64 : FIB_TEST(!fib_test_validate_entry(fei,
6300 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6301 : 1,
6302 : &ip_o_1_1_1_2),
6303 : "recursive via medium preference paths");
6304 :
6305 : /*
6306 : * withdraw medium pref resolving entry
6307 : */
6308 64 : fib_table_entry_delete(0,
6309 : &pfx_1_1_1_2_s_32,
6310 : FIB_SOURCE_API);
6311 :
6312 : /* suspend so the update walk kicks int */
6313 64 : vlib_process_suspend(vlib_get_main(), 1e-5);
6314 :
6315 64 : FIB_TEST(!fib_test_validate_entry(fei,
6316 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6317 : 1,
6318 : &ip_o_1_1_1_3),
6319 : "recursive via low preference paths");
6320 :
6321 : /*
6322 : * add back paths for next iteration
6323 : */
6324 64 : fei = fib_table_entry_update(0,
6325 : &pfx_1_1_1_2_s_32,
6326 : FIB_SOURCE_API,
6327 : FIB_ENTRY_FLAG_NONE,
6328 : nr_paths);
6329 64 : fei = fib_table_entry_update(0,
6330 : &pfx_1_1_1_1_s_32,
6331 : FIB_SOURCE_API,
6332 : FIB_ENTRY_FLAG_NONE,
6333 : nr_paths);
6334 :
6335 : /* suspend so the update walk kicks int */
6336 64 : vlib_process_suspend(vlib_get_main(), 1e-5);
6337 :
6338 64 : fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6339 64 : FIB_TEST(!fib_test_validate_entry(fei,
6340 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6341 : 1,
6342 : &ip_o_1_1_1_1),
6343 : "recursive via high preference paths");
6344 : }
6345 :
6346 :
6347 1 : fib_table_entry_delete(0,
6348 : &pfx_1_1_1_1_s_32,
6349 : FIB_SOURCE_API);
6350 :
6351 : /* suspend so the update walk kicks int */
6352 1 : vlib_process_suspend(vlib_get_main(), 1e-5);
6353 :
6354 65 : for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6355 : {
6356 64 : fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6357 :
6358 64 : FIB_TEST(!fib_test_validate_entry(fei,
6359 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6360 : 1,
6361 : &ip_o_1_1_1_2),
6362 : "recursive via medium preference paths");
6363 : }
6364 65 : for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6365 : {
6366 64 : fib_table_entry_delete(0,
6367 64 : &pfx_r[n_pfxs],
6368 : FIB_SOURCE_API);
6369 : }
6370 :
6371 : /*
6372 : * Cleanup
6373 : */
6374 1 : fib_table_entry_delete(0,
6375 : &pfx_1_1_1_2_s_32,
6376 : FIB_SOURCE_API);
6377 1 : fib_table_entry_delete(0,
6378 : &pfx_1_1_1_3_s_32,
6379 : FIB_SOURCE_API);
6380 :
6381 1 : dpo_reset(&ip_1_1_1_1);
6382 1 : dpo_reset(&ip_1_1_1_2);
6383 1 : dpo_reset(&ip_1_1_1_3);
6384 1 : adj_unlock(ai_low_2);
6385 1 : adj_unlock(ai_low_1);
6386 1 : adj_unlock(ai_med_2);
6387 1 : adj_unlock(ai_med_1);
6388 1 : adj_unlock(ai_hi_2);
6389 1 : adj_unlock(ai_hi_1);
6390 :
6391 1 : return (res);
6392 : }
6393 :
6394 : /*
6395 : * Test the recursive route route handling for GRE tunnels
6396 : */
6397 : static int
6398 1 : fib_test_label (void)
6399 : {
6400 : fib_node_index_t fei, ai_mpls_10_10_10_1, ai_v4_10_10_11_1, ai_v4_10_10_11_2, ai_mpls_10_10_11_2, ai_mpls_10_10_11_1;
6401 1 : const u32 fib_index = 0;
6402 : int lb_count, ii, res;
6403 : test_main_t *tm;
6404 :
6405 1 : res = 0;
6406 1 : lb_count = pool_elts(load_balance_pool);
6407 1 : tm = &test_main;
6408 :
6409 : /*
6410 : * add interface routes. We'll assume this works. It's more rigorously
6411 : * tested elsewhere.
6412 : */
6413 2 : fib_prefix_t local0_pfx = {
6414 : .fp_len = 24,
6415 : .fp_proto = FIB_PROTOCOL_IP4,
6416 : .fp_addr = {
6417 : .ip4 = {
6418 : /* 10.10.10.10 */
6419 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6420 : },
6421 : },
6422 : };
6423 :
6424 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6425 : adj_nbr_db_size());
6426 :
6427 1 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[0]->sw_if_index, fib_index);
6428 :
6429 1 : fib_table_entry_update_one_path(fib_index, &local0_pfx,
6430 : FIB_SOURCE_INTERFACE,
6431 : (FIB_ENTRY_FLAG_CONNECTED |
6432 : FIB_ENTRY_FLAG_ATTACHED),
6433 : DPO_PROTO_IP4,
6434 : NULL,
6435 1 : tm->hw[0]->sw_if_index,
6436 : ~0,
6437 : 1,
6438 : NULL,
6439 : FIB_ROUTE_PATH_FLAG_NONE);
6440 1 : fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6441 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6442 : "attached interface route present");
6443 :
6444 1 : local0_pfx.fp_len = 32;
6445 1 : fib_table_entry_update_one_path(fib_index, &local0_pfx,
6446 : FIB_SOURCE_INTERFACE,
6447 : (FIB_ENTRY_FLAG_CONNECTED |
6448 : FIB_ENTRY_FLAG_LOCAL),
6449 : DPO_PROTO_IP4,
6450 : NULL,
6451 1 : tm->hw[0]->sw_if_index,
6452 : ~0, // invalid fib index
6453 : 1,
6454 : NULL,
6455 : FIB_ROUTE_PATH_FLAG_NONE);
6456 1 : fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6457 :
6458 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6459 : "local interface route present");
6460 :
6461 2 : fib_prefix_t local1_pfx = {
6462 : .fp_len = 24,
6463 : .fp_proto = FIB_PROTOCOL_IP4,
6464 : .fp_addr = {
6465 : .ip4 = {
6466 : /* 10.10.11.10 */
6467 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6468 : },
6469 : },
6470 : };
6471 :
6472 1 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[1]->sw_if_index, fib_index);
6473 :
6474 1 : fib_table_entry_update_one_path(fib_index, &local1_pfx,
6475 : FIB_SOURCE_INTERFACE,
6476 : (FIB_ENTRY_FLAG_CONNECTED |
6477 : FIB_ENTRY_FLAG_ATTACHED),
6478 : DPO_PROTO_IP4,
6479 : NULL,
6480 1 : tm->hw[1]->sw_if_index,
6481 : ~0,
6482 : 1,
6483 : NULL,
6484 : FIB_ROUTE_PATH_FLAG_NONE);
6485 1 : fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6486 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6487 : "attached interface route present");
6488 :
6489 1 : local1_pfx.fp_len = 32;
6490 1 : fib_table_entry_update_one_path(fib_index, &local1_pfx,
6491 : FIB_SOURCE_INTERFACE,
6492 : (FIB_ENTRY_FLAG_CONNECTED |
6493 : FIB_ENTRY_FLAG_LOCAL),
6494 : DPO_PROTO_IP4,
6495 : NULL,
6496 1 : tm->hw[1]->sw_if_index,
6497 : ~0, // invalid fib index
6498 : 1,
6499 : NULL,
6500 : FIB_ROUTE_PATH_FLAG_NONE);
6501 1 : fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6502 :
6503 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6504 : "local interface route present");
6505 :
6506 2 : ip46_address_t nh_10_10_10_1 = {
6507 : .ip4 = {
6508 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6509 : },
6510 : };
6511 2 : ip46_address_t nh_10_10_11_1 = {
6512 : .ip4 = {
6513 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6514 : },
6515 : };
6516 2 : ip46_address_t nh_10_10_11_2 = {
6517 : .ip4 = {
6518 1 : .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6519 : },
6520 : };
6521 :
6522 1 : ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6523 : VNET_LINK_IP4,
6524 : &nh_10_10_11_1,
6525 1 : tm->hw[1]->sw_if_index);
6526 1 : ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6527 : VNET_LINK_IP4,
6528 : &nh_10_10_11_2,
6529 1 : tm->hw[1]->sw_if_index);
6530 1 : ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6531 : VNET_LINK_MPLS,
6532 : &nh_10_10_10_1,
6533 1 : tm->hw[0]->sw_if_index);
6534 1 : ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6535 : VNET_LINK_MPLS,
6536 : &nh_10_10_11_2,
6537 1 : tm->hw[1]->sw_if_index);
6538 1 : ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6539 : VNET_LINK_MPLS,
6540 : &nh_10_10_11_1,
6541 1 : tm->hw[1]->sw_if_index);
6542 :
6543 : /*
6544 : * Add an etry with one path with a real out-going label
6545 : */
6546 2 : fib_prefix_t pfx_1_1_1_1_s_32 = {
6547 : .fp_len = 32,
6548 : .fp_proto = FIB_PROTOCOL_IP4,
6549 : .fp_addr = {
6550 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6551 : },
6552 : };
6553 1 : fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6554 : .type = FT_LB_LABEL_O_ADJ,
6555 : .label_o_adj = {
6556 : .adj = ai_mpls_10_10_10_1,
6557 : .label = 99,
6558 : .eos = MPLS_EOS,
6559 : },
6560 : };
6561 1 : fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6562 : .type = FT_LB_LABEL_O_ADJ,
6563 : .label_o_adj = {
6564 : .adj = ai_mpls_10_10_10_1,
6565 : .label = 99,
6566 : .eos = MPLS_NON_EOS,
6567 : },
6568 : };
6569 1 : fib_mpls_label_t *l99 = NULL, fml99 = {
6570 : .fml_value = 99,
6571 : };
6572 1 : vec_add1(l99, fml99);
6573 :
6574 1 : fib_table_entry_update_one_path(fib_index,
6575 : &pfx_1_1_1_1_s_32,
6576 : FIB_SOURCE_API,
6577 : FIB_ENTRY_FLAG_NONE,
6578 : DPO_PROTO_IP4,
6579 : &nh_10_10_10_1,
6580 1 : tm->hw[0]->sw_if_index,
6581 : ~0, // invalid fib index
6582 : 1,
6583 : l99,
6584 : FIB_ROUTE_PATH_FLAG_NONE);
6585 :
6586 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6587 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6588 :
6589 1 : FIB_TEST(!fib_test_validate_entry(fei,
6590 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6591 : 1,
6592 : &l99_eos_o_10_10_10_1),
6593 : "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6594 :
6595 : /*
6596 : * add a path with an implicit NULL label
6597 : */
6598 1 : fib_test_lb_bucket_t a_o_10_10_11_1 = {
6599 : .type = FT_LB_ADJ,
6600 : .adj = {
6601 : .adj = ai_v4_10_10_11_1,
6602 : },
6603 : };
6604 1 : fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6605 : .type = FT_LB_ADJ,
6606 : .adj = {
6607 : .adj = ai_mpls_10_10_11_1,
6608 : },
6609 : };
6610 1 : fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
6611 : .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
6612 : };
6613 1 : vec_add1(l_imp_null, fml_imp_null);
6614 :
6615 1 : fei = fib_table_entry_path_add(fib_index,
6616 : &pfx_1_1_1_1_s_32,
6617 : FIB_SOURCE_API,
6618 : FIB_ENTRY_FLAG_NONE,
6619 : DPO_PROTO_IP4,
6620 : &nh_10_10_11_1,
6621 1 : tm->hw[1]->sw_if_index,
6622 : ~0, // invalid fib index
6623 : 1,
6624 : l_imp_null,
6625 : FIB_ROUTE_PATH_FLAG_NONE);
6626 :
6627 1 : FIB_TEST(!fib_test_validate_entry(fei,
6628 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6629 : 2,
6630 : &l99_eos_o_10_10_10_1,
6631 : &a_o_10_10_11_1),
6632 : "1.1.1.1/32 LB 2 buckets via: "
6633 : "label 99 over 10.10.10.1, "
6634 : "adj over 10.10.11.1");
6635 :
6636 : /*
6637 : * assign the route a local label
6638 : */
6639 1 : fib_table_entry_local_label_add(fib_index,
6640 : &pfx_1_1_1_1_s_32,
6641 : 24001);
6642 :
6643 1 : fib_prefix_t pfx_24001_eos = {
6644 : .fp_proto = FIB_PROTOCOL_MPLS,
6645 : .fp_label = 24001,
6646 : .fp_eos = MPLS_EOS,
6647 : };
6648 1 : fib_prefix_t pfx_24001_neos = {
6649 : .fp_proto = FIB_PROTOCOL_MPLS,
6650 : .fp_label = 24001,
6651 : .fp_eos = MPLS_NON_EOS,
6652 : };
6653 1 : fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6654 : .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6655 : .adj = {
6656 : .adj = ai_v4_10_10_11_1,
6657 : },
6658 : };
6659 :
6660 : /*
6661 : * The EOS entry should link to both the paths,
6662 : * and use an ip adj for the imp-null
6663 : * The NON-EOS entry should link to both the paths,
6664 : * and use an mpls adj for the imp-null
6665 : */
6666 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6667 : &pfx_24001_eos);
6668 1 : FIB_TEST(!fib_test_validate_entry(fei,
6669 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6670 : 2,
6671 : &l99_eos_o_10_10_10_1,
6672 : &disp_o_10_10_11_1),
6673 : "24001/eos LB 2 buckets via: "
6674 : "label 99 over 10.10.10.1, "
6675 : "mpls disp adj over 10.10.11.1");
6676 :
6677 :
6678 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6679 : &pfx_24001_neos);
6680 1 : FIB_TEST(!fib_test_validate_entry(fei,
6681 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6682 : 2,
6683 : &l99_neos_o_10_10_10_1,
6684 : &a_mpls_o_10_10_11_1),
6685 : "24001/neos LB 1 bucket via: "
6686 : "label 99 over 10.10.10.1 ",
6687 : "mpls-adj via 10.10.11.1");
6688 :
6689 : /*
6690 : * add an unlabelled path, this is excluded from the neos chains,
6691 : */
6692 1 : fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6693 : .type = FT_LB_ADJ,
6694 : .adj = {
6695 : .adj = ai_v4_10_10_11_2,
6696 : },
6697 : };
6698 1 : fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6699 : .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6700 : .adj = {
6701 : .adj = ai_v4_10_10_11_2,
6702 : },
6703 : };
6704 :
6705 :
6706 1 : fei = fib_table_entry_path_add(fib_index,
6707 : &pfx_1_1_1_1_s_32,
6708 : FIB_SOURCE_API,
6709 : FIB_ENTRY_FLAG_NONE,
6710 : DPO_PROTO_IP4,
6711 : &nh_10_10_11_2,
6712 1 : tm->hw[1]->sw_if_index,
6713 : ~0, // invalid fib index
6714 : 1,
6715 : NULL,
6716 : FIB_ROUTE_PATH_FLAG_NONE);
6717 :
6718 1 : FIB_TEST(!fib_test_validate_entry(fei,
6719 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6720 : 16, // 3 choices spread over 16 buckets
6721 : &l99_eos_o_10_10_10_1,
6722 : &l99_eos_o_10_10_10_1,
6723 : &l99_eos_o_10_10_10_1,
6724 : &l99_eos_o_10_10_10_1,
6725 : &l99_eos_o_10_10_10_1,
6726 : &l99_eos_o_10_10_10_1,
6727 : &a_o_10_10_11_1,
6728 : &a_o_10_10_11_1,
6729 : &a_o_10_10_11_1,
6730 : &a_o_10_10_11_1,
6731 : &a_o_10_10_11_1,
6732 : &adj_o_10_10_11_2,
6733 : &adj_o_10_10_11_2,
6734 : &adj_o_10_10_11_2,
6735 : &adj_o_10_10_11_2,
6736 : &adj_o_10_10_11_2),
6737 : "1.1.1.1/32 LB 16 buckets via: "
6738 : "label 99 over 10.10.10.1, "
6739 : "adj over 10.10.11.1",
6740 : "adj over 10.10.11.2");
6741 :
6742 : /*
6743 : * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6744 : */
6745 1 : dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6746 1 : fib_entry_contribute_forwarding(fei,
6747 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6748 : &non_eos_1_1_1_1);
6749 :
6750 : /*
6751 : * n-eos has only the 2 labelled paths
6752 : */
6753 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6754 : &pfx_24001_neos);
6755 :
6756 1 : FIB_TEST(!fib_test_validate_entry(fei,
6757 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6758 : 2,
6759 : &l99_neos_o_10_10_10_1,
6760 : &a_mpls_o_10_10_11_1),
6761 : "24001/neos LB 2 buckets via: "
6762 : "label 99 over 10.10.10.1, "
6763 : "adj-mpls over 10.10.11.2");
6764 :
6765 : /*
6766 : * A labelled recursive
6767 : */
6768 2 : fib_prefix_t pfx_2_2_2_2_s_32 = {
6769 : .fp_len = 32,
6770 : .fp_proto = FIB_PROTOCOL_IP4,
6771 : .fp_addr = {
6772 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6773 : },
6774 : };
6775 1 : fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6776 : .type = FT_LB_LABEL_O_LB,
6777 : .label_o_lb = {
6778 1 : .lb = non_eos_1_1_1_1.dpoi_index,
6779 : .label = 1600,
6780 : .eos = MPLS_EOS,
6781 : .mode = FIB_MPLS_LSP_MODE_UNIFORM,
6782 : },
6783 : };
6784 1 : fib_mpls_label_t *l1600 = NULL, fml1600 = {
6785 : .fml_value = 1600,
6786 : .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
6787 : };
6788 1 : vec_add1(l1600, fml1600);
6789 :
6790 1 : fei = fib_table_entry_update_one_path(fib_index,
6791 : &pfx_2_2_2_2_s_32,
6792 : FIB_SOURCE_API,
6793 : FIB_ENTRY_FLAG_NONE,
6794 : DPO_PROTO_IP4,
6795 : &pfx_1_1_1_1_s_32.fp_addr,
6796 : ~0,
6797 : fib_index,
6798 : 1,
6799 : l1600,
6800 : FIB_ROUTE_PATH_FLAG_NONE);
6801 :
6802 1 : FIB_TEST(!fib_test_validate_entry(fei,
6803 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6804 : 1,
6805 : &l1600_eos_o_1_1_1_1),
6806 : "2.2.2.2.2/32 LB 1 buckets via: "
6807 : "label 1600 over 1.1.1.1");
6808 :
6809 1 : dpo_id_t dpo_44 = DPO_INVALID;
6810 : index_t urpfi;
6811 :
6812 1 : fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6813 1 : urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6814 :
6815 1 : FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6816 : "uRPF check for 2.2.2.2/32 on %d OK",
6817 : tm->hw[0]->sw_if_index);
6818 1 : FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6819 : "uRPF check for 2.2.2.2/32 on %d OK",
6820 : tm->hw[1]->sw_if_index);
6821 1 : FIB_TEST(!fib_urpf_check(urpfi, 99),
6822 : "uRPF check for 2.2.2.2/32 on 99 not-OK",
6823 : 99);
6824 :
6825 1 : fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6826 1 : FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6827 : "Shared uRPF on IP and non-EOS chain");
6828 :
6829 1 : dpo_reset(&dpo_44);
6830 :
6831 : /*
6832 : * we are holding a lock on the non-eos LB of the via-entry.
6833 : * do a PIC-core failover by shutting the link of the via-entry.
6834 : *
6835 : * shut down the link with the valid label
6836 : */
6837 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6838 1 : tm->hw[0]->sw_if_index,
6839 : 0);
6840 :
6841 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6842 1 : FIB_TEST(!fib_test_validate_entry(fei,
6843 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6844 : 2,
6845 : &a_o_10_10_11_1,
6846 : &adj_o_10_10_11_2),
6847 : "1.1.1.1/32 LB 2 buckets via: "
6848 : "adj over 10.10.11.1, ",
6849 : "adj-v4 over 10.10.11.2");
6850 :
6851 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6852 : &pfx_24001_eos);
6853 1 : FIB_TEST(!fib_test_validate_entry(fei,
6854 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6855 : 2,
6856 : &disp_o_10_10_11_1,
6857 : &disp_o_10_10_11_2),
6858 : "24001/eos LB 2 buckets via: "
6859 : "mpls-disp adj over 10.10.11.1, ",
6860 : "mpls-disp adj-v4 over 10.10.11.2");
6861 :
6862 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6863 : &pfx_24001_neos);
6864 1 : FIB_TEST(!fib_test_validate_entry(fei,
6865 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6866 : 1,
6867 : &a_mpls_o_10_10_11_1),
6868 : "24001/neos LB 1 buckets via: "
6869 : "adj-mpls over 10.10.11.2");
6870 :
6871 : /*
6872 : * test that the pre-failover load-balance has been in-place
6873 : * modified
6874 : */
6875 1 : dpo_id_t current = DPO_INVALID;
6876 1 : fib_entry_contribute_forwarding(fei,
6877 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6878 : ¤t);
6879 :
6880 1 : FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6881 : ¤t),
6882 : "PIC-core LB inplace modified %U %U",
6883 : format_dpo_id, &non_eos_1_1_1_1, 0,
6884 : format_dpo_id, ¤t, 0);
6885 :
6886 1 : dpo_reset(&non_eos_1_1_1_1);
6887 1 : dpo_reset(¤t);
6888 :
6889 : /*
6890 : * no-shut the link with the valid label
6891 : */
6892 1 : vnet_sw_interface_set_flags(vnet_get_main(),
6893 1 : tm->hw[0]->sw_if_index,
6894 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6895 :
6896 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6897 1 : FIB_TEST(!fib_test_validate_entry(fei,
6898 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6899 : 16, // 3 choices spread over 16 buckets
6900 : &l99_eos_o_10_10_10_1,
6901 : &l99_eos_o_10_10_10_1,
6902 : &l99_eos_o_10_10_10_1,
6903 : &l99_eos_o_10_10_10_1,
6904 : &l99_eos_o_10_10_10_1,
6905 : &l99_eos_o_10_10_10_1,
6906 : &a_o_10_10_11_1,
6907 : &a_o_10_10_11_1,
6908 : &a_o_10_10_11_1,
6909 : &a_o_10_10_11_1,
6910 : &a_o_10_10_11_1,
6911 : &adj_o_10_10_11_2,
6912 : &adj_o_10_10_11_2,
6913 : &adj_o_10_10_11_2,
6914 : &adj_o_10_10_11_2,
6915 : &adj_o_10_10_11_2),
6916 : "1.1.1.1/32 LB 16 buckets via: "
6917 : "label 99 over 10.10.10.1, "
6918 : "adj over 10.10.11.1",
6919 : "adj-v4 over 10.10.11.2");
6920 :
6921 :
6922 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6923 : &pfx_24001_eos);
6924 1 : FIB_TEST(!fib_test_validate_entry(fei,
6925 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6926 : 16, // 3 choices spread over 16 buckets
6927 : &l99_eos_o_10_10_10_1,
6928 : &l99_eos_o_10_10_10_1,
6929 : &l99_eos_o_10_10_10_1,
6930 : &l99_eos_o_10_10_10_1,
6931 : &l99_eos_o_10_10_10_1,
6932 : &l99_eos_o_10_10_10_1,
6933 : &disp_o_10_10_11_1,
6934 : &disp_o_10_10_11_1,
6935 : &disp_o_10_10_11_1,
6936 : &disp_o_10_10_11_1,
6937 : &disp_o_10_10_11_1,
6938 : &disp_o_10_10_11_2,
6939 : &disp_o_10_10_11_2,
6940 : &disp_o_10_10_11_2,
6941 : &disp_o_10_10_11_2,
6942 : &disp_o_10_10_11_2),
6943 : "24001/eos LB 16 buckets via: "
6944 : "label 99 over 10.10.10.1, "
6945 : "MPLS disp adj over 10.10.11.1",
6946 : "MPLS disp adj-v4 over 10.10.11.2");
6947 :
6948 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6949 : &pfx_24001_neos);
6950 1 : FIB_TEST(!fib_test_validate_entry(fei,
6951 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6952 : 2,
6953 : &l99_neos_o_10_10_10_1,
6954 : &a_mpls_o_10_10_11_1),
6955 : "24001/neos LB 2 buckets via: "
6956 : "label 99 over 10.10.10.1, "
6957 : "adj-mpls over 10.10.11.2");
6958 :
6959 : /*
6960 : * remove the first path with the valid label
6961 : */
6962 1 : fib_table_entry_path_remove(fib_index,
6963 : &pfx_1_1_1_1_s_32,
6964 : FIB_SOURCE_API,
6965 : DPO_PROTO_IP4,
6966 : &nh_10_10_10_1,
6967 1 : tm->hw[0]->sw_if_index,
6968 : ~0, // invalid fib index
6969 : 1,
6970 : FIB_ROUTE_PATH_FLAG_NONE);
6971 :
6972 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6973 1 : FIB_TEST(!fib_test_validate_entry(fei,
6974 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6975 : 2,
6976 : &a_o_10_10_11_1,
6977 : &adj_o_10_10_11_2),
6978 : "1.1.1.1/32 LB 2 buckets via: "
6979 : "adj over 10.10.11.1, "
6980 : "adj-v4 over 10.10.11.2");
6981 :
6982 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6983 : &pfx_24001_eos);
6984 1 : FIB_TEST(!fib_test_validate_entry(fei,
6985 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6986 : 2,
6987 : &disp_o_10_10_11_1,
6988 : &disp_o_10_10_11_2),
6989 : "24001/eos LB 2 buckets via: "
6990 : "MPLS disp adj over 10.10.11.1, "
6991 : "MPLS disp adj-v4 over 10.10.11.2");
6992 :
6993 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6994 : &pfx_24001_neos);
6995 :
6996 1 : FIB_TEST(!fib_test_validate_entry(fei,
6997 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6998 : 1,
6999 : &a_mpls_o_10_10_11_1),
7000 : "24001/neos LB 1 buckets via: "
7001 : "adj-mpls over 10.10.11.2");
7002 :
7003 : /*
7004 : * remove the other path with a valid label
7005 : */
7006 1 : fib_test_lb_bucket_t bucket_drop = {
7007 : .type = FT_LB_DROP,
7008 : };
7009 1 : fib_test_lb_bucket_t mpls_bucket_drop = {
7010 : .type = FT_LB_DROP,
7011 : .special = {
7012 : .adj = DPO_PROTO_MPLS,
7013 : },
7014 : };
7015 :
7016 1 : fib_table_entry_path_remove(fib_index,
7017 : &pfx_1_1_1_1_s_32,
7018 : FIB_SOURCE_API,
7019 : DPO_PROTO_IP4,
7020 : &nh_10_10_11_1,
7021 1 : tm->hw[1]->sw_if_index,
7022 : ~0, // invalid fib index
7023 : 1,
7024 : FIB_ROUTE_PATH_FLAG_NONE);
7025 :
7026 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7027 1 : FIB_TEST(!fib_test_validate_entry(fei,
7028 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7029 : 1,
7030 : &adj_o_10_10_11_2),
7031 : "1.1.1.1/32 LB 1 buckets via: "
7032 : "adj over 10.10.11.2");
7033 :
7034 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7035 : &pfx_24001_eos);
7036 1 : FIB_TEST(!fib_test_validate_entry(fei,
7037 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7038 : 1,
7039 : &disp_o_10_10_11_2),
7040 : "24001/eos LB 1 buckets via: "
7041 : "MPLS disp adj over 10.10.11.2");
7042 :
7043 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7044 : &pfx_24001_neos);
7045 1 : FIB_TEST(!fib_test_validate_entry(fei,
7046 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7047 : 1,
7048 : &mpls_bucket_drop),
7049 : "24001/neos LB 1 buckets via: DROP");
7050 :
7051 : /*
7052 : * add back the path with the valid label
7053 : */
7054 1 : l99 = NULL;
7055 1 : vec_add1(l99, fml99);
7056 :
7057 1 : fib_table_entry_path_add(fib_index,
7058 : &pfx_1_1_1_1_s_32,
7059 : FIB_SOURCE_API,
7060 : FIB_ENTRY_FLAG_NONE,
7061 : DPO_PROTO_IP4,
7062 : &nh_10_10_10_1,
7063 1 : tm->hw[0]->sw_if_index,
7064 : ~0, // invalid fib index
7065 : 1,
7066 : l99,
7067 : FIB_ROUTE_PATH_FLAG_NONE);
7068 :
7069 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7070 1 : FIB_TEST(!fib_test_validate_entry(fei,
7071 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7072 : 2,
7073 : &l99_eos_o_10_10_10_1,
7074 : &adj_o_10_10_11_2),
7075 : "1.1.1.1/32 LB 2 buckets via: "
7076 : "label 99 over 10.10.10.1, "
7077 : "adj over 10.10.11.2");
7078 :
7079 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7080 : &pfx_24001_eos);
7081 1 : FIB_TEST(!fib_test_validate_entry(fei,
7082 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7083 : 2,
7084 : &l99_eos_o_10_10_10_1,
7085 : &disp_o_10_10_11_2),
7086 : "24001/eos LB 2 buckets via: "
7087 : "label 99 over 10.10.10.1, "
7088 : "MPLS disp adj over 10.10.11.2");
7089 :
7090 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7091 : &pfx_24001_neos);
7092 1 : FIB_TEST(!fib_test_validate_entry(fei,
7093 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7094 : 1,
7095 : &l99_neos_o_10_10_10_1),
7096 : "24001/neos LB 1 buckets via: "
7097 : "label 99 over 10.10.10.1");
7098 :
7099 : /*
7100 : * change the local label
7101 : */
7102 1 : fib_table_entry_local_label_add(fib_index,
7103 : &pfx_1_1_1_1_s_32,
7104 : 25005);
7105 :
7106 1 : fib_prefix_t pfx_25005_eos = {
7107 : .fp_proto = FIB_PROTOCOL_MPLS,
7108 : .fp_label = 25005,
7109 : .fp_eos = MPLS_EOS,
7110 : };
7111 1 : fib_prefix_t pfx_25005_neos = {
7112 : .fp_proto = FIB_PROTOCOL_MPLS,
7113 : .fp_label = 25005,
7114 : .fp_eos = MPLS_NON_EOS,
7115 : };
7116 :
7117 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
7118 : fib_table_lookup(fib_index, &pfx_24001_eos)),
7119 : "24001/eos removed after label change");
7120 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
7121 : fib_table_lookup(fib_index, &pfx_24001_neos)),
7122 : "24001/eos removed after label change");
7123 :
7124 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7125 : &pfx_25005_eos);
7126 1 : FIB_TEST(!fib_test_validate_entry(fei,
7127 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7128 : 2,
7129 : &l99_eos_o_10_10_10_1,
7130 : &disp_o_10_10_11_2),
7131 : "25005/eos LB 2 buckets via: "
7132 : "label 99 over 10.10.10.1, "
7133 : "MPLS disp adj over 10.10.11.2");
7134 :
7135 1 : fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7136 : &pfx_25005_neos);
7137 1 : FIB_TEST(!fib_test_validate_entry(fei,
7138 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7139 : 1,
7140 : &l99_neos_o_10_10_10_1),
7141 : "25005/neos LB 1 buckets via: "
7142 : "label 99 over 10.10.10.1");
7143 :
7144 : /*
7145 : * remove the local label.
7146 : * the check that the MPLS entries are gone is done by the fact the
7147 : * MPLS table is no longer present.
7148 : */
7149 1 : fib_table_entry_local_label_remove(fib_index,
7150 : &pfx_1_1_1_1_s_32,
7151 : 25005);
7152 :
7153 1 : fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7154 1 : FIB_TEST(!fib_test_validate_entry(fei,
7155 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7156 : 2,
7157 : &l99_eos_o_10_10_10_1,
7158 : &adj_o_10_10_11_2),
7159 : "24001/eos LB 2 buckets via: "
7160 : "label 99 over 10.10.10.1, "
7161 : "adj over 10.10.11.2");
7162 :
7163 1 : FIB_TEST((FIB_NODE_INDEX_INVALID ==
7164 : mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
7165 : "No more MPLS FIB entries => table removed");
7166 :
7167 : /*
7168 : * add another via-entry for the recursive
7169 : */
7170 2 : fib_prefix_t pfx_1_1_1_2_s_32 = {
7171 : .fp_len = 32,
7172 : .fp_proto = FIB_PROTOCOL_IP4,
7173 : .fp_addr = {
7174 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
7175 : },
7176 : };
7177 1 : fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
7178 : .type = FT_LB_LABEL_O_ADJ,
7179 : .label_o_adj = {
7180 : .adj = ai_mpls_10_10_10_1,
7181 : .label = 101,
7182 : .eos = MPLS_EOS,
7183 : },
7184 : };
7185 1 : fib_mpls_label_t *l101 = NULL, fml101 = {
7186 : .fml_value = 101,
7187 : };
7188 1 : vec_add1(l101, fml101);
7189 :
7190 1 : fei = fib_table_entry_update_one_path(fib_index,
7191 : &pfx_1_1_1_2_s_32,
7192 : FIB_SOURCE_API,
7193 : FIB_ENTRY_FLAG_NONE,
7194 : DPO_PROTO_IP4,
7195 : &nh_10_10_10_1,
7196 1 : tm->hw[0]->sw_if_index,
7197 : ~0, // invalid fib index
7198 : 1,
7199 : l101,
7200 : FIB_ROUTE_PATH_FLAG_NONE);
7201 :
7202 1 : FIB_TEST(!fib_test_validate_entry(fei,
7203 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7204 : 1,
7205 : &l101_eos_o_10_10_10_1),
7206 : "1.1.1.2/32 LB 1 buckets via: "
7207 : "label 101 over 10.10.10.1");
7208 :
7209 1 : dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
7210 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7211 : &pfx_1_1_1_1_s_32),
7212 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7213 : &non_eos_1_1_1_1);
7214 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7215 : &pfx_1_1_1_2_s_32),
7216 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7217 : &non_eos_1_1_1_2);
7218 :
7219 1 : fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
7220 : .type = FT_LB_LABEL_O_LB,
7221 : .label_o_lb = {
7222 1 : .lb = non_eos_1_1_1_2.dpoi_index,
7223 : .label = 1601,
7224 : .eos = MPLS_EOS,
7225 : },
7226 : };
7227 1 : fib_mpls_label_t *l1601 = NULL, fml1601 = {
7228 : .fml_value = 1601,
7229 : };
7230 1 : vec_add1(l1601, fml1601);
7231 :
7232 1 : l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
7233 :
7234 1 : fei = fib_table_entry_path_add(fib_index,
7235 : &pfx_2_2_2_2_s_32,
7236 : FIB_SOURCE_API,
7237 : FIB_ENTRY_FLAG_NONE,
7238 : DPO_PROTO_IP4,
7239 : &pfx_1_1_1_2_s_32.fp_addr,
7240 : ~0,
7241 : fib_index,
7242 : 1,
7243 : l1601,
7244 : FIB_ROUTE_PATH_FLAG_NONE);
7245 :
7246 1 : FIB_TEST(!fib_test_validate_entry(fei,
7247 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7248 : 2,
7249 : &l1600_eos_o_1_1_1_1,
7250 : &l1601_eos_o_1_1_1_2),
7251 : "2.2.2.2/32 LB 2 buckets via: "
7252 : "label 1600 via 1.1,1.1, "
7253 : "label 16001 via 1.1.1.2");
7254 :
7255 : /*
7256 : * update the via-entry so it no longer has an imp-null path.
7257 : * the LB for the recursive can use an imp-null
7258 : */
7259 1 : l_imp_null = NULL;
7260 1 : vec_add1(l_imp_null, fml_imp_null);
7261 :
7262 1 : fei = fib_table_entry_update_one_path(fib_index,
7263 : &pfx_1_1_1_2_s_32,
7264 : FIB_SOURCE_API,
7265 : FIB_ENTRY_FLAG_NONE,
7266 : DPO_PROTO_IP4,
7267 : &nh_10_10_11_1,
7268 1 : tm->hw[1]->sw_if_index,
7269 : ~0, // invalid fib index
7270 : 1,
7271 : l_imp_null,
7272 : FIB_ROUTE_PATH_FLAG_NONE);
7273 :
7274 1 : FIB_TEST(!fib_test_validate_entry(fei,
7275 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7276 : 1,
7277 : &a_o_10_10_11_1),
7278 : "1.1.1.2/32 LB 1 buckets via: "
7279 : "adj 10.10.11.1");
7280 :
7281 1 : fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7282 1 : FIB_TEST(!fib_test_validate_entry(fei,
7283 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7284 : 2,
7285 : &l1600_eos_o_1_1_1_1,
7286 : &l1601_eos_o_1_1_1_2),
7287 : "2.2.2.2/32 LB 2 buckets via: "
7288 : "label 1600 via 1.1,1.1, "
7289 : "label 16001 via 1.1.1.2");
7290 :
7291 : /*
7292 : * update the via-entry so it no longer has labelled paths.
7293 : * the LB for the recursive should exclue this via form its LB
7294 : */
7295 1 : fei = fib_table_entry_update_one_path(fib_index,
7296 : &pfx_1_1_1_2_s_32,
7297 : FIB_SOURCE_API,
7298 : FIB_ENTRY_FLAG_NONE,
7299 : DPO_PROTO_IP4,
7300 : &nh_10_10_11_1,
7301 1 : tm->hw[1]->sw_if_index,
7302 : ~0, // invalid fib index
7303 : 1,
7304 : NULL,
7305 : FIB_ROUTE_PATH_FLAG_NONE);
7306 :
7307 1 : FIB_TEST(!fib_test_validate_entry(fei,
7308 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7309 : 1,
7310 : &a_o_10_10_11_1),
7311 : "1.1.1.2/32 LB 1 buckets via: "
7312 : "adj 10.10.11.1");
7313 :
7314 1 : fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7315 1 : FIB_TEST(!fib_test_validate_entry(fei,
7316 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7317 : 1,
7318 : &l1600_eos_o_1_1_1_1),
7319 : "2.2.2.2/32 LB 1 buckets via: "
7320 : "label 1600 via 1.1,1.1");
7321 :
7322 1 : dpo_reset(&non_eos_1_1_1_1);
7323 1 : dpo_reset(&non_eos_1_1_1_2);
7324 :
7325 : /*
7326 : * Add a recursive with no out-labels. We expect to use the IP of the via
7327 : */
7328 2 : fib_prefix_t pfx_2_2_2_3_s_32 = {
7329 : .fp_len = 32,
7330 : .fp_proto = FIB_PROTOCOL_IP4,
7331 : .fp_addr = {
7332 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7333 : },
7334 : };
7335 1 : dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7336 :
7337 1 : fib_table_entry_update_one_path(fib_index,
7338 : &pfx_2_2_2_3_s_32,
7339 : FIB_SOURCE_API,
7340 : FIB_ENTRY_FLAG_NONE,
7341 : DPO_PROTO_IP4,
7342 : &pfx_1_1_1_1_s_32.fp_addr,
7343 : ~0,
7344 : fib_index,
7345 : 1,
7346 : NULL,
7347 : FIB_ROUTE_PATH_FLAG_NONE);
7348 :
7349 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7350 : &pfx_1_1_1_1_s_32),
7351 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7352 : &ip_1_1_1_1);
7353 :
7354 1 : fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7355 : .type = FT_LB_O_LB,
7356 : .lb = {
7357 1 : .lb = ip_1_1_1_1.dpoi_index,
7358 : },
7359 : };
7360 :
7361 1 : fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7362 1 : FIB_TEST(!fib_test_validate_entry(fei,
7363 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7364 : 1,
7365 : &ip_o_1_1_1_1),
7366 : "2.2.2.2.3/32 LB 1 buckets via: "
7367 : "ip 1.1.1.1");
7368 :
7369 : /*
7370 : * Add a recursive with an imp-null out-label.
7371 : * We expect to use the IP of the via
7372 : */
7373 2 : fib_prefix_t pfx_2_2_2_4_s_32 = {
7374 : .fp_len = 32,
7375 : .fp_proto = FIB_PROTOCOL_IP4,
7376 : .fp_addr = {
7377 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7378 : },
7379 : };
7380 :
7381 1 : fib_table_entry_update_one_path(fib_index,
7382 : &pfx_2_2_2_4_s_32,
7383 : FIB_SOURCE_API,
7384 : FIB_ENTRY_FLAG_NONE,
7385 : DPO_PROTO_IP4,
7386 : &pfx_1_1_1_1_s_32.fp_addr,
7387 : ~0,
7388 : fib_index,
7389 : 1,
7390 : NULL,
7391 : FIB_ROUTE_PATH_FLAG_NONE);
7392 :
7393 1 : fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7394 1 : FIB_TEST(!fib_test_validate_entry(fei,
7395 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7396 : 1,
7397 : &ip_o_1_1_1_1),
7398 : "2.2.2.2.4/32 LB 1 buckets via: "
7399 : "ip 1.1.1.1");
7400 :
7401 1 : dpo_reset(&ip_1_1_1_1);
7402 :
7403 : /*
7404 : * Create an entry with a deep label stack
7405 : */
7406 2 : fib_prefix_t pfx_2_2_5_5_s_32 = {
7407 : .fp_len = 32,
7408 : .fp_proto = FIB_PROTOCOL_IP4,
7409 : .fp_addr = {
7410 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7411 : },
7412 : };
7413 1 : fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7414 : .type = FT_LB_LABEL_STACK_O_ADJ,
7415 : .label_stack_o_adj = {
7416 : .adj = ai_mpls_10_10_11_1,
7417 : .label_stack_size = 8,
7418 : .label_stack = {
7419 : 200, 201, 202, 203, 204, 205, 206, 207
7420 : },
7421 : .eos = MPLS_EOS,
7422 : },
7423 : };
7424 1 : fib_mpls_label_t *label_stack = NULL;
7425 1 : vec_validate(label_stack, 7);
7426 9 : for (ii = 0; ii < 8; ii++)
7427 : {
7428 8 : label_stack[ii].fml_value = ii + 200;
7429 : }
7430 :
7431 1 : fei = fib_table_entry_update_one_path(fib_index,
7432 : &pfx_2_2_5_5_s_32,
7433 : FIB_SOURCE_API,
7434 : FIB_ENTRY_FLAG_NONE,
7435 : DPO_PROTO_IP4,
7436 : &nh_10_10_11_1,
7437 1 : tm->hw[1]->sw_if_index,
7438 : ~0, // invalid fib index
7439 : 1,
7440 : label_stack,
7441 : FIB_ROUTE_PATH_FLAG_NONE);
7442 :
7443 1 : FIB_TEST(!fib_test_validate_entry(fei,
7444 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7445 : 1,
7446 : &ls_eos_o_10_10_10_1),
7447 : "2.2.5.5/32 LB 1 buckets via: "
7448 : "adj 10.10.11.1");
7449 1 : fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7450 :
7451 : /*
7452 : * A prefix with outgoing labels. We'll RR source a /32 it covers
7453 : * and test that the RR source picks up the out-going labels
7454 : */
7455 2 : fib_prefix_t pfx_100_s_8 = {
7456 : .fp_len = 8,
7457 : .fp_proto = FIB_PROTOCOL_IP4,
7458 : .fp_addr = {
7459 1 : .ip4.as_u32 = clib_host_to_net_u32(0x64000000),
7460 : },
7461 : };
7462 1 : fib_test_lb_bucket_t l_100_eos_o_10_10_10_1 = {
7463 : .type = FT_LB_LABEL_O_ADJ,
7464 : .label_o_adj = {
7465 : .adj = ai_mpls_10_10_11_1,
7466 : .label = 1602,
7467 : .eos = MPLS_EOS,
7468 : },
7469 : };
7470 1 : fib_mpls_label_t *l1602 = NULL, fml1602 = {
7471 : .fml_value = 1602,
7472 : };
7473 1 : vec_add1(l1602, fml1602);
7474 1 : fei = fib_table_entry_update_one_path(fib_index,
7475 : &pfx_100_s_8,
7476 : FIB_SOURCE_API,
7477 : FIB_ENTRY_FLAG_NONE,
7478 : DPO_PROTO_IP4,
7479 : &nh_10_10_11_1,
7480 1 : tm->hw[1]->sw_if_index,
7481 : ~0, // invalid fib index
7482 : 1,
7483 : l1602,
7484 : FIB_ROUTE_PATH_FLAG_NONE);
7485 :
7486 1 : FIB_TEST(!fib_test_validate_entry(fei,
7487 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7488 : 1,
7489 : &l_100_eos_o_10_10_10_1),
7490 : "100.0.0.0/8 LB 1 buckets via: lbl 101 "
7491 : "adj 10.10.11.1");
7492 :
7493 2 : fib_prefix_t pfx_100_1_1_1_s_32 = {
7494 : .fp_len = 32,
7495 : .fp_proto = FIB_PROTOCOL_IP4,
7496 : .fp_addr = {
7497 1 : .ip4.as_u32 = clib_host_to_net_u32(0x64010101),
7498 : },
7499 : };
7500 :
7501 1 : fei = fib_table_entry_special_add(fib_index,
7502 : &pfx_100_1_1_1_s_32,
7503 : FIB_SOURCE_RR,
7504 : FIB_ENTRY_FLAG_NONE);
7505 :
7506 1 : FIB_TEST(!fib_test_validate_entry(fei,
7507 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7508 : 1,
7509 : &l_100_eos_o_10_10_10_1),
7510 : "100.1.1.1/32 LB 1 buckets via: "
7511 : "adj 10.10.11.1");
7512 :
7513 1 : fib_table_entry_delete(fib_index,
7514 : &pfx_100_s_8,
7515 : FIB_SOURCE_API);
7516 1 : fib_table_entry_delete_index(fei, FIB_SOURCE_RR);
7517 :
7518 : /*
7519 : * cleanup
7520 : */
7521 1 : fib_table_entry_delete(fib_index,
7522 : &pfx_1_1_1_2_s_32,
7523 : FIB_SOURCE_API);
7524 :
7525 1 : fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7526 1 : FIB_TEST(!fib_test_validate_entry(fei,
7527 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7528 : 1,
7529 : &l1600_eos_o_1_1_1_1),
7530 : "2.2.2.2/32 LB 1 buckets via: "
7531 : "label 1600 via 1.1,1.1");
7532 :
7533 1 : fib_table_entry_delete(fib_index,
7534 : &pfx_1_1_1_1_s_32,
7535 : FIB_SOURCE_API);
7536 :
7537 1 : FIB_TEST(!fib_test_validate_entry(fei,
7538 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7539 : 1,
7540 : &bucket_drop),
7541 : "2.2.2.2/32 LB 1 buckets via: DROP");
7542 :
7543 1 : fib_table_entry_delete(fib_index,
7544 : &pfx_2_2_2_2_s_32,
7545 : FIB_SOURCE_API);
7546 1 : fib_table_entry_delete(fib_index,
7547 : &pfx_2_2_2_3_s_32,
7548 : FIB_SOURCE_API);
7549 1 : fib_table_entry_delete(fib_index,
7550 : &pfx_2_2_2_4_s_32,
7551 : FIB_SOURCE_API);
7552 :
7553 1 : adj_unlock(ai_mpls_10_10_10_1);
7554 1 : adj_unlock(ai_mpls_10_10_11_2);
7555 1 : adj_unlock(ai_v4_10_10_11_1);
7556 1 : adj_unlock(ai_v4_10_10_11_2);
7557 1 : adj_unlock(ai_mpls_10_10_11_1);
7558 :
7559 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7560 : adj_nbr_db_size());
7561 :
7562 1 : local0_pfx.fp_len = 32;
7563 1 : fib_table_entry_delete(fib_index,
7564 : &local0_pfx,
7565 : FIB_SOURCE_INTERFACE);
7566 1 : local0_pfx.fp_len = 24;
7567 1 : fib_table_entry_delete(fib_index,
7568 : &local0_pfx,
7569 : FIB_SOURCE_INTERFACE);
7570 1 : local1_pfx.fp_len = 32;
7571 1 : fib_table_entry_delete(fib_index,
7572 : &local1_pfx,
7573 : FIB_SOURCE_INTERFACE);
7574 1 : local1_pfx.fp_len = 24;
7575 1 : fib_table_entry_delete(fib_index,
7576 : &local1_pfx,
7577 : FIB_SOURCE_INTERFACE);
7578 :
7579 : /*
7580 : * +1 for the drop LB in the MPLS tables.
7581 : */
7582 1 : FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7583 : "Load-balance resources freed %d of %d",
7584 : lb_count+1, pool_elts(load_balance_pool));
7585 :
7586 1 : return (res);
7587 : }
7588 :
7589 : #define N_TEST_CHILDREN 4
7590 : #define PARENT_INDEX 0
7591 :
7592 : typedef struct fib_node_test_t_
7593 : {
7594 : fib_node_t node;
7595 : u32 sibling;
7596 : u32 index;
7597 : fib_node_back_walk_ctx_t *ctxs;
7598 : u32 destroyed;
7599 : } fib_node_test_t;
7600 :
7601 : static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7602 :
7603 : #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7604 :
7605 : #define FOR_EACH_TEST_CHILD(_tc) \
7606 : for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7607 : ii < N_TEST_CHILDREN+1; \
7608 : ii++, (_tc) = &fib_test_nodes[ii])
7609 :
7610 : static fib_node_t *
7611 349 : fib_test_child_get_node (fib_node_index_t index)
7612 : {
7613 349 : return (&fib_test_nodes[index].node);
7614 : }
7615 :
7616 : static int fib_test_walk_spawns_walks;
7617 : static fib_node_type_t test_node_type;
7618 :
7619 : static fib_node_back_walk_rc_t
7620 132 : fib_test_child_back_walk_notify (fib_node_t *node,
7621 : fib_node_back_walk_ctx_t *ctx)
7622 : {
7623 132 : fib_node_test_t *tc = (fib_node_test_t*) node;
7624 :
7625 132 : vec_add1(tc->ctxs, *ctx);
7626 :
7627 132 : if (1 == fib_test_walk_spawns_walks)
7628 16 : fib_walk_sync(test_node_type, tc->index, ctx);
7629 132 : if (2 == fib_test_walk_spawns_walks)
7630 80 : fib_walk_async(test_node_type, tc->index,
7631 : FIB_WALK_PRIORITY_HIGH, ctx);
7632 :
7633 132 : return (FIB_NODE_BACK_WALK_CONTINUE);
7634 : }
7635 :
7636 : static void
7637 5 : fib_test_child_last_lock_gone (fib_node_t *node)
7638 : {
7639 5 : fib_node_test_t *tc = (fib_node_test_t *)node;
7640 :
7641 5 : tc->destroyed = 1;
7642 5 : }
7643 :
7644 : /**
7645 : * The FIB walk's graph node virtual function table
7646 : */
7647 : static const fib_node_vft_t fib_test_child_vft = {
7648 : .fnv_get = fib_test_child_get_node,
7649 : .fnv_last_lock = fib_test_child_last_lock_gone,
7650 : .fnv_back_walk = fib_test_child_back_walk_notify,
7651 : };
7652 :
7653 : /*
7654 : * the function (that should have been static but isn't so I can do this)
7655 : * that processes the walk from the async queue,
7656 : */
7657 : f64 fib_walk_process_queues(vlib_main_t * vm,
7658 : const f64 quota);
7659 : u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7660 :
7661 : static int
7662 1 : fib_test_walk (void)
7663 : {
7664 1 : fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7665 : fib_node_test_t *tc;
7666 : vlib_main_t *vm;
7667 : u32 ii, res;
7668 :
7669 1 : res = 0;
7670 1 : vm = vlib_get_main();
7671 1 : test_node_type = fib_node_register_new_type("fib-test", &fib_test_child_vft);
7672 :
7673 : /*
7674 : * init a fake node on which we will add children
7675 : */
7676 1 : fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7677 : test_node_type);
7678 :
7679 5 : FOR_EACH_TEST_CHILD(tc)
7680 : {
7681 4 : fib_node_init(&tc->node, test_node_type);
7682 4 : fib_node_lock(&tc->node);
7683 4 : tc->ctxs = NULL;
7684 4 : tc->index = ii;
7685 4 : tc->sibling = fib_node_child_add(test_node_type,
7686 : PARENT_INDEX,
7687 : test_node_type, ii);
7688 : }
7689 :
7690 : /*
7691 : * enqueue a walk across the parents children.
7692 : */
7693 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7694 :
7695 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7696 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7697 1 : FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7698 : "Parent has %d children pre-walk",
7699 : fib_node_list_get_size(PARENT()->fn_children));
7700 :
7701 : /*
7702 : * give the walk a large amount of time so it gets to the end
7703 : */
7704 1 : fib_walk_process_queues(vm, 1);
7705 :
7706 5 : FOR_EACH_TEST_CHILD(tc)
7707 : {
7708 4 : FIB_TEST(1 == vec_len(tc->ctxs),
7709 : "%d child visitsed %d times",
7710 : ii, vec_len(tc->ctxs));
7711 4 : vec_free(tc->ctxs);
7712 : }
7713 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7714 : "Queue is empty post walk");
7715 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7716 : "Parent has %d children post walk",
7717 : fib_node_list_get_size(PARENT()->fn_children));
7718 :
7719 : /*
7720 : * walk again. should be no increase in the number of visits, since
7721 : * the walk will have terminated.
7722 : */
7723 1 : fib_walk_process_queues(vm, 1);
7724 :
7725 5 : FOR_EACH_TEST_CHILD(tc)
7726 : {
7727 4 : FIB_TEST(0 == vec_len(tc->ctxs),
7728 : "%d child visitsed %d times",
7729 : ii, vec_len(tc->ctxs));
7730 : }
7731 :
7732 : /*
7733 : * schedule a low and hig priority walk. expect the high to be performed
7734 : * before the low.
7735 : * schedule the high prio walk first so that it is further from the head
7736 : * of the dependency list. that way it won't merge with the low one.
7737 : */
7738 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7739 1 : low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7740 :
7741 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7742 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7743 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7744 : FIB_WALK_PRIORITY_LOW, &low_ctx);
7745 :
7746 1 : fib_walk_process_queues(vm, 1);
7747 :
7748 5 : FOR_EACH_TEST_CHILD(tc)
7749 : {
7750 4 : FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7751 : "%d child visitsed by high prio walk", ii);
7752 4 : FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7753 : "%d child visitsed by low prio walk", ii);
7754 4 : vec_free(tc->ctxs);
7755 : }
7756 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7757 : "Queue is empty post prio walk");
7758 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7759 : "Parent has %d children post prio walk",
7760 : fib_node_list_get_size(PARENT()->fn_children));
7761 :
7762 : /*
7763 : * schedule 2 walks of the same priority that can be megred.
7764 : * expect that each child is thus visited only once.
7765 : */
7766 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7767 1 : low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7768 :
7769 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7770 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7771 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7772 : FIB_WALK_PRIORITY_HIGH, &low_ctx);
7773 :
7774 1 : fib_walk_process_queues(vm, 1);
7775 :
7776 5 : FOR_EACH_TEST_CHILD(tc)
7777 : {
7778 4 : FIB_TEST(1 == vec_len(tc->ctxs),
7779 : "%d child visitsed %d times during merge walk",
7780 : ii, vec_len(tc->ctxs));
7781 4 : vec_free(tc->ctxs);
7782 : }
7783 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7784 : "Queue is empty post merge walk");
7785 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7786 : "Parent has %d children post merge walk",
7787 : fib_node_list_get_size(PARENT()->fn_children));
7788 :
7789 : /*
7790 : * schedule 2 walks of the same priority that cannot be megred.
7791 : * expect that each child is thus visited twice and in the order
7792 : * in which the walks were scheduled.
7793 : */
7794 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7795 1 : low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7796 :
7797 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7798 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7799 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7800 : FIB_WALK_PRIORITY_HIGH, &low_ctx);
7801 :
7802 1 : fib_walk_process_queues(vm, 1);
7803 :
7804 5 : FOR_EACH_TEST_CHILD(tc)
7805 : {
7806 4 : FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7807 : "%d child visitsed by high prio walk", ii);
7808 4 : FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7809 : "%d child visitsed by low prio walk", ii);
7810 4 : vec_free(tc->ctxs);
7811 : }
7812 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7813 : "Queue is empty post no-merge walk");
7814 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7815 : "Parent has %d children post no-merge walk",
7816 : fib_node_list_get_size(PARENT()->fn_children));
7817 :
7818 : /*
7819 : * schedule a walk that makes one one child progress.
7820 : * we do this by giving the queue draining process zero
7821 : * time quanta. it's a do..while loop, so it does something.
7822 : */
7823 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7824 :
7825 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7826 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7827 1 : fib_walk_process_queues(vm, 0);
7828 :
7829 5 : FOR_EACH_TEST_CHILD(tc)
7830 : {
7831 4 : if (ii == N_TEST_CHILDREN)
7832 : {
7833 1 : FIB_TEST(1 == vec_len(tc->ctxs),
7834 : "%d child visitsed %d times in zero quanta walk",
7835 : ii, vec_len(tc->ctxs));
7836 : }
7837 : else
7838 : {
7839 3 : FIB_TEST(0 == vec_len(tc->ctxs),
7840 : "%d child visitsed %d times in 0 quanta walk",
7841 : ii, vec_len(tc->ctxs));
7842 : }
7843 : }
7844 1 : FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7845 : "Queue is not empty post zero quanta walk");
7846 1 : FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7847 : "Parent has %d children post zero qunta walk",
7848 : fib_node_list_get_size(PARENT()->fn_children));
7849 :
7850 : /*
7851 : * another one step
7852 : */
7853 1 : fib_walk_process_queues(vm, 0);
7854 :
7855 5 : FOR_EACH_TEST_CHILD(tc)
7856 : {
7857 4 : if (ii >= N_TEST_CHILDREN-1)
7858 : {
7859 2 : FIB_TEST(1 == vec_len(tc->ctxs),
7860 : "%d child visitsed %d times in 2nd zero quanta walk",
7861 : ii, vec_len(tc->ctxs));
7862 : }
7863 : else
7864 : {
7865 2 : FIB_TEST(0 == vec_len(tc->ctxs),
7866 : "%d child visitsed %d times in 2nd 0 quanta walk",
7867 : ii, vec_len(tc->ctxs));
7868 : }
7869 : }
7870 1 : FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7871 : "Queue is not empty post zero quanta walk");
7872 1 : FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7873 : "Parent has %d children post zero qunta walk",
7874 : fib_node_list_get_size(PARENT()->fn_children));
7875 :
7876 : /*
7877 : * schedule another walk that will catch-up and merge.
7878 : */
7879 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7880 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7881 1 : fib_walk_process_queues(vm, 1);
7882 :
7883 5 : FOR_EACH_TEST_CHILD(tc)
7884 : {
7885 4 : if (ii >= N_TEST_CHILDREN-1)
7886 : {
7887 2 : FIB_TEST(2 == vec_len(tc->ctxs),
7888 : "%d child visitsed %d times in 2nd zero quanta merge walk",
7889 : ii, vec_len(tc->ctxs));
7890 2 : vec_free(tc->ctxs);
7891 : }
7892 : else
7893 : {
7894 2 : FIB_TEST(1 == vec_len(tc->ctxs),
7895 : "%d child visitsed %d times in 2nd 0 quanta merge walk",
7896 : ii, vec_len(tc->ctxs));
7897 2 : vec_free(tc->ctxs);
7898 : }
7899 : }
7900 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7901 : "Queue is not empty post 2nd zero quanta merge walk");
7902 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7903 : "Parent has %d children post 2nd zero qunta merge walk",
7904 : fib_node_list_get_size(PARENT()->fn_children));
7905 :
7906 : /*
7907 : * park a async walk in the middle of the list, then have an sync walk catch
7908 : * it. same expectations as async catches async.
7909 : */
7910 1 : high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7911 :
7912 1 : fib_walk_async(test_node_type, PARENT_INDEX,
7913 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
7914 :
7915 1 : fib_walk_process_queues(vm, 0);
7916 1 : fib_walk_process_queues(vm, 0);
7917 :
7918 1 : fib_walk_sync(test_node_type, PARENT_INDEX, &high_ctx);
7919 :
7920 5 : FOR_EACH_TEST_CHILD(tc)
7921 : {
7922 4 : if (ii >= N_TEST_CHILDREN-1)
7923 : {
7924 2 : FIB_TEST(2 == vec_len(tc->ctxs),
7925 : "%d child visitsed %d times in sync catches async walk",
7926 : ii, vec_len(tc->ctxs));
7927 2 : vec_free(tc->ctxs);
7928 : }
7929 : else
7930 : {
7931 2 : FIB_TEST(1 == vec_len(tc->ctxs),
7932 : "%d child visitsed %d times in sync catches async walk",
7933 : ii, vec_len(tc->ctxs));
7934 2 : vec_free(tc->ctxs);
7935 : }
7936 : }
7937 1 : FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7938 : "Queue is not empty post 2nd zero quanta merge walk");
7939 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7940 : "Parent has %d children post 2nd zero qunta merge walk",
7941 : fib_node_list_get_size(PARENT()->fn_children));
7942 :
7943 : /*
7944 : * make the parent a child of one of its children, thus inducing a routing loop.
7945 : */
7946 1 : fib_test_nodes[PARENT_INDEX].sibling =
7947 1 : fib_node_child_add(test_node_type,
7948 : 1, // the first child
7949 : test_node_type,
7950 : PARENT_INDEX);
7951 :
7952 : /*
7953 : * execute a sync walk from the parent. each child visited spawns more sync
7954 : * walks. we expect the walk to terminate.
7955 : */
7956 1 : fib_test_walk_spawns_walks = 1;
7957 :
7958 1 : fib_walk_sync(test_node_type, PARENT_INDEX, &high_ctx);
7959 :
7960 5 : FOR_EACH_TEST_CHILD(tc)
7961 : {
7962 : /*
7963 : * child 1 - which is last in the list - has the loop.
7964 : * the other children a re thus visitsed first. the we meet
7965 : * child 1. we go round the loop again, visting the other children.
7966 : * then we meet the walk in the dep list and bail. child 1 is not visitsed
7967 : * again.
7968 : */
7969 4 : if (1 == ii)
7970 : {
7971 1 : FIB_TEST(1 == vec_len(tc->ctxs),
7972 : "child %d visitsed %d times during looped sync walk",
7973 : ii, vec_len(tc->ctxs));
7974 : }
7975 : else
7976 : {
7977 3 : FIB_TEST(2 == vec_len(tc->ctxs),
7978 : "child %d visitsed %d times during looped sync walk",
7979 : ii, vec_len(tc->ctxs));
7980 : }
7981 4 : vec_free(tc->ctxs);
7982 : }
7983 1 : FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7984 : "Parent has %d children post sync loop walk",
7985 : fib_node_list_get_size(PARENT()->fn_children));
7986 :
7987 : /*
7988 : * the walk doesn't reach the max depth because the infra knows that sync
7989 : * meets sync implies a loop and bails early.
7990 : */
7991 1 : FIB_TEST(high_ctx.fnbw_depth == 9,
7992 : "Walk context depth %d post sync loop walk",
7993 : high_ctx.fnbw_depth);
7994 :
7995 : /*
7996 : * execute an async walk of the graph loop, with each child spawns sync walks
7997 : */
7998 1 : high_ctx.fnbw_depth = 0;
7999 1 : fib_walk_async(test_node_type, PARENT_INDEX,
8000 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
8001 :
8002 1 : fib_walk_process_queues(vm, 1);
8003 :
8004 5 : FOR_EACH_TEST_CHILD(tc)
8005 : {
8006 : /*
8007 : * we don't really care how many times the children are visited, as long as
8008 : * it is more than once.
8009 : */
8010 4 : FIB_TEST(1 <= vec_len(tc->ctxs),
8011 : "child %d visitsed %d times during looped aync spawns sync walk",
8012 : ii, vec_len(tc->ctxs));
8013 4 : vec_free(tc->ctxs);
8014 : }
8015 :
8016 : /*
8017 : * execute an async walk of the graph loop, with each child spawns async walks
8018 : */
8019 1 : fib_test_walk_spawns_walks = 2;
8020 1 : high_ctx.fnbw_depth = 0;
8021 1 : fib_walk_async(test_node_type, PARENT_INDEX,
8022 : FIB_WALK_PRIORITY_HIGH, &high_ctx);
8023 :
8024 1 : fib_walk_process_queues(vm, 1);
8025 :
8026 5 : FOR_EACH_TEST_CHILD(tc)
8027 : {
8028 : /*
8029 : * we don't really care how many times the children are visited, as long as
8030 : * it is more than once.
8031 : */
8032 4 : FIB_TEST(1 <= vec_len(tc->ctxs),
8033 : "child %d visitsed %d times during looped async spawns async walk",
8034 : ii, vec_len(tc->ctxs));
8035 4 : vec_free(tc->ctxs);
8036 : }
8037 :
8038 :
8039 1 : fib_node_child_remove(test_node_type,
8040 : 1, // the first child
8041 : fib_test_nodes[PARENT_INDEX].sibling);
8042 :
8043 : /*
8044 : * cleanup
8045 : */
8046 5 : FOR_EACH_TEST_CHILD(tc)
8047 : {
8048 4 : fib_node_child_remove(test_node_type, PARENT_INDEX,
8049 : tc->sibling);
8050 4 : fib_node_deinit(&tc->node);
8051 4 : fib_node_unlock(&tc->node);
8052 : }
8053 1 : fib_node_deinit(PARENT());
8054 :
8055 : /*
8056 : * The parent will be destroyed when the last lock on it goes.
8057 : * this test ensures all the walk objects are unlocking it.
8058 : */
8059 1 : FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
8060 : "Parent was destroyed");
8061 :
8062 1 : return (res);
8063 : }
8064 :
8065 : /*
8066 : * declaration of the otherwise static callback functions
8067 : */
8068 : void fib_bfd_notify (bfd_listen_event_e event,
8069 : const bfd_session_t *session);
8070 : void adj_bfd_notify (bfd_listen_event_e event,
8071 : const bfd_session_t *session);
8072 :
8073 : /**
8074 : * Test BFD session interaction with FIB
8075 : */
8076 : static int
8077 1 : fib_test_bfd (void)
8078 : {
8079 : fib_node_index_t fei;
8080 : test_main_t *tm;
8081 : int n_feis, res;
8082 :
8083 1 : res = 0;
8084 : /* via 10.10.10.1 */
8085 2 : ip46_address_t nh_10_10_10_1 = {
8086 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8087 : };
8088 : /* via 10.10.10.2 */
8089 2 : ip46_address_t nh_10_10_10_2 = {
8090 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
8091 : };
8092 : /* via 10.10.10.10 */
8093 2 : ip46_address_t nh_10_10_10_10 = {
8094 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
8095 : };
8096 1 : n_feis = fib_entry_pool_size();
8097 :
8098 1 : tm = &test_main;
8099 :
8100 : /*
8101 : * add interface routes. we'll assume this works. it's tested elsewhere
8102 : */
8103 1 : fib_prefix_t pfx_10_10_10_10_s_24 = {
8104 : .fp_len = 24,
8105 : .fp_proto = FIB_PROTOCOL_IP4,
8106 : .fp_addr = nh_10_10_10_10,
8107 : };
8108 :
8109 1 : fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
8110 : FIB_SOURCE_INTERFACE,
8111 : (FIB_ENTRY_FLAG_CONNECTED |
8112 : FIB_ENTRY_FLAG_ATTACHED),
8113 : DPO_PROTO_IP4,
8114 : NULL,
8115 1 : tm->hw[0]->sw_if_index,
8116 : ~0, // invalid fib index
8117 : 1, // weight
8118 : NULL,
8119 : FIB_ROUTE_PATH_FLAG_NONE);
8120 :
8121 1 : fib_prefix_t pfx_10_10_10_10_s_32 = {
8122 : .fp_len = 32,
8123 : .fp_proto = FIB_PROTOCOL_IP4,
8124 : .fp_addr = nh_10_10_10_10,
8125 : };
8126 1 : fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
8127 : FIB_SOURCE_INTERFACE,
8128 : (FIB_ENTRY_FLAG_CONNECTED |
8129 : FIB_ENTRY_FLAG_LOCAL),
8130 : DPO_PROTO_IP4,
8131 : NULL,
8132 1 : tm->hw[0]->sw_if_index,
8133 : ~0, // invalid fib index
8134 : 1, // weight
8135 : NULL,
8136 : FIB_ROUTE_PATH_FLAG_NONE);
8137 :
8138 : /*
8139 : * A BFD session via a neighbour we do not yet know
8140 : */
8141 1 : bfd_session_t bfd_10_10_10_1 = {
8142 : .udp = {
8143 : .key = {
8144 : .fib_index = 0,
8145 : .peer_addr = nh_10_10_10_1,
8146 : },
8147 : },
8148 : .hop_type = BFD_HOP_TYPE_MULTI,
8149 : .local_state = BFD_STATE_init,
8150 : };
8151 :
8152 1 : fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8153 :
8154 : /*
8155 : * A new entry will be created that forwards via the adj
8156 : */
8157 1 : adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8158 : VNET_LINK_IP4,
8159 : &nh_10_10_10_1,
8160 1 : tm->hw[0]->sw_if_index);
8161 1 : fib_prefix_t pfx_10_10_10_1_s_32 = {
8162 : .fp_addr = nh_10_10_10_1,
8163 : .fp_len = 32,
8164 : .fp_proto = FIB_PROTOCOL_IP4,
8165 : };
8166 1 : fib_test_lb_bucket_t adj_o_10_10_10_1 = {
8167 : .type = FT_LB_ADJ,
8168 : .adj = {
8169 : .adj = ai_10_10_10_1,
8170 : },
8171 : };
8172 :
8173 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8174 1 : FIB_TEST(!fib_test_validate_entry(fei,
8175 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8176 : 1,
8177 : &adj_o_10_10_10_1),
8178 : "BFD sourced %U via %U",
8179 : format_fib_prefix, &pfx_10_10_10_1_s_32,
8180 : format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8181 :
8182 : /*
8183 : * Delete the BFD session. Expect the fib_entry to be removed
8184 : */
8185 1 : fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8186 :
8187 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8188 1 : FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
8189 : "BFD sourced %U removed",
8190 : format_fib_prefix, &pfx_10_10_10_1_s_32);
8191 :
8192 : /*
8193 : * Add the BFD source back
8194 : */
8195 1 : fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8196 :
8197 : /*
8198 : * source the entry via the ADJ fib
8199 : */
8200 1 : fei = fib_table_entry_path_add(0,
8201 : &pfx_10_10_10_1_s_32,
8202 : FIB_SOURCE_ADJ,
8203 : FIB_ENTRY_FLAG_ATTACHED,
8204 : DPO_PROTO_IP4,
8205 : &nh_10_10_10_1,
8206 1 : tm->hw[0]->sw_if_index,
8207 : ~0, // invalid fib index
8208 : 1,
8209 : NULL,
8210 : FIB_ROUTE_PATH_FLAG_NONE);
8211 :
8212 : /*
8213 : * Delete the BFD session. Expect the fib_entry to remain
8214 : */
8215 1 : fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8216 :
8217 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8218 1 : FIB_TEST(!fib_test_validate_entry(fei,
8219 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8220 : 1,
8221 : &adj_o_10_10_10_1),
8222 : "BFD sourced %U remains via %U",
8223 : format_fib_prefix, &pfx_10_10_10_1_s_32,
8224 : format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8225 :
8226 : /*
8227 : * Add the BFD source back
8228 : */
8229 1 : fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8230 :
8231 : /*
8232 : * Create another ADJ FIB
8233 : */
8234 1 : fib_prefix_t pfx_10_10_10_2_s_32 = {
8235 : .fp_addr = nh_10_10_10_2,
8236 : .fp_len = 32,
8237 : .fp_proto = FIB_PROTOCOL_IP4,
8238 : };
8239 1 : fib_table_entry_path_add(0,
8240 : &pfx_10_10_10_2_s_32,
8241 : FIB_SOURCE_ADJ,
8242 : FIB_ENTRY_FLAG_ATTACHED,
8243 : DPO_PROTO_IP4,
8244 : &nh_10_10_10_2,
8245 1 : tm->hw[0]->sw_if_index,
8246 : ~0, // invalid fib index
8247 : 1,
8248 : NULL,
8249 : FIB_ROUTE_PATH_FLAG_NONE);
8250 : /*
8251 : * A BFD session for the new ADJ FIB
8252 : */
8253 1 : bfd_session_t bfd_10_10_10_2 = {
8254 : .udp = {
8255 : .key = {
8256 : .fib_index = 0,
8257 : .peer_addr = nh_10_10_10_2,
8258 : },
8259 : },
8260 : .hop_type = BFD_HOP_TYPE_MULTI,
8261 : .local_state = BFD_STATE_init,
8262 : };
8263 :
8264 1 : fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
8265 :
8266 : /*
8267 : * remove the adj-fib source whilst the session is present
8268 : * then add it back
8269 : */
8270 1 : fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8271 1 : fib_table_entry_path_add(0,
8272 : &pfx_10_10_10_2_s_32,
8273 : FIB_SOURCE_ADJ,
8274 : FIB_ENTRY_FLAG_ATTACHED,
8275 : DPO_PROTO_IP4,
8276 : &nh_10_10_10_2,
8277 1 : tm->hw[0]->sw_if_index,
8278 : ~0, // invalid fib index
8279 : 1,
8280 : NULL,
8281 : FIB_ROUTE_PATH_FLAG_NONE);
8282 :
8283 : /*
8284 : * Before adding a recursive via the BFD tracked ADJ-FIBs,
8285 : * bring one of the sessions UP, leave the other down
8286 : */
8287 1 : bfd_10_10_10_1.local_state = BFD_STATE_up;
8288 1 : fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8289 1 : bfd_10_10_10_2.local_state = BFD_STATE_down;
8290 1 : fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8291 :
8292 : /*
8293 : * A recursive prefix via both of the ADJ FIBs
8294 : */
8295 2 : fib_prefix_t pfx_200_0_0_0_s_24 = {
8296 : .fp_proto = FIB_PROTOCOL_IP4,
8297 : .fp_len = 32,
8298 : .fp_addr = {
8299 1 : .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
8300 : },
8301 : };
8302 : const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
8303 :
8304 : dpo_10_10_10_1 =
8305 1 : fib_entry_contribute_ip_forwarding(
8306 : fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
8307 : dpo_10_10_10_2 =
8308 1 : fib_entry_contribute_ip_forwarding(
8309 : fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
8310 :
8311 1 : fib_test_lb_bucket_t lb_o_10_10_10_1 = {
8312 : .type = FT_LB_O_LB,
8313 : .lb = {
8314 1 : .lb = dpo_10_10_10_1->dpoi_index,
8315 : },
8316 : };
8317 1 : fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8318 : .type = FT_LB_O_LB,
8319 : .lb = {
8320 1 : .lb = dpo_10_10_10_2->dpoi_index,
8321 : },
8322 : };
8323 :
8324 : /*
8325 : * A prefix via the adj-fib that is BFD down => DROP
8326 : */
8327 1 : fei = fib_table_entry_path_add(0,
8328 : &pfx_200_0_0_0_s_24,
8329 : FIB_SOURCE_API,
8330 : FIB_ENTRY_FLAG_NONE,
8331 : DPO_PROTO_IP4,
8332 : &nh_10_10_10_2,
8333 : ~0, // recursive
8334 : 0, // default fib index
8335 : 1,
8336 : NULL,
8337 : FIB_ROUTE_PATH_FLAG_NONE);
8338 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8339 : "%U resolves via drop",
8340 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8341 :
8342 : /*
8343 : * add a path via the UP BFD adj-fib.
8344 : * we expect that the DOWN BFD ADJ FIB is not used.
8345 : */
8346 1 : fei = fib_table_entry_path_add(0,
8347 : &pfx_200_0_0_0_s_24,
8348 : FIB_SOURCE_API,
8349 : FIB_ENTRY_FLAG_NONE,
8350 : DPO_PROTO_IP4,
8351 : &nh_10_10_10_1,
8352 : ~0, // recursive
8353 : 0, // default fib index
8354 : 1,
8355 : NULL,
8356 : FIB_ROUTE_PATH_FLAG_NONE);
8357 :
8358 1 : FIB_TEST(!fib_test_validate_entry(fei,
8359 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8360 : 1,
8361 : &lb_o_10_10_10_1),
8362 : "Recursive %U only UP BFD adj-fibs",
8363 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8364 :
8365 : /*
8366 : * Send a BFD state change to UP - both sessions are now up
8367 : * the recursive prefix should LB over both
8368 : */
8369 1 : bfd_10_10_10_2.local_state = BFD_STATE_up;
8370 1 : fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8371 :
8372 :
8373 1 : FIB_TEST(!fib_test_validate_entry(fei,
8374 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8375 : 2,
8376 : &lb_o_10_10_10_1,
8377 : &lb_o_10_10_10_2),
8378 : "Recursive %U via both UP BFD adj-fibs",
8379 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8380 :
8381 : /*
8382 : * Send a BFD state change to DOWN
8383 : * the recursive prefix should exclude the down
8384 : */
8385 1 : bfd_10_10_10_2.local_state = BFD_STATE_down;
8386 1 : fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8387 :
8388 :
8389 1 : FIB_TEST(!fib_test_validate_entry(fei,
8390 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8391 : 1,
8392 : &lb_o_10_10_10_1),
8393 : "Recursive %U via only UP",
8394 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8395 :
8396 : /*
8397 : * Delete the BFD session while it is in the DOWN state.
8398 : * FIB should consider the entry's state as back up
8399 : */
8400 1 : fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8401 :
8402 1 : FIB_TEST(!fib_test_validate_entry(fei,
8403 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8404 : 2,
8405 : &lb_o_10_10_10_1,
8406 : &lb_o_10_10_10_2),
8407 : "Recursive %U via both UP BFD adj-fibs post down session delete",
8408 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8409 :
8410 : /*
8411 : * Delete the BFD other session while it is in the UP state.
8412 : */
8413 1 : fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8414 :
8415 1 : FIB_TEST(!fib_test_validate_entry(fei,
8416 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8417 : 2,
8418 : &lb_o_10_10_10_1,
8419 : &lb_o_10_10_10_2),
8420 : "Recursive %U via both UP BFD adj-fibs post up session delete",
8421 : format_fib_prefix, &pfx_200_0_0_0_s_24);
8422 :
8423 : /*
8424 : * cleaup
8425 : */
8426 1 : fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8427 1 : fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8428 1 : fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8429 :
8430 1 : fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8431 1 : fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8432 :
8433 1 : adj_unlock(ai_10_10_10_1);
8434 : /*
8435 : * test no-one left behind
8436 : */
8437 1 : FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8438 1 : FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8439 :
8440 : /*
8441 : * Single-hop BFD tests
8442 : */
8443 1 : bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8444 1 : bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8445 :
8446 1 : ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8447 : VNET_LINK_IP4,
8448 : &nh_10_10_10_1,
8449 1 : tm->hw[0]->sw_if_index);
8450 1 : bfd_10_10_10_1.udp.adj_index = ai_10_10_10_1;
8451 :
8452 1 : adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8453 :
8454 : /*
8455 : * whilst the BFD session is not signalled, the adj is up
8456 : */
8457 1 : FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
8458 :
8459 : /*
8460 : * bring the BFD session up
8461 : */
8462 1 : bfd_10_10_10_1.local_state = BFD_STATE_up;
8463 1 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8464 1 : FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8465 :
8466 : /*
8467 : * bring the BFD session down
8468 : */
8469 1 : bfd_10_10_10_1.local_state = BFD_STATE_down;
8470 1 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8471 1 : FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8472 :
8473 : /*
8474 : * add an attached next hop FIB entry via the down adj
8475 : */
8476 2 : fib_prefix_t pfx_5_5_5_5_s_32 = {
8477 : .fp_addr = {
8478 : .ip4 = {
8479 1 : .as_u32 = clib_host_to_net_u32(0x05050505),
8480 : },
8481 : },
8482 : .fp_len = 32,
8483 : .fp_proto = FIB_PROTOCOL_IP4,
8484 : };
8485 :
8486 1 : fei = fib_table_entry_path_add(0,
8487 : &pfx_5_5_5_5_s_32,
8488 : FIB_SOURCE_CLI,
8489 : FIB_ENTRY_FLAG_NONE,
8490 : DPO_PROTO_IP4,
8491 : &nh_10_10_10_1,
8492 1 : tm->hw[0]->sw_if_index,
8493 : ~0, // invalid fib index
8494 : 1,
8495 : NULL,
8496 : FIB_ROUTE_PATH_FLAG_NONE);
8497 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8498 : "%U resolves via drop",
8499 : format_fib_prefix, &pfx_5_5_5_5_s_32);
8500 :
8501 : /*
8502 : * Add a path via an ADJ that is up
8503 : */
8504 1 : adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8505 : VNET_LINK_IP4,
8506 : &nh_10_10_10_2,
8507 1 : tm->hw[0]->sw_if_index);
8508 :
8509 1 : fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8510 : .type = FT_LB_ADJ,
8511 : .adj = {
8512 : .adj = ai_10_10_10_2,
8513 : },
8514 : };
8515 1 : adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8516 :
8517 1 : fei = fib_table_entry_path_add(0,
8518 : &pfx_5_5_5_5_s_32,
8519 : FIB_SOURCE_CLI,
8520 : FIB_ENTRY_FLAG_NONE,
8521 : DPO_PROTO_IP4,
8522 : &nh_10_10_10_2,
8523 1 : tm->hw[0]->sw_if_index,
8524 : ~0, // invalid fib index
8525 : 1,
8526 : NULL,
8527 : FIB_ROUTE_PATH_FLAG_NONE);
8528 :
8529 1 : FIB_TEST(!fib_test_validate_entry(fei,
8530 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8531 : 1,
8532 : &adj_o_10_10_10_2),
8533 : "BFD sourced %U via %U",
8534 : format_fib_prefix, &pfx_5_5_5_5_s_32,
8535 : format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8536 :
8537 : /*
8538 : * Bring up the down session - should now LB
8539 : */
8540 1 : bfd_10_10_10_1.local_state = BFD_STATE_up;
8541 1 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8542 1 : FIB_TEST(!fib_test_validate_entry(fei,
8543 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8544 : 2,
8545 : &adj_o_10_10_10_1,
8546 : &adj_o_10_10_10_2),
8547 : "BFD sourced %U via noth adjs",
8548 : format_fib_prefix, &pfx_5_5_5_5_s_32);
8549 :
8550 : /*
8551 : * remove the BFD session state from the adj
8552 : */
8553 1 : adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8554 :
8555 : /*
8556 : * clean-up
8557 : */
8558 1 : fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8559 1 : adj_unlock(ai_10_10_10_1);
8560 1 : adj_unlock(ai_10_10_10_2);
8561 :
8562 : /*
8563 : * test no-one left behind
8564 : */
8565 1 : FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8566 1 : FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8567 :
8568 1 : return (res);
8569 : }
8570 :
8571 : static int
8572 1 : lfib_test (void)
8573 : {
8574 1 : const mpls_label_t deag_label = 50;
8575 : adj_index_t ai_mpls_10_10_10_1;
8576 1 : dpo_id_t dpo = DPO_INVALID;
8577 1 : const u32 lfib_index = 0;
8578 1 : const u32 fib_index = 0;
8579 : const dpo_id_t *dpo1;
8580 : fib_node_index_t lfe;
8581 : lookup_dpo_t *lkd;
8582 : int lb_count, res;
8583 : test_main_t *tm;
8584 :
8585 1 : res = 0;
8586 1 : tm = &test_main;
8587 1 : lb_count = pool_elts(load_balance_pool);
8588 :
8589 1 : FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8590 : adj_nbr_db_size());
8591 :
8592 : /*
8593 : * MPLS enable an interface so we get the MPLS table created
8594 : */
8595 1 : mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8596 1 : mpls_sw_interface_enable_disable(&mpls_main,
8597 1 : tm->hw[0]->sw_if_index,
8598 : 1);
8599 :
8600 2 : ip46_address_t nh_10_10_10_1 = {
8601 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8602 : };
8603 1 : ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8604 : VNET_LINK_MPLS,
8605 : &nh_10_10_10_1,
8606 1 : tm->hw[0]->sw_if_index);
8607 :
8608 : /*
8609 : * Test the specials stack properly.
8610 : */
8611 1 : fib_prefix_t exp_null_v6_pfx = {
8612 : .fp_proto = FIB_PROTOCOL_MPLS,
8613 : .fp_eos = MPLS_EOS,
8614 : .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8615 : .fp_payload_proto = DPO_PROTO_IP6,
8616 : };
8617 1 : lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8618 1 : FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8619 : "%U/%U present",
8620 : format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8621 : format_mpls_eos_bit, MPLS_EOS);
8622 1 : fib_entry_contribute_forwarding(lfe,
8623 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8624 : &dpo);
8625 1 : dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8626 1 : lkd = lookup_dpo_get(dpo1->dpoi_index);
8627 :
8628 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
8629 : "%U/%U is deag in %d %U",
8630 : format_mpls_unicast_label, deag_label,
8631 : format_mpls_eos_bit, MPLS_EOS,
8632 : lkd->lkd_fib_index,
8633 : format_dpo_id, &dpo, 0);
8634 1 : FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8635 : "%U/%U is dst deag",
8636 : format_mpls_unicast_label, deag_label,
8637 : format_mpls_eos_bit, MPLS_EOS);
8638 1 : FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8639 : "%U/%U is lookup in interface's table",
8640 : format_mpls_unicast_label, deag_label,
8641 : format_mpls_eos_bit, MPLS_EOS);
8642 1 : FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8643 : "%U/%U is %U dst deag",
8644 : format_mpls_unicast_label, deag_label,
8645 : format_mpls_eos_bit, MPLS_EOS,
8646 : format_dpo_proto, lkd->lkd_proto);
8647 :
8648 : /*
8649 : * A route deag route for EOS
8650 : */
8651 1 : fib_prefix_t pfx = {
8652 : .fp_proto = FIB_PROTOCOL_MPLS,
8653 : .fp_eos = MPLS_EOS,
8654 : .fp_label = deag_label,
8655 : .fp_payload_proto = DPO_PROTO_IP4,
8656 : };
8657 : mpls_disp_dpo_t *mdd;
8658 1 : lfe = fib_table_entry_path_add(lfib_index,
8659 : &pfx,
8660 : FIB_SOURCE_CLI,
8661 : FIB_ENTRY_FLAG_NONE,
8662 : DPO_PROTO_IP4,
8663 : &zero_addr,
8664 : ~0,
8665 : fib_index,
8666 : 1,
8667 : NULL,
8668 : FIB_ROUTE_PATH_FLAG_NONE);
8669 :
8670 1 : FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8671 : "%U/%U present",
8672 : format_mpls_unicast_label, deag_label,
8673 : format_mpls_eos_bit, MPLS_EOS);
8674 :
8675 1 : fib_entry_contribute_forwarding(lfe,
8676 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8677 : &dpo);
8678 1 : dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8679 1 : mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8680 :
8681 1 : FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
8682 : "%U/%U disp is pipe mode",
8683 : format_mpls_unicast_label, deag_label,
8684 : format_mpls_eos_bit, MPLS_EOS);
8685 :
8686 1 : lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8687 :
8688 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
8689 : "%U/%U is deag in %d %U",
8690 : format_mpls_unicast_label, deag_label,
8691 : format_mpls_eos_bit, MPLS_EOS,
8692 : lkd->lkd_fib_index,
8693 : format_dpo_id, &dpo, 0);
8694 1 : FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8695 : "%U/%U is dst deag",
8696 : format_mpls_unicast_label, deag_label,
8697 : format_mpls_eos_bit, MPLS_EOS);
8698 1 : FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8699 : "%U/%U is %U dst deag",
8700 : format_mpls_unicast_label, deag_label,
8701 : format_mpls_eos_bit, MPLS_EOS,
8702 : format_dpo_proto, lkd->lkd_proto);
8703 :
8704 1 : fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8705 :
8706 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8707 : &pfx)),
8708 : "%U/%U not present",
8709 : format_mpls_unicast_label, deag_label,
8710 : format_mpls_eos_bit, MPLS_EOS);
8711 1 : dpo_reset(&dpo);
8712 :
8713 : /*
8714 : * A route deag route for EOS with LSP mode uniform
8715 : */
8716 1 : fib_mpls_label_t *l_pops = NULL, l_pop = {
8717 : .fml_value = MPLS_LABEL_POP,
8718 : .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
8719 : };
8720 1 : vec_add1(l_pops, l_pop);
8721 1 : lfe = fib_table_entry_path_add(lfib_index,
8722 : &pfx,
8723 : FIB_SOURCE_CLI,
8724 : FIB_ENTRY_FLAG_NONE,
8725 : DPO_PROTO_IP4,
8726 : &zero_addr,
8727 : ~0,
8728 : fib_index,
8729 : 1,
8730 : l_pops,
8731 : FIB_ROUTE_PATH_FLAG_NONE);
8732 :
8733 1 : FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8734 : "%U/%U present",
8735 : format_mpls_unicast_label, deag_label,
8736 : format_mpls_eos_bit, MPLS_EOS);
8737 :
8738 1 : fib_entry_contribute_forwarding(lfe,
8739 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8740 : &dpo);
8741 1 : dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8742 1 : mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8743 :
8744 1 : FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
8745 : "%U/%U disp is uniform mode",
8746 : format_mpls_unicast_label, deag_label,
8747 : format_mpls_eos_bit, MPLS_EOS);
8748 :
8749 1 : lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8750 :
8751 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
8752 : "%U/%U is deag in %d %U",
8753 : format_mpls_unicast_label, deag_label,
8754 : format_mpls_eos_bit, MPLS_EOS,
8755 : lkd->lkd_fib_index,
8756 : format_dpo_id, &dpo, 0);
8757 1 : FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8758 : "%U/%U is dst deag",
8759 : format_mpls_unicast_label, deag_label,
8760 : format_mpls_eos_bit, MPLS_EOS);
8761 1 : FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8762 : "%U/%U is %U dst deag",
8763 : format_mpls_unicast_label, deag_label,
8764 : format_mpls_eos_bit, MPLS_EOS,
8765 : format_dpo_proto, lkd->lkd_proto);
8766 :
8767 1 : fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8768 :
8769 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8770 : &pfx)),
8771 : "%U/%U not present",
8772 : format_mpls_unicast_label, deag_label,
8773 : format_mpls_eos_bit, MPLS_EOS);
8774 1 : dpo_reset(&dpo);
8775 :
8776 : /*
8777 : * A route deag route for non-EOS
8778 : */
8779 1 : pfx.fp_eos = MPLS_NON_EOS;
8780 1 : lfe = fib_table_entry_path_add(lfib_index,
8781 : &pfx,
8782 : FIB_SOURCE_CLI,
8783 : FIB_ENTRY_FLAG_NONE,
8784 : DPO_PROTO_IP4,
8785 : &zero_addr,
8786 : ~0,
8787 : lfib_index,
8788 : 1,
8789 : NULL,
8790 : FIB_ROUTE_PATH_FLAG_NONE);
8791 :
8792 1 : FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8793 : "%U/%U present",
8794 : format_mpls_unicast_label, deag_label,
8795 : format_mpls_eos_bit, MPLS_NON_EOS);
8796 :
8797 1 : fib_entry_contribute_forwarding(lfe,
8798 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8799 : &dpo);
8800 1 : dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8801 1 : lkd = lookup_dpo_get(dpo1->dpoi_index);
8802 :
8803 1 : FIB_TEST((fib_index == lkd->lkd_fib_index),
8804 : "%U/%U is deag in %d %U",
8805 : format_mpls_unicast_label, deag_label,
8806 : format_mpls_eos_bit, MPLS_NON_EOS,
8807 : lkd->lkd_fib_index,
8808 : format_dpo_id, &dpo, 0);
8809 1 : FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8810 : "%U/%U is dst deag",
8811 : format_mpls_unicast_label, deag_label,
8812 : format_mpls_eos_bit, MPLS_NON_EOS);
8813 :
8814 1 : FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8815 : "%U/%U is %U dst deag",
8816 : format_mpls_unicast_label, deag_label,
8817 : format_mpls_eos_bit, MPLS_NON_EOS,
8818 : format_dpo_proto, lkd->lkd_proto);
8819 :
8820 1 : fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8821 :
8822 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8823 : &pfx)),
8824 : "%U/%U not present",
8825 : format_mpls_unicast_label, deag_label,
8826 : format_mpls_eos_bit, MPLS_EOS);
8827 :
8828 1 : dpo_reset(&dpo);
8829 :
8830 : /*
8831 : * An MPLS x-connect
8832 : */
8833 1 : fib_prefix_t pfx_1200 = {
8834 : .fp_len = 21,
8835 : .fp_proto = FIB_PROTOCOL_MPLS,
8836 : .fp_label = 1200,
8837 : .fp_eos = MPLS_NON_EOS,
8838 : };
8839 1 : fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8840 : .type = FT_LB_LABEL_STACK_O_ADJ,
8841 : .label_stack_o_adj = {
8842 : .adj = ai_mpls_10_10_10_1,
8843 : .label_stack_size = 4,
8844 : .label_stack = {
8845 : 200, 300, 400, 500,
8846 : },
8847 : .eos = MPLS_NON_EOS,
8848 : },
8849 : };
8850 1 : dpo_id_t neos_1200 = DPO_INVALID;
8851 1 : dpo_id_t ip_1200 = DPO_INVALID;
8852 1 : fib_mpls_label_t *l200 = NULL;
8853 : u32 ii;
8854 5 : for (ii = 0; ii < 4; ii++)
8855 : {
8856 4 : fib_mpls_label_t fml = {
8857 4 : .fml_value = 200 + (ii * 100),
8858 : };
8859 4 : vec_add1(l200, fml);
8860 : };
8861 :
8862 1 : lfe = fib_table_entry_update_one_path(fib_index,
8863 : &pfx_1200,
8864 : FIB_SOURCE_API,
8865 : FIB_ENTRY_FLAG_NONE,
8866 : DPO_PROTO_IP4,
8867 : &nh_10_10_10_1,
8868 1 : tm->hw[0]->sw_if_index,
8869 : ~0, // invalid fib index
8870 : 1,
8871 : l200,
8872 : FIB_ROUTE_PATH_FLAG_NONE);
8873 :
8874 1 : FIB_TEST(!fib_test_validate_entry(lfe,
8875 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8876 : 1,
8877 : &neos_o_10_10_10_1),
8878 : "1200/0 LB 1 buckets via: "
8879 : "adj 10.10.11.1");
8880 :
8881 : /*
8882 : * A recursive route via the MPLS x-connect
8883 : */
8884 2 : fib_prefix_t pfx_2_2_2_3_s_32 = {
8885 : .fp_len = 32,
8886 : .fp_proto = FIB_PROTOCOL_IP4,
8887 : .fp_addr = {
8888 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8889 : },
8890 : };
8891 1 : fib_route_path_t *rpaths = NULL, rpath = {
8892 : .frp_proto = DPO_PROTO_MPLS,
8893 : .frp_local_label = 1200,
8894 : .frp_eos = MPLS_NON_EOS,
8895 : .frp_sw_if_index = ~0, // recurive
8896 : .frp_fib_index = 0, // Default MPLS fib
8897 : .frp_weight = 1,
8898 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8899 : .frp_label_stack = NULL,
8900 : };
8901 1 : vec_add1(rpaths, rpath);
8902 :
8903 1 : fib_table_entry_path_add2(fib_index,
8904 : &pfx_2_2_2_3_s_32,
8905 : FIB_SOURCE_API,
8906 : FIB_ENTRY_FLAG_NONE,
8907 : rpaths);
8908 :
8909 : /*
8910 : * A labelled recursive route via the MPLS x-connect
8911 : */
8912 2 : fib_prefix_t pfx_2_2_2_4_s_32 = {
8913 : .fp_len = 32,
8914 : .fp_proto = FIB_PROTOCOL_IP4,
8915 : .fp_addr = {
8916 1 : .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8917 : },
8918 : };
8919 1 : fib_mpls_label_t *l999 = NULL, fml_999 = {
8920 : .fml_value = 999,
8921 : };
8922 1 : vec_add1(l999, fml_999);
8923 1 : rpaths[0].frp_label_stack = l999,
8924 :
8925 1 : fib_table_entry_path_add2(fib_index,
8926 : &pfx_2_2_2_4_s_32,
8927 : FIB_SOURCE_API,
8928 : FIB_ENTRY_FLAG_NONE,
8929 : rpaths);
8930 :
8931 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8932 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8933 : &ip_1200);
8934 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8935 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8936 : &neos_1200);
8937 :
8938 1 : fib_test_lb_bucket_t ip_o_1200 = {
8939 : .type = FT_LB_O_LB,
8940 : .lb = {
8941 1 : .lb = ip_1200.dpoi_index,
8942 : },
8943 : };
8944 1 : fib_test_lb_bucket_t mpls_o_1200 = {
8945 : .type = FT_LB_LABEL_O_LB,
8946 : .label_o_lb = {
8947 1 : .lb = neos_1200.dpoi_index,
8948 : .label = 999,
8949 : .eos = MPLS_EOS,
8950 : },
8951 : };
8952 :
8953 1 : lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8954 1 : FIB_TEST(!fib_test_validate_entry(lfe,
8955 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8956 : 1,
8957 : &ip_o_1200),
8958 : "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8959 1 : lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8960 1 : FIB_TEST(!fib_test_validate_entry(lfe,
8961 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8962 : 1,
8963 : &mpls_o_1200),
8964 : "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8965 :
8966 1 : fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8967 1 : fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8968 1 : fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8969 :
8970 1 : dpo_reset(&neos_1200);
8971 1 : dpo_reset(&ip_1200);
8972 :
8973 : /*
8974 : * A recursive via a label that does not exist
8975 : */
8976 1 : fib_test_lb_bucket_t bucket_drop = {
8977 : .type = FT_LB_DROP,
8978 : .special = {
8979 : .adj = DPO_PROTO_IP4,
8980 : },
8981 : };
8982 1 : fib_test_lb_bucket_t mpls_bucket_drop = {
8983 : .type = FT_LB_DROP,
8984 : .special = {
8985 : .adj = DPO_PROTO_MPLS,
8986 : },
8987 : };
8988 :
8989 1 : rpaths[0].frp_label_stack = NULL;
8990 1 : lfe = fib_table_entry_path_add2(fib_index,
8991 : &pfx_2_2_2_4_s_32,
8992 : FIB_SOURCE_API,
8993 : FIB_ENTRY_FLAG_NONE,
8994 : rpaths);
8995 :
8996 1 : fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8997 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8998 : &ip_1200);
8999 1 : ip_o_1200.lb.lb = ip_1200.dpoi_index;
9000 :
9001 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9002 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9003 : 1,
9004 : &bucket_drop),
9005 : "2.2.2.2.4/32 LB 1 buckets via: drop");
9006 1 : lfe = fib_table_lookup(fib_index, &pfx_1200);
9007 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9008 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9009 : 1,
9010 : &bucket_drop),
9011 : "1200/neos LB 1 buckets via: ip4-DROP");
9012 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9013 : FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
9014 : 1,
9015 : &mpls_bucket_drop),
9016 : "1200/neos LB 1 buckets via: mpls-DROP");
9017 :
9018 1 : fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
9019 :
9020 1 : dpo_reset(&ip_1200);
9021 :
9022 : /*
9023 : * An rx-interface route.
9024 : * like the tail of an mcast LSP
9025 : */
9026 1 : dpo_id_t idpo = DPO_INVALID;
9027 :
9028 1 : interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
9029 1 : tm->hw[0]->sw_if_index,
9030 : &idpo);
9031 :
9032 1 : fib_prefix_t pfx_2500 = {
9033 : .fp_len = 21,
9034 : .fp_proto = FIB_PROTOCOL_MPLS,
9035 : .fp_label = 2500,
9036 : .fp_eos = MPLS_EOS,
9037 : .fp_payload_proto = DPO_PROTO_IP4,
9038 : };
9039 1 : fib_test_lb_bucket_t rx_intf_0 = {
9040 : .type = FT_LB_INTF,
9041 : .adj = {
9042 1 : .adj = idpo.dpoi_index,
9043 : },
9044 : };
9045 :
9046 1 : lfe = fib_table_entry_update_one_path(fib_index,
9047 : &pfx_2500,
9048 : FIB_SOURCE_API,
9049 : FIB_ENTRY_FLAG_NONE,
9050 : DPO_PROTO_IP4,
9051 : NULL,
9052 1 : tm->hw[0]->sw_if_index,
9053 : ~0, // invalid fib index
9054 : 0,
9055 : NULL,
9056 : FIB_ROUTE_PATH_INTF_RX);
9057 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9058 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9059 : 1,
9060 : &rx_intf_0),
9061 : "2500 rx-interface 0");
9062 1 : fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
9063 :
9064 : /*
9065 : * An MPLS mulicast entry
9066 : */
9067 1 : fib_prefix_t pfx_3500 = {
9068 : .fp_len = 21,
9069 : .fp_proto = FIB_PROTOCOL_MPLS,
9070 : .fp_label = 3500,
9071 : .fp_eos = MPLS_EOS,
9072 : .fp_payload_proto = DPO_PROTO_IP4,
9073 : };
9074 1 : fib_test_rep_bucket_t mc_0 = {
9075 : .type = FT_REP_LABEL_O_ADJ,
9076 : .label_o_adj = {
9077 : .adj = ai_mpls_10_10_10_1,
9078 : .label = 3300,
9079 : .eos = MPLS_EOS,
9080 : },
9081 : };
9082 1 : fib_test_rep_bucket_t mc_intf_0 = {
9083 : .type = FT_REP_INTF,
9084 : .adj = {
9085 1 : .adj = idpo.dpoi_index,
9086 : },
9087 : };
9088 1 : fib_mpls_label_t *l3300 = NULL, fml_3300 = {
9089 : .fml_value = 3300,
9090 : };
9091 1 : vec_add1(l3300, fml_3300);
9092 :
9093 1 : lfe = fib_table_entry_update_one_path(lfib_index,
9094 : &pfx_3500,
9095 : FIB_SOURCE_API,
9096 : FIB_ENTRY_FLAG_MULTICAST,
9097 : DPO_PROTO_IP4,
9098 : &nh_10_10_10_1,
9099 1 : tm->hw[0]->sw_if_index,
9100 : ~0, // invalid fib index
9101 : 1,
9102 : l3300,
9103 : FIB_ROUTE_PATH_FLAG_NONE);
9104 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9105 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9106 : 1,
9107 : &mc_0),
9108 : "3500 via replicate over 10.10.10.1");
9109 :
9110 : /*
9111 : * MPLS Bud-node. Add a replication via an interface-receieve path
9112 : */
9113 1 : lfe = fib_table_entry_path_add(lfib_index,
9114 : &pfx_3500,
9115 : FIB_SOURCE_API,
9116 : FIB_ENTRY_FLAG_MULTICAST,
9117 : DPO_PROTO_IP4,
9118 : NULL,
9119 1 : tm->hw[0]->sw_if_index,
9120 : ~0, // invalid fib index
9121 : 0,
9122 : NULL,
9123 : FIB_ROUTE_PATH_INTF_RX);
9124 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9125 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9126 : 2,
9127 : &mc_0,
9128 : &mc_intf_0),
9129 : "3500 via replicate over 10.10.10.1 and interface-rx");
9130 :
9131 : /*
9132 : * Add a replication via an interface-free for-us path
9133 : */
9134 1 : fib_test_rep_bucket_t mc_disp = {
9135 : .type = FT_REP_DISP_MFIB_LOOKUP,
9136 : .adj = {
9137 1 : .adj = idpo.dpoi_index,
9138 : },
9139 : };
9140 1 : lfe = fib_table_entry_path_add(lfib_index,
9141 : &pfx_3500,
9142 : FIB_SOURCE_API,
9143 : FIB_ENTRY_FLAG_MULTICAST,
9144 : DPO_PROTO_IP4,
9145 : NULL,
9146 : 5, // rpf-id
9147 : 0, // default table
9148 : 0,
9149 : NULL,
9150 : FIB_ROUTE_PATH_RPF_ID);
9151 1 : FIB_TEST(!fib_test_validate_entry(lfe,
9152 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9153 : 3,
9154 : &mc_0,
9155 : &mc_disp,
9156 : &mc_intf_0),
9157 : "3500 via replicate over 10.10.10.1 and interface-rx");
9158 :
9159 :
9160 :
9161 1 : fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
9162 1 : dpo_reset(&idpo);
9163 :
9164 : /*
9165 : * cleanup
9166 : */
9167 1 : mpls_sw_interface_enable_disable(&mpls_main,
9168 1 : tm->hw[0]->sw_if_index,
9169 : 0);
9170 1 : mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
9171 :
9172 1 : FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
9173 : "mpls_disp_dpo resources freed %d of %d",
9174 : 0, pool_elts(mpls_disp_dpo_pool));
9175 1 : FIB_TEST(lb_count == pool_elts(load_balance_pool),
9176 : "Load-balance resources freed %d of %d",
9177 : lb_count, pool_elts(load_balance_pool));
9178 1 : FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
9179 : "interface_rx_dpo resources freed %d of %d",
9180 : 0, pool_elts(interface_rx_dpo_pool));
9181 :
9182 1 : return (res);
9183 : }
9184 :
9185 : static int
9186 1 : fib_test_inherit (void)
9187 : {
9188 : fib_node_index_t fei;
9189 : int n_feis, res, i;
9190 : test_main_t *tm;
9191 :
9192 1 : tm = &test_main;
9193 1 : res = 0;
9194 :
9195 4 : for (i = 0; i <= 2; i++)
9196 : {
9197 3 : fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[i]->sw_if_index, 0);
9198 3 : fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[i]->sw_if_index, 0);
9199 : }
9200 1 : n_feis = fib_entry_pool_size();
9201 :
9202 2 : const ip46_address_t nh_10_10_10_1 = {
9203 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
9204 : };
9205 2 : const ip46_address_t nh_10_10_10_2 = {
9206 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
9207 : };
9208 2 : const ip46_address_t nh_10_10_10_3 = {
9209 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
9210 : };
9211 2 : const ip46_address_t nh_10_10_10_16 = {
9212 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
9213 : };
9214 2 : const ip46_address_t nh_10_10_10_20 = {
9215 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
9216 : };
9217 2 : const ip46_address_t nh_10_10_10_21 = {
9218 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
9219 : };
9220 2 : const ip46_address_t nh_10_10_10_22 = {
9221 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
9222 : };
9223 2 : const ip46_address_t nh_10_10_10_255 = {
9224 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
9225 : };
9226 2 : const ip46_address_t nh_10_10_10_0 = {
9227 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
9228 : };
9229 2 : const ip46_address_t nh_10_10_0_0 = {
9230 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
9231 : };
9232 2 : const ip46_address_t nh_11_11_11_11 = {
9233 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
9234 : };
9235 2 : const ip46_address_t nh_11_11_11_0 = {
9236 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
9237 : };
9238 :
9239 : /*
9240 : * prefixes at the base of a sub-tree
9241 : */
9242 1 : const fib_prefix_t pfx_10_10_10_21_s_32 = {
9243 : .fp_len = 32,
9244 : .fp_proto = FIB_PROTOCOL_IP4,
9245 : .fp_addr = nh_10_10_10_21,
9246 : };
9247 1 : const fib_prefix_t pfx_10_10_10_22_s_32 = {
9248 : .fp_len = 32,
9249 : .fp_proto = FIB_PROTOCOL_IP4,
9250 : .fp_addr = nh_10_10_10_22,
9251 : };
9252 1 : const fib_prefix_t pfx_10_10_10_255_s_32 = {
9253 : .fp_len = 32,
9254 : .fp_proto = FIB_PROTOCOL_IP4,
9255 : .fp_addr = nh_10_10_10_255,
9256 : };
9257 1 : const u32 N_PLS = fib_path_list_pool_size();
9258 :
9259 1 : fib_table_entry_special_add(0,
9260 : &pfx_10_10_10_21_s_32,
9261 : FIB_SOURCE_CLI,
9262 : FIB_ENTRY_FLAG_DROP);
9263 1 : fib_table_entry_special_add(0,
9264 : &pfx_10_10_10_22_s_32,
9265 : FIB_SOURCE_CLI,
9266 : FIB_ENTRY_FLAG_DROP);
9267 1 : fib_table_entry_special_add(0,
9268 : &pfx_10_10_10_255_s_32,
9269 : FIB_SOURCE_CLI,
9270 : FIB_ENTRY_FLAG_DROP);
9271 :
9272 : /*
9273 : * source an entry that pushes its state down the sub-tree
9274 : */
9275 1 : const fib_prefix_t pfx_10_10_10_16_s_28 = {
9276 : .fp_len = 28,
9277 : .fp_proto = FIB_PROTOCOL_IP4,
9278 : .fp_addr = nh_10_10_10_16,
9279 : };
9280 1 : fib_table_entry_update_one_path(0,
9281 : &pfx_10_10_10_16_s_28,
9282 : FIB_SOURCE_API,
9283 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9284 : DPO_PROTO_IP4,
9285 : &nh_10_10_10_1,
9286 1 : tm->hw[0]->sw_if_index,
9287 : ~0,
9288 : 1,
9289 : NULL,
9290 : FIB_ROUTE_PATH_FLAG_NONE);
9291 :
9292 : /*
9293 : * this covering entry and all those below it should have
9294 : * the same forwarding information.
9295 : */
9296 1 : adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9297 : VNET_LINK_IP4,
9298 : &nh_10_10_10_1,
9299 1 : tm->hw[0]->sw_if_index);
9300 1 : fib_test_lb_bucket_t adj_o_10_10_10_1 = {
9301 : .type = FT_LB_ADJ,
9302 : .adj = {
9303 : .adj = ai_10_10_10_1,
9304 : },
9305 : };
9306 :
9307 1 : fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
9308 1 : FIB_TEST(!fib_test_validate_entry(fei,
9309 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9310 : 1,
9311 : &adj_o_10_10_10_1),
9312 : "%U via 10.10.10.1",
9313 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9314 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9315 1 : FIB_TEST(!fib_test_validate_entry(fei,
9316 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9317 : 1,
9318 : &adj_o_10_10_10_1),
9319 : "%U via 10.10.10.1",
9320 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9321 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9322 1 : FIB_TEST(!fib_test_validate_entry(fei,
9323 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9324 : 1,
9325 : &adj_o_10_10_10_1),
9326 : "%U via 10.10.10.1",
9327 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9328 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9329 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9330 : "%U resolves via drop",
9331 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9332 :
9333 : /*
9334 : * remove the inherting cover - covereds go back to drop
9335 : */
9336 1 : fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9337 :
9338 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9339 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9340 : "%U resolves via drop",
9341 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9342 :
9343 : /*
9344 : * source an entry that pushes its state down the sub-tree
9345 : */
9346 1 : const fib_prefix_t pfx_10_10_10_0_s_24 = {
9347 : .fp_len = 24,
9348 : .fp_proto = FIB_PROTOCOL_IP4,
9349 : .fp_addr = nh_10_10_10_0,
9350 : };
9351 1 : fib_table_entry_update_one_path(0,
9352 : &pfx_10_10_10_0_s_24,
9353 : FIB_SOURCE_API,
9354 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9355 : DPO_PROTO_IP4,
9356 : &nh_10_10_10_1,
9357 1 : tm->hw[0]->sw_if_index,
9358 : ~0,
9359 : 1,
9360 : NULL,
9361 : FIB_ROUTE_PATH_FLAG_NONE);
9362 :
9363 : /*
9364 : * whole sub-tree now covered
9365 : */
9366 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9367 1 : FIB_TEST(!fib_test_validate_entry(fei,
9368 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9369 : 1,
9370 : &adj_o_10_10_10_1),
9371 : "%U via 10.10.10.1",
9372 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9373 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9374 1 : FIB_TEST(!fib_test_validate_entry(fei,
9375 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9376 : 1,
9377 : &adj_o_10_10_10_1),
9378 : "%U via 10.10.10.1",
9379 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9380 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9381 1 : FIB_TEST(!fib_test_validate_entry(fei,
9382 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9383 : 1,
9384 : &adj_o_10_10_10_1),
9385 : "%U via 10.10.10.1",
9386 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9387 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9388 1 : FIB_TEST(!fib_test_validate_entry(fei,
9389 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9390 : 1,
9391 : &adj_o_10_10_10_1),
9392 : "%U via 10.10.10.1",
9393 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9394 :
9395 : /*
9396 : * insert a more specific into the sub-tree - expect inheritance
9397 : * this one is directly covered by the root
9398 : */
9399 1 : fib_table_entry_special_add(0,
9400 : &pfx_10_10_10_16_s_28,
9401 : FIB_SOURCE_CLI,
9402 : FIB_ENTRY_FLAG_DROP);
9403 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9404 1 : FIB_TEST(!fib_test_validate_entry(fei,
9405 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9406 : 1,
9407 : &adj_o_10_10_10_1),
9408 : "%U via 10.10.10.1",
9409 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9410 :
9411 : /*
9412 : * insert a more specific into the sub-tree - expect inheritance
9413 : * this one is indirectly covered by the root
9414 : */
9415 1 : const fib_prefix_t pfx_10_10_10_20_s_30 = {
9416 : .fp_len = 30,
9417 : .fp_proto = FIB_PROTOCOL_IP4,
9418 : .fp_addr = nh_10_10_10_20,
9419 : };
9420 1 : fib_table_entry_special_add(0,
9421 : &pfx_10_10_10_20_s_30,
9422 : FIB_SOURCE_CLI,
9423 : FIB_ENTRY_FLAG_DROP);
9424 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9425 1 : FIB_TEST(!fib_test_validate_entry(fei,
9426 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9427 : 1,
9428 : &adj_o_10_10_10_1),
9429 : "%U via 10.10.10.1",
9430 : format_fib_prefix, &pfx_10_10_10_20_s_30);
9431 :
9432 : /*
9433 : * remove the prefix from the middle of the sub-tree
9434 : * the inherited source will be the only one remaining - expect
9435 : * it to be withdrawn and hence the prefix is removed.
9436 : */
9437 1 : fib_table_entry_special_remove(0,
9438 : &pfx_10_10_10_20_s_30,
9439 : FIB_SOURCE_CLI);
9440 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9441 1 : FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9442 : "%U gone",
9443 : format_fib_prefix, &pfx_10_10_10_20_s_30);
9444 :
9445 : /*
9446 : * inheriting source is modifed - expect the modification to be present
9447 : * throughout the sub-tree
9448 : */
9449 1 : adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9450 : VNET_LINK_IP4,
9451 : &nh_10_10_10_2,
9452 1 : tm->hw[0]->sw_if_index);
9453 1 : fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9454 : .type = FT_LB_ADJ,
9455 : .adj = {
9456 : .adj = ai_10_10_10_2,
9457 : },
9458 : };
9459 :
9460 1 : fib_table_entry_update_one_path(0,
9461 : &pfx_10_10_10_0_s_24,
9462 : FIB_SOURCE_API,
9463 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9464 : DPO_PROTO_IP4,
9465 : &nh_10_10_10_2,
9466 1 : tm->hw[0]->sw_if_index,
9467 : ~0,
9468 : 1,
9469 : NULL,
9470 : FIB_ROUTE_PATH_FLAG_NONE);
9471 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9472 1 : FIB_TEST(!fib_test_validate_entry(fei,
9473 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9474 : 1,
9475 : &adj_o_10_10_10_2),
9476 : "%U via 10.10.10.2",
9477 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9478 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9479 1 : FIB_TEST(!fib_test_validate_entry(fei,
9480 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9481 : 1,
9482 : &adj_o_10_10_10_2),
9483 : "%U via 10.10.10.2",
9484 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9485 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9486 1 : FIB_TEST(!fib_test_validate_entry(fei,
9487 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9488 : 1,
9489 : &adj_o_10_10_10_2),
9490 : "%U via 10.10.10.2",
9491 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9492 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9493 1 : FIB_TEST(!fib_test_validate_entry(fei,
9494 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9495 : 1,
9496 : &adj_o_10_10_10_2),
9497 : "%U via 10.10.10.2",
9498 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9499 :
9500 1 : fib_source_t hi_src = fib_source_allocate("test", 0x50,
9501 : FIB_SOURCE_BH_SIMPLE);
9502 :
9503 : /*
9504 : * add the source that replaces inherited state.
9505 : * inheriting source is not the best, so it doesn't push state.
9506 : */
9507 1 : fib_table_entry_update_one_path(0,
9508 : &pfx_10_10_10_0_s_24,
9509 : hi_src,
9510 : FIB_ENTRY_FLAG_NONE,
9511 : DPO_PROTO_IP4,
9512 : &nh_10_10_10_1,
9513 1 : tm->hw[0]->sw_if_index,
9514 : ~0,
9515 : 1,
9516 : NULL,
9517 : FIB_ROUTE_PATH_FLAG_NONE);
9518 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9519 1 : FIB_TEST(!fib_test_validate_entry(fei,
9520 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9521 : 1,
9522 : &adj_o_10_10_10_1),
9523 : "%U via 10.10.10.1",
9524 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9525 :
9526 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9527 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9528 : "%U resolves via drop",
9529 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9530 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9531 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9532 : "%U resolves via drop",
9533 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9534 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9535 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9536 : "%U resolves via drop",
9537 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9538 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9539 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9540 : "%U resolves via drop",
9541 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9542 :
9543 : /*
9544 : * withdraw the higher priority source and expect the inherited to return
9545 : * throughout the sub-tree
9546 : */
9547 1 : fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, hi_src);
9548 :
9549 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9550 1 : FIB_TEST(!fib_test_validate_entry(fei,
9551 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9552 : 1,
9553 : &adj_o_10_10_10_2),
9554 : "%U via 10.10.10.2",
9555 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9556 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9557 1 : FIB_TEST(!fib_test_validate_entry(fei,
9558 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9559 : 1,
9560 : &adj_o_10_10_10_2),
9561 : "%U via 10.10.10.2",
9562 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9563 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9564 1 : FIB_TEST(!fib_test_validate_entry(fei,
9565 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9566 : 1,
9567 : &adj_o_10_10_10_2),
9568 : "%U via 10.10.10.2",
9569 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9570 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9571 1 : FIB_TEST(!fib_test_validate_entry(fei,
9572 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9573 : 1,
9574 : &adj_o_10_10_10_2),
9575 : "%U via 10.10.10.2",
9576 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9577 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9578 1 : FIB_TEST(!fib_test_validate_entry(fei,
9579 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9580 : 1,
9581 : &adj_o_10_10_10_2),
9582 : "%U via 10.10.10.2",
9583 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9584 :
9585 : /*
9586 : * source a covered entry in the sub-tree with the same inherting source
9587 : * - expect that it now owns the sub-tree and thus over-rides its cover
9588 : */
9589 1 : fib_table_entry_update_one_path(0,
9590 : &pfx_10_10_10_16_s_28,
9591 : FIB_SOURCE_API,
9592 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9593 : DPO_PROTO_IP4,
9594 : &nh_10_10_10_1,
9595 1 : tm->hw[0]->sw_if_index,
9596 : ~0,
9597 : 1,
9598 : NULL,
9599 : FIB_ROUTE_PATH_FLAG_NONE);
9600 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9601 1 : FIB_TEST(!fib_test_validate_entry(fei,
9602 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9603 : 1,
9604 : &adj_o_10_10_10_1),
9605 : "%U via 10.10.10.1",
9606 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9607 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9608 1 : FIB_TEST(!fib_test_validate_entry(fei,
9609 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9610 : 1,
9611 : &adj_o_10_10_10_1),
9612 : "%U via 10.10.10.2",
9613 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9614 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9615 1 : FIB_TEST(!fib_test_validate_entry(fei,
9616 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9617 : 1,
9618 : &adj_o_10_10_10_1),
9619 : "%U via 10.10.10.2",
9620 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9621 :
9622 : /* these two unaffected by the sub-tree change */
9623 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9624 1 : FIB_TEST(!fib_test_validate_entry(fei,
9625 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9626 : 1,
9627 : &adj_o_10_10_10_2),
9628 : "%U via 10.10.10.2",
9629 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9630 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9631 1 : FIB_TEST(!fib_test_validate_entry(fei,
9632 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9633 : 1,
9634 : &adj_o_10_10_10_2),
9635 : "%U via 10.10.10.2",
9636 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9637 :
9638 : /*
9639 : * removes the more specific, expect the /24 to now re-owns the sub-tree
9640 : */
9641 1 : fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9642 :
9643 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9644 1 : FIB_TEST(!fib_test_validate_entry(fei,
9645 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9646 : 1,
9647 : &adj_o_10_10_10_2),
9648 : "%U via 10.10.10.2",
9649 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9650 1 : FIB_TEST(!fib_test_validate_entry(fei,
9651 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9652 : 1,
9653 : &adj_o_10_10_10_2),
9654 : "%U via 10.10.10.2",
9655 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9656 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9657 1 : FIB_TEST(!fib_test_validate_entry(fei,
9658 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9659 : 1,
9660 : &adj_o_10_10_10_2),
9661 : "%U via 10.10.10.2",
9662 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9663 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9664 1 : FIB_TEST(!fib_test_validate_entry(fei,
9665 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9666 : 1,
9667 : &adj_o_10_10_10_2),
9668 : "%U via 10.10.10.2",
9669 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9670 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9671 1 : FIB_TEST(!fib_test_validate_entry(fei,
9672 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9673 : 1,
9674 : &adj_o_10_10_10_2),
9675 : "%U via 10.10.10.2",
9676 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9677 : /*
9678 : * modify the /24. expect the new forwarding to be pushed down
9679 : */
9680 1 : fib_table_entry_update_one_path(0,
9681 : &pfx_10_10_10_0_s_24,
9682 : FIB_SOURCE_API,
9683 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9684 : DPO_PROTO_IP4,
9685 : &nh_10_10_10_1,
9686 1 : tm->hw[0]->sw_if_index,
9687 : ~0,
9688 : 1,
9689 : NULL,
9690 : FIB_ROUTE_PATH_FLAG_NONE);
9691 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9692 1 : FIB_TEST(!fib_test_validate_entry(fei,
9693 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9694 : 1,
9695 : &adj_o_10_10_10_1),
9696 : "%U via 10.10.10.1",
9697 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9698 1 : FIB_TEST(!fib_test_validate_entry(fei,
9699 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9700 : 1,
9701 : &adj_o_10_10_10_1),
9702 : "%U via 10.10.10.1",
9703 : format_fib_prefix, &pfx_10_10_10_21_s_32);
9704 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9705 1 : FIB_TEST(!fib_test_validate_entry(fei,
9706 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9707 : 1,
9708 : &adj_o_10_10_10_1),
9709 : "%U via 10.10.10.1",
9710 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9711 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9712 1 : FIB_TEST(!fib_test_validate_entry(fei,
9713 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9714 : 1,
9715 : &adj_o_10_10_10_1),
9716 : "%U via 10.10.10.1",
9717 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9718 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9719 1 : FIB_TEST(!fib_test_validate_entry(fei,
9720 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9721 : 1,
9722 : &adj_o_10_10_10_1),
9723 : "%U via 10.10.10.1",
9724 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9725 :
9726 : /*
9727 : * add an entry less specific to /24. it should not own the /24's tree
9728 : */
9729 1 : const fib_prefix_t pfx_10_10_0_0_s_16 = {
9730 : .fp_len = 16,
9731 : .fp_proto = FIB_PROTOCOL_IP4,
9732 : .fp_addr = nh_10_10_0_0,
9733 : };
9734 1 : fib_table_entry_update_one_path(0,
9735 : &pfx_10_10_0_0_s_16,
9736 : FIB_SOURCE_API,
9737 : FIB_ENTRY_FLAG_COVERED_INHERIT,
9738 : DPO_PROTO_IP4,
9739 : &nh_10_10_10_2,
9740 1 : tm->hw[0]->sw_if_index,
9741 : ~0,
9742 : 1,
9743 : NULL,
9744 : FIB_ROUTE_PATH_FLAG_NONE);
9745 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9746 1 : FIB_TEST(!fib_test_validate_entry(fei,
9747 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9748 : 1,
9749 : &adj_o_10_10_10_1),
9750 : "%U via 10.10.10.1",
9751 : format_fib_prefix, &pfx_10_10_10_16_s_28);
9752 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9753 1 : FIB_TEST(!fib_test_validate_entry(fei,
9754 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9755 : 1,
9756 : &adj_o_10_10_10_1),
9757 : "%U via 10.10.10.1",
9758 : format_fib_prefix, &pfx_10_10_10_22_s_32);
9759 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9760 1 : FIB_TEST(!fib_test_validate_entry(fei,
9761 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9762 : 1,
9763 : &adj_o_10_10_10_1),
9764 : "%U via 10.10.10.1",
9765 : format_fib_prefix, &pfx_10_10_10_255_s_32);
9766 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9767 1 : FIB_TEST(!fib_test_validate_entry(fei,
9768 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9769 : 1,
9770 : &adj_o_10_10_10_1),
9771 : "%U via 10.10.10.1",
9772 : format_fib_prefix, &pfx_10_10_10_0_s_24);
9773 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
9774 1 : FIB_TEST(!fib_test_validate_entry(fei,
9775 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9776 : 1,
9777 : &adj_o_10_10_10_2),
9778 : "%U via 10.10.10.2",
9779 : format_fib_prefix, &pfx_10_10_0_0_s_16);
9780 :
9781 : /*
9782 : * Add/remove an interposer source to a new /32
9783 : */
9784 1 : const fib_prefix_t pfx_11_11_11_11_s_32 = {
9785 : .fp_len = 32,
9786 : .fp_proto = FIB_PROTOCOL_IP4,
9787 : .fp_addr = nh_11_11_11_11,
9788 : };
9789 :
9790 1 : fib_table_entry_update_one_path(0,
9791 : &pfx_11_11_11_11_s_32,
9792 : FIB_SOURCE_API,
9793 : FIB_ENTRY_FLAG_NONE,
9794 : DPO_PROTO_IP4,
9795 : &nh_10_10_10_3,
9796 1 : tm->hw[0]->sw_if_index,
9797 : ~0,
9798 : 1,
9799 : NULL,
9800 : FIB_ROUTE_PATH_FLAG_NONE);
9801 :
9802 1 : dpo_id_t interposer = DPO_INVALID;
9803 1 : fib_mpls_label_t *l99 = NULL, fml_99 = {
9804 : .fml_value = 99,
9805 : };
9806 1 : vec_add1(l99, fml_99);
9807 :
9808 1 : mpls_label_dpo_create(l99,
9809 : MPLS_EOS,
9810 : DPO_PROTO_IP4,
9811 : MPLS_LABEL_DPO_FLAG_NONE,
9812 : punt_dpo_get(DPO_PROTO_MPLS),
9813 : &interposer);
9814 :
9815 1 : adj_index_t ai_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9816 : VNET_LINK_IP4,
9817 : &nh_10_10_10_3,
9818 1 : tm->hw[0]->sw_if_index);
9819 1 : fib_test_lb_bucket_t adj_o_10_10_10_3 = {
9820 : .type = FT_LB_ADJ,
9821 : .adj = {
9822 : .adj = ai_10_10_10_3,
9823 : },
9824 : };
9825 1 : fib_test_lb_bucket_t l99_o_10_10_10_3 = {
9826 : .type = FT_LB_LABEL_O_ADJ,
9827 : .label_o_adj = {
9828 : .adj = ai_10_10_10_3,
9829 : .label = 99,
9830 : .eos = MPLS_EOS,
9831 : },
9832 : };
9833 :
9834 1 : fei = fib_table_entry_special_dpo_add(0,
9835 : &pfx_11_11_11_11_s_32,
9836 : FIB_SOURCE_SPECIAL,
9837 : FIB_ENTRY_FLAG_INTERPOSE,
9838 : &interposer);
9839 1 : FIB_TEST(!fib_test_validate_entry(fei,
9840 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9841 : 1,
9842 : &l99_o_10_10_10_3),
9843 : "%U via interposer adj",
9844 : format_fib_prefix,&pfx_11_11_11_11_s_32);
9845 :
9846 1 : fib_table_entry_special_remove(0,
9847 : &pfx_11_11_11_11_s_32,
9848 : FIB_SOURCE_SPECIAL);
9849 1 : FIB_TEST(!fib_test_validate_entry(fei,
9850 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9851 : 1,
9852 : &adj_o_10_10_10_3),
9853 : "%U via 10.10.10.1",
9854 : format_fib_prefix, &pfx_11_11_11_11_s_32);
9855 1 : dpo_reset(&interposer);
9856 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9857 :
9858 : /*
9859 : * add an interposer to a source with path-extensions
9860 : */
9861 1 : fib_mpls_label_t *l3300 = NULL, fml_3300 = {
9862 : .fml_value = 3300,
9863 : };
9864 1 : vec_add1(l3300, fml_3300);
9865 1 : fib_table_entry_update_one_path(0,
9866 : &pfx_11_11_11_11_s_32,
9867 : FIB_SOURCE_API,
9868 : FIB_ENTRY_FLAG_NONE,
9869 : DPO_PROTO_IP4,
9870 : &nh_10_10_10_3,
9871 1 : tm->hw[0]->sw_if_index,
9872 : ~0,
9873 : 1,
9874 : l3300,
9875 : FIB_ROUTE_PATH_FLAG_NONE);
9876 :
9877 1 : mpls_label_dpo_create(l99,
9878 : MPLS_EOS,
9879 : DPO_PROTO_IP4,
9880 : MPLS_LABEL_DPO_FLAG_NONE,
9881 : punt_dpo_get(DPO_PROTO_MPLS),
9882 : &interposer);
9883 :
9884 1 : adj_index_t ai_mpls_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9885 : VNET_LINK_MPLS,
9886 : &nh_10_10_10_3,
9887 1 : tm->hw[0]->sw_if_index);
9888 1 : fib_test_lb_bucket_t l3300_o_10_10_10_3 = {
9889 : .type = FT_LB_LABEL_O_ADJ,
9890 : .label_o_adj = {
9891 : .adj = ai_mpls_10_10_10_3,
9892 : .label = 3300,
9893 : .eos = MPLS_EOS,
9894 : },
9895 : };
9896 1 : fib_test_lb_bucket_t lchain_o_10_10_10_3 = {
9897 : .type = FT_LB_LABEL_CHAIN_O_ADJ,
9898 : .label_chain_o_adj = {
9899 : .adj = ai_mpls_10_10_10_3,
9900 : .label_chain_size = 2,
9901 : .label_chain = {
9902 : 99, 3300
9903 : },
9904 : .eos = MPLS_EOS,
9905 : },
9906 : };
9907 :
9908 1 : fei = fib_table_entry_special_dpo_add(0,
9909 : &pfx_11_11_11_11_s_32,
9910 : FIB_SOURCE_SPECIAL,
9911 : FIB_ENTRY_FLAG_INTERPOSE,
9912 : &interposer);
9913 :
9914 1 : FIB_TEST(!fib_test_validate_entry(fei,
9915 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9916 : 1,
9917 : &lchain_o_10_10_10_3),
9918 : "%U via interposer & mpls on adj",
9919 : format_fib_prefix, &pfx_11_11_11_11_s_32);
9920 :
9921 1 : fib_table_entry_special_remove(0,
9922 : &pfx_11_11_11_11_s_32,
9923 : FIB_SOURCE_SPECIAL);
9924 1 : FIB_TEST(!fib_test_validate_entry(fei,
9925 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9926 : 1,
9927 : &l3300_o_10_10_10_3),
9928 : "%U via 10.10.10.1",
9929 : format_fib_prefix, &pfx_11_11_11_11_s_32);
9930 1 : adj_unlock(ai_mpls_10_10_10_3);
9931 :
9932 : /*
9933 : * remove and re-add the second best API source while the interpose
9934 : * is present
9935 : */
9936 1 : fei = fib_table_entry_special_dpo_add(0,
9937 : &pfx_11_11_11_11_s_32,
9938 : FIB_SOURCE_SPECIAL,
9939 : FIB_ENTRY_FLAG_INTERPOSE,
9940 : &interposer);
9941 1 : FIB_TEST(!fib_test_validate_entry(fei,
9942 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9943 : 1,
9944 : &lchain_o_10_10_10_3),
9945 : "%U via interposer adj",
9946 : format_fib_prefix,&pfx_11_11_11_11_s_32);
9947 :
9948 1 : FIB_TEST(3 == pool_elts(mpls_label_dpo_pool),
9949 : "MPLS label pool: %d",
9950 : pool_elts(mpls_label_dpo_pool));
9951 :
9952 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9953 :
9954 : /*
9955 : * the interpose does not get stacked when there are not valid paths
9956 : */
9957 1 : fib_test_lb_bucket_t bucket_drop = {
9958 : .type = FT_LB_DROP,
9959 : .special = {
9960 : .adj = DPO_PROTO_IP4,
9961 : },
9962 : };
9963 1 : FIB_TEST(!fib_test_validate_entry(fei,
9964 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9965 : 1,
9966 : &bucket_drop),
9967 : "%U via drop",
9968 : format_fib_prefix,&pfx_11_11_11_11_s_32);
9969 :
9970 1 : fib_table_entry_update_one_path(0,
9971 : &pfx_11_11_11_11_s_32,
9972 : FIB_SOURCE_API,
9973 : FIB_ENTRY_FLAG_NONE,
9974 : DPO_PROTO_IP4,
9975 : &nh_10_10_10_3,
9976 1 : tm->hw[0]->sw_if_index,
9977 : ~0,
9978 : 1,
9979 : NULL,
9980 : FIB_ROUTE_PATH_FLAG_NONE);
9981 1 : FIB_TEST(!fib_test_validate_entry(fei,
9982 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9983 : 1,
9984 : &l99_o_10_10_10_3),
9985 : "%U via interposer adj",
9986 : format_fib_prefix,&pfx_11_11_11_11_s_32);
9987 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9988 :
9989 : /*
9990 : * add a cover for the interposed entry, so that we test it selects
9991 : * the covers forwarding.
9992 : */
9993 1 : const fib_prefix_t pfx_11_11_11_0_s_24 = {
9994 : .fp_len = 24,
9995 : .fp_proto = FIB_PROTOCOL_IP4,
9996 : .fp_addr = nh_11_11_11_0,
9997 : };
9998 1 : fib_table_entry_update_one_path(0,
9999 : &pfx_11_11_11_0_s_24,
10000 : FIB_SOURCE_API,
10001 : FIB_ENTRY_FLAG_NONE,
10002 : DPO_PROTO_IP4,
10003 : &nh_10_10_10_3,
10004 1 : tm->hw[0]->sw_if_index,
10005 : ~0,
10006 : 1,
10007 : NULL,
10008 : FIB_ROUTE_PATH_FLAG_NONE);
10009 1 : FIB_TEST(!fib_test_validate_entry(fei,
10010 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10011 : 1,
10012 : &l99_o_10_10_10_3),
10013 : "%U via interposer adj",
10014 : format_fib_prefix,&pfx_11_11_11_11_s_32);
10015 :
10016 : /*
10017 : * multiple interpose sources on the same entry. Only the high
10018 : * priority source gets to add the interpose.
10019 : */
10020 1 : fib_table_entry_update_one_path(0,
10021 : &pfx_11_11_11_11_s_32,
10022 : FIB_SOURCE_API,
10023 : FIB_ENTRY_FLAG_NONE,
10024 : DPO_PROTO_IP4,
10025 : &nh_10_10_10_3,
10026 1 : tm->hw[0]->sw_if_index,
10027 : ~0,
10028 : 1,
10029 : NULL,
10030 : FIB_ROUTE_PATH_FLAG_NONE);
10031 :
10032 1 : dpo_id_t interposer2 = DPO_INVALID;
10033 1 : fib_mpls_label_t *l100 = NULL, fml_100 = {
10034 : .fml_value = 100,
10035 : };
10036 1 : vec_add1(l100, fml_100);
10037 :
10038 1 : mpls_label_dpo_create(l100,
10039 : MPLS_EOS,
10040 : DPO_PROTO_IP4,
10041 : MPLS_LABEL_DPO_FLAG_NONE,
10042 : punt_dpo_get(DPO_PROTO_MPLS),
10043 : &interposer2);
10044 :
10045 1 : fei = fib_table_entry_special_dpo_add(0,
10046 : &pfx_11_11_11_11_s_32,
10047 : FIB_SOURCE_CLASSIFY,
10048 : FIB_ENTRY_FLAG_INTERPOSE,
10049 : &interposer2);
10050 :
10051 1 : fib_test_lb_bucket_t lc100_o_10_10_10_3 = {
10052 : .type = FT_LB_LABEL_CHAIN_O_ADJ,
10053 : .label_chain_o_adj = {
10054 : .adj = ai_10_10_10_3,
10055 : .label_chain_size = 2,
10056 : .label_chain = {
10057 : 99, 100
10058 : },
10059 : .eos = MPLS_EOS,
10060 : },
10061 : };
10062 :
10063 1 : FIB_TEST(!fib_test_validate_entry(fei,
10064 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10065 : 1,
10066 : &lc100_o_10_10_10_3),
10067 : "%U via interposer label 99",
10068 : format_fib_prefix,&pfx_11_11_11_11_s_32);
10069 :
10070 1 : fib_test_lb_bucket_t l100_o_10_10_10_3 = {
10071 : .type = FT_LB_LABEL_O_ADJ,
10072 : .label_o_adj = {
10073 : .adj = ai_10_10_10_3,
10074 : .label = 100,
10075 : .eos = MPLS_EOS,
10076 : },
10077 : };
10078 :
10079 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_SPECIAL);
10080 :
10081 1 : FIB_TEST(!fib_test_validate_entry(fei,
10082 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10083 : 1,
10084 : &l100_o_10_10_10_3),
10085 : "%U via interposer label 99",
10086 : format_fib_prefix,&pfx_11_11_11_11_s_32);
10087 :
10088 1 : fib_table_entry_delete(0, &pfx_11_11_11_0_s_24, FIB_SOURCE_API);
10089 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
10090 1 : FIB_TEST(!fib_test_validate_entry(fei,
10091 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10092 : 1,
10093 : &bucket_drop),
10094 : "%U via drop",
10095 : format_fib_prefix,&pfx_11_11_11_11_s_32);
10096 1 : fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_CLASSIFY);
10097 :
10098 : /*
10099 : * update a source to/from interpose.
10100 : */
10101 : /* fib_table_entry_update_one_path(0, */
10102 : /* &pfx_11_11_11_0_s_24, */
10103 : /* FIB_SOURCE_API, */
10104 : /* FIB_ENTRY_FLAG_NONE, */
10105 : /* DPO_PROTO_IP4, */
10106 : /* &nh_10_10_10_3, */
10107 : /* tm->hw[0]->sw_if_index, */
10108 : /* ~0, */
10109 : /* 1, */
10110 : /* NULL, */
10111 : /* FIB_ROUTE_PATH_FLAG_NONE); */
10112 : /* fei = fib_table_entry_special_dpo_add(0, */
10113 : /* &pfx_11_11_11_11_s_32, */
10114 : /* FIB_SOURCE_API, */
10115 : /* FIB_ENTRY_FLAG_INTERPOSE, */
10116 : /* &interposer); */
10117 : /* FIB_TEST(!fib_test_validate_entry(fei, */
10118 : /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10119 : /* 1, */
10120 : /* &l99_o_10_10_10_3), */
10121 : /* "%U via interposer label 99", */
10122 : /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
10123 :
10124 : /* FIB_TEST(3 == pool_elts(mpls_label_dpo_pool), */
10125 : /* "MPLS label pool: %d", */
10126 : /* pool_elts(mpls_label_dpo_pool)); */
10127 : /* FIB_TEST((2 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
10128 : /* "Interposer %d locks", */
10129 : /* mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
10130 :
10131 : /* fib_table_entry_update_one_path(0, */
10132 : /* &pfx_11_11_11_11_s_32, */
10133 : /* FIB_SOURCE_API, */
10134 : /* FIB_ENTRY_FLAG_NONE, */
10135 : /* DPO_PROTO_IP4, */
10136 : /* &nh_10_10_10_2, */
10137 : /* tm->hw[0]->sw_if_index, */
10138 : /* ~0, */
10139 : /* 1, */
10140 : /* NULL, */
10141 : /* FIB_ROUTE_PATH_FLAG_NONE); */
10142 : /* FIB_TEST(!fib_test_validate_entry(fei, */
10143 : /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10144 : /* 1, */
10145 : /* &adj_o_10_10_10_2), */
10146 : /* "%U via 10.10.10.2", */
10147 : /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
10148 :
10149 : /* FIB_TEST((1 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
10150 : /* "Interposer %d locks", */
10151 : /* mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
10152 : /* FIB_TEST(2 == pool_elts(mpls_label_dpo_pool), */
10153 : /* "MPLS label pool: %d", */
10154 : /* pool_elts(mpls_label_dpo_pool)); */
10155 :
10156 : /* fei = fib_table_entry_special_dpo_add(0, */
10157 : /* &pfx_11_11_11_11_s_32, */
10158 : /* FIB_SOURCE_API, */
10159 : /* FIB_ENTRY_FLAG_INTERPOSE, */
10160 : /* &interposer); */
10161 : /* FIB_TEST(!fib_test_validate_entry(fei, */
10162 : /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10163 : /* 1, */
10164 : /* &l99_o_10_10_10_3), */
10165 : /* "%U via interposer label 99", */
10166 : /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
10167 :
10168 : /* fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API); */
10169 :
10170 : /*
10171 : * Add/remove an interposer source from the top of the subtrie. The
10172 : * interposer source is not inherited.
10173 : */
10174 1 : fib_table_entry_update_one_path(0,
10175 : &pfx_10_10_10_0_s_24,
10176 : FIB_SOURCE_API,
10177 : FIB_ENTRY_FLAG_COVERED_INHERIT,
10178 : DPO_PROTO_IP4,
10179 : &nh_10_10_10_3,
10180 1 : tm->hw[0]->sw_if_index,
10181 : ~0,
10182 : 1,
10183 : NULL,
10184 : FIB_ROUTE_PATH_FLAG_NONE);
10185 1 : fei = fib_table_entry_special_dpo_add(0,
10186 : &pfx_10_10_10_0_s_24,
10187 : FIB_SOURCE_SPECIAL,
10188 : FIB_ENTRY_FLAG_INTERPOSE,
10189 : &interposer);
10190 1 : FIB_TEST(!fib_test_validate_entry(fei,
10191 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10192 : 1,
10193 : &l99_o_10_10_10_3),
10194 : "%U via interposer label",
10195 : format_fib_prefix,&pfx_10_10_10_0_s_24);
10196 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10197 1 : FIB_TEST(!fib_test_validate_entry(fei,
10198 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10199 : 1,
10200 : &bucket_drop),
10201 : "%U via drop",
10202 : format_fib_prefix, &pfx_10_10_10_21_s_32);
10203 :
10204 1 : fib_table_entry_special_remove(0,
10205 : &pfx_10_10_10_0_s_24,
10206 : FIB_SOURCE_SPECIAL);
10207 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
10208 1 : FIB_TEST(!fib_test_validate_entry(fei,
10209 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10210 : 1,
10211 : &adj_o_10_10_10_3),
10212 : "%U via 10.10.10.1",
10213 : format_fib_prefix, &pfx_10_10_10_0_s_24);
10214 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10215 1 : FIB_TEST(!fib_test_validate_entry(fei,
10216 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10217 : 1,
10218 : &adj_o_10_10_10_3),
10219 : "%U via via 10.10.10.1",
10220 : format_fib_prefix, &pfx_10_10_10_21_s_32);
10221 :
10222 : /*
10223 : * Add/remove an interposer source from the top of the subtrie. The
10224 : * interposer source is inherited.
10225 : */
10226 1 : fei = fib_table_entry_special_dpo_add(0,
10227 : &pfx_10_10_10_0_s_24,
10228 : FIB_SOURCE_SPECIAL,
10229 : (FIB_ENTRY_FLAG_COVERED_INHERIT |
10230 : FIB_ENTRY_FLAG_INTERPOSE),
10231 : &interposer);
10232 1 : FIB_TEST(!fib_test_validate_entry(fei,
10233 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10234 : 1,
10235 : &l99_o_10_10_10_3),
10236 : "%U via interposer label",
10237 : format_fib_prefix,&pfx_10_10_10_0_s_24);
10238 :
10239 : /* interposer gets forwarding from the drop cli source */
10240 1 : fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10241 1 : FIB_TEST(!fib_test_validate_entry(fei,
10242 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10243 : 1,
10244 : &bucket_drop),
10245 : "%U via drop",
10246 : format_fib_prefix,&pfx_10_10_10_21_s_32);
10247 :
10248 1 : fib_table_entry_update_one_path(0,
10249 : &pfx_10_10_10_21_s_32,
10250 : FIB_SOURCE_API,
10251 : FIB_ENTRY_FLAG_NONE,
10252 : DPO_PROTO_IP4,
10253 : &nh_10_10_10_3,
10254 1 : tm->hw[0]->sw_if_index,
10255 : ~0,
10256 : 1,
10257 : NULL,
10258 : FIB_ROUTE_PATH_FLAG_NONE);
10259 1 : fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
10260 : /* interposer gets forwarding from the API source */
10261 1 : FIB_TEST(!fib_test_validate_entry(fei,
10262 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10263 : 1,
10264 : &l99_o_10_10_10_3),
10265 : "%U via interposer label",
10266 : format_fib_prefix,&pfx_10_10_10_21_s_32);
10267 :
10268 : /*
10269 : * cleanup
10270 : */
10271 1 : fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
10272 1 : fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_API);
10273 1 : fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
10274 1 : fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
10275 1 : fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
10276 1 : fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
10277 1 : fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_SPECIAL);
10278 1 : adj_unlock(ai_10_10_10_1);
10279 1 : adj_unlock(ai_10_10_10_2);
10280 1 : adj_unlock(ai_10_10_10_3);
10281 1 : dpo_reset(&interposer);
10282 1 : dpo_reset(&interposer2);
10283 1 : FIB_TEST(0 == pool_elts(mpls_label_dpo_pool),
10284 : "MPLS label pool empty: %d",
10285 : pool_elts(mpls_label_dpo_pool));
10286 1 : FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10287 1 : FIB_TEST(N_PLS == fib_path_list_pool_size(),
10288 : "number of path-lists: %d = %d",
10289 : N_PLS, fib_path_list_pool_size());
10290 :
10291 : /*
10292 : * test the v6 tree walk.
10293 : * a /64 that covers everything. a /96 that covers one /128
10294 : * a second /128 covered only by the /64.
10295 : */
10296 3 : const fib_prefix_t pfx_2001_s_64 = {
10297 : .fp_len = 64,
10298 : .fp_proto = FIB_PROTOCOL_IP6,
10299 : .fp_addr = {
10300 : .ip6 = {
10301 : .as_u64 = {
10302 1 : [0] = clib_host_to_net_u64(0x2001000000000000),
10303 1 : [1] = clib_host_to_net_u64(0x0000000000000000),
10304 : },
10305 : },
10306 : },
10307 : };
10308 3 : const fib_prefix_t pfx_2001_1_s_96 = {
10309 : .fp_len = 96,
10310 : .fp_proto = FIB_PROTOCOL_IP6,
10311 : .fp_addr = {
10312 : .ip6 = {
10313 : .as_u64 = {
10314 1 : [0] = clib_host_to_net_u64(0x2001000000000000),
10315 1 : [1] = clib_host_to_net_u64(0x1000000000000000),
10316 : },
10317 : },
10318 : },
10319 : };
10320 3 : const fib_prefix_t pfx_2001_1_1_s_128 = {
10321 : .fp_len = 128,
10322 : .fp_proto = FIB_PROTOCOL_IP6,
10323 : .fp_addr = {
10324 : .ip6 = {
10325 : .as_u64 = {
10326 1 : [0] = clib_host_to_net_u64(0x2001000000000000),
10327 1 : [1] = clib_host_to_net_u64(0x1000000000000001),
10328 : },
10329 : },
10330 : },
10331 : };
10332 3 : const fib_prefix_t pfx_2001_0_1_s_128 = {
10333 : .fp_len = 128,
10334 : .fp_proto = FIB_PROTOCOL_IP6,
10335 : .fp_addr = {
10336 : .ip6 = {
10337 : .as_u64 = {
10338 1 : [0] = clib_host_to_net_u64(0x2001000000000000),
10339 1 : [1] = clib_host_to_net_u64(0x0000000000000001),
10340 : },
10341 : },
10342 : },
10343 : };
10344 2 : const ip46_address_t nh_3000_1 = {
10345 : .ip6 = {
10346 : .as_u64 = {
10347 1 : [0] = clib_host_to_net_u64(0x3000000000000000),
10348 1 : [1] = clib_host_to_net_u64(0x0000000000000001),
10349 : },
10350 : },
10351 : };
10352 2 : const ip46_address_t nh_3000_2 = {
10353 : .ip6 = {
10354 : .as_u64 = {
10355 1 : [0] = clib_host_to_net_u64(0x3000000000000000),
10356 1 : [1] = clib_host_to_net_u64(0x0000000000000002),
10357 : },
10358 : },
10359 : };
10360 1 : adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10361 : VNET_LINK_IP6,
10362 : &nh_3000_1,
10363 1 : tm->hw[0]->sw_if_index);
10364 1 : adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10365 : VNET_LINK_IP6,
10366 : &nh_3000_2,
10367 1 : tm->hw[0]->sw_if_index);
10368 1 : fib_test_lb_bucket_t adj_o_3000_1 = {
10369 : .type = FT_LB_ADJ,
10370 : .adj = {
10371 : .adj = ai_3000_1,
10372 : },
10373 : };
10374 1 : fib_test_lb_bucket_t adj_o_3000_2 = {
10375 : .type = FT_LB_ADJ,
10376 : .adj = {
10377 : .adj = ai_3000_2,
10378 : },
10379 : };
10380 :
10381 1 : fib_table_entry_special_add(0,
10382 : &pfx_2001_0_1_s_128,
10383 : FIB_SOURCE_CLI,
10384 : FIB_ENTRY_FLAG_DROP);
10385 1 : fib_table_entry_special_add(0,
10386 : &pfx_2001_1_1_s_128,
10387 : FIB_SOURCE_CLI,
10388 : FIB_ENTRY_FLAG_DROP);
10389 :
10390 : /*
10391 : * /96 has inherited forwarding pushed down to its covered /128
10392 : */
10393 1 : fib_table_entry_update_one_path(0,
10394 : &pfx_2001_1_s_96,
10395 : FIB_SOURCE_API,
10396 : FIB_ENTRY_FLAG_COVERED_INHERIT,
10397 : DPO_PROTO_IP6,
10398 : &nh_3000_1,
10399 1 : tm->hw[0]->sw_if_index,
10400 : ~0,
10401 : 1,
10402 : NULL,
10403 : FIB_ROUTE_PATH_FLAG_NONE);
10404 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10405 1 : FIB_TEST(!fib_test_validate_entry(fei,
10406 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10407 : 1,
10408 : &adj_o_3000_1),
10409 : "%U via 3000::1",
10410 : format_fib_prefix, &pfx_2001_1_s_96);
10411 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10412 1 : FIB_TEST(!fib_test_validate_entry(fei,
10413 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10414 : 1,
10415 : &adj_o_3000_1),
10416 : "%U via 3000::1",
10417 : format_fib_prefix, &pfx_2001_1_1_s_128);
10418 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10419 1 : FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
10420 : "%U resolves via drop",
10421 : format_fib_prefix, &pfx_2001_0_1_s_128);
10422 :
10423 : /*
10424 : * /64 has inherited forwarding pushed down to all, but the /96
10425 : * and its sub-tree remain unaffected.
10426 : */
10427 1 : fib_table_entry_update_one_path(0,
10428 : &pfx_2001_s_64,
10429 : FIB_SOURCE_API,
10430 : FIB_ENTRY_FLAG_COVERED_INHERIT,
10431 : DPO_PROTO_IP6,
10432 : &nh_3000_2,
10433 1 : tm->hw[0]->sw_if_index,
10434 : ~0,
10435 : 1,
10436 : NULL,
10437 : FIB_ROUTE_PATH_FLAG_NONE);
10438 :
10439 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
10440 1 : FIB_TEST(!fib_test_validate_entry(fei,
10441 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10442 : 1,
10443 : &adj_o_3000_2),
10444 : "%U via 3000::2",
10445 : format_fib_prefix, &pfx_2001_s_64);
10446 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10447 1 : FIB_TEST(!fib_test_validate_entry(fei,
10448 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10449 : 1,
10450 : &adj_o_3000_2),
10451 : "%U via 3000::1",
10452 : format_fib_prefix, &pfx_2001_0_1_s_128);
10453 :
10454 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10455 1 : FIB_TEST(!fib_test_validate_entry(fei,
10456 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10457 : 1,
10458 : &adj_o_3000_1),
10459 : "%U via 3000::1",
10460 : format_fib_prefix, &pfx_2001_1_s_96);
10461 1 : fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10462 1 : FIB_TEST(!fib_test_validate_entry(fei,
10463 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10464 : 1,
10465 : &adj_o_3000_1),
10466 : "%U via 3000::1",
10467 : format_fib_prefix, &pfx_2001_1_1_s_128);
10468 :
10469 : /*
10470 : * Cleanup
10471 : */
10472 1 : fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
10473 1 : fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
10474 1 : fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
10475 1 : fib_table_entry_delete(0, &pfx_2001_1_s_96, FIB_SOURCE_API);
10476 1 : adj_unlock(ai_3000_1);
10477 1 : adj_unlock(ai_3000_2);
10478 :
10479 : /*
10480 : * test no-one left behind
10481 : */
10482 1 : FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
10483 1 : FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10484 :
10485 1 : return (res);
10486 : }
10487 :
10488 : static int
10489 0 : fib_test_sticky (void)
10490 : {
10491 0 : fib_route_path_t *r_paths = NULL;
10492 0 : test_main_t *tm = &test_main;
10493 : u32 ii, lb_count, pl_count;
10494 0 : dpo_id_t dpo = DPO_INVALID;
10495 : fib_node_index_t pl_index;
10496 0 : int res = 0;
10497 : #define N_PATHS 16
10498 :
10499 : fib_test_lb_bucket_t buckets[N_PATHS];
10500 0 : bfd_session_t bfds[N_PATHS] = {{0}};
10501 :
10502 0 : lb_count = pool_elts(load_balance_pool);
10503 0 : pl_count = fib_path_list_pool_size();
10504 :
10505 0 : for (ii = 0; ii < N_PATHS; ii++)
10506 : {
10507 0 : ip46_address_t nh = {
10508 0 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10509 : };
10510 : adj_index_t ai;
10511 :
10512 0 : ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
10513 : VNET_LINK_IP4,
10514 0 : &nh, tm->hw[0]->sw_if_index);
10515 :
10516 0 : buckets[ii].type = FT_LB_ADJ;
10517 0 : buckets[ii].adj.adj = ai;
10518 :
10519 0 : bfds[ii].udp.key.peer_addr = nh;
10520 0 : bfds[ii].udp.key.sw_if_index = tm->hw[0]->sw_if_index;
10521 0 : bfds[ii].hop_type = BFD_HOP_TYPE_SINGLE;
10522 0 : bfds[ii].local_state = BFD_STATE_init;
10523 0 : adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfds[ii]);
10524 0 : bfds[ii].local_state = BFD_STATE_up;
10525 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[ii]);
10526 : }
10527 :
10528 0 : for (ii = 0; ii < N_PATHS; ii++)
10529 : {
10530 0 : fib_route_path_t r_path = {
10531 : .frp_proto = DPO_PROTO_IP4,
10532 : .frp_addr = {
10533 0 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10534 : },
10535 0 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
10536 : .frp_weight = 1,
10537 : .frp_fib_index = ~0,
10538 : };
10539 0 : vec_add1(r_paths, r_path);
10540 : };
10541 :
10542 0 : pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths);
10543 0 : fib_path_list_lock(pl_index);
10544 :
10545 0 : fib_path_list_contribute_forwarding(pl_index,
10546 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10547 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10548 : &dpo);
10549 :
10550 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10551 : 16,
10552 : &buckets[0],
10553 : &buckets[1],
10554 : &buckets[2],
10555 : &buckets[3],
10556 : &buckets[4],
10557 : &buckets[5],
10558 : &buckets[6],
10559 : &buckets[7],
10560 : &buckets[8],
10561 : &buckets[9],
10562 : &buckets[10],
10563 : &buckets[11],
10564 : &buckets[12],
10565 : &buckets[13],
10566 : &buckets[14],
10567 : &buckets[15]),
10568 : "Setup OK");
10569 :
10570 : /* take down paths */
10571 0 : bfds[0].local_state = BFD_STATE_down;
10572 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10573 :
10574 0 : fib_path_list_contribute_forwarding(pl_index,
10575 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10576 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10577 : &dpo);
10578 :
10579 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10580 : 16,
10581 : &buckets[1],
10582 : &buckets[1],
10583 : &buckets[2],
10584 : &buckets[3],
10585 : &buckets[4],
10586 : &buckets[5],
10587 : &buckets[6],
10588 : &buckets[7],
10589 : &buckets[8],
10590 : &buckets[9],
10591 : &buckets[10],
10592 : &buckets[11],
10593 : &buckets[12],
10594 : &buckets[13],
10595 : &buckets[14],
10596 : &buckets[15]),
10597 : "Failed at shut-down path 0");
10598 :
10599 0 : bfds[7].local_state = BFD_STATE_down;
10600 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10601 :
10602 0 : fib_path_list_contribute_forwarding(pl_index,
10603 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10604 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10605 : &dpo);
10606 :
10607 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10608 : 16,
10609 : &buckets[1],
10610 : &buckets[1],
10611 : &buckets[2],
10612 : &buckets[3],
10613 : &buckets[4],
10614 : &buckets[5],
10615 : &buckets[6],
10616 : &buckets[2],
10617 : &buckets[8],
10618 : &buckets[9],
10619 : &buckets[10],
10620 : &buckets[11],
10621 : &buckets[12],
10622 : &buckets[13],
10623 : &buckets[14],
10624 : &buckets[15]),
10625 : "Failed at shut-down path 7");
10626 :
10627 : /* paths back up */
10628 0 : bfds[0].local_state = BFD_STATE_up;
10629 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10630 0 : bfds[7].local_state = BFD_STATE_up;
10631 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10632 :
10633 0 : fib_path_list_contribute_forwarding(pl_index,
10634 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10635 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10636 : &dpo);
10637 :
10638 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10639 : 16,
10640 : &buckets[0],
10641 : &buckets[1],
10642 : &buckets[2],
10643 : &buckets[3],
10644 : &buckets[4],
10645 : &buckets[5],
10646 : &buckets[6],
10647 : &buckets[7],
10648 : &buckets[8],
10649 : &buckets[9],
10650 : &buckets[10],
10651 : &buckets[11],
10652 : &buckets[12],
10653 : &buckets[13],
10654 : &buckets[14],
10655 : &buckets[15]),
10656 : "recovery OK");
10657 :
10658 0 : fib_path_list_unlock(pl_index);
10659 :
10660 : /*
10661 : * non-power of 2 number of buckets
10662 : */
10663 0 : fib_route_path_t *r_paths2 = NULL;
10664 :
10665 0 : r_paths2 = vec_dup(r_paths);
10666 0 : vec_set_len (r_paths2, 3);
10667 :
10668 0 : pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths2);
10669 0 : fib_path_list_lock(pl_index);
10670 :
10671 0 : fib_path_list_contribute_forwarding(pl_index,
10672 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10673 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10674 : &dpo);
10675 :
10676 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10677 : 16,
10678 : &buckets[0],
10679 : &buckets[0],
10680 : &buckets[0],
10681 : &buckets[0],
10682 : &buckets[0],
10683 : &buckets[0],
10684 : &buckets[1],
10685 : &buckets[1],
10686 : &buckets[1],
10687 : &buckets[1],
10688 : &buckets[1],
10689 : &buckets[2],
10690 : &buckets[2],
10691 : &buckets[2],
10692 : &buckets[2],
10693 : &buckets[2]),
10694 : "non-power of 2");
10695 :
10696 0 : bfds[1].local_state = BFD_STATE_down;
10697 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10698 :
10699 0 : fib_path_list_contribute_forwarding(pl_index,
10700 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10701 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10702 : &dpo);
10703 :
10704 : /*
10705 : * path 1's buckets alternate between path 0 and 2
10706 : */
10707 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10708 : 16,
10709 : &buckets[0],
10710 : &buckets[0],
10711 : &buckets[0],
10712 : &buckets[0],
10713 : &buckets[0],
10714 : &buckets[0],
10715 : &buckets[0],
10716 : &buckets[2],
10717 : &buckets[0],
10718 : &buckets[2],
10719 : &buckets[0],
10720 : &buckets[2],
10721 : &buckets[2],
10722 : &buckets[2],
10723 : &buckets[2],
10724 : &buckets[2]),
10725 : "non-power of 2");
10726 0 : bfds[1].local_state = BFD_STATE_up;
10727 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10728 :
10729 0 : fib_path_list_unlock(pl_index);
10730 :
10731 : /*
10732 : * unequal cost
10733 : */
10734 0 : fib_route_path_t *r_paths3 = NULL;
10735 :
10736 0 : r_paths3 = vec_dup(r_paths);
10737 0 : vec_set_len (r_paths3, 3);
10738 :
10739 0 : r_paths3[0].frp_weight = 3;
10740 :
10741 0 : pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths3);
10742 0 : fib_path_list_lock(pl_index);
10743 :
10744 0 : fib_path_list_contribute_forwarding(pl_index,
10745 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10746 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10747 : &dpo);
10748 :
10749 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10750 : 16,
10751 : &buckets[1],
10752 : &buckets[1],
10753 : &buckets[1],
10754 : &buckets[2],
10755 : &buckets[2],
10756 : &buckets[2],
10757 : &buckets[0],
10758 : &buckets[0],
10759 : &buckets[0],
10760 : &buckets[0],
10761 : &buckets[0],
10762 : &buckets[0],
10763 : &buckets[0],
10764 : &buckets[0],
10765 : &buckets[0],
10766 : &buckets[0]),
10767 : "UCMP");
10768 :
10769 0 : bfds[1].local_state = BFD_STATE_down;
10770 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10771 :
10772 0 : fib_path_list_contribute_forwarding(pl_index,
10773 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10774 : FIB_PATH_LIST_FWD_FLAG_STICKY,
10775 : &dpo);
10776 : /* No attempt to Un-equal distribute the down path's buckets */
10777 0 : FIB_TEST(!fib_test_validate_lb(&dpo,
10778 : 16,
10779 : &buckets[2],
10780 : &buckets[0],
10781 : &buckets[2],
10782 : &buckets[2],
10783 : &buckets[2],
10784 : &buckets[2],
10785 : &buckets[0],
10786 : &buckets[0],
10787 : &buckets[0],
10788 : &buckets[0],
10789 : &buckets[0],
10790 : &buckets[0],
10791 : &buckets[0],
10792 : &buckets[0],
10793 : &buckets[0],
10794 : &buckets[0]),
10795 : "UCMP");
10796 0 : bfds[1].local_state = BFD_STATE_up;
10797 0 : adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10798 :
10799 0 : dpo_reset(&dpo);
10800 0 : fib_path_list_unlock(pl_index);
10801 :
10802 0 : vec_free(r_paths);
10803 0 : vec_free(r_paths2);
10804 0 : vec_free(r_paths3);
10805 :
10806 0 : FIB_TEST(lb_count == pool_elts(load_balance_pool), "no leaked LBs");
10807 0 : FIB_TEST(pl_count == fib_path_list_pool_size(), "no leaked PLs");
10808 :
10809 0 : return 0;
10810 : }
10811 :
10812 : static clib_error_t *
10813 1 : fib_test (vlib_main_t * vm,
10814 : unformat_input_t * input,
10815 : vlib_cli_command_t * cmd_arg)
10816 : {
10817 : int res;
10818 :
10819 1 : res = 0;
10820 :
10821 1 : fib_test_mk_intf(4);
10822 :
10823 1 : if (unformat (input, "debug"))
10824 : {
10825 0 : fib_test_do_debug = 1;
10826 : }
10827 :
10828 1 : if (unformat (input, "ip4"))
10829 : {
10830 0 : res += fib_test_v4();
10831 : }
10832 1 : else if (unformat (input, "ip6"))
10833 : {
10834 0 : res += fib_test_v6();
10835 : }
10836 1 : else if (unformat (input, "ip"))
10837 : {
10838 0 : res += fib_test_v4();
10839 0 : res += fib_test_v6();
10840 : }
10841 1 : else if (unformat (input, "label"))
10842 : {
10843 0 : res += fib_test_label();
10844 : }
10845 1 : else if (unformat (input, "ae"))
10846 : {
10847 0 : res += fib_test_ae();
10848 : }
10849 1 : else if (unformat (input, "pref"))
10850 : {
10851 0 : res += fib_test_pref();
10852 : }
10853 1 : else if (unformat (input, "lfib"))
10854 : {
10855 0 : res += lfib_test();
10856 : }
10857 1 : else if (unformat (input, "walk"))
10858 : {
10859 0 : res += fib_test_walk();
10860 : }
10861 1 : else if (unformat (input, "bfd"))
10862 : {
10863 0 : res += fib_test_bfd();
10864 : }
10865 1 : else if (unformat (input, "inherit"))
10866 : {
10867 0 : res += fib_test_inherit();
10868 : }
10869 1 : else if (unformat (input, "sticky"))
10870 : {
10871 0 : res += fib_test_sticky();
10872 : }
10873 : else
10874 : {
10875 1 : res += fib_test_v4();
10876 1 : res += fib_test_v6();
10877 1 : res += fib_test_ae();
10878 1 : res += fib_test_bfd();
10879 1 : res += fib_test_pref();
10880 1 : res += fib_test_label();
10881 1 : res += fib_test_inherit();
10882 1 : res += lfib_test();
10883 :
10884 : /*
10885 : * fib-walk process must be disabled in order for the walk tests to work
10886 : */
10887 1 : fib_walk_process_disable();
10888 1 : res += fib_test_walk();
10889 1 : fib_walk_process_enable();
10890 : }
10891 :
10892 1 : fflush(NULL);
10893 1 : if (res)
10894 : {
10895 0 : return clib_error_return(0, "FIB Unit Test Failed");
10896 : }
10897 : else
10898 : {
10899 1 : return (NULL);
10900 : }
10901 : }
10902 :
10903 16239 : VLIB_CLI_COMMAND (test_fib_command, static) = {
10904 : .path = "test fib",
10905 : .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
10906 : .function = fib_test,
10907 : };
10908 :
10909 : clib_error_t *
10910 559 : fib_test_init (vlib_main_t *vm)
10911 : {
10912 559 : return 0;
10913 : }
10914 :
10915 2239 : VLIB_INIT_FUNCTION (fib_test_init);
10916 :
10917 : // clang-format on
|