IP Multicast FIB (mfib)
[vpp.git] / src / vnet / mfib / mfib_test.c
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/mpls/mpls_types.h>
17
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
23 #include <vnet/dpo/replicate_dpo.h>
24 #include <vnet/adj/adj_mcast.h>
25
26 #define MFIB_TEST_I(_cond, _comment, _args...)                  \
27 ({                                                              \
28     int _evald = (_cond);                                       \
29     if (!(_evald)) {                                            \
30         fformat(stderr, "FAIL:%d: " _comment "\n",              \
31                 __LINE__, ##_args);                             \
32     } else {                                                    \
33         fformat(stderr, "PASS:%d: " _comment "\n",              \
34                 __LINE__, ##_args);                             \
35     }                                                           \
36     _evald;                                                     \
37 })
38 #define MFIB_TEST(_cond, _comment, _args...)                    \
39 {                                                               \
40     if (!MFIB_TEST_I(_cond, _comment, ##_args)) {               \
41         return 1;\
42         ASSERT(!("FAIL: " _comment));                           \
43     }                                                           \
44 }
45 #define MFIB_TEST_NS(_cond)                                     \
46 {                                                               \
47     if (!MFIB_TEST_I(_cond, "")) {                              \
48         return 1;\
49         ASSERT(!("FAIL: "));                                    \
50     }                                                           \
51 }
52
53 /**
54  * A 'i'm not fussed is this is not efficient' store of test data
55  */
56 typedef struct test_main_t_ {
57     /**
58      * HW if indicies
59      */
60     u32 hw_if_indicies[4];
61     /**
62      * HW interfaces
63      */
64     vnet_hw_interface_t * hw[4];
65
66 } test_main_t;
67 static test_main_t test_main;
68
69 /* fake ethernet device class, distinct from "fake-ethX" */
70 static u8 * format_test_interface_name (u8 * s, va_list * args)
71 {
72   u32 dev_instance = va_arg (*args, u32);
73   return format (s, "test-eth%d", dev_instance);
74 }
75
76 static uword dummy_interface_tx (vlib_main_t * vm,
77                                  vlib_node_runtime_t * node,
78                                  vlib_frame_t * frame)
79 {
80   clib_warning ("you shouldn't be here, leaking buffers...");
81   return frame->n_vectors;
82 }
83
84 static clib_error_t *
85 test_interface_admin_up_down (vnet_main_t * vnm,
86                               u32 hw_if_index,
87                               u32 flags)
88 {
89   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
90     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
91   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
92   return 0;
93 }
94
95 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
96   .name = "Test interface",
97   .format_device_name = format_test_interface_name,
98   .tx_function = dummy_interface_tx,
99   .admin_up_down_function = test_interface_admin_up_down,
100 };
101
102 static u8 *hw_address;
103
104 static int
105 mfib_test_mk_intf (u32 ninterfaces)
106 {
107     clib_error_t * error = NULL;
108     test_main_t *tm = &test_main;
109     u8 byte;
110     u32 i;
111
112     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
113
114     for (i=0; i<6; i++)
115     {
116         byte = 0xd0+i;
117         vec_add1(hw_address, byte);
118     }
119
120     for (i = 0; i < ninterfaces; i++)
121     {
122         hw_address[5] = i;
123
124         error = ethernet_register_interface(vnet_get_main(),
125                                             test_interface_device_class.index,
126                                             i /* instance */,
127                                             hw_address,
128                                             &tm->hw_if_indicies[i],
129                                             /* flag change */ 0);
130
131         MFIB_TEST((NULL == error), "ADD interface %d", i);
132
133         error = vnet_hw_interface_set_flags(vnet_get_main(),
134                                             tm->hw_if_indicies[i],
135                                             VNET_HW_INTERFACE_FLAG_LINK_UP);
136         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
137                                           tm->hw_if_indicies[i]);
138         vec_validate (ip4_main.fib_index_by_sw_if_index,
139                       tm->hw[i]->sw_if_index);
140         vec_validate (ip6_main.fib_index_by_sw_if_index,
141                       tm->hw[i]->sw_if_index);
142         ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
143         ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
144
145         vec_validate (ip4_main.mfib_index_by_sw_if_index,
146                       tm->hw[i]->sw_if_index);
147         vec_validate (ip6_main.mfib_index_by_sw_if_index,
148                       tm->hw[i]->sw_if_index);
149         ip4_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
150         ip6_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
151
152         error = vnet_sw_interface_set_flags(vnet_get_main(),
153                                             tm->hw[i]->sw_if_index,
154                                             VNET_SW_INTERFACE_FLAG_ADMIN_UP);
155         MFIB_TEST((NULL == error), "UP interface %d", i);
156     }
157     /*
158      * re-eval after the inevitable realloc
159      */
160     for (i = 0; i < ninterfaces; i++)
161     {
162         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
163                                           tm->hw_if_indicies[i]);
164     }
165
166     return (0);
167 }
168
169 #define MFIB_TEST_REP(_cond, _comment, _args...)                \
170 {                                                               \
171     if (!MFIB_TEST_I(_cond, _comment, ##_args)) {               \
172         return (0);                                             \
173     }                                                           \
174 }
175
176 static int
177 mfib_test_validate_rep_v (const replicate_t *rep,
178                           u16 n_buckets,
179                           va_list ap)
180 {
181     const dpo_id_t *dpo;
182     adj_index_t ai;
183     dpo_type_t dt;
184     int bucket;
185
186     MFIB_TEST_REP((n_buckets == rep->rep_n_buckets),
187                   "n_buckets = %d", rep->rep_n_buckets);
188
189     for (bucket = 0; bucket < n_buckets; bucket++)
190     {
191         dt = va_arg(ap, int);  // type promotion
192         ai = va_arg(ap, adj_index_t);
193         dpo = replicate_get_bucket_i(rep, bucket);
194
195         MFIB_TEST_REP((dt == dpo->dpoi_type),
196                       "bucket %d stacks on %U",
197                       bucket,
198                       format_dpo_type, dpo->dpoi_type);
199
200         if (DPO_RECEIVE != dt)
201         {
202             MFIB_TEST_REP((ai == dpo->dpoi_index),
203                           "bucket %d stacks on %U",
204                           bucket,
205                           format_dpo_id, dpo, 0);
206         }
207     }
208     return (!0);
209 }
210
211 static fib_forward_chain_type_t
212 fib_forw_chain_type_from_fib_proto (fib_protocol_t proto)
213 {
214     switch (proto)
215     {
216     case FIB_PROTOCOL_IP4:
217         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
218     case FIB_PROTOCOL_IP6:
219         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
220     default:
221         break;
222     }
223     ASSERT(0);
224     return (0);
225 }
226
227
228 static int
229 mfib_test_entry (fib_node_index_t fei,
230                  mfib_entry_flags_t eflags,
231                  u16 n_buckets,
232                  ...)
233 {
234     const mfib_entry_t *mfe;
235     const replicate_t *rep;
236     mfib_prefix_t pfx;
237     va_list ap;
238
239     va_start(ap, n_buckets);
240
241     mfe = mfib_entry_get(fei);
242     mfib_entry_get_prefix(fei, &pfx);
243
244     MFIB_TEST_REP((eflags == mfe->mfe_flags),
245                   "%U has %U expect %U",
246                   format_mfib_prefix, &pfx,
247                   format_mfib_entry_flags, mfe->mfe_flags,
248                   format_mfib_entry_flags, eflags);
249
250     if (0 == n_buckets)
251     {
252         MFIB_TEST_REP((DPO_DROP == mfe->mfe_rep.dpoi_type),
253                       "%U links to %U",
254                       format_mfib_prefix, &pfx,
255                       format_dpo_id, &mfe->mfe_rep, 0);
256         return (!0);
257     }
258     else
259     {
260         dpo_id_t tmp = DPO_INVALID;
261         int res;
262
263         mfib_entry_contribute_forwarding(
264             fei,
265             fib_forw_chain_type_from_fib_proto(pfx.fp_proto),
266             &tmp);
267         rep = replicate_get(tmp.dpoi_index);
268
269         MFIB_TEST_REP((DPO_REPLICATE == tmp.dpoi_type),
270                       "%U links to %U",
271                       format_mfib_prefix, &pfx,
272                       format_dpo_type, tmp.dpoi_type);
273
274         res = mfib_test_validate_rep_v(rep, n_buckets, ap);
275
276         dpo_reset(&tmp);
277
278         return (res);
279     }
280 }
281
282 static int
283 mfib_test_entry_itf (fib_node_index_t fei,
284                      u32 sw_if_index,
285                      mfib_itf_flags_t flags)
286 {
287     const mfib_entry_t *mfe;
288     const mfib_itf_t *mfi;
289     mfib_prefix_t pfx;
290
291     mfe = mfib_entry_get(fei);
292     mfi = mfib_entry_get_itf(mfe, sw_if_index);
293     mfib_entry_get_prefix(fei, &pfx);
294
295     MFIB_TEST_REP((NULL != mfi),
296                   "%U has interface %d",
297                   format_mfib_prefix, &pfx, sw_if_index);
298
299     MFIB_TEST_REP((flags == mfi->mfi_flags),
300                   "%U interface %d has flags %U expect %U",
301                   format_mfib_prefix, &pfx, sw_if_index,
302                   format_mfib_itf_flags, flags,
303                   format_mfib_itf_flags, mfi->mfi_flags);
304
305     return (!0);
306 }
307
308 static int
309 mfib_test_entry_no_itf (fib_node_index_t fei,
310                         u32 sw_if_index)
311 {
312     const mfib_entry_t *mfe;
313     const mfib_itf_t *mfi;
314     mfib_prefix_t pfx;
315
316     mfe = mfib_entry_get(fei);
317     mfi = mfib_entry_get_itf(mfe, sw_if_index);
318     mfib_entry_get_prefix(fei, &pfx);
319
320     MFIB_TEST_REP((NULL == mfi),
321                   "%U has no interface %d",
322                   format_mfib_prefix, &pfx, sw_if_index);
323
324     return (!0);
325 }
326
327 static int
328 mfib_test_i (fib_protocol_t PROTO,
329              vnet_link_t LINKT,
330              const mfib_prefix_t *pfx_no_forward,
331              const mfib_prefix_t *pfx_s_g,
332              const mfib_prefix_t *pfx_star_g_1,
333              const mfib_prefix_t *pfx_star_g_2,
334              const mfib_prefix_t *pfx_star_g_3,
335              const mfib_prefix_t *pfx_star_g_slash_m)
336 {
337     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;
338     u32 fib_index, n_entries, n_itfs, n_reps;
339     fib_node_index_t ai_1, ai_2, ai_3;
340     test_main_t *tm;
341
342     mfib_prefix_t all_1s;
343     memset(&all_1s, 0xfd, sizeof(all_1s));
344
345     n_entries = pool_elts(mfib_entry_pool);
346     n_itfs = pool_elts(mfib_itf_pool);
347     n_reps = pool_elts(replicate_pool);
348     tm = &test_main;
349
350     ai_1 = adj_mcast_add_or_lock(PROTO,
351                                  LINKT,
352                                  tm->hw[1]->sw_if_index);
353     ai_2 = adj_mcast_add_or_lock(PROTO,
354                                  LINKT,
355                                  tm->hw[2]->sw_if_index);
356     ai_3 = adj_mcast_add_or_lock(PROTO,
357                                  LINKT,
358                                  tm->hw[3]->sw_if_index);
359
360     MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
361
362     /* Find or create FIB table 11 */
363     fib_index = mfib_table_find_or_create_and_lock(PROTO, 11);
364
365     mfib_prefix_t pfx_dft = {
366         .fp_len = 0,
367         .fp_proto = PROTO,
368     };
369     mfei_dflt = mfib_table_lookup_exact_match(fib_index, &pfx_dft);
370     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
371     MFIB_TEST(mfib_test_entry(mfei_dflt,
372                               MFIB_ENTRY_FLAG_DROP,
373                               0),
374               "(*,*) no replcaitions");
375
376     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
377     MFIB_TEST(mfib_test_entry(mfei_dflt,
378                               MFIB_ENTRY_FLAG_DROP,
379                               0),
380               "(*,*) no replcaitions");
381
382
383     fib_route_path_t path_via_if0 = {
384         .frp_proto = PROTO,
385         .frp_addr = zero_addr,
386         .frp_sw_if_index = tm->hw[0]->sw_if_index,
387         .frp_fib_index = ~0,
388         .frp_weight = 0,
389         .frp_flags = 0,
390     };
391
392     mfib_table_entry_path_update(fib_index,
393                                  pfx_no_forward,
394                                  MFIB_SOURCE_API,
395                                  &path_via_if0,
396                                  MFIB_ITF_FLAG_ACCEPT);
397
398     mfei_no_f = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
399     MFIB_TEST(mfib_test_entry(mfei_no_f,
400                               MFIB_ENTRY_FLAG_NONE,
401                               0),
402               "%U no replcaitions",
403               format_mfib_prefix, pfx_no_forward);
404     MFIB_TEST_NS(mfib_test_entry_itf(mfei_no_f, tm->hw[0]->sw_if_index,
405                                      MFIB_ITF_FLAG_ACCEPT));
406
407     fib_route_path_t path_via_if1 = {
408         .frp_proto = PROTO,
409         .frp_addr = zero_addr,
410         .frp_sw_if_index = tm->hw[1]->sw_if_index,
411         .frp_fib_index = ~0,
412         .frp_weight = 0,
413         .frp_flags = 0,
414     };
415     fib_route_path_t path_via_if2 = {
416         .frp_proto = PROTO,
417         .frp_addr = zero_addr,
418         .frp_sw_if_index = tm->hw[2]->sw_if_index,
419         .frp_fib_index = ~0,
420         .frp_weight = 0,
421         .frp_flags = 0,
422     };
423     fib_route_path_t path_via_if3 = {
424         .frp_proto = PROTO,
425         .frp_addr = zero_addr,
426         .frp_sw_if_index = tm->hw[3]->sw_if_index,
427         .frp_fib_index = ~0,
428         .frp_weight = 0,
429         .frp_flags = 0,
430     };
431     fib_route_path_t path_for_us = {
432         .frp_proto = PROTO,
433         .frp_addr = zero_addr,
434         .frp_sw_if_index = 0xffffffff,
435         .frp_fib_index = ~0,
436         .frp_weight = 0,
437         .frp_flags = FIB_ROUTE_PATH_LOCAL,
438     };
439
440     /*
441      * An (S,G) with 1 accepting and 3 forwarding paths
442      */
443     mfib_table_entry_path_update(fib_index,
444                                  pfx_s_g,
445                                  MFIB_SOURCE_API,
446                                  &path_via_if0,
447                                  MFIB_ITF_FLAG_ACCEPT);
448     mfib_table_entry_path_update(fib_index,
449                                  pfx_s_g,
450                                  MFIB_SOURCE_API,
451                                  &path_via_if1,
452                                  MFIB_ITF_FLAG_FORWARD);
453     mfib_table_entry_path_update(fib_index,
454                                  pfx_s_g,
455                                  MFIB_SOURCE_API,
456                                  &path_via_if2,
457                                  MFIB_ITF_FLAG_FORWARD);
458     mfib_table_entry_path_update(fib_index,
459                                  pfx_s_g,
460                                  MFIB_SOURCE_API,
461                                  &path_via_if3,
462                                  (MFIB_ITF_FLAG_FORWARD |
463                                   MFIB_ITF_FLAG_NEGATE_SIGNAL));
464
465     mfei_s_g = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
466
467     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_s_g,
468               "%U present",
469               format_mfib_prefix, pfx_s_g);
470     MFIB_TEST(mfib_test_entry(mfei_s_g,
471                               MFIB_ENTRY_FLAG_NONE,
472                               3,
473                               DPO_ADJACENCY_MCAST, ai_1,
474                               DPO_ADJACENCY_MCAST, ai_2,
475                               DPO_ADJACENCY_MCAST, ai_3),
476               "%U replicate ok",
477               format_mfib_prefix, pfx_s_g);
478     MFIB_TEST_NS(mfib_test_entry_itf(mfei_s_g, tm->hw[0]->sw_if_index,
479                                      MFIB_ITF_FLAG_ACCEPT));
480     MFIB_TEST_NS(mfib_test_entry_itf(mfei_s_g, tm->hw[1]->sw_if_index,
481                                      MFIB_ITF_FLAG_FORWARD));
482     MFIB_TEST_NS(mfib_test_entry_itf(mfei_s_g, tm->hw[2]->sw_if_index,
483                                      MFIB_ITF_FLAG_FORWARD));
484     MFIB_TEST_NS(mfib_test_entry_itf(mfei_s_g, tm->hw[3]->sw_if_index,
485                                      (MFIB_ITF_FLAG_FORWARD |
486                                       MFIB_ITF_FLAG_NEGATE_SIGNAL)));
487
488     /*
489      * A (*,G), which the same G as the (S,G).
490      * different paths. test our LPM.
491      */
492     mfei_g_1 = mfib_table_entry_path_update(fib_index,
493                                             pfx_star_g_1,
494                                             MFIB_SOURCE_API,
495                                             &path_via_if0,
496                                             MFIB_ITF_FLAG_ACCEPT);
497     mfib_table_entry_path_update(fib_index,
498                                  pfx_star_g_1,
499                                  MFIB_SOURCE_API,
500                                  &path_via_if1,
501                                  MFIB_ITF_FLAG_FORWARD);
502
503     /*
504      * test we find the *,G and S,G via LPM and exact matches
505      */
506     mfei = mfib_table_lookup_exact_match(fib_index,
507                                          pfx_star_g_1);
508     MFIB_TEST(mfei == mfei_g_1,
509               "%U found via exact match",
510               format_mfib_prefix, pfx_star_g_1);
511     MFIB_TEST(mfib_test_entry(mfei,
512                               MFIB_ENTRY_FLAG_NONE,
513                               1,
514                               DPO_ADJACENCY_MCAST, ai_1),
515               "%U replicate ok",
516               format_mfib_prefix, pfx_star_g_1);
517
518     mfei = mfib_table_lookup(fib_index,
519                              pfx_star_g_1);
520     MFIB_TEST(mfei == mfei_g_1,
521               "%U found via LP match",
522               format_mfib_prefix, pfx_star_g_1);
523
524     MFIB_TEST(mfib_test_entry(mfei,
525                               MFIB_ENTRY_FLAG_NONE,
526                               1,
527                               DPO_ADJACENCY_MCAST, ai_1),
528               "%U replicate ok",
529               format_mfib_prefix, pfx_star_g_1);
530
531     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
532     MFIB_TEST(mfei == mfei_s_g,
533               "%U found via exact match",
534               format_mfib_prefix, pfx_s_g);
535
536     MFIB_TEST(mfib_test_entry(mfei,
537                               MFIB_ENTRY_FLAG_NONE,
538                               3,
539                               DPO_ADJACENCY_MCAST, ai_1,
540                               DPO_ADJACENCY_MCAST, ai_2,
541                               DPO_ADJACENCY_MCAST, ai_3),
542               "%U replicate OK",
543               format_mfib_prefix, pfx_s_g);
544     mfei = mfib_table_lookup(fib_index, pfx_s_g);
545     MFIB_TEST(mfei == mfei_s_g,
546               "%U found via LP match",
547               format_mfib_prefix, pfx_s_g);
548
549     MFIB_TEST(mfib_test_entry(mfei,
550                               MFIB_ENTRY_FLAG_NONE,
551                               3,
552                               DPO_ADJACENCY_MCAST, ai_1,
553                               DPO_ADJACENCY_MCAST, ai_2,
554                               DPO_ADJACENCY_MCAST, ai_3),
555               "%U replicate OK",
556               format_mfib_prefix, pfx_s_g);
557
558     /*
559      * A (*,G/m), which the same root G as the (*,G).
560      * different paths. test our LPM.
561      */
562     mfei_g_m = mfib_table_entry_path_update(fib_index,
563                                             pfx_star_g_slash_m,
564                                             MFIB_SOURCE_API,
565                                             &path_via_if2,
566                                             MFIB_ITF_FLAG_ACCEPT);
567     mfib_table_entry_path_update(fib_index,
568                                  pfx_star_g_slash_m,
569                                  MFIB_SOURCE_API,
570                                  &path_via_if3,
571                                  MFIB_ITF_FLAG_FORWARD);
572
573     /*
574      * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
575      */
576     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
577     MFIB_TEST((mfei_g_1 == mfei),
578               "%U found via DP LPM: %d",
579               format_mfib_prefix, pfx_star_g_1, mfei);
580
581     MFIB_TEST(mfib_test_entry(mfei,
582                               MFIB_ENTRY_FLAG_NONE,
583                               1,
584                               DPO_ADJACENCY_MCAST, ai_1),
585               "%U replicate ok",
586               format_mfib_prefix, pfx_star_g_1);
587
588     mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
589
590     MFIB_TEST(mfib_test_entry(mfei,
591                               MFIB_ENTRY_FLAG_NONE,
592                               1,
593                               DPO_ADJACENCY_MCAST, ai_1),
594               "%U replicate ok",
595               format_mfib_prefix, pfx_star_g_1);
596
597     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
598
599     MFIB_TEST(mfib_test_entry(mfei,
600                               MFIB_ENTRY_FLAG_NONE,
601                               3,
602                               DPO_ADJACENCY_MCAST, ai_1,
603                               DPO_ADJACENCY_MCAST, ai_2,
604                               DPO_ADJACENCY_MCAST, ai_3),
605               "%U replicate OK",
606               format_mfib_prefix, pfx_s_g);
607     mfei = mfib_table_lookup(fib_index, pfx_s_g);
608
609     MFIB_TEST(mfib_test_entry(mfei,
610                               MFIB_ENTRY_FLAG_NONE,
611                               3,
612                               DPO_ADJACENCY_MCAST, ai_1,
613                               DPO_ADJACENCY_MCAST, ai_2,
614                               DPO_ADJACENCY_MCAST, ai_3),
615               "%U replicate OK",
616               format_mfib_prefix, pfx_s_g);
617
618     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
619     MFIB_TEST(mfei = mfei_g_m,
620               "%U Found via exact match",
621               format_mfib_prefix, pfx_star_g_slash_m);
622     MFIB_TEST(mfib_test_entry(mfei,
623                               MFIB_ENTRY_FLAG_NONE,
624                               1,
625                               DPO_ADJACENCY_MCAST, ai_3),
626               "%U replicate OK",
627               format_mfib_prefix, pfx_star_g_slash_m);
628     MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
629               "%U found via LPM",
630               format_mfib_prefix, pfx_star_g_slash_m);
631
632     /*
633      * Add a for-us path
634      */
635     mfei = mfib_table_entry_path_update(fib_index,
636                                         pfx_s_g,
637                                         MFIB_SOURCE_API,
638                                         &path_for_us,
639                                         MFIB_ITF_FLAG_FORWARD);
640
641     MFIB_TEST(mfib_test_entry(mfei,
642                               MFIB_ENTRY_FLAG_NONE,
643                               4,
644                               DPO_ADJACENCY_MCAST, ai_1,
645                               DPO_ADJACENCY_MCAST, ai_2,
646                               DPO_ADJACENCY_MCAST, ai_3,
647                               DPO_RECEIVE, 0),
648               "%U replicate OK",
649               format_mfib_prefix, pfx_s_g);
650
651     /*
652      * remove a for-us path
653      */
654     mfib_table_entry_path_remove(fib_index,
655                                  pfx_s_g,
656                                  MFIB_SOURCE_API,
657                                  &path_for_us);
658
659     MFIB_TEST(mfib_test_entry(mfei,
660                               MFIB_ENTRY_FLAG_NONE,
661                               3,
662                               DPO_ADJACENCY_MCAST, ai_1,
663                               DPO_ADJACENCY_MCAST, ai_2,
664                               DPO_ADJACENCY_MCAST, ai_3),
665               "%U replicate OK",
666               format_mfib_prefix, pfx_s_g);
667
668     /*
669      * update an existing forwarding path to be only accepting
670      *   - expect it to be removed from the replication set.
671      */
672     mfib_table_entry_path_update(fib_index,
673                                  pfx_s_g,
674                                  MFIB_SOURCE_API,
675                                  &path_via_if3,
676                                  MFIB_ITF_FLAG_ACCEPT);
677
678     MFIB_TEST(mfib_test_entry(mfei,
679                               MFIB_ENTRY_FLAG_NONE,
680                               2,
681                               DPO_ADJACENCY_MCAST, ai_1,
682                               DPO_ADJACENCY_MCAST, ai_2),
683               "%U replicate OK",
684               format_mfib_prefix, pfx_s_g);
685     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
686                                      MFIB_ITF_FLAG_ACCEPT));
687     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
688                                      MFIB_ITF_FLAG_FORWARD));
689     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
690                                      MFIB_ITF_FLAG_FORWARD));
691     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
692                                      MFIB_ITF_FLAG_ACCEPT));
693     /*
694      * Make the path forwarding again
695      *  - expect it to be added back to the replication set
696      */
697     mfib_table_entry_path_update(fib_index,
698                                  pfx_s_g,
699                                  MFIB_SOURCE_API,
700                                  &path_via_if3,
701                                  (MFIB_ITF_FLAG_FORWARD |
702                                   MFIB_ITF_FLAG_ACCEPT |
703                                   MFIB_ITF_FLAG_NEGATE_SIGNAL));
704
705     mfei = mfib_table_lookup_exact_match(fib_index,
706                                          pfx_s_g);
707
708     MFIB_TEST(mfib_test_entry(mfei,
709                               MFIB_ENTRY_FLAG_NONE,
710                               3,
711                               DPO_ADJACENCY_MCAST, ai_1,
712                               DPO_ADJACENCY_MCAST, ai_2,
713                               DPO_ADJACENCY_MCAST, ai_3),
714               "%U replicate OK",
715               format_mfib_prefix, pfx_s_g);
716     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
717                                      MFIB_ITF_FLAG_ACCEPT));
718      MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
719                                      MFIB_ITF_FLAG_FORWARD));
720     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
721                                      MFIB_ITF_FLAG_FORWARD));
722     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
723                                      (MFIB_ITF_FLAG_FORWARD |
724                                       MFIB_ITF_FLAG_ACCEPT |
725                                       MFIB_ITF_FLAG_NEGATE_SIGNAL)));
726
727     /*
728      * update flags on the entry
729      */
730     mfib_table_entry_update(fib_index,
731                             pfx_s_g,
732                             MFIB_SOURCE_API,
733                             MFIB_ENTRY_FLAG_SIGNAL);
734     MFIB_TEST(mfib_test_entry(mfei,
735                               MFIB_ENTRY_FLAG_SIGNAL,
736                               3,
737                               DPO_ADJACENCY_MCAST, ai_1,
738                               DPO_ADJACENCY_MCAST, ai_2,
739                               DPO_ADJACENCY_MCAST, ai_3),
740               "%U replicate OK",
741               format_mfib_prefix, pfx_s_g);
742
743     /*
744      * remove paths
745      */
746     mfib_table_entry_path_remove(fib_index,
747                                  pfx_s_g,
748                                  MFIB_SOURCE_API,
749                                  &path_via_if3);
750
751     MFIB_TEST(mfib_test_entry(mfei,
752                               MFIB_ENTRY_FLAG_SIGNAL,
753                               2,
754                               DPO_ADJACENCY_MCAST, ai_1,
755                               DPO_ADJACENCY_MCAST, ai_2),
756               "%U replicate OK",
757               format_mfib_prefix, pfx_s_g);
758     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
759                                      MFIB_ITF_FLAG_ACCEPT));
760     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
761                                      MFIB_ITF_FLAG_FORWARD));
762     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
763                                      MFIB_ITF_FLAG_FORWARD));
764     MFIB_TEST_NS(mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
765
766     mfib_table_entry_path_remove(fib_index,
767                                  pfx_s_g,
768                                  MFIB_SOURCE_API,
769                                  &path_via_if1);
770
771     MFIB_TEST(mfib_test_entry(mfei,
772                               MFIB_ENTRY_FLAG_SIGNAL,
773                               1,
774                               DPO_ADJACENCY_MCAST, ai_2),
775               "%U replicate OK",
776               format_mfib_prefix, pfx_s_g);
777     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
778                                      MFIB_ITF_FLAG_ACCEPT));
779     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
780                                      MFIB_ITF_FLAG_FORWARD));
781     MFIB_TEST_NS(mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
782
783     /*
784      * remove the accpeting only interface
785      */
786     mfib_table_entry_path_remove(fib_index,
787                                  pfx_s_g,
788                                  MFIB_SOURCE_API,
789                                  &path_via_if0);
790
791     MFIB_TEST(mfib_test_entry(mfei,
792                               MFIB_ENTRY_FLAG_SIGNAL,
793                               1,
794                               DPO_ADJACENCY_MCAST, ai_2),
795               "%U replicate OK",
796               format_mfib_prefix, pfx_s_g);
797     MFIB_TEST_NS(mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
798                                      MFIB_ITF_FLAG_FORWARD));
799     MFIB_TEST_NS(mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index));
800     MFIB_TEST_NS(mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index));
801     MFIB_TEST_NS(mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
802
803     /*
804      * remove the last path, the entry still has flags so it remains
805      */
806     mfib_table_entry_path_remove(fib_index,
807                                  pfx_s_g,
808                                  MFIB_SOURCE_API,
809                                  &path_via_if2);
810
811     MFIB_TEST(mfib_test_entry(mfei,
812                               MFIB_ENTRY_FLAG_SIGNAL,
813                               0),
814               "%U no replications",
815               format_mfib_prefix, pfx_s_g);
816
817     /*
818      * update flags on the entry
819      */
820     mfib_table_entry_update(fib_index,
821                             pfx_s_g,
822                             MFIB_SOURCE_API,
823                             (MFIB_ENTRY_FLAG_SIGNAL |
824                              MFIB_ENTRY_FLAG_CONNECTED));
825     MFIB_TEST(mfib_test_entry(mfei,
826                               (MFIB_ENTRY_FLAG_SIGNAL |
827                                MFIB_ENTRY_FLAG_CONNECTED),
828                               0),
829               "%U no replications",
830               format_mfib_prefix, pfx_s_g);
831
832     /*
833      * An entry with a NS interface
834      */
835     mfei_g_2 = mfib_table_entry_path_update(fib_index,
836                                             pfx_star_g_2,
837                                             MFIB_SOURCE_API,
838                                             &path_via_if0,
839                                             (MFIB_ITF_FLAG_ACCEPT |
840                                              MFIB_ITF_FLAG_NEGATE_SIGNAL));
841     MFIB_TEST(mfib_test_entry(mfei_g_2,
842                               MFIB_ENTRY_FLAG_NONE,
843                               0),
844               "%U No replications",
845               format_mfib_prefix, pfx_star_g_2);
846
847     /*
848      * Simulate a signal from the data-plane
849      */
850     {
851         mfib_entry_t *mfe;
852         mfib_itf_t *mfi;
853
854         mfe = mfib_entry_get(mfei_g_2);
855         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
856
857         mfib_signal_push(mfe, mfi, NULL);
858     }
859
860     /*
861      * An entry with a NS interface
862      */
863     mfei_g_3 = mfib_table_entry_path_update(fib_index,
864                                             pfx_star_g_3,
865                                             MFIB_SOURCE_API,
866                                             &path_via_if0,
867                                             (MFIB_ITF_FLAG_ACCEPT |
868                                              MFIB_ITF_NEGATE_SIGNAL));
869     MFIB_TEST(mfib_test_entry(mfei_g_3,
870                               MFIB_ENTRY_FLAG_NONE,
871                               0),
872               "%U No replications",
873               format_mfib_prefix, pfx_star_g_3);
874
875     /*
876      * Simulate a signal from the data-plane
877      */
878     {
879         mfib_entry_t *mfe;
880         mfib_itf_t *mfi;
881
882         mfe = mfib_entry_get(mfei_g_3);
883         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
884
885         mfib_signal_push(mfe, mfi, NULL);
886     }
887
888     if (FIB_PROTOCOL_IP6 == PROTO)
889     {
890         /*
891          * All the entries are present. let's ensure we can find them all
892          * via exact and longest prefix matches.
893          */
894         /*
895          * A source address we will never match
896          */
897         ip6_address_t src = {
898             .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
899             .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
900         };
901
902         /*
903          * Find the (*,G/m)
904          */
905         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
906                                    ip6_mfib_get(fib_index),
907                                    &src,
908                                    &pfx_star_g_slash_m->fp_grp_addr.ip6)),
909                   "%U found via DP LPM grp=%U",
910                   format_mfib_prefix, pfx_star_g_slash_m,
911                   format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
912
913         ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
914         tmp.as_u8[15] = 0xff;
915
916         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
917                                    ip6_mfib_get(fib_index),
918                                    &pfx_s_g->fp_src_addr.ip6,
919                                    &tmp)),
920                   "%U found via DP LPM grp=%U",
921                   format_mfib_prefix, pfx_star_g_slash_m,
922                   format_ip6_address, &tmp);
923
924         /*
925          * Find the (S,G).
926          */
927         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
928                                       &pfx_s_g->fp_src_addr.ip6,
929                                       &pfx_s_g->fp_grp_addr.ip6);
930         MFIB_TEST((mfei_s_g == mfei),
931                   "%U found via DP LPM: %d",
932                   format_mfib_prefix, pfx_s_g, mfei);
933
934         /*
935          * Find the 3 (*,G) s
936          */
937         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
938                                       &src,
939                                       &pfx_star_g_1->fp_grp_addr.ip6);
940         MFIB_TEST((mfei_g_1 == mfei),
941                   "%U found via DP LPM: %d",
942                   format_mfib_prefix, pfx_star_g_1, mfei);
943         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
944                                       &src,
945                                       &pfx_star_g_2->fp_grp_addr.ip6);
946         MFIB_TEST((mfei_g_2 == mfei),
947                   "%U found via DP LPM: %d",
948                   format_mfib_prefix, pfx_star_g_2, mfei);
949         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
950                                       &src,
951                                       &pfx_star_g_3->fp_grp_addr.ip6);
952         MFIB_TEST((mfei_g_3 == mfei),
953                   "%U found via DP LPM: %d",
954                   format_mfib_prefix, pfx_star_g_3, mfei);
955     }
956
957     /*
958      * remove flags on the entry. This is the last of the
959      * state associated with the entry, so now it goes.
960      */
961     mfib_table_entry_update(fib_index,
962                             pfx_s_g,
963                             MFIB_SOURCE_API,
964                             MFIB_ENTRY_FLAG_NONE);
965     mfei = mfib_table_lookup_exact_match(fib_index,
966                                          pfx_s_g);
967     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
968               "%U gone",
969               format_mfib_prefix, pfx_s_g);
970
971     /*
972      * remove the last path on the no forward entry - the last entry
973      */
974     mfib_table_entry_path_remove(fib_index,
975                                  pfx_no_forward,
976                                  MFIB_SOURCE_API,
977                                  &path_via_if0);
978
979     mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
980     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
981               "%U gone",
982               format_mfib_prefix, pfx_no_forward);
983
984     /*
985      * hard delete the (*,232.1.1.1)
986      */
987     mfib_table_entry_delete(fib_index,
988                             pfx_star_g_1,
989                             MFIB_SOURCE_API);
990
991     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
992     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
993               "%U gone",
994               format_mfib_prefix, pfx_star_g_1);
995     /*
996      * remove the entry whilst the signal is pending
997      */
998     mfib_table_entry_delete(fib_index,
999                             pfx_star_g_2,
1000                             MFIB_SOURCE_API);
1001
1002     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1003     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1004               "%U Gone",
1005               format_mfib_prefix, pfx_star_g_2);
1006     mfib_table_entry_delete(fib_index,
1007                             pfx_star_g_3,
1008                             MFIB_SOURCE_API);
1009
1010     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1011     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1012               "%U Gone",
1013               format_mfib_prefix, pfx_star_g_3);
1014
1015     mfib_table_entry_delete(fib_index,
1016                             pfx_star_g_slash_m,
1017                             MFIB_SOURCE_API);
1018
1019     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1020     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1021               "%U Gone",
1022               format_mfib_prefix, pfx_star_g_slash_m);
1023
1024     /*
1025      * Unlock the table - it's the last lock so should be gone thereafter
1026      */
1027     mfib_table_unlock(fib_index, PROTO);
1028
1029     MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1030                mfib_table_find(PROTO, fib_index)),
1031               "MFIB table %d gone", fib_index);
1032
1033     adj_unlock(ai_1);
1034     adj_unlock(ai_2);
1035     adj_unlock(ai_3);
1036
1037     /*
1038      * test we've leaked no resources
1039      */
1040     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1041     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1042               n_reps, pool_elts(replicate_pool));
1043     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1044               " No more entries %d!=%d",
1045               n_entries, pool_elts(mfib_entry_pool));
1046     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1047               " No more Interfaces %d!=%d",
1048               n_itfs, pool_elts(mfib_itf_pool));
1049
1050     return (0);
1051 }
1052
1053 static int
1054 mfib_test_v4 (void)
1055 {
1056     const mfib_prefix_t pfx_224_s_8 = {
1057         .fp_len = 8,
1058         .fp_proto = FIB_PROTOCOL_IP4,
1059         .fp_grp_addr = {
1060             .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1061         }
1062     };
1063     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1064         .fp_len = 64,
1065         .fp_proto = FIB_PROTOCOL_IP4,
1066         .fp_grp_addr = {
1067             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1068         },
1069         .fp_src_addr = {
1070             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1071         },
1072     };
1073     const mfib_prefix_t pfx_239_1_1_1 = {
1074         .fp_len = 32,
1075         .fp_proto = FIB_PROTOCOL_IP4,
1076         .fp_grp_addr = {
1077             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1078         },
1079         .fp_src_addr = {
1080             .ip4.as_u32 = 0,
1081         },
1082     };
1083     const mfib_prefix_t pfx_239_1_1_2 = {
1084         .fp_len = 32,
1085         .fp_proto = FIB_PROTOCOL_IP4,
1086         .fp_grp_addr = {
1087             .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1088         },
1089         .fp_src_addr = {
1090             .ip4.as_u32 = 0,
1091         },
1092     };
1093     const mfib_prefix_t pfx_239_1_1_3 = {
1094         .fp_len = 32,
1095         .fp_proto = FIB_PROTOCOL_IP4,
1096         .fp_grp_addr = {
1097             .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1098         },
1099         .fp_src_addr = {
1100             .ip4.as_u32 = 0,
1101         },
1102     };
1103     const mfib_prefix_t pfx_239 = {
1104         .fp_len = 8,
1105         .fp_proto = FIB_PROTOCOL_IP4,
1106         .fp_grp_addr = {
1107             .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1108         },
1109         .fp_src_addr = {
1110             .ip4.as_u32 = 0,
1111         },
1112     };
1113
1114     return (mfib_test_i(FIB_PROTOCOL_IP4,
1115                         VNET_LINK_IP4,
1116                         &pfx_224_s_8,
1117                         &pfx_1_1_1_1_c_239_1_1_1,
1118                         &pfx_239_1_1_1,
1119                         &pfx_239_1_1_2,
1120                         &pfx_239_1_1_3,
1121                         &pfx_239));
1122 }
1123
1124 static int
1125 mfib_test_v6 (void)
1126 {
1127     const mfib_prefix_t pfx_ffd_s_12 = {
1128         .fp_len = 12,
1129         .fp_proto = FIB_PROTOCOL_IP6,
1130         .fp_grp_addr = {
1131             .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1132         }
1133     };
1134     const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1135         .fp_len = 256,
1136         .fp_proto = FIB_PROTOCOL_IP6,
1137         .fp_grp_addr = {
1138             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1139             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1140         },
1141         .fp_src_addr = {
1142             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1143             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1144         },
1145     };
1146     const mfib_prefix_t pfx_ff_1 = {
1147         .fp_len = 128,
1148         .fp_proto = FIB_PROTOCOL_IP6,
1149         .fp_grp_addr = {
1150             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1151             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1152         },
1153     };
1154     const mfib_prefix_t pfx_ff_2 = {
1155         .fp_len = 128,
1156         .fp_proto = FIB_PROTOCOL_IP6,
1157         .fp_grp_addr = {
1158             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1159             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1160         },
1161     };
1162     const mfib_prefix_t pfx_ff_3 = {
1163         /*
1164          * this is the ALL DHCP routers address
1165          */
1166         .fp_len = 128,
1167         .fp_proto = FIB_PROTOCOL_IP6,
1168         .fp_grp_addr = {
1169             .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1170             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1171         },
1172     };
1173     const mfib_prefix_t pfx_ff = {
1174         .fp_len = 16,
1175         .fp_proto = FIB_PROTOCOL_IP6,
1176         .fp_grp_addr = {
1177             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1178             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1179         },
1180     };
1181
1182     return (mfib_test_i(FIB_PROTOCOL_IP6,
1183                         VNET_LINK_IP6,
1184                         &pfx_ffd_s_12,
1185                         &pfx_2001_1_c_ff_1,
1186                         &pfx_ff_1,
1187                         &pfx_ff_2,
1188                         &pfx_ff_3,
1189                         &pfx_ff));
1190 }
1191
1192 static clib_error_t *
1193 mfib_test (vlib_main_t * vm,
1194            unformat_input_t * input,
1195            vlib_cli_command_t * cmd_arg)
1196 {
1197     int res = 0;
1198
1199     res += mfib_test_mk_intf(4);
1200     res += mfib_test_v4();
1201     res += mfib_test_v6();
1202
1203     if (res)
1204     {
1205         return clib_error_return(0, "MFIB Unit Test Failed");
1206     }
1207     else
1208     {
1209         return (NULL);
1210     }
1211 }
1212
1213 VLIB_CLI_COMMAND (test_fib_command, static) = {
1214     .path = "test mfib",
1215     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1216     .function = mfib_test,
1217 };
1218
1219 clib_error_t *
1220 mfib_test_init (vlib_main_t *vm)
1221 {
1222     return 0;
1223 }
1224
1225 VLIB_INIT_FUNCTION (mfib_test_init);