interface: fix init fib_index_by_sw_if_index
[vpp.git] / src / plugins / unittest / 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 #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>
26
27 #include <vnet/dpo/replicate_dpo.h>
28 #include <vnet/adj/adj_mcast.h>
29
30 #define MFIB_TEST_I(_cond, _comment, _args...)                  \
31 ({                                                              \
32     int _evald = (_cond);                                       \
33     if (!(_evald)) {                                            \
34         fformat(stderr, "FAIL:%d: " _comment "\n",              \
35                 __LINE__, ##_args);                             \
36         res = 1;                                                \
37     }                                                           \
38     res;                                                        \
39 })
40 #define MFIB_TEST(_cond, _comment, _args...)                    \
41 {                                                               \
42     if (MFIB_TEST_I(_cond, _comment, ##_args)) {                \
43         return 1;                                               \
44         ASSERT(!("FAIL: " _comment));                           \
45     }                                                           \
46 }
47 #define MFIB_TEST_NS(_cond)                                     \
48 {                                                               \
49     if (MFIB_TEST_I(_cond, "")) {                               \
50         return 1;                                               \
51         ASSERT(!("FAIL: "));                                    \
52     }                                                           \
53 }
54
55 /**
56  * A 'i'm not fussed is this is not efficient' store of test data
57  */
58 typedef struct test_main_t_ {
59     /**
60      * HW if indicies
61      */
62     u32 hw_if_indicies[4];
63     /**
64      * HW interfaces
65      */
66     vnet_hw_interface_t * hw[4];
67
68 } test_main_t;
69 static test_main_t test_main;
70
71 /* fake ethernet device class, distinct from "fake-ethX" */
72 static u8 * format_test_interface_name (u8 * s, va_list * args)
73 {
74   u32 dev_instance = va_arg (*args, u32);
75   return format (s, "test-eth%d", dev_instance);
76 }
77
78 static uword placeholder_interface_tx (vlib_main_t * vm,
79                                  vlib_node_runtime_t * node,
80                                  vlib_frame_t * frame)
81 {
82   clib_warning ("you shouldn't be here, leaking buffers...");
83   return frame->n_vectors;
84 }
85
86 static clib_error_t *
87 test_interface_admin_up_down (vnet_main_t * vnm,
88                               u32 hw_if_index,
89                               u32 flags)
90 {
91   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
92     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
93   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
94   return 0;
95 }
96
97 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
98   .name = "Test interface",
99   .format_device_name = format_test_interface_name,
100   .tx_function = placeholder_interface_tx,
101   .admin_up_down_function = test_interface_admin_up_down,
102 };
103
104 static u8 *hw_address;
105
106 static int
107 mfib_test_mk_intf (u32 ninterfaces)
108 {
109     clib_error_t * error = NULL;
110     test_main_t *tm = &test_main;
111     u8 byte;
112     int res;
113     u32 i;
114
115     res = 0;
116     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
117
118     for (i=0; i<6; i++)
119     {
120         byte = 0xd0+i;
121         vec_add1(hw_address, byte);
122     }
123
124     for (i = 0; i < ninterfaces; i++)
125     {
126         hw_address[5] = i;
127
128         error = ethernet_register_interface(vnet_get_main(),
129                                             test_interface_device_class.index,
130                                             i /* instance */,
131                                             hw_address,
132                                             &tm->hw_if_indicies[i],
133                                             /* flag change */ 0);
134
135         MFIB_TEST((NULL == error), "ADD interface %d", i);
136
137         error = vnet_hw_interface_set_flags(vnet_get_main(),
138                                             tm->hw_if_indicies[i],
139                                             VNET_HW_INTERFACE_FLAG_LINK_UP);
140         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
141                                           tm->hw_if_indicies[i]);
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         ip4_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
146         ip6_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
147
148         error = vnet_sw_interface_set_flags(vnet_get_main(),
149                                             tm->hw[i]->sw_if_index,
150                                             VNET_SW_INTERFACE_FLAG_ADMIN_UP);
151         MFIB_TEST((NULL == error), "UP interface %d", i);
152     }
153     /*
154      * re-eval after the inevitable realloc
155      */
156     for (i = 0; i < ninterfaces; i++)
157     {
158         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
159                                           tm->hw_if_indicies[i]);
160     }
161
162     return (res);
163 }
164
165 #define MFIB_TEST_REP(_cond, _comment, _args...)                \
166 {                                                               \
167     if (MFIB_TEST_I(_cond, _comment, ##_args)) {                \
168         return (1);                                             \
169     }                                                           \
170 }
171
172 static int
173 mfib_test_validate_rep_v (const replicate_t *rep,
174                           u16 n_buckets,
175                           va_list *ap)
176 {
177     const dpo_id_t *dpo;
178     adj_index_t ai;
179     dpo_type_t dt;
180     int bucket;
181     int res;
182
183     res = 0;
184     MFIB_TEST_REP((n_buckets == rep->rep_n_buckets),
185                   "n_buckets = %d", rep->rep_n_buckets);
186
187     for (bucket = 0; bucket < n_buckets; bucket++)
188     {
189         dt = va_arg(*ap, int);  // type promotion
190         ai = va_arg(*ap, adj_index_t);
191         dpo = replicate_get_bucket_i(rep, bucket);
192
193         MFIB_TEST_REP((dt == dpo->dpoi_type),
194                       "bucket %d stacks on %U",
195                       bucket,
196                       format_dpo_type, dpo->dpoi_type);
197
198         if (DPO_RECEIVE != dt)
199         {
200             MFIB_TEST_REP((ai == dpo->dpoi_index),
201                           "bucket %d [exp:%d] stacks on %U",
202                           bucket, ai,
203                           format_dpo_id, dpo, 0);
204         }
205     }
206     return (res);
207 }
208
209 static int
210 mfib_test_entry (fib_node_index_t fei,
211                  mfib_entry_flags_t eflags,
212                  int n_buckets,
213                  ...)
214 {
215     const mfib_prefix_t *pfx;
216     const mfib_entry_t *mfe;
217     const replicate_t *rep;
218     va_list ap;
219     int res;
220
221
222     res = 0;
223     mfe = mfib_entry_get(fei);
224     pfx = mfib_entry_get_prefix(fei);
225
226     MFIB_TEST_REP((eflags == mfe->mfe_flags),
227                   "%U has %U expect %U",
228                   format_mfib_prefix, pfx,
229                   format_mfib_entry_flags, mfe->mfe_flags,
230                   format_mfib_entry_flags, eflags);
231
232     if (0 == n_buckets)
233     {
234         MFIB_TEST_REP((DPO_DROP == mfe->mfe_rep.dpoi_type),
235                       "%U links to %U",
236                       format_mfib_prefix, pfx,
237                       format_dpo_id, &mfe->mfe_rep, 0);
238     }
239     else
240     {
241         dpo_id_t tmp = DPO_INVALID;
242
243         mfib_entry_contribute_forwarding(
244             fei,
245             mfib_forw_chain_type_from_fib_proto(pfx->fp_proto),
246             MFIB_ENTRY_FWD_FLAG_NONE,
247             &tmp);
248         rep = replicate_get(tmp.dpoi_index);
249
250         MFIB_TEST_REP((DPO_REPLICATE == tmp.dpoi_type),
251                       "%U links to %U",
252                       format_mfib_prefix, pfx,
253                       format_dpo_type, tmp.dpoi_type);
254
255         va_start(ap, n_buckets);
256         res = mfib_test_validate_rep_v(rep, n_buckets, &ap);
257         va_end(ap);
258
259         dpo_reset(&tmp);
260     }
261
262
263     return (res);
264 }
265
266 static int
267 mfib_test_entry_itf (fib_node_index_t fei,
268                      u32 sw_if_index,
269                      mfib_itf_flags_t flags)
270 {
271     const mfib_prefix_t *pfx;
272     const mfib_entry_t *mfe;
273     const mfib_itf_t *mfi;
274     int res;
275
276     res = 0;
277     mfe = mfib_entry_get(fei);
278     mfi = mfib_entry_get_itf(mfe, sw_if_index);
279     pfx = mfib_entry_get_prefix(fei);
280
281     MFIB_TEST_REP((NULL != mfi),
282                   "%U has interface %d",
283                   format_mfib_prefix, pfx, sw_if_index);
284
285     MFIB_TEST_REP((flags == mfi->mfi_flags),
286                   "%U interface %d has flags %U expect %U",
287                   format_mfib_prefix, pfx, sw_if_index,
288                   format_mfib_itf_flags, flags,
289                   format_mfib_itf_flags, mfi->mfi_flags);
290
291     return (res);
292 }
293
294 static int
295 mfib_test_entry_no_itf (fib_node_index_t fei,
296                         u32 sw_if_index)
297 {
298     const mfib_prefix_t *pfx;
299     const mfib_entry_t *mfe;
300     const mfib_itf_t *mfi;
301     int res;
302
303     res = 0;
304     mfe = mfib_entry_get(fei);
305     mfi = mfib_entry_get_itf(mfe, sw_if_index);
306     pfx = mfib_entry_get_prefix(fei);
307
308     MFIB_TEST_REP((NULL == mfi),
309                   "%U has no interface %d",
310                   format_mfib_prefix, pfx, sw_if_index);
311
312     return (res);
313 }
314
315 static int
316 mfib_test_i (fib_protocol_t PROTO,
317              vnet_link_t LINKT,
318              const mfib_prefix_t *pfx_no_forward,
319              const mfib_prefix_t *pfx_s_g,
320              const mfib_prefix_t *pfx_star_g_1,
321              const mfib_prefix_t *pfx_star_g_2,
322              const mfib_prefix_t *pfx_star_g_3,
323              const mfib_prefix_t *pfx_star_g_slash_m,
324              const fib_prefix_t *pfx_itf,
325              const ip46_address_t *addr_nbr1,
326              const ip46_address_t *addr_nbr2)
327 {
328     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;
329     u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
330     fib_node_index_t ai_1, ai_2, ai_3, ai_nbr1, ai_nbr2;
331     test_main_t *tm;
332     int res;
333
334     mfib_prefix_t all_1s;
335     clib_memset(&all_1s, 0xfd, sizeof(all_1s));
336
337     res = 0;
338     n_entries = pool_elts(mfib_entry_pool);
339     n_itfs = pool_elts(mfib_itf_pool);
340     n_reps = pool_elts(replicate_pool);
341     n_pls = fib_path_list_pool_size();
342     tm = &test_main;
343
344     ai_1 = adj_mcast_add_or_lock(PROTO,
345                                  LINKT,
346                                  tm->hw[1]->sw_if_index);
347     ai_2 = adj_mcast_add_or_lock(PROTO,
348                                  LINKT,
349                                  tm->hw[2]->sw_if_index);
350     ai_3 = adj_mcast_add_or_lock(PROTO,
351                                  LINKT,
352                                  tm->hw[3]->sw_if_index);
353     ai_nbr1 = adj_nbr_add_or_lock(PROTO,
354                                   LINKT,
355                                   addr_nbr1,
356                                   tm->hw[0]->sw_if_index);
357     ai_nbr2 = adj_nbr_add_or_lock(PROTO,
358                                   LINKT,
359                                   addr_nbr2,
360                                   tm->hw[0]->sw_if_index);
361
362     MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
363
364     /* Find or create FIB table 11 */
365     fib_index = mfib_table_find_or_create_and_lock(PROTO, 11, MFIB_SOURCE_API);
366
367     fib_table_entry_update_one_path(0,
368                                     pfx_itf,
369                                     FIB_SOURCE_INTERFACE,
370                                     (FIB_ENTRY_FLAG_CONNECTED |
371                                      FIB_ENTRY_FLAG_ATTACHED),
372                                     DPO_PROTO_IP4,
373                                     NULL,
374                                     tm->hw[0]->sw_if_index,
375                                     ~0, // invalid fib index
376                                     1, // weight
377                                     NULL,
378                                     FIB_ROUTE_PATH_FLAG_NONE);
379
380     mfib_prefix_t pfx_dft = {
381         .fp_len = 0,
382         .fp_proto = PROTO,
383     };
384     mfei_dflt = mfib_table_lookup_exact_match(fib_index, &pfx_dft);
385     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
386     MFIB_TEST(!mfib_test_entry(mfei_dflt,
387                                MFIB_ENTRY_FLAG_DROP,
388                                0),
389               "(*,*) no replcaitions");
390
391     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
392     MFIB_TEST(!mfib_test_entry(mfei_dflt,
393                                MFIB_ENTRY_FLAG_DROP,
394                                0),
395               "(*,*) no replcaitions");
396
397
398     fib_route_path_t path_via_if0 = {
399         .frp_proto = fib_proto_to_dpo(PROTO),
400         .frp_addr = zero_addr,
401         .frp_sw_if_index = tm->hw[0]->sw_if_index,
402         .frp_fib_index = ~0,
403         .frp_weight = 1,
404         .frp_flags = 0,
405         .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
406     };
407
408     mfib_table_entry_path_update(fib_index,
409                                  pfx_no_forward,
410                                  MFIB_SOURCE_API,
411                                  &path_via_if0);
412
413     mfei_no_f = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
414     MFIB_TEST(!mfib_test_entry(mfei_no_f,
415                                MFIB_ENTRY_FLAG_NONE,
416                                0),
417               "%U no replcaitions",
418               format_mfib_prefix, pfx_no_forward);
419     MFIB_TEST(!mfib_test_entry_itf(mfei_no_f, tm->hw[0]->sw_if_index,
420                                    MFIB_ITF_FLAG_ACCEPT),
421               "%U interface not accepting",
422               format_mfib_prefix, pfx_no_forward);
423
424     fib_route_path_t path_via_if1 = {
425         .frp_proto = fib_proto_to_dpo(PROTO),
426         .frp_addr = zero_addr,
427         .frp_sw_if_index = tm->hw[1]->sw_if_index,
428         .frp_fib_index = ~0,
429         .frp_weight = 1,
430         .frp_flags = 0,
431         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
432     };
433     fib_route_path_t path_via_if2 = {
434         .frp_proto = fib_proto_to_dpo(PROTO),
435         .frp_addr = zero_addr,
436         .frp_sw_if_index = tm->hw[2]->sw_if_index,
437         .frp_fib_index = ~0,
438         .frp_weight = 1,
439         .frp_flags = 0,
440         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
441     };
442     fib_route_path_t path_via_if3 = {
443         .frp_proto = fib_proto_to_dpo(PROTO),
444         .frp_addr = zero_addr,
445         .frp_sw_if_index = tm->hw[3]->sw_if_index,
446         .frp_fib_index = ~0,
447         .frp_weight = 1,
448         .frp_flags = 0,
449         .frp_mitf_flags = (MFIB_ITF_FLAG_FORWARD |
450                            MFIB_ITF_FLAG_NEGATE_SIGNAL),
451     };
452     fib_route_path_t *two_paths = NULL;
453     vec_add1(two_paths, path_via_if2);
454     vec_add1(two_paths, path_via_if3);
455
456     /*
457      * An (S,G) with 1 accepting and 3 forwarding paths
458      */
459     mfib_table_entry_path_update(fib_index,
460                                  pfx_s_g,
461                                  MFIB_SOURCE_API,
462                                  &path_via_if0);
463     mfib_table_entry_path_update(fib_index,
464                                  pfx_s_g,
465                                  MFIB_SOURCE_API,
466                                  &path_via_if1);
467     mfib_table_entry_paths_update(fib_index,
468                                   pfx_s_g,
469                                   MFIB_SOURCE_API,
470                                   two_paths);
471
472     mfei_s_g = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
473
474     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_s_g,
475               "%U present",
476               format_mfib_prefix, pfx_s_g);
477     MFIB_TEST(!mfib_test_entry(mfei_s_g,
478                                MFIB_ENTRY_FLAG_NONE,
479                                3,
480                                DPO_ADJACENCY_MCAST, ai_1,
481                                DPO_ADJACENCY_MCAST, ai_2,
482                                DPO_ADJACENCY_MCAST, ai_3),
483               "%U replicate ok",
484               format_mfib_prefix, pfx_s_g);
485     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[0]->sw_if_index,
486                                       MFIB_ITF_FLAG_ACCEPT));
487     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[1]->sw_if_index,
488                                       MFIB_ITF_FLAG_FORWARD));
489     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[2]->sw_if_index,
490                                       MFIB_ITF_FLAG_FORWARD));
491     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[3]->sw_if_index,
492                                       (MFIB_ITF_FLAG_FORWARD |
493                                        MFIB_ITF_FLAG_NEGATE_SIGNAL)));
494
495     /*
496      * A (*,G), which the same G as the (S,G).
497      * different paths. test our LPM.
498      */
499     mfei_g_1 = mfib_table_entry_path_update(fib_index,
500                                             pfx_star_g_1,
501                                             MFIB_SOURCE_API,
502                                             &path_via_if0);
503     mfib_table_entry_path_update(fib_index,
504                                  pfx_star_g_1,
505                                  MFIB_SOURCE_API,
506                                  &path_via_if1);
507
508     /*
509      * test we find the *,G and S,G via LPM and exact matches
510      */
511     mfei = mfib_table_lookup_exact_match(fib_index,
512                                          pfx_star_g_1);
513     MFIB_TEST(mfei == mfei_g_1,
514               "%U found via exact match",
515               format_mfib_prefix, pfx_star_g_1);
516     MFIB_TEST(!mfib_test_entry(mfei,
517                                MFIB_ENTRY_FLAG_NONE,
518                                1,
519                                DPO_ADJACENCY_MCAST, ai_1),
520               "%U replicate ok",
521               format_mfib_prefix, pfx_star_g_1);
522
523     mfei = mfib_table_lookup(fib_index,
524                              pfx_star_g_1);
525     MFIB_TEST(mfei == mfei_g_1,
526               "[e:%d a:%d] %U found via LP match",
527               mfei, mfei_g_1,
528               format_mfib_prefix, pfx_star_g_1);
529
530     MFIB_TEST(!mfib_test_entry(mfei,
531                                MFIB_ENTRY_FLAG_NONE,
532                                1,
533                                DPO_ADJACENCY_MCAST, ai_1),
534               "%U replicate ok",
535               format_mfib_prefix, pfx_star_g_1);
536
537     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
538     MFIB_TEST(mfei == mfei_s_g,
539               "%U found via exact match",
540               format_mfib_prefix, pfx_s_g);
541
542     MFIB_TEST(!mfib_test_entry(mfei,
543                                MFIB_ENTRY_FLAG_NONE,
544                                3,
545                                DPO_ADJACENCY_MCAST, ai_1,
546                                DPO_ADJACENCY_MCAST, ai_2,
547                                DPO_ADJACENCY_MCAST, ai_3),
548               "%U replicate OK",
549               format_mfib_prefix, pfx_s_g);
550     mfei = mfib_table_lookup(fib_index, pfx_s_g);
551     MFIB_TEST(mfei == mfei_s_g,
552               "%U found via LP match",
553               format_mfib_prefix, pfx_s_g);
554
555     MFIB_TEST(!mfib_test_entry(mfei,
556                                MFIB_ENTRY_FLAG_NONE,
557                                3,
558                                DPO_ADJACENCY_MCAST, ai_1,
559                                DPO_ADJACENCY_MCAST, ai_2,
560                                DPO_ADJACENCY_MCAST, ai_3),
561               "%U replicate OK",
562               format_mfib_prefix, pfx_s_g);
563
564     /*
565      * A (*,G/m), which the same root G as the (*,G).
566      * different paths. test our LPM.
567      */
568     path_via_if2.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
569     mfei_g_m = mfib_table_entry_path_update(fib_index,
570                                             pfx_star_g_slash_m,
571                                             MFIB_SOURCE_API,
572                                             &path_via_if2);
573     mfib_table_entry_path_update(fib_index,
574                                  pfx_star_g_slash_m,
575                                  MFIB_SOURCE_API,
576                                  &path_via_if3);
577
578     /*
579      * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
580      */
581     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
582     MFIB_TEST((mfei_g_1 == mfei),
583               "%U found via DP LPM: %d",
584               format_mfib_prefix, pfx_star_g_1, mfei);
585
586     MFIB_TEST(!mfib_test_entry(mfei,
587                                MFIB_ENTRY_FLAG_NONE,
588                                1,
589                                DPO_ADJACENCY_MCAST, ai_1),
590               "%U replicate ok",
591               format_mfib_prefix, pfx_star_g_1);
592
593     mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
594
595     MFIB_TEST(!mfib_test_entry(mfei,
596                                MFIB_ENTRY_FLAG_NONE,
597                                1,
598                                DPO_ADJACENCY_MCAST, ai_1),
599               "%U replicate ok",
600               format_mfib_prefix, pfx_star_g_1);
601
602     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
603
604     MFIB_TEST(!mfib_test_entry(mfei,
605                                MFIB_ENTRY_FLAG_NONE,
606                                3,
607                                DPO_ADJACENCY_MCAST, ai_1,
608                                DPO_ADJACENCY_MCAST, ai_2,
609                                DPO_ADJACENCY_MCAST, ai_3),
610               "%U replicate OK",
611               format_mfib_prefix, pfx_s_g);
612     mfei = mfib_table_lookup(fib_index, pfx_s_g);
613
614     MFIB_TEST(!mfib_test_entry(mfei,
615                                MFIB_ENTRY_FLAG_NONE,
616                                3,
617                                DPO_ADJACENCY_MCAST, ai_1,
618                                DPO_ADJACENCY_MCAST, ai_2,
619                                DPO_ADJACENCY_MCAST, ai_3),
620               "%U replicate OK",
621               format_mfib_prefix, pfx_s_g);
622
623     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
624     MFIB_TEST(mfei = mfei_g_m,
625               "%U Found via exact match",
626               format_mfib_prefix, pfx_star_g_slash_m);
627     MFIB_TEST(!mfib_test_entry(mfei,
628                                MFIB_ENTRY_FLAG_NONE,
629                                1,
630                                DPO_ADJACENCY_MCAST, ai_3),
631               "%U replicate OK",
632               format_mfib_prefix, pfx_star_g_slash_m);
633     MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
634               "%U found via LPM",
635               format_mfib_prefix, pfx_star_g_slash_m);
636
637     /*
638      * Add a for-us path
639      */
640     fib_route_path_t path_for_us = {
641         .frp_proto = fib_proto_to_dpo(PROTO),
642         .frp_addr = zero_addr,
643         .frp_sw_if_index = 0xffffffff,
644         .frp_fib_index = ~0,
645         .frp_weight = 1,
646         .frp_flags = FIB_ROUTE_PATH_LOCAL,
647         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
648     };
649
650     mfei = mfib_table_entry_path_update(fib_index,
651                                         pfx_s_g,
652                                         MFIB_SOURCE_API,
653                                         &path_for_us);
654
655     MFIB_TEST(!mfib_test_entry(mfei,
656                                MFIB_ENTRY_FLAG_NONE,
657                                4,
658                                DPO_ADJACENCY_MCAST, ai_1,
659                                DPO_ADJACENCY_MCAST, ai_2,
660                                DPO_ADJACENCY_MCAST, ai_3,
661                                DPO_RECEIVE, 0),
662               "%U replicate OK",
663               format_mfib_prefix, pfx_s_g);
664
665     /*
666      * remove a for-us path
667      */
668     mfib_table_entry_path_remove(fib_index,
669                                  pfx_s_g,
670                                  MFIB_SOURCE_API,
671                                  &path_for_us);
672
673     MFIB_TEST(!mfib_test_entry(mfei,
674                                MFIB_ENTRY_FLAG_NONE,
675                                3,
676                                DPO_ADJACENCY_MCAST, ai_1,
677                                DPO_ADJACENCY_MCAST, ai_2,
678                                DPO_ADJACENCY_MCAST, ai_3),
679               "%U replicate OK",
680               format_mfib_prefix, pfx_s_g);
681
682     /*
683      * update an existing forwarding path to be only accepting
684      *   - expect it to be removed from the replication set.
685      */
686     path_via_if3.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
687     mfib_table_entry_path_update(fib_index,
688                                  pfx_s_g,
689                                  MFIB_SOURCE_API,
690                                  &path_via_if3);
691
692     MFIB_TEST(!mfib_test_entry(mfei,
693                                MFIB_ENTRY_FLAG_NONE,
694                                2,
695                                DPO_ADJACENCY_MCAST, ai_1,
696                                DPO_ADJACENCY_MCAST, ai_2),
697               "%U replicate OK",
698               format_mfib_prefix, pfx_s_g);
699     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
700                                       MFIB_ITF_FLAG_ACCEPT));
701     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
702                                       MFIB_ITF_FLAG_FORWARD));
703     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
704                                       MFIB_ITF_FLAG_FORWARD));
705     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
706                                       MFIB_ITF_FLAG_ACCEPT));
707     /*
708      * Make the path forwarding again
709      *  - expect it to be added back to the replication set
710      */
711     path_via_if3.frp_mitf_flags = (MFIB_ITF_FLAG_FORWARD |
712                               MFIB_ITF_FLAG_ACCEPT |
713                               MFIB_ITF_FLAG_NEGATE_SIGNAL);
714     mfib_table_entry_path_update(fib_index,
715                                  pfx_s_g,
716                                  MFIB_SOURCE_API,
717                                  &path_via_if3);
718
719     mfei = mfib_table_lookup_exact_match(fib_index,
720                                          pfx_s_g);
721
722     MFIB_TEST(!mfib_test_entry(mfei,
723                                MFIB_ENTRY_FLAG_NONE,
724                                3,
725                                DPO_ADJACENCY_MCAST, ai_1,
726                                DPO_ADJACENCY_MCAST, ai_2,
727                                DPO_ADJACENCY_MCAST, ai_3),
728               "%U replicate OK",
729               format_mfib_prefix, pfx_s_g);
730     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
731                                       MFIB_ITF_FLAG_ACCEPT));
732     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
733                                       MFIB_ITF_FLAG_FORWARD));
734     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
735                                       MFIB_ITF_FLAG_FORWARD));
736     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
737                                       (MFIB_ITF_FLAG_FORWARD |
738                                        MFIB_ITF_FLAG_ACCEPT |
739                                        MFIB_ITF_FLAG_NEGATE_SIGNAL)));
740
741     /*
742      * update flags on the entry
743      */
744     mfib_table_entry_update(fib_index,
745                             pfx_s_g,
746                             MFIB_SOURCE_API,
747                             MFIB_RPF_ID_NONE,
748                             MFIB_ENTRY_FLAG_SIGNAL);
749     MFIB_TEST(!mfib_test_entry(mfei,
750                                MFIB_ENTRY_FLAG_SIGNAL,
751                                3,
752                                DPO_ADJACENCY_MCAST, ai_1,
753                                DPO_ADJACENCY_MCAST, ai_2,
754                                DPO_ADJACENCY_MCAST, ai_3),
755               "%U replicate OK",
756               format_mfib_prefix, pfx_s_g);
757
758     /*
759      * remove paths
760      */
761     mfib_table_entry_path_remove(fib_index,
762                                  pfx_s_g,
763                                  MFIB_SOURCE_API,
764                                  &path_via_if3);
765
766     MFIB_TEST(!mfib_test_entry(mfei,
767                                MFIB_ENTRY_FLAG_SIGNAL,
768                                2,
769                                DPO_ADJACENCY_MCAST, ai_1,
770                                DPO_ADJACENCY_MCAST, ai_2),
771               "%U replicate OK",
772               format_mfib_prefix, pfx_s_g);
773     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
774                                       MFIB_ITF_FLAG_ACCEPT));
775     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
776                                       MFIB_ITF_FLAG_FORWARD));
777     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
778                                       MFIB_ITF_FLAG_FORWARD));
779     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
780
781     mfib_table_entry_path_remove(fib_index,
782                                  pfx_s_g,
783                                  MFIB_SOURCE_API,
784                                  &path_via_if1);
785
786     MFIB_TEST(!mfib_test_entry(mfei,
787                                MFIB_ENTRY_FLAG_SIGNAL,
788                                1,
789                                DPO_ADJACENCY_MCAST, ai_2),
790               "%U replicate OK",
791               format_mfib_prefix, pfx_s_g);
792     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
793                                       MFIB_ITF_FLAG_ACCEPT));
794     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
795                                       MFIB_ITF_FLAG_FORWARD));
796     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
797
798     /*
799      * remove
800      */
801     /* mfib_table_entry_path_remove(fib_index, */
802     /*                              pfx_s_g, */
803     /*                              MFIB_SOURCE_API, */
804     /*                              &path_via_if0); */
805
806     /* MFIB_TEST(!mfib_test_entry(mfei, */
807     /*                            MFIB_ENTRY_FLAG_SIGNAL, */
808     /*                            1, */
809     /*                            DPO_ADJACENCY_MCAST, ai_2), */
810     /*           "%U replicate OK", */
811     /*           format_mfib_prefix, pfx_s_g); */
812     /* MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index, */
813     /*                                   MFIB_ITF_FLAG_FORWARD)); */
814     /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index)); */
815     /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index)); */
816     /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index)); */
817
818     /*
819      * remove the last path and the accpeting only interface,
820      * the entry still has flags so it remains
821      */
822     vec_reset_length(two_paths);
823     vec_add1(two_paths, path_via_if0);
824     vec_add1(two_paths, path_via_if2);
825
826     mfib_table_entry_paths_remove(fib_index,
827                                   pfx_s_g,
828                                   MFIB_SOURCE_API,
829                                   two_paths);
830
831     MFIB_TEST(!mfib_test_entry(mfei,
832                                MFIB_ENTRY_FLAG_SIGNAL,
833                                0),
834               "%U no replications",
835               format_mfib_prefix, pfx_s_g);
836
837     /*
838      * update flags on the entry
839      */
840     mfib_table_entry_update(fib_index,
841                             pfx_s_g,
842                             MFIB_SOURCE_API,
843                             MFIB_RPF_ID_NONE,
844                             (MFIB_ENTRY_FLAG_SIGNAL |
845                              MFIB_ENTRY_FLAG_CONNECTED));
846     MFIB_TEST(!mfib_test_entry(mfei,
847                                (MFIB_ENTRY_FLAG_SIGNAL |
848                                 MFIB_ENTRY_FLAG_CONNECTED),
849                                0),
850               "%U no replications",
851               format_mfib_prefix, pfx_s_g);
852
853     /*
854      * An entry with a NS interface
855      */
856     path_via_if0.frp_mitf_flags = (MFIB_ITF_FLAG_ACCEPT |
857                               MFIB_ITF_FLAG_NEGATE_SIGNAL);
858     mfei_g_2 = mfib_table_entry_path_update(fib_index,
859                                             pfx_star_g_2,
860                                             MFIB_SOURCE_API,
861                                             &path_via_if0);
862     MFIB_TEST(!mfib_test_entry(mfei_g_2,
863                                MFIB_ENTRY_FLAG_NONE,
864                                0),
865               "%U No replications",
866               format_mfib_prefix, pfx_star_g_2);
867
868     /*
869      * Simulate a signal from the data-plane
870      */
871     {
872         mfib_entry_t *mfe;
873         mfib_itf_t *mfi;
874
875         mfe = mfib_entry_get(mfei_g_2);
876         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
877
878         mfib_signal_push(mfe, mfi, NULL);
879     }
880
881     /*
882      * An entry with a NS interface
883      */
884     path_via_if0.frp_mitf_flags = (MFIB_ITF_FLAG_ACCEPT |
885                               MFIB_ITF_FLAG_NEGATE_SIGNAL);
886     mfei_g_3 = mfib_table_entry_path_update(fib_index,
887                                             pfx_star_g_3,
888                                             MFIB_SOURCE_API,
889                                             &path_via_if0);
890     MFIB_TEST(!mfib_test_entry(mfei_g_3,
891                                MFIB_ENTRY_FLAG_NONE,
892                                0),
893               "%U No replications",
894               format_mfib_prefix, pfx_star_g_3);
895
896     /*
897      * Simulate a signal from the data-plane
898      */
899     {
900         mfib_entry_t *mfe;
901         mfib_itf_t *mfi;
902
903         mfe = mfib_entry_get(mfei_g_3);
904         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
905
906         mfib_signal_push(mfe, mfi, NULL);
907     }
908
909     if (FIB_PROTOCOL_IP6 == PROTO)
910     {
911         /*
912          * All the entries are present. let's ensure we can find them all
913          * via exact and longest prefix matches.
914          */
915         /*
916          * A source address we will never match
917          */
918         ip6_address_t src = {
919             .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
920             .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
921         };
922
923         /*
924          * Find the (*,G/m)
925          */
926         MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
927                        ip6_mfib_get(fib_index),
928                        &src,
929                        &pfx_star_g_slash_m->fp_grp_addr.ip6)),
930                   "%U found via DP LPM grp=%U",
931                   format_mfib_prefix, pfx_star_g_slash_m,
932                   format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
933
934         ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
935         tmp.as_u8[15] = 0xff;
936
937         MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
938                        ip6_mfib_get(fib_index),
939                        &pfx_s_g->fp_src_addr.ip6,
940                        &tmp)),
941                   "%U found via DP LPM grp=%U",
942                   format_mfib_prefix, pfx_star_g_slash_m,
943                   format_ip6_address, &tmp);
944
945         /*
946          * Find the (S,G).
947          */
948         mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
949                                          &pfx_s_g->fp_src_addr.ip6,
950                                          &pfx_s_g->fp_grp_addr.ip6);
951         MFIB_TEST((mfei_s_g == mfei),
952                   "%U found via DP LPM: %d",
953                   format_mfib_prefix, pfx_s_g, mfei);
954
955         /*
956          * Find the 3 (*,G) s
957          */
958         mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
959                                          &src,
960                                          &pfx_star_g_1->fp_grp_addr.ip6);
961         MFIB_TEST((mfei_g_1 == mfei),
962                   "%U found via DP LPM: %d",
963                   format_mfib_prefix, pfx_star_g_1, mfei);
964         mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
965                                          &src,
966                                          &pfx_star_g_2->fp_grp_addr.ip6);
967         MFIB_TEST((mfei_g_2 == mfei),
968                   "%U found via DP LPM: %d",
969                   format_mfib_prefix, pfx_star_g_2, mfei);
970         mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
971                                          &src,
972                                          &pfx_star_g_3->fp_grp_addr.ip6);
973         MFIB_TEST((mfei_g_3 == mfei),
974                   "%U found via DP LPM: %d",
975                   format_mfib_prefix, pfx_star_g_3, mfei);
976     }
977
978     /*
979      * remove flags on the entry. This is the last of the
980      * state associated with the entry, so now it goes.
981      */
982     mfib_table_entry_update(fib_index,
983                             pfx_s_g,
984                             MFIB_SOURCE_API,
985                             MFIB_RPF_ID_NONE,
986                             MFIB_ENTRY_FLAG_NONE);
987     mfei = mfib_table_lookup_exact_match(fib_index,
988                                          pfx_s_g);
989     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
990               "%U gone",
991               format_mfib_prefix, pfx_s_g);
992
993     /*
994      * remove the last path on the no forward entry - the last entry
995      */
996     mfib_table_entry_path_remove(fib_index,
997                                  pfx_no_forward,
998                                  MFIB_SOURCE_API,
999                                  &path_via_if0);
1000
1001     mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
1002     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1003               "%U gone",
1004               format_mfib_prefix, pfx_no_forward);
1005
1006     /*
1007      * hard delete the (*,232.1.1.1)
1008      */
1009     mfib_table_entry_delete(fib_index,
1010                             pfx_star_g_1,
1011                             MFIB_SOURCE_API);
1012
1013     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1014     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1015               "%U gone",
1016               format_mfib_prefix, pfx_star_g_1);
1017     /*
1018      * remove the entry whilst the signal is pending
1019      */
1020     mfib_table_entry_delete(fib_index,
1021                             pfx_star_g_2,
1022                             MFIB_SOURCE_API);
1023
1024     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1025     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1026               "%U Gone",
1027               format_mfib_prefix, pfx_star_g_2);
1028     mfib_table_entry_delete(fib_index,
1029                             pfx_star_g_3,
1030                             MFIB_SOURCE_API);
1031
1032     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1033     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1034               "%U Gone",
1035               format_mfib_prefix, pfx_star_g_3);
1036
1037     mfib_table_entry_delete(fib_index,
1038                             pfx_star_g_slash_m,
1039                             MFIB_SOURCE_API);
1040
1041     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1042     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1043               "%U Gone",
1044               format_mfib_prefix, pfx_star_g_slash_m);
1045
1046     /*
1047      * Entries with paths via unicast next-hops
1048      */
1049     fib_route_path_t path_via_nbr1 = {
1050         .frp_proto = fib_proto_to_dpo(PROTO),
1051         .frp_addr = *addr_nbr1,
1052         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1053         .frp_fib_index = ~0,
1054         .frp_weight = 1,
1055         .frp_flags = 0,
1056         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1057     };
1058     fib_route_path_t path_via_nbr2 = {
1059         .frp_proto = fib_proto_to_dpo(PROTO),
1060         .frp_addr = *addr_nbr2,
1061         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1062         .frp_fib_index = ~0,
1063         .frp_weight = 1,
1064         .frp_flags = 0,
1065         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1066     };
1067
1068     mfei_g_1 = mfib_table_entry_path_update(fib_index,
1069                                             pfx_star_g_1,
1070                                             MFIB_SOURCE_API,
1071                                             &path_via_nbr1);
1072     mfei_g_1 = mfib_table_entry_path_update(fib_index,
1073                                             pfx_star_g_1,
1074                                             MFIB_SOURCE_API,
1075                                             &path_via_nbr2);
1076     MFIB_TEST(!mfib_test_entry(mfei_g_1,
1077                                MFIB_ENTRY_FLAG_NONE,
1078                                2,
1079                                DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
1080                                DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1081               "%U replicate OK",
1082               format_mfib_prefix, pfx_star_g_1);
1083     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1084                                       MFIB_ITF_FLAG_FORWARD));
1085
1086     mfib_table_entry_path_remove(fib_index,
1087                                  pfx_star_g_1,
1088                                  MFIB_SOURCE_API,
1089                                  &path_via_nbr1);
1090
1091     MFIB_TEST(!mfib_test_entry(mfei_g_1,
1092                                MFIB_ENTRY_FLAG_NONE,
1093                                1,
1094                                DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1095               "%U replicate OK",
1096               format_mfib_prefix, pfx_star_g_1);
1097     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1098                                       MFIB_ITF_FLAG_FORWARD));
1099
1100     mfib_table_entry_path_remove(fib_index,
1101                                  pfx_star_g_1,
1102                                  MFIB_SOURCE_API,
1103                                  &path_via_nbr2);
1104     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1105     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1106               "%U Gone",
1107               format_mfib_prefix, pfx_star_g_1);
1108
1109     /*
1110      * Add a prefix as a special/exclusive route
1111      */
1112     dpo_id_t td = DPO_INVALID;
1113     index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
1114
1115     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
1116     replicate_set_bucket(repi, 0, &td);
1117
1118     mfei = mfib_table_entry_special_add(fib_index,
1119                                         pfx_star_g_3,
1120                                         MFIB_SOURCE_SRv6,
1121                                         MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1122                                         repi);
1123     MFIB_TEST(!mfib_test_entry(mfei,
1124                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1125                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1126                                1,
1127                                DPO_ADJACENCY_MCAST, ai_2),
1128               "%U exclusive replicate OK",
1129               format_mfib_prefix, pfx_star_g_3);
1130
1131     /*
1132      * update a special/exclusive route
1133      */
1134     index_t repi2 = replicate_create(1, fib_proto_to_dpo(PROTO));
1135
1136     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1);
1137     replicate_set_bucket(repi2, 0, &td);
1138
1139     mfib_entry_update(mfei,
1140                       MFIB_SOURCE_SRv6,
1141                       (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1142                        MFIB_ENTRY_FLAG_EXCLUSIVE),
1143                       MFIB_RPF_ID_NONE,
1144                       repi2);
1145     MFIB_TEST(!mfib_test_entry(mfei,
1146                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1147                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1148                                1,
1149                                DPO_ADJACENCY_MCAST, ai_1),
1150               "%U exclusive update replicate OK",
1151               format_mfib_prefix, pfx_star_g_3);
1152
1153     mfib_table_entry_delete(fib_index,
1154                             pfx_star_g_3,
1155                             MFIB_SOURCE_SRv6);
1156     dpo_reset(&td);
1157
1158     /*
1159      * A Multicast LSP. This a mLDP head-end
1160      */
1161     fib_node_index_t ai_mpls_10_10_10_1, lfei;
1162     ip46_address_t nh_10_10_10_1 = {
1163         .ip4 = {
1164             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1165         },
1166     };
1167     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1168                                              VNET_LINK_MPLS,
1169                                              &nh_10_10_10_1,
1170                                              tm->hw[0]->sw_if_index);
1171
1172     fib_prefix_t pfx_3500 = {
1173         .fp_len = 21,
1174         .fp_proto = FIB_PROTOCOL_MPLS,
1175         .fp_label = 3500,
1176         .fp_eos = MPLS_EOS,
1177         .fp_payload_proto = DPO_PROTO_IP4,
1178     };
1179     fib_test_rep_bucket_t mc_0 = {
1180         .type = FT_REP_LABEL_O_ADJ,
1181         .label_o_adj = {
1182             .adj = ai_mpls_10_10_10_1,
1183             .label = 3300,
1184             .eos = MPLS_EOS,
1185         },
1186     };
1187     fib_mpls_label_t *l3300 = NULL, fml3300 = {
1188         .fml_value = 3300,
1189     };
1190     vec_add1(l3300, fml3300);
1191
1192     /*
1193      * MPLS enable an interface so we get the MPLS table created
1194      */
1195     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
1196     mpls_sw_interface_enable_disable(&mpls_main,
1197                                      tm->hw[0]->sw_if_index,
1198                                      1, 0);
1199
1200     lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1201                                            &pfx_3500,
1202                                            FIB_SOURCE_API,
1203                                            FIB_ENTRY_FLAG_MULTICAST,
1204                                            DPO_PROTO_IP4,
1205                                            &nh_10_10_10_1,
1206                                            tm->hw[0]->sw_if_index,
1207                                            ~0, // invalid fib index
1208                                            1,
1209                                            l3300,
1210                                            FIB_ROUTE_PATH_FLAG_NONE);
1211     MFIB_TEST(!fib_test_validate_entry(lfei,
1212                                        FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1213                                        1,
1214                                        &mc_0),
1215               "3500 via replicate over 10.10.10.1");
1216
1217     /*
1218      * An (S,G) that resolves via the mLDP head-end
1219      */
1220     fib_route_path_t path_via_mldp = {
1221         .frp_proto = DPO_PROTO_MPLS,
1222         .frp_local_label = pfx_3500.fp_label,
1223         .frp_eos = MPLS_EOS,
1224         .frp_sw_if_index = 0xffffffff,
1225         .frp_fib_index = 0,
1226         .frp_weight = 1,
1227         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1228         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1229     };
1230     dpo_id_t mldp_dpo = DPO_INVALID;
1231
1232     fib_entry_contribute_forwarding(lfei,
1233                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1234                                     &mldp_dpo);
1235
1236     mfei = mfib_table_entry_path_update(fib_index,
1237                                         pfx_s_g,
1238                                         MFIB_SOURCE_API,
1239                                         &path_via_mldp);
1240
1241     MFIB_TEST(!mfib_test_entry(mfei,
1242                                MFIB_ENTRY_FLAG_NONE,
1243                                1,
1244                                DPO_REPLICATE, mldp_dpo.dpoi_index),
1245               "%U over-mLDP replicate OK",
1246               format_mfib_prefix, pfx_s_g);
1247
1248     /*
1249      * add a for-us path. this tests two types of non-attached paths on one entry
1250      */
1251     mfei = mfib_table_entry_path_update(fib_index,
1252                                         pfx_s_g,
1253                                         MFIB_SOURCE_API,
1254                                         &path_for_us);
1255     MFIB_TEST(!mfib_test_entry(mfei,
1256                                MFIB_ENTRY_FLAG_NONE,
1257                                2,
1258                                DPO_REPLICATE, mldp_dpo.dpoi_index,
1259                                DPO_RECEIVE, 0),
1260               "%U mLDP+for-us replicate OK",
1261               format_mfib_prefix, pfx_s_g);
1262
1263     mfib_table_entry_delete(fib_index,
1264                             pfx_s_g,
1265                             MFIB_SOURCE_API);
1266     fib_table_entry_delete(0,
1267                            &pfx_3500,
1268                            FIB_SOURCE_API);
1269     dpo_reset(&mldp_dpo);
1270
1271     /*
1272      * Unlock the table - it's the last lock so should be gone thereafter
1273      */
1274     MFIB_TEST(((PROTO == FIB_PROTOCOL_IP4 ? 3 : 5) ==
1275                mfib_table_get_n_routes(fib_index, PROTO)),
1276               "1 = %d route left in the FIB",
1277               mfib_table_get_n_routes(fib_index, PROTO));
1278
1279     mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1280
1281     MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1282                mfib_table_find(PROTO, fib_index)),
1283               "MFIB table %d gone", fib_index);
1284
1285     adj_unlock(ai_1);
1286     adj_unlock(ai_2);
1287     adj_unlock(ai_3);
1288     adj_unlock(ai_nbr1);
1289     adj_unlock(ai_nbr2);
1290
1291     /*
1292      * MPLS disable the interface
1293      */
1294     mpls_sw_interface_enable_disable(&mpls_main,
1295                                      tm->hw[0]->sw_if_index,
1296                                      0, 0);
1297     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1298
1299     /*
1300      * remove the connected
1301      */
1302     fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
1303
1304     /*
1305      * test we've leaked no resources
1306      */
1307     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1308     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1309               n_pls, fib_path_list_pool_size());
1310     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1311               n_reps, pool_elts(replicate_pool));
1312     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1313               " No more entries %d!=%d",
1314               n_entries, pool_elts(mfib_entry_pool));
1315     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1316               " No more Interfaces %d!=%d",
1317               n_itfs, pool_elts(mfib_itf_pool));
1318     vec_free(two_paths);
1319
1320     return (res);
1321 }
1322
1323 static int
1324 mfib_test_v4 (void)
1325 {
1326     const mfib_prefix_t pfx_224_s_8 = {
1327         .fp_len = 8,
1328         .fp_proto = FIB_PROTOCOL_IP4,
1329         .fp_grp_addr = {
1330             .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1331         }
1332     };
1333     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1334         .fp_len = 64,
1335         .fp_proto = FIB_PROTOCOL_IP4,
1336         .fp_grp_addr = {
1337             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1338         },
1339         .fp_src_addr = {
1340             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1341         },
1342     };
1343     const mfib_prefix_t pfx_239_1_1_1 = {
1344         .fp_len = 32,
1345         .fp_proto = FIB_PROTOCOL_IP4,
1346         .fp_grp_addr = {
1347             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1348         },
1349         .fp_src_addr = {
1350             .ip4.as_u32 = 0,
1351         },
1352     };
1353     const mfib_prefix_t pfx_239_1_1_2 = {
1354         .fp_len = 32,
1355         .fp_proto = FIB_PROTOCOL_IP4,
1356         .fp_grp_addr = {
1357             .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1358         },
1359         .fp_src_addr = {
1360             .ip4.as_u32 = 0,
1361         },
1362     };
1363     const mfib_prefix_t pfx_239_1_1_3 = {
1364         .fp_len = 32,
1365         .fp_proto = FIB_PROTOCOL_IP4,
1366         .fp_grp_addr = {
1367             .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1368         },
1369         .fp_src_addr = {
1370             .ip4.as_u32 = 0,
1371         },
1372     };
1373     const mfib_prefix_t pfx_239 = {
1374         .fp_len = 8,
1375         .fp_proto = FIB_PROTOCOL_IP4,
1376         .fp_grp_addr = {
1377             .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1378         },
1379         .fp_src_addr = {
1380             .ip4.as_u32 = 0,
1381         },
1382     };
1383     const fib_prefix_t pfx_itf = {
1384         .fp_len = 24,
1385         .fp_proto = FIB_PROTOCOL_IP4,
1386         .fp_addr = {
1387             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
1388         },
1389     };
1390     const ip46_address_t nbr1 = {
1391         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
1392     };
1393     const ip46_address_t nbr2 = {
1394         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
1395     };
1396     return (mfib_test_i(FIB_PROTOCOL_IP4,
1397                         VNET_LINK_IP4,
1398                         &pfx_224_s_8,
1399                         &pfx_1_1_1_1_c_239_1_1_1,
1400                         &pfx_239_1_1_1,
1401                         &pfx_239_1_1_2,
1402                         &pfx_239_1_1_3,
1403                         &pfx_239,
1404                         &pfx_itf,
1405                         &nbr1,
1406                         &nbr2));
1407 }
1408
1409 static int
1410 mfib_test_v6 (void)
1411 {
1412     const mfib_prefix_t pfx_ffd_s_12 = {
1413         .fp_len = 12,
1414         .fp_proto = FIB_PROTOCOL_IP6,
1415         .fp_grp_addr = {
1416             .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1417         }
1418     };
1419     const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1420         .fp_len = 256,
1421         .fp_proto = FIB_PROTOCOL_IP6,
1422         .fp_grp_addr = {
1423             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1424             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1425         },
1426         .fp_src_addr = {
1427             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1428             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1429         },
1430     };
1431     const mfib_prefix_t pfx_ff_1 = {
1432         .fp_len = 128,
1433         .fp_proto = FIB_PROTOCOL_IP6,
1434         .fp_grp_addr = {
1435             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1436             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1437         },
1438     };
1439     const mfib_prefix_t pfx_ff_2 = {
1440         .fp_len = 128,
1441         .fp_proto = FIB_PROTOCOL_IP6,
1442         .fp_grp_addr = {
1443             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1444             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1445         },
1446     };
1447     const mfib_prefix_t pfx_ff_3 = {
1448         /*
1449          * this is the ALL DHCP routers address
1450          */
1451         .fp_len = 128,
1452         .fp_proto = FIB_PROTOCOL_IP6,
1453         .fp_grp_addr = {
1454             .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1455             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1456         },
1457     };
1458     const mfib_prefix_t pfx_ff = {
1459         .fp_len = 16,
1460         .fp_proto = FIB_PROTOCOL_IP6,
1461         .fp_grp_addr = {
1462             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1463             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1464         },
1465     };
1466     const fib_prefix_t pfx_itf = {
1467         .fp_len = 64,
1468         .fp_proto = FIB_PROTOCOL_IP6,
1469         .fp_addr = {
1470             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1471             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1472         },
1473     };
1474     const ip46_address_t nbr1 = {
1475             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1476             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1477     };
1478     const ip46_address_t nbr2 = {
1479             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1480             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
1481     };
1482
1483     return (mfib_test_i(FIB_PROTOCOL_IP6,
1484                         VNET_LINK_IP6,
1485                         &pfx_ffd_s_12,
1486                         &pfx_2001_1_c_ff_1,
1487                         &pfx_ff_1,
1488                         &pfx_ff_2,
1489                         &pfx_ff_3,
1490                         &pfx_ff,
1491                         &pfx_itf,
1492                         &nbr1,
1493                         &nbr2));
1494 }
1495
1496 static int
1497 mfib_test_rr_i (fib_protocol_t FPROTO,
1498                 dpo_proto_t DPROTO,
1499                 vnet_link_t LINKT,
1500                 const mfib_prefix_t *pfx_cover,
1501                 const mfib_prefix_t *pfx_host1,
1502                 const mfib_prefix_t *pfx_host2)
1503 {
1504     fib_node_index_t mfei_cover, mfei_host1, mfei_host2, ai_1, ai_2;
1505     u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
1506     test_main_t *tm;
1507     int res;
1508
1509     res = 0;
1510     n_entries = pool_elts(mfib_entry_pool);
1511     n_itfs = pool_elts(mfib_itf_pool);
1512     n_reps = pool_elts(replicate_pool);
1513     n_pls = fib_path_list_pool_size();
1514     tm = &test_main;
1515
1516     fib_index = 0;
1517     ai_1 = adj_mcast_add_or_lock(FPROTO,
1518                                  LINKT,
1519                                  tm->hw[1]->sw_if_index);
1520     ai_2 = adj_mcast_add_or_lock(FPROTO,
1521                                  LINKT,
1522                                  tm->hw[2]->sw_if_index);
1523
1524     fib_route_path_t path_via_if0 = {
1525         .frp_proto = DPROTO,
1526         .frp_addr = zero_addr,
1527         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1528         .frp_fib_index = ~0,
1529         .frp_weight = 1,
1530         .frp_flags = 0,
1531         .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
1532     };
1533     fib_route_path_t path_via_if1 = {
1534         .frp_proto = DPROTO,
1535         .frp_addr = zero_addr,
1536         .frp_sw_if_index = tm->hw[1]->sw_if_index,
1537         .frp_fib_index = ~0,
1538         .frp_weight = 1,
1539         .frp_flags = 0,
1540         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1541     };
1542     fib_route_path_t path_via_if2 = {
1543         .frp_proto = DPROTO,
1544         .frp_addr = zero_addr,
1545         .frp_sw_if_index = tm->hw[2]->sw_if_index,
1546         .frp_fib_index = ~0,
1547         .frp_weight = 1,
1548         .frp_flags = 0,
1549         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1550     };
1551     fib_route_path_t path_for_us = {
1552         .frp_proto = DPROTO,
1553         .frp_addr = zero_addr,
1554         .frp_sw_if_index = 0xffffffff,
1555         .frp_fib_index = ~0,
1556         .frp_weight = 1,
1557         .frp_flags = FIB_ROUTE_PATH_LOCAL,
1558         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1559     };
1560
1561     /*
1562      * with only the default in place, recusre thru the /32
1563      */
1564     mfei_host1 = mfib_table_entry_special_add(fib_index, pfx_host1,
1565                                               MFIB_SOURCE_RR,
1566                                               MFIB_ENTRY_FLAG_NONE,
1567                                               INDEX_INVALID);
1568     /*
1569      * expect its forwarding to match the cover's
1570      */
1571     MFIB_TEST(!mfib_test_entry(mfei_host1,
1572                                MFIB_ENTRY_FLAG_DROP,
1573                                0),
1574               "%U no replications OK",
1575               format_mfib_prefix, pfx_host1);
1576
1577     /*
1578      * Insert the less specific /28
1579      */
1580     mfib_table_entry_path_update(fib_index,
1581                                  pfx_cover,
1582                                  MFIB_SOURCE_API,
1583                                  &path_via_if1);
1584
1585     mfei_cover = mfib_table_lookup_exact_match(fib_index, pfx_cover);
1586
1587     MFIB_TEST(!mfib_test_entry(mfei_cover,
1588                                MFIB_ENTRY_FLAG_NONE,
1589                                1,
1590                                DPO_ADJACENCY_MCAST, ai_1),
1591               "%U replicate OK",
1592               format_mfib_prefix, pfx_cover);
1593
1594     /*
1595      * expect the /32 forwarding to match the new cover's
1596      */
1597     MFIB_TEST(!mfib_test_entry(mfei_host1,
1598                                MFIB_ENTRY_FLAG_NONE,
1599                                1,
1600                                DPO_ADJACENCY_MCAST, ai_1),
1601               "%U replicate OK",
1602               format_mfib_prefix, pfx_host1);
1603
1604     /*
1605      * add another path to the cover
1606      */
1607     mfib_table_entry_path_update(fib_index,
1608                                  pfx_cover,
1609                                  MFIB_SOURCE_API,
1610                                  &path_via_if2);
1611
1612     /*
1613      * expect the /32 and /28 to be via both boths
1614      */
1615     MFIB_TEST(!mfib_test_entry(mfei_cover,
1616                                MFIB_ENTRY_FLAG_NONE,
1617                                2,
1618                                DPO_ADJACENCY_MCAST, ai_1,
1619                                DPO_ADJACENCY_MCAST, ai_2),
1620               "%U replicate OK",
1621               format_mfib_prefix, pfx_cover);
1622     MFIB_TEST(!mfib_test_entry(mfei_host1,
1623                                MFIB_ENTRY_FLAG_NONE,
1624                                2,
1625                                DPO_ADJACENCY_MCAST, ai_1,
1626                                DPO_ADJACENCY_MCAST, ai_2),
1627               "%U replicate OK",
1628               format_mfib_prefix, pfx_host1);
1629
1630     /*
1631      * and the other host whilst all is ready
1632      */
1633     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1634                                               MFIB_SOURCE_RR,
1635                                               MFIB_ENTRY_FLAG_NONE,
1636                                               INDEX_INVALID);
1637     MFIB_TEST(!mfib_test_entry(mfei_host2,
1638                                MFIB_ENTRY_FLAG_NONE,
1639                                2,
1640                                DPO_ADJACENCY_MCAST, ai_1,
1641                                DPO_ADJACENCY_MCAST, ai_2),
1642               "%U replicate OK",
1643               format_mfib_prefix, pfx_host2);
1644
1645     /*
1646      * repaet multiple time to simulate multiple recursve children
1647      */
1648     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1649                                               MFIB_SOURCE_RR,
1650                                               MFIB_ENTRY_FLAG_NONE,
1651                                               INDEX_INVALID);
1652     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1653                                               MFIB_SOURCE_RR,
1654                                               MFIB_ENTRY_FLAG_NONE,
1655                                               INDEX_INVALID);
1656     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1657                                               MFIB_SOURCE_RR,
1658                                               MFIB_ENTRY_FLAG_NONE,
1659                                               INDEX_INVALID);
1660
1661     /*
1662      * add an accepting path to the cover
1663      */
1664     mfib_table_entry_path_update(fib_index,
1665                                  pfx_cover,
1666                                  MFIB_SOURCE_API,
1667                                  &path_via_if0);
1668
1669     /*
1670      * expect the /32 and /28 to be via both boths
1671      */
1672     MFIB_TEST(!mfib_test_entry(mfei_cover,
1673                                MFIB_ENTRY_FLAG_NONE,
1674                                2,
1675                                DPO_ADJACENCY_MCAST, ai_1,
1676                                DPO_ADJACENCY_MCAST, ai_2),
1677               "%U replicate OK",
1678               format_mfib_prefix, pfx_cover);
1679     MFIB_TEST(!mfib_test_entry(mfei_host1,
1680                                MFIB_ENTRY_FLAG_NONE,
1681                                2,
1682                                DPO_ADJACENCY_MCAST, ai_1,
1683                                DPO_ADJACENCY_MCAST, ai_2),
1684               "%U replicate OK",
1685               format_mfib_prefix, pfx_cover);
1686     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[0]->sw_if_index,
1687                                       MFIB_ITF_FLAG_ACCEPT));
1688     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[0]->sw_if_index,
1689                                       MFIB_ITF_FLAG_ACCEPT));
1690     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[1]->sw_if_index,
1691                                       MFIB_ITF_FLAG_FORWARD));
1692     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[1]->sw_if_index,
1693                                       MFIB_ITF_FLAG_FORWARD));
1694     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[2]->sw_if_index,
1695                                       MFIB_ITF_FLAG_FORWARD));
1696     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[2]->sw_if_index,
1697                                       MFIB_ITF_FLAG_FORWARD));
1698
1699     /*
1700      * add a for-us path to the cover
1701      */
1702     mfib_table_entry_path_update(fib_index,
1703                                  pfx_cover,
1704                                  MFIB_SOURCE_API,
1705                                  &path_for_us);
1706
1707     /*
1708      * expect the /32 and /28 to be via all three paths
1709      */
1710     MFIB_TEST(!mfib_test_entry(mfei_cover,
1711                                MFIB_ENTRY_FLAG_NONE,
1712                                3,
1713                                DPO_ADJACENCY_MCAST, ai_1,
1714                                DPO_ADJACENCY_MCAST, ai_2,
1715                                DPO_RECEIVE, 0),
1716               "%U replicate OK",
1717               format_mfib_prefix, pfx_cover);
1718     MFIB_TEST(!mfib_test_entry(mfei_host1,
1719                                MFIB_ENTRY_FLAG_NONE,
1720                                3,
1721                                DPO_ADJACENCY_MCAST, ai_1,
1722                                DPO_ADJACENCY_MCAST, ai_2,
1723                                DPO_RECEIVE, 0),
1724               "%U replicate OK",
1725               format_mfib_prefix, pfx_cover);
1726
1727     /*
1728      * get the forwarding chain from the RR prefix
1729      */
1730     replicate_t *rep;
1731     dpo_id_t dpo = DPO_INVALID;
1732
1733     mfib_entry_contribute_forwarding(
1734         mfei_host1,
1735         mfib_forw_chain_type_from_dpo_proto(DPROTO),
1736         MFIB_ENTRY_FWD_FLAG_NONE,
1737         &dpo);
1738
1739     rep = replicate_get(dpo.dpoi_index);
1740     MFIB_TEST((3 == rep->rep_n_buckets),
1741               "%U replicate 3 buckets",
1742               format_mfib_prefix, pfx_host1);
1743
1744     /*
1745      * get the forwarding chain from the RR prefix without local paths
1746      */
1747     mfib_entry_contribute_forwarding(
1748         mfei_host1,
1749         mfib_forw_chain_type_from_dpo_proto(DPROTO),
1750         MFIB_ENTRY_FWD_FLAG_NO_LOCAL,
1751         &dpo);
1752
1753     rep = replicate_get(dpo.dpoi_index);
1754     MFIB_TEST((2 == rep->rep_n_buckets),
1755               "%U no-local replicate 2 buckets",
1756               format_mfib_prefix, pfx_host1);
1757
1758     dpo_reset(&dpo);
1759
1760     /*
1761      * delete the cover, expect the /32 to be via the default
1762      */
1763     mfib_table_entry_delete(fib_index, pfx_cover, MFIB_SOURCE_API);
1764     MFIB_TEST(!mfib_test_entry(mfei_host1,
1765                                MFIB_ENTRY_FLAG_DROP,
1766                                0),
1767               "%U no replications OK",
1768               format_mfib_prefix, pfx_host1);
1769
1770     /*
1771      * source the /32 with its own path
1772      */
1773     mfei_host1 = mfib_table_entry_path_update(fib_index,
1774                                               pfx_host1,
1775                                               MFIB_SOURCE_API,
1776                                               &path_via_if2);
1777     MFIB_TEST(!mfib_test_entry(mfei_host1,
1778                                MFIB_ENTRY_FLAG_NONE,
1779                                1,
1780                                DPO_ADJACENCY_MCAST, ai_2),
1781               "%U replicate OK",
1782               format_mfib_prefix, pfx_host1);
1783
1784     /*
1785      * remove host2 - as many times as it was added
1786      */
1787     mfib_table_entry_delete(fib_index, pfx_host2,
1788                             MFIB_SOURCE_RR);
1789     mfib_table_entry_delete(fib_index, pfx_host2,
1790                             MFIB_SOURCE_RR);
1791     mfib_table_entry_delete(fib_index, pfx_host2,
1792                             MFIB_SOURCE_RR);
1793     mfib_table_entry_delete(fib_index, pfx_host2,
1794                             MFIB_SOURCE_RR);
1795
1796
1797     /*
1798      * remove the RR source with paths present
1799      */
1800     mfib_table_entry_delete(fib_index, pfx_host1,
1801                             MFIB_SOURCE_RR);
1802
1803     /*
1804      * add the RR back then remove the path and RR
1805      */
1806     mfei_host1 = mfib_table_entry_path_update(fib_index,
1807                                               pfx_host1,
1808                                               MFIB_SOURCE_API,
1809                                               &path_via_if2);
1810     MFIB_TEST(!mfib_test_entry(mfei_host1,
1811                                MFIB_ENTRY_FLAG_NONE,
1812                                1,
1813                                DPO_ADJACENCY_MCAST, ai_2),
1814               "%U replicate OK",
1815               format_mfib_prefix, pfx_host1);
1816
1817     mfib_table_entry_delete(fib_index, pfx_host1,
1818                             MFIB_SOURCE_API);
1819     mfib_table_entry_delete(fib_index, pfx_host1,
1820                             MFIB_SOURCE_RR);
1821
1822     /*
1823      * test we've leaked no resources
1824      */
1825     adj_unlock(ai_1);
1826     adj_unlock(ai_2);
1827     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1828     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1829               n_pls, fib_path_list_pool_size());
1830     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1831               n_reps, pool_elts(replicate_pool));
1832     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1833               " No more entries %d!=%d",
1834               n_entries, pool_elts(mfib_entry_pool));
1835     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1836               " No more Interfaces %d!=%d",
1837               n_itfs, pool_elts(mfib_itf_pool));
1838     return (res);
1839 }
1840
1841 static int
1842 mfib_test_rr_v4 (void)
1843 {
1844     /*
1845      * 2 length of prefix to play with
1846      */
1847     const mfib_prefix_t pfx_host1 = {
1848         .fp_len = 32,
1849         .fp_proto = FIB_PROTOCOL_IP4,
1850         .fp_grp_addr = {
1851             .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1852         },
1853     };
1854     const mfib_prefix_t pfx_host2 = {
1855         .fp_len = 64,
1856         .fp_proto = FIB_PROTOCOL_IP4,
1857         .fp_grp_addr = {
1858             .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1859         },
1860         .fp_src_addr = {
1861             .ip4.as_u32 = clib_host_to_net_u32(0x10101010),
1862         },
1863     };
1864     const mfib_prefix_t pfx_cover = {
1865         .fp_len = 28,
1866         .fp_proto = FIB_PROTOCOL_IP4,
1867         .fp_grp_addr = {
1868             .ip4.as_u32 = clib_host_to_net_u32(0xe0001010),
1869         },
1870     };
1871
1872     return (mfib_test_rr_i(FIB_PROTOCOL_IP4,
1873                            DPO_PROTO_IP4,
1874                            VNET_LINK_IP4,
1875                            &pfx_cover,
1876                            &pfx_host1,
1877                            &pfx_host2));
1878 }
1879
1880 static int
1881 mfib_test_rr_v6 (void)
1882 {
1883     /*
1884      * 2 length of prefix to play with
1885      */
1886     const mfib_prefix_t pfx_host1 = {
1887         .fp_len = 128,
1888         .fp_proto = FIB_PROTOCOL_IP6,
1889         .fp_grp_addr = {
1890             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1891             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1892         },
1893     };
1894     const mfib_prefix_t pfx_host2 = {
1895         .fp_len = 256,
1896         .fp_proto = FIB_PROTOCOL_IP6,
1897         .fp_grp_addr = {
1898             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1899             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1900         },
1901         .fp_src_addr = {
1902             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1903             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1904         },
1905     };
1906     const mfib_prefix_t pfx_cover = {
1907         .fp_len = 64,
1908         .fp_proto = FIB_PROTOCOL_IP6,
1909         .fp_grp_addr = {
1910             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1911             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1912         },
1913     };
1914
1915     return (mfib_test_rr_i(FIB_PROTOCOL_IP6,
1916                            DPO_PROTO_IP6,
1917                            VNET_LINK_IP6,
1918                            &pfx_cover,
1919                            &pfx_host1,
1920                            &pfx_host2));
1921 }
1922
1923 static clib_error_t *
1924 mfib_test (vlib_main_t * vm,
1925            unformat_input_t * input,
1926            vlib_cli_command_t * cmd_arg)
1927 {
1928     int res = 0;
1929
1930     res += mfib_test_mk_intf(4);
1931     res += mfib_test_rr_v4();
1932
1933     if (res)
1934     {
1935         return clib_error_return(0, "MFIB RR V4 Unit Test Failed");
1936     }
1937
1938     res += mfib_test_rr_v6();
1939
1940     if (res)
1941     {
1942         return clib_error_return(0, "MFIB RR V6 Unit Test Failed");
1943     }
1944
1945     res += mfib_test_v4();
1946
1947     if (res)
1948     {
1949         return clib_error_return(0, "MFIB V4 Unit Test Failed");
1950     }
1951
1952     res += mfib_test_v6();
1953
1954     if (res)
1955     {
1956         return clib_error_return(0, "MFIB V6 Unit Test Failed");
1957     }
1958
1959     return (NULL);
1960 }
1961
1962 VLIB_CLI_COMMAND (test_fib_command, static) = {
1963     .path = "test mfib",
1964     .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1965     .function = mfib_test,
1966 };
1967
1968 clib_error_t *
1969 mfib_test_init (vlib_main_t *vm)
1970 {
1971     return 0;
1972 }
1973
1974 VLIB_INIT_FUNCTION (mfib_test_init);