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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/mpls/mpls_types.h>
18 #include <vnet/mfib/mfib_table.h>
19 #include <vnet/mfib/mfib_entry.h>
20 #include <vnet/mfib/mfib_signal.h>
21 #include <vnet/mfib/ip6_mfib.h>
22 #include <vnet/fib/fib_path_list.h>
23 #include <vnet/fib/fib_test.h>
24 #include <vnet/fib/fib_table.h>
25 #include <vnet/fib/mpls_fib.h>
27 #include <vnet/dpo/replicate_dpo.h>
28 #include <vnet/adj/adj_mcast.h>
30 #define MFIB_TEST_I(_cond, _comment, _args...) \
32 int _evald = (_cond); \
34 fformat(stderr, "FAIL:%d: " _comment "\n", \
38 fformat(stderr, "PASS:%d: " _comment "\n", \
43 #define MFIB_TEST(_cond, _comment, _args...) \
45 if (MFIB_TEST_I(_cond, _comment, ##_args)) { \
47 ASSERT(!("FAIL: " _comment)); \
50 #define MFIB_TEST_NS(_cond) \
52 if (MFIB_TEST_I(_cond, "")) { \
54 ASSERT(!("FAIL: ")); \
59 * A 'i'm not fussed is this is not efficient' store of test data
61 typedef struct test_main_t_ {
65 u32 hw_if_indicies[4];
69 vnet_hw_interface_t * hw[4];
72 static test_main_t test_main;
74 /* fake ethernet device class, distinct from "fake-ethX" */
75 static u8 * format_test_interface_name (u8 * s, va_list * args)
77 u32 dev_instance = va_arg (*args, u32);
78 return format (s, "test-eth%d", dev_instance);
81 static uword dummy_interface_tx (vlib_main_t * vm,
82 vlib_node_runtime_t * node,
85 clib_warning ("you shouldn't be here, leaking buffers...");
86 return frame->n_vectors;
90 test_interface_admin_up_down (vnet_main_t * vnm,
94 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
95 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
96 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
100 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
101 .name = "Test interface",
102 .format_device_name = format_test_interface_name,
103 .tx_function = dummy_interface_tx,
104 .admin_up_down_function = test_interface_admin_up_down,
107 static u8 *hw_address;
110 mfib_test_mk_intf (u32 ninterfaces)
112 clib_error_t * error = NULL;
113 test_main_t *tm = &test_main;
119 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
124 vec_add1(hw_address, byte);
127 for (i = 0; i < ninterfaces; i++)
131 error = ethernet_register_interface(vnet_get_main(),
132 test_interface_device_class.index,
135 &tm->hw_if_indicies[i],
136 /* flag change */ 0);
138 MFIB_TEST((NULL == error), "ADD interface %d", i);
140 error = vnet_hw_interface_set_flags(vnet_get_main(),
141 tm->hw_if_indicies[i],
142 VNET_HW_INTERFACE_FLAG_LINK_UP);
143 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
144 tm->hw_if_indicies[i]);
145 vec_validate (ip4_main.fib_index_by_sw_if_index,
146 tm->hw[i]->sw_if_index);
147 vec_validate (ip6_main.fib_index_by_sw_if_index,
148 tm->hw[i]->sw_if_index);
149 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
150 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
152 vec_validate (ip4_main.mfib_index_by_sw_if_index,
153 tm->hw[i]->sw_if_index);
154 vec_validate (ip6_main.mfib_index_by_sw_if_index,
155 tm->hw[i]->sw_if_index);
156 ip4_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
157 ip6_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
159 error = vnet_sw_interface_set_flags(vnet_get_main(),
160 tm->hw[i]->sw_if_index,
161 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
162 MFIB_TEST((NULL == error), "UP interface %d", i);
165 * re-eval after the inevitable realloc
167 for (i = 0; i < ninterfaces; i++)
169 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
170 tm->hw_if_indicies[i]);
176 #define MFIB_TEST_REP(_cond, _comment, _args...) \
178 if (MFIB_TEST_I(_cond, _comment, ##_args)) { \
184 mfib_test_validate_rep_v (const replicate_t *rep,
195 MFIB_TEST_REP((n_buckets == rep->rep_n_buckets),
196 "n_buckets = %d", rep->rep_n_buckets);
198 for (bucket = 0; bucket < n_buckets; bucket++)
200 dt = va_arg(*ap, int); // type promotion
201 ai = va_arg(*ap, adj_index_t);
202 dpo = replicate_get_bucket_i(rep, bucket);
204 MFIB_TEST_REP((dt == dpo->dpoi_type),
205 "bucket %d stacks on %U",
207 format_dpo_type, dpo->dpoi_type);
209 if (DPO_RECEIVE != dt)
211 MFIB_TEST_REP((ai == dpo->dpoi_index),
212 "bucket %d [exp:%d] stacks on %U",
214 format_dpo_id, dpo, 0);
221 mfib_test_entry (fib_node_index_t fei,
222 mfib_entry_flags_t eflags,
226 const mfib_entry_t *mfe;
227 const replicate_t *rep;
234 mfe = mfib_entry_get(fei);
235 mfib_entry_get_prefix(fei, &pfx);
237 MFIB_TEST_REP((eflags == mfe->mfe_flags),
238 "%U has %U expect %U",
239 format_mfib_prefix, &pfx,
240 format_mfib_entry_flags, mfe->mfe_flags,
241 format_mfib_entry_flags, eflags);
245 MFIB_TEST_REP((DPO_DROP == mfe->mfe_rep.dpoi_type),
247 format_mfib_prefix, &pfx,
248 format_dpo_id, &mfe->mfe_rep, 0);
252 dpo_id_t tmp = DPO_INVALID;
254 mfib_entry_contribute_forwarding(
256 fib_forw_chain_type_from_fib_proto(pfx.fp_proto),
258 rep = replicate_get(tmp.dpoi_index);
260 MFIB_TEST_REP((DPO_REPLICATE == tmp.dpoi_type),
262 format_mfib_prefix, &pfx,
263 format_dpo_type, tmp.dpoi_type);
265 va_start(ap, n_buckets);
266 res = mfib_test_validate_rep_v(rep, n_buckets, &ap);
277 mfib_test_entry_itf (fib_node_index_t fei,
279 mfib_itf_flags_t flags)
281 const mfib_entry_t *mfe;
282 const mfib_itf_t *mfi;
287 mfe = mfib_entry_get(fei);
288 mfi = mfib_entry_get_itf(mfe, sw_if_index);
289 mfib_entry_get_prefix(fei, &pfx);
291 MFIB_TEST_REP((NULL != mfi),
292 "%U has interface %d",
293 format_mfib_prefix, &pfx, sw_if_index);
295 MFIB_TEST_REP((flags == mfi->mfi_flags),
296 "%U interface %d has flags %U expect %U",
297 format_mfib_prefix, &pfx, sw_if_index,
298 format_mfib_itf_flags, flags,
299 format_mfib_itf_flags, mfi->mfi_flags);
305 mfib_test_entry_no_itf (fib_node_index_t fei,
308 const mfib_entry_t *mfe;
309 const mfib_itf_t *mfi;
314 mfe = mfib_entry_get(fei);
315 mfi = mfib_entry_get_itf(mfe, sw_if_index);
316 mfib_entry_get_prefix(fei, &pfx);
318 MFIB_TEST_REP((NULL == mfi),
319 "%U has no interface %d",
320 format_mfib_prefix, &pfx, sw_if_index);
326 mfib_test_i (fib_protocol_t PROTO,
328 const mfib_prefix_t *pfx_no_forward,
329 const mfib_prefix_t *pfx_s_g,
330 const mfib_prefix_t *pfx_star_g_1,
331 const mfib_prefix_t *pfx_star_g_2,
332 const mfib_prefix_t *pfx_star_g_3,
333 const mfib_prefix_t *pfx_star_g_slash_m,
334 const fib_prefix_t *pfx_itf,
335 const ip46_address_t *addr_nbr1,
336 const ip46_address_t *addr_nbr2)
338 fib_node_index_t mfei, mfei_dflt, mfei_no_f, mfei_s_g, mfei_g_1, mfei_g_2, mfei_g_3, mfei_g_m;
339 u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
340 fib_node_index_t ai_1, ai_2, ai_3, ai_nbr1, ai_nbr2;
344 mfib_prefix_t all_1s;
345 clib_memset(&all_1s, 0xfd, sizeof(all_1s));
348 n_entries = pool_elts(mfib_entry_pool);
349 n_itfs = pool_elts(mfib_itf_pool);
350 n_reps = pool_elts(replicate_pool);
351 n_pls = fib_path_list_pool_size();
354 ai_1 = adj_mcast_add_or_lock(PROTO,
356 tm->hw[1]->sw_if_index);
357 ai_2 = adj_mcast_add_or_lock(PROTO,
359 tm->hw[2]->sw_if_index);
360 ai_3 = adj_mcast_add_or_lock(PROTO,
362 tm->hw[3]->sw_if_index);
363 ai_nbr1 = adj_nbr_add_or_lock(PROTO,
366 tm->hw[0]->sw_if_index);
367 ai_nbr2 = adj_nbr_add_or_lock(PROTO,
370 tm->hw[0]->sw_if_index);
372 MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
374 /* Find or create FIB table 11 */
375 fib_index = mfib_table_find_or_create_and_lock(PROTO, 11, MFIB_SOURCE_API);
377 fib_table_entry_update_one_path(0,
379 FIB_SOURCE_INTERFACE,
380 (FIB_ENTRY_FLAG_CONNECTED |
381 FIB_ENTRY_FLAG_ATTACHED),
384 tm->hw[0]->sw_if_index,
385 ~0, // invalid fib index
388 FIB_ROUTE_PATH_FLAG_NONE);
390 mfib_prefix_t pfx_dft = {
394 mfei_dflt = mfib_table_lookup_exact_match(fib_index, &pfx_dft);
395 MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
396 MFIB_TEST(!mfib_test_entry(mfei_dflt,
397 MFIB_ENTRY_FLAG_DROP,
399 "(*,*) no replcaitions");
401 MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
402 MFIB_TEST(!mfib_test_entry(mfei_dflt,
403 MFIB_ENTRY_FLAG_DROP,
405 "(*,*) no replcaitions");
408 fib_route_path_t path_via_if0 = {
409 .frp_proto = fib_proto_to_dpo(PROTO),
410 .frp_addr = zero_addr,
411 .frp_sw_if_index = tm->hw[0]->sw_if_index,
417 mfib_table_entry_path_update(fib_index,
421 MFIB_ITF_FLAG_ACCEPT);
423 mfei_no_f = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
424 MFIB_TEST(!mfib_test_entry(mfei_no_f,
425 MFIB_ENTRY_FLAG_NONE,
427 "%U no replcaitions",
428 format_mfib_prefix, pfx_no_forward);
429 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_no_f, tm->hw[0]->sw_if_index,
430 MFIB_ITF_FLAG_ACCEPT));
432 fib_route_path_t path_via_if1 = {
433 .frp_proto = fib_proto_to_dpo(PROTO),
434 .frp_addr = zero_addr,
435 .frp_sw_if_index = tm->hw[1]->sw_if_index,
440 fib_route_path_t path_via_if2 = {
441 .frp_proto = fib_proto_to_dpo(PROTO),
442 .frp_addr = zero_addr,
443 .frp_sw_if_index = tm->hw[2]->sw_if_index,
448 fib_route_path_t path_via_if3 = {
449 .frp_proto = fib_proto_to_dpo(PROTO),
450 .frp_addr = zero_addr,
451 .frp_sw_if_index = tm->hw[3]->sw_if_index,
456 fib_route_path_t path_for_us = {
457 .frp_proto = fib_proto_to_dpo(PROTO),
458 .frp_addr = zero_addr,
459 .frp_sw_if_index = 0xffffffff,
462 .frp_flags = FIB_ROUTE_PATH_LOCAL,
466 * An (S,G) with 1 accepting and 3 forwarding paths
468 mfib_table_entry_path_update(fib_index,
472 MFIB_ITF_FLAG_ACCEPT);
473 mfib_table_entry_path_update(fib_index,
477 MFIB_ITF_FLAG_FORWARD);
478 mfib_table_entry_path_update(fib_index,
482 MFIB_ITF_FLAG_FORWARD);
483 mfib_table_entry_path_update(fib_index,
487 (MFIB_ITF_FLAG_FORWARD |
488 MFIB_ITF_FLAG_NEGATE_SIGNAL));
490 mfei_s_g = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
492 MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_s_g,
494 format_mfib_prefix, pfx_s_g);
495 MFIB_TEST(!mfib_test_entry(mfei_s_g,
496 MFIB_ENTRY_FLAG_NONE,
498 DPO_ADJACENCY_MCAST, ai_1,
499 DPO_ADJACENCY_MCAST, ai_2,
500 DPO_ADJACENCY_MCAST, ai_3),
502 format_mfib_prefix, pfx_s_g);
503 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[0]->sw_if_index,
504 MFIB_ITF_FLAG_ACCEPT));
505 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[1]->sw_if_index,
506 MFIB_ITF_FLAG_FORWARD));
507 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[2]->sw_if_index,
508 MFIB_ITF_FLAG_FORWARD));
509 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[3]->sw_if_index,
510 (MFIB_ITF_FLAG_FORWARD |
511 MFIB_ITF_FLAG_NEGATE_SIGNAL)));
514 * A (*,G), which the same G as the (S,G).
515 * different paths. test our LPM.
517 mfei_g_1 = mfib_table_entry_path_update(fib_index,
521 MFIB_ITF_FLAG_ACCEPT);
522 mfib_table_entry_path_update(fib_index,
526 MFIB_ITF_FLAG_FORWARD);
529 * test we find the *,G and S,G via LPM and exact matches
531 mfei = mfib_table_lookup_exact_match(fib_index,
533 MFIB_TEST(mfei == mfei_g_1,
534 "%U found via exact match",
535 format_mfib_prefix, pfx_star_g_1);
536 MFIB_TEST(!mfib_test_entry(mfei,
537 MFIB_ENTRY_FLAG_NONE,
539 DPO_ADJACENCY_MCAST, ai_1),
541 format_mfib_prefix, pfx_star_g_1);
543 mfei = mfib_table_lookup(fib_index,
545 MFIB_TEST(mfei == mfei_g_1,
546 "[e:%d a:%d] %U found via LP match",
548 format_mfib_prefix, pfx_star_g_1);
550 MFIB_TEST(!mfib_test_entry(mfei,
551 MFIB_ENTRY_FLAG_NONE,
553 DPO_ADJACENCY_MCAST, ai_1),
555 format_mfib_prefix, pfx_star_g_1);
557 mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
558 MFIB_TEST(mfei == mfei_s_g,
559 "%U found via exact match",
560 format_mfib_prefix, pfx_s_g);
562 MFIB_TEST(!mfib_test_entry(mfei,
563 MFIB_ENTRY_FLAG_NONE,
565 DPO_ADJACENCY_MCAST, ai_1,
566 DPO_ADJACENCY_MCAST, ai_2,
567 DPO_ADJACENCY_MCAST, ai_3),
569 format_mfib_prefix, pfx_s_g);
570 mfei = mfib_table_lookup(fib_index, pfx_s_g);
571 MFIB_TEST(mfei == mfei_s_g,
572 "%U found via LP match",
573 format_mfib_prefix, pfx_s_g);
575 MFIB_TEST(!mfib_test_entry(mfei,
576 MFIB_ENTRY_FLAG_NONE,
578 DPO_ADJACENCY_MCAST, ai_1,
579 DPO_ADJACENCY_MCAST, ai_2,
580 DPO_ADJACENCY_MCAST, ai_3),
582 format_mfib_prefix, pfx_s_g);
585 * A (*,G/m), which the same root G as the (*,G).
586 * different paths. test our LPM.
588 mfei_g_m = mfib_table_entry_path_update(fib_index,
592 MFIB_ITF_FLAG_ACCEPT);
593 mfib_table_entry_path_update(fib_index,
597 MFIB_ITF_FLAG_FORWARD);
600 * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
602 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
603 MFIB_TEST((mfei_g_1 == mfei),
604 "%U found via DP LPM: %d",
605 format_mfib_prefix, pfx_star_g_1, mfei);
607 MFIB_TEST(!mfib_test_entry(mfei,
608 MFIB_ENTRY_FLAG_NONE,
610 DPO_ADJACENCY_MCAST, ai_1),
612 format_mfib_prefix, pfx_star_g_1);
614 mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
616 MFIB_TEST(!mfib_test_entry(mfei,
617 MFIB_ENTRY_FLAG_NONE,
619 DPO_ADJACENCY_MCAST, ai_1),
621 format_mfib_prefix, pfx_star_g_1);
623 mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
625 MFIB_TEST(!mfib_test_entry(mfei,
626 MFIB_ENTRY_FLAG_NONE,
628 DPO_ADJACENCY_MCAST, ai_1,
629 DPO_ADJACENCY_MCAST, ai_2,
630 DPO_ADJACENCY_MCAST, ai_3),
632 format_mfib_prefix, pfx_s_g);
633 mfei = mfib_table_lookup(fib_index, pfx_s_g);
635 MFIB_TEST(!mfib_test_entry(mfei,
636 MFIB_ENTRY_FLAG_NONE,
638 DPO_ADJACENCY_MCAST, ai_1,
639 DPO_ADJACENCY_MCAST, ai_2,
640 DPO_ADJACENCY_MCAST, ai_3),
642 format_mfib_prefix, pfx_s_g);
644 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
645 MFIB_TEST(mfei = mfei_g_m,
646 "%U Found via exact match",
647 format_mfib_prefix, pfx_star_g_slash_m);
648 MFIB_TEST(!mfib_test_entry(mfei,
649 MFIB_ENTRY_FLAG_NONE,
651 DPO_ADJACENCY_MCAST, ai_3),
653 format_mfib_prefix, pfx_star_g_slash_m);
654 MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
656 format_mfib_prefix, pfx_star_g_slash_m);
661 mfei = mfib_table_entry_path_update(fib_index,
665 MFIB_ITF_FLAG_FORWARD);
667 MFIB_TEST(!mfib_test_entry(mfei,
668 MFIB_ENTRY_FLAG_NONE,
670 DPO_ADJACENCY_MCAST, ai_1,
671 DPO_ADJACENCY_MCAST, ai_2,
672 DPO_ADJACENCY_MCAST, ai_3,
675 format_mfib_prefix, pfx_s_g);
678 * remove a for-us path
680 mfib_table_entry_path_remove(fib_index,
685 MFIB_TEST(!mfib_test_entry(mfei,
686 MFIB_ENTRY_FLAG_NONE,
688 DPO_ADJACENCY_MCAST, ai_1,
689 DPO_ADJACENCY_MCAST, ai_2,
690 DPO_ADJACENCY_MCAST, ai_3),
692 format_mfib_prefix, pfx_s_g);
695 * update an existing forwarding path to be only accepting
696 * - expect it to be removed from the replication set.
698 mfib_table_entry_path_update(fib_index,
702 MFIB_ITF_FLAG_ACCEPT);
704 MFIB_TEST(!mfib_test_entry(mfei,
705 MFIB_ENTRY_FLAG_NONE,
707 DPO_ADJACENCY_MCAST, ai_1,
708 DPO_ADJACENCY_MCAST, ai_2),
710 format_mfib_prefix, pfx_s_g);
711 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
712 MFIB_ITF_FLAG_ACCEPT));
713 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
714 MFIB_ITF_FLAG_FORWARD));
715 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
716 MFIB_ITF_FLAG_FORWARD));
717 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
718 MFIB_ITF_FLAG_ACCEPT));
720 * Make the path forwarding again
721 * - expect it to be added back to the replication set
723 mfib_table_entry_path_update(fib_index,
727 (MFIB_ITF_FLAG_FORWARD |
728 MFIB_ITF_FLAG_ACCEPT |
729 MFIB_ITF_FLAG_NEGATE_SIGNAL));
731 mfei = mfib_table_lookup_exact_match(fib_index,
734 MFIB_TEST(!mfib_test_entry(mfei,
735 MFIB_ENTRY_FLAG_NONE,
737 DPO_ADJACENCY_MCAST, ai_1,
738 DPO_ADJACENCY_MCAST, ai_2,
739 DPO_ADJACENCY_MCAST, ai_3),
741 format_mfib_prefix, pfx_s_g);
742 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
743 MFIB_ITF_FLAG_ACCEPT));
744 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
745 MFIB_ITF_FLAG_FORWARD));
746 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
747 MFIB_ITF_FLAG_FORWARD));
748 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
749 (MFIB_ITF_FLAG_FORWARD |
750 MFIB_ITF_FLAG_ACCEPT |
751 MFIB_ITF_FLAG_NEGATE_SIGNAL)));
754 * update flags on the entry
756 mfib_table_entry_update(fib_index,
760 MFIB_ENTRY_FLAG_SIGNAL);
761 MFIB_TEST(!mfib_test_entry(mfei,
762 MFIB_ENTRY_FLAG_SIGNAL,
764 DPO_ADJACENCY_MCAST, ai_1,
765 DPO_ADJACENCY_MCAST, ai_2,
766 DPO_ADJACENCY_MCAST, ai_3),
768 format_mfib_prefix, pfx_s_g);
773 mfib_table_entry_path_remove(fib_index,
778 MFIB_TEST(!mfib_test_entry(mfei,
779 MFIB_ENTRY_FLAG_SIGNAL,
781 DPO_ADJACENCY_MCAST, ai_1,
782 DPO_ADJACENCY_MCAST, ai_2),
784 format_mfib_prefix, pfx_s_g);
785 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
786 MFIB_ITF_FLAG_ACCEPT));
787 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
788 MFIB_ITF_FLAG_FORWARD));
789 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
790 MFIB_ITF_FLAG_FORWARD));
791 MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
793 mfib_table_entry_path_remove(fib_index,
798 MFIB_TEST(!mfib_test_entry(mfei,
799 MFIB_ENTRY_FLAG_SIGNAL,
801 DPO_ADJACENCY_MCAST, ai_2),
803 format_mfib_prefix, pfx_s_g);
804 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
805 MFIB_ITF_FLAG_ACCEPT));
806 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
807 MFIB_ITF_FLAG_FORWARD));
808 MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
811 * remove the accpeting only interface
813 mfib_table_entry_path_remove(fib_index,
818 MFIB_TEST(!mfib_test_entry(mfei,
819 MFIB_ENTRY_FLAG_SIGNAL,
821 DPO_ADJACENCY_MCAST, ai_2),
823 format_mfib_prefix, pfx_s_g);
824 MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
825 MFIB_ITF_FLAG_FORWARD));
826 MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index));
827 MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index));
828 MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
831 * remove the last path, the entry still has flags so it remains
833 mfib_table_entry_path_remove(fib_index,
838 MFIB_TEST(!mfib_test_entry(mfei,
839 MFIB_ENTRY_FLAG_SIGNAL,
841 "%U no replications",
842 format_mfib_prefix, pfx_s_g);
845 * update flags on the entry
847 mfib_table_entry_update(fib_index,
851 (MFIB_ENTRY_FLAG_SIGNAL |
852 MFIB_ENTRY_FLAG_CONNECTED));
853 MFIB_TEST(!mfib_test_entry(mfei,
854 (MFIB_ENTRY_FLAG_SIGNAL |
855 MFIB_ENTRY_FLAG_CONNECTED),
857 "%U no replications",
858 format_mfib_prefix, pfx_s_g);
861 * An entry with a NS interface
863 mfei_g_2 = mfib_table_entry_path_update(fib_index,
867 (MFIB_ITF_FLAG_ACCEPT |
868 MFIB_ITF_FLAG_NEGATE_SIGNAL));
869 MFIB_TEST(!mfib_test_entry(mfei_g_2,
870 MFIB_ENTRY_FLAG_NONE,
872 "%U No replications",
873 format_mfib_prefix, pfx_star_g_2);
876 * Simulate a signal from the data-plane
882 mfe = mfib_entry_get(mfei_g_2);
883 mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
885 mfib_signal_push(mfe, mfi, NULL);
889 * An entry with a NS interface
891 mfei_g_3 = mfib_table_entry_path_update(fib_index,
895 (MFIB_ITF_FLAG_ACCEPT |
896 MFIB_ITF_NEGATE_SIGNAL));
897 MFIB_TEST(!mfib_test_entry(mfei_g_3,
898 MFIB_ENTRY_FLAG_NONE,
900 "%U No replications",
901 format_mfib_prefix, pfx_star_g_3);
904 * Simulate a signal from the data-plane
910 mfe = mfib_entry_get(mfei_g_3);
911 mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
913 mfib_signal_push(mfe, mfi, NULL);
916 if (FIB_PROTOCOL_IP6 == PROTO)
919 * All the entries are present. let's ensure we can find them all
920 * via exact and longest prefix matches.
923 * A source address we will never match
925 ip6_address_t src = {
926 .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
927 .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
933 MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
934 ip6_mfib_get(fib_index),
936 &pfx_star_g_slash_m->fp_grp_addr.ip6)),
937 "%U found via DP LPM grp=%U",
938 format_mfib_prefix, pfx_star_g_slash_m,
939 format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
941 ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
942 tmp.as_u8[15] = 0xff;
944 MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
945 ip6_mfib_get(fib_index),
946 &pfx_s_g->fp_src_addr.ip6,
948 "%U found via DP LPM grp=%U",
949 format_mfib_prefix, pfx_star_g_slash_m,
950 format_ip6_address, &tmp);
955 mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
956 &pfx_s_g->fp_src_addr.ip6,
957 &pfx_s_g->fp_grp_addr.ip6);
958 MFIB_TEST((mfei_s_g == mfei),
959 "%U found via DP LPM: %d",
960 format_mfib_prefix, pfx_s_g, mfei);
965 mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
967 &pfx_star_g_1->fp_grp_addr.ip6);
968 MFIB_TEST((mfei_g_1 == mfei),
969 "%U found via DP LPM: %d",
970 format_mfib_prefix, pfx_star_g_1, mfei);
971 mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
973 &pfx_star_g_2->fp_grp_addr.ip6);
974 MFIB_TEST((mfei_g_2 == mfei),
975 "%U found via DP LPM: %d",
976 format_mfib_prefix, pfx_star_g_2, mfei);
977 mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
979 &pfx_star_g_3->fp_grp_addr.ip6);
980 MFIB_TEST((mfei_g_3 == mfei),
981 "%U found via DP LPM: %d",
982 format_mfib_prefix, pfx_star_g_3, mfei);
986 * remove flags on the entry. This is the last of the
987 * state associated with the entry, so now it goes.
989 mfib_table_entry_update(fib_index,
993 MFIB_ENTRY_FLAG_NONE);
994 mfei = mfib_table_lookup_exact_match(fib_index,
996 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
998 format_mfib_prefix, pfx_s_g);
1001 * remove the last path on the no forward entry - the last entry
1003 mfib_table_entry_path_remove(fib_index,
1008 mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
1009 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1011 format_mfib_prefix, pfx_no_forward);
1014 * hard delete the (*,232.1.1.1)
1016 mfib_table_entry_delete(fib_index,
1020 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1021 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1023 format_mfib_prefix, pfx_star_g_1);
1025 * remove the entry whilst the signal is pending
1027 mfib_table_entry_delete(fib_index,
1031 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1032 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1034 format_mfib_prefix, pfx_star_g_2);
1035 mfib_table_entry_delete(fib_index,
1039 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1040 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1042 format_mfib_prefix, pfx_star_g_3);
1044 mfib_table_entry_delete(fib_index,
1048 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1049 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1051 format_mfib_prefix, pfx_star_g_slash_m);
1054 * Entries with paths via unicast next-hops
1056 fib_route_path_t path_via_nbr1 = {
1057 .frp_proto = fib_proto_to_dpo(PROTO),
1058 .frp_addr = *addr_nbr1,
1059 .frp_sw_if_index = tm->hw[0]->sw_if_index,
1060 .frp_fib_index = ~0,
1064 fib_route_path_t path_via_nbr2 = {
1065 .frp_proto = fib_proto_to_dpo(PROTO),
1066 .frp_addr = *addr_nbr2,
1067 .frp_sw_if_index = tm->hw[0]->sw_if_index,
1068 .frp_fib_index = ~0,
1073 mfei_g_1 = mfib_table_entry_path_update(fib_index,
1077 (MFIB_ITF_FLAG_FORWARD));
1078 mfei_g_1 = mfib_table_entry_path_update(fib_index,
1082 (MFIB_ITF_FLAG_FORWARD));
1083 MFIB_TEST(!mfib_test_entry(mfei_g_1,
1084 MFIB_ENTRY_FLAG_NONE,
1086 DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
1087 DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1089 format_mfib_prefix, pfx_star_g_1);
1090 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1091 MFIB_ITF_FLAG_FORWARD));
1093 mfib_table_entry_path_remove(fib_index,
1098 MFIB_TEST(!mfib_test_entry(mfei_g_1,
1099 MFIB_ENTRY_FLAG_NONE,
1101 DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1103 format_mfib_prefix, pfx_star_g_1);
1104 MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1105 MFIB_ITF_FLAG_FORWARD));
1107 mfib_table_entry_path_remove(fib_index,
1111 mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1112 MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1114 format_mfib_prefix, pfx_star_g_1);
1117 * Add a prefix as a special/exclusive route
1119 dpo_id_t td = DPO_INVALID;
1120 index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
1122 dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
1123 replicate_set_bucket(repi, 0, &td);
1125 mfei = mfib_table_entry_special_add(fib_index,
1128 MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1130 MFIB_TEST(!mfib_test_entry(mfei,
1131 (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1132 MFIB_ENTRY_FLAG_EXCLUSIVE),
1134 DPO_ADJACENCY_MCAST, ai_2),
1135 "%U exclusive replicate OK",
1136 format_mfib_prefix, pfx_star_g_3);
1139 * update a special/exclusive route
1141 index_t repi2 = replicate_create(1, fib_proto_to_dpo(PROTO));
1143 dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1);
1144 replicate_set_bucket(repi2, 0, &td);
1146 mfei = mfib_table_entry_special_add(fib_index,
1149 MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1151 MFIB_TEST(!mfib_test_entry(mfei,
1152 (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1153 MFIB_ENTRY_FLAG_EXCLUSIVE),
1155 DPO_ADJACENCY_MCAST, ai_1),
1156 "%U exclusive update replicate OK",
1157 format_mfib_prefix, pfx_star_g_3);
1159 mfib_table_entry_delete(fib_index,
1165 * A Multicast LSP. This a mLDP head-end
1167 fib_node_index_t ai_mpls_10_10_10_1, lfei;
1168 ip46_address_t nh_10_10_10_1 = {
1170 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1173 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1176 tm->hw[0]->sw_if_index);
1178 fib_prefix_t pfx_3500 = {
1180 .fp_proto = FIB_PROTOCOL_MPLS,
1183 .fp_payload_proto = DPO_PROTO_IP4,
1185 fib_test_rep_bucket_t mc_0 = {
1186 .type = FT_REP_LABEL_O_ADJ,
1188 .adj = ai_mpls_10_10_10_1,
1193 fib_mpls_label_t *l3300 = NULL, fml3300 = {
1196 vec_add1(l3300, fml3300);
1199 * MPLS enable an interface so we get the MPLS table created
1201 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
1202 mpls_sw_interface_enable_disable(&mpls_main,
1203 tm->hw[0]->sw_if_index,
1206 lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1209 FIB_ENTRY_FLAG_MULTICAST,
1212 tm->hw[0]->sw_if_index,
1213 ~0, // invalid fib index
1216 FIB_ROUTE_PATH_FLAG_NONE);
1217 MFIB_TEST(!fib_test_validate_entry(lfei,
1218 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1221 "3500 via replicate over 10.10.10.1");
1224 * An (S,G) that resolves via the mLDP head-end
1226 fib_route_path_t path_via_mldp = {
1227 .frp_proto = DPO_PROTO_MPLS,
1228 .frp_local_label = pfx_3500.fp_label,
1229 .frp_eos = MPLS_EOS,
1230 .frp_sw_if_index = 0xffffffff,
1233 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1235 dpo_id_t mldp_dpo = DPO_INVALID;
1237 fib_entry_contribute_forwarding(lfei,
1238 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1241 mfei = mfib_table_entry_path_update(fib_index,
1245 MFIB_ITF_FLAG_FORWARD);
1247 MFIB_TEST(!mfib_test_entry(mfei,
1248 MFIB_ENTRY_FLAG_NONE,
1250 DPO_REPLICATE, mldp_dpo.dpoi_index),
1251 "%U over-mLDP replicate OK",
1252 format_mfib_prefix, pfx_s_g);
1255 * add a for-us path. this tests two types of non-attached paths on one entry
1257 mfei = mfib_table_entry_path_update(fib_index,
1261 MFIB_ITF_FLAG_FORWARD);
1262 MFIB_TEST(!mfib_test_entry(mfei,
1263 MFIB_ENTRY_FLAG_NONE,
1265 DPO_REPLICATE, mldp_dpo.dpoi_index,
1267 "%U mLDP+for-us replicate OK",
1268 format_mfib_prefix, pfx_s_g);
1270 mfib_table_entry_delete(fib_index,
1273 fib_table_entry_delete(0,
1276 dpo_reset(&mldp_dpo);
1279 * Unlock the table - it's the last lock so should be gone thereafter
1281 mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1283 MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1284 mfib_table_find(PROTO, fib_index)),
1285 "MFIB table %d gone", fib_index);
1290 adj_unlock(ai_nbr1);
1291 adj_unlock(ai_nbr2);
1294 * MPLS disable the interface
1296 mpls_sw_interface_enable_disable(&mpls_main,
1297 tm->hw[0]->sw_if_index,
1299 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1302 * remove the connected
1304 fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
1307 * test we've leaked no resources
1309 MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1310 MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1311 n_pls, fib_path_list_pool_size());
1312 MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1313 n_reps, pool_elts(replicate_pool));
1314 MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1315 " No more entries %d!=%d",
1316 n_entries, pool_elts(mfib_entry_pool));
1317 MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1318 " No more Interfaces %d!=%d",
1319 n_itfs, pool_elts(mfib_itf_pool));
1327 const mfib_prefix_t pfx_224_s_8 = {
1329 .fp_proto = FIB_PROTOCOL_IP4,
1331 .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1334 const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1336 .fp_proto = FIB_PROTOCOL_IP4,
1338 .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1341 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1344 const mfib_prefix_t pfx_239_1_1_1 = {
1346 .fp_proto = FIB_PROTOCOL_IP4,
1348 .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1354 const mfib_prefix_t pfx_239_1_1_2 = {
1356 .fp_proto = FIB_PROTOCOL_IP4,
1358 .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1364 const mfib_prefix_t pfx_239_1_1_3 = {
1366 .fp_proto = FIB_PROTOCOL_IP4,
1368 .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1374 const mfib_prefix_t pfx_239 = {
1376 .fp_proto = FIB_PROTOCOL_IP4,
1378 .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1384 const fib_prefix_t pfx_itf = {
1386 .fp_proto = FIB_PROTOCOL_IP4,
1388 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
1391 const ip46_address_t nbr1 = {
1392 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
1394 const ip46_address_t nbr2 = {
1395 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
1397 return (mfib_test_i(FIB_PROTOCOL_IP4,
1400 &pfx_1_1_1_1_c_239_1_1_1,
1413 const mfib_prefix_t pfx_ffd_s_12 = {
1415 .fp_proto = FIB_PROTOCOL_IP6,
1417 .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1420 const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1422 .fp_proto = FIB_PROTOCOL_IP6,
1424 .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1425 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1428 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1429 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1432 const mfib_prefix_t pfx_ff_1 = {
1434 .fp_proto = FIB_PROTOCOL_IP6,
1436 .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1437 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1440 const mfib_prefix_t pfx_ff_2 = {
1442 .fp_proto = FIB_PROTOCOL_IP6,
1444 .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1445 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1448 const mfib_prefix_t pfx_ff_3 = {
1450 * this is the ALL DHCP routers address
1453 .fp_proto = FIB_PROTOCOL_IP6,
1455 .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1456 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1459 const mfib_prefix_t pfx_ff = {
1461 .fp_proto = FIB_PROTOCOL_IP6,
1463 .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1464 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1467 const fib_prefix_t pfx_itf = {
1469 .fp_proto = FIB_PROTOCOL_IP6,
1471 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1472 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1475 const ip46_address_t nbr1 = {
1476 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1477 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1479 const ip46_address_t nbr2 = {
1480 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1481 .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
1484 return (mfib_test_i(FIB_PROTOCOL_IP6,
1497 static clib_error_t *
1498 mfib_test (vlib_main_t * vm,
1499 unformat_input_t * input,
1500 vlib_cli_command_t * cmd_arg)
1504 res += mfib_test_mk_intf(4);
1505 res += mfib_test_v4();
1509 return clib_error_return(0, "MFIB Unit Test Failed");
1512 res += mfib_test_v6();
1516 return clib_error_return(0, "MFIB Unit Test Failed");
1524 VLIB_CLI_COMMAND (test_fib_command, static) = {
1525 .path = "test mfib",
1526 .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1527 .function = mfib_test,
1531 mfib_test_init (vlib_main_t *vm)
1536 VLIB_INIT_FUNCTION (mfib_test_init);