ip: fix fib and mfib locks
[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 accepting 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, tm->hw[0]->sw_if_index, 1);
1197
1198     lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1199                                            &pfx_3500,
1200                                            FIB_SOURCE_API,
1201                                            FIB_ENTRY_FLAG_MULTICAST,
1202                                            DPO_PROTO_IP4,
1203                                            &nh_10_10_10_1,
1204                                            tm->hw[0]->sw_if_index,
1205                                            ~0, // invalid fib index
1206                                            1,
1207                                            l3300,
1208                                            FIB_ROUTE_PATH_FLAG_NONE);
1209     MFIB_TEST(!fib_test_validate_entry(lfei,
1210                                        FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1211                                        1,
1212                                        &mc_0),
1213               "3500 via replicate over 10.10.10.1");
1214
1215     /*
1216      * An (S,G) that resolves via the mLDP head-end
1217      */
1218     fib_route_path_t path_via_mldp = {
1219         .frp_proto = DPO_PROTO_MPLS,
1220         .frp_local_label = pfx_3500.fp_label,
1221         .frp_eos = MPLS_EOS,
1222         .frp_sw_if_index = 0xffffffff,
1223         .frp_fib_index = 0,
1224         .frp_weight = 1,
1225         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1226         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1227     };
1228     dpo_id_t mldp_dpo = DPO_INVALID;
1229
1230     fib_entry_contribute_forwarding(lfei,
1231                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1232                                     &mldp_dpo);
1233
1234     mfei = mfib_table_entry_path_update(fib_index,
1235                                         pfx_s_g,
1236                                         MFIB_SOURCE_API,
1237                                         &path_via_mldp);
1238
1239     MFIB_TEST(!mfib_test_entry(mfei,
1240                                MFIB_ENTRY_FLAG_NONE,
1241                                1,
1242                                DPO_REPLICATE, mldp_dpo.dpoi_index),
1243               "%U over-mLDP replicate OK",
1244               format_mfib_prefix, pfx_s_g);
1245
1246     /*
1247      * add a for-us path. this tests two types of non-attached paths on one entry
1248      */
1249     mfei = mfib_table_entry_path_update(fib_index,
1250                                         pfx_s_g,
1251                                         MFIB_SOURCE_API,
1252                                         &path_for_us);
1253     MFIB_TEST(!mfib_test_entry(mfei,
1254                                MFIB_ENTRY_FLAG_NONE,
1255                                2,
1256                                DPO_REPLICATE, mldp_dpo.dpoi_index,
1257                                DPO_RECEIVE, 0),
1258               "%U mLDP+for-us replicate OK",
1259               format_mfib_prefix, pfx_s_g);
1260
1261     mfib_table_entry_delete(fib_index,
1262                             pfx_s_g,
1263                             MFIB_SOURCE_API);
1264     fib_table_entry_delete(0,
1265                            &pfx_3500,
1266                            FIB_SOURCE_API);
1267     dpo_reset(&mldp_dpo);
1268
1269     /*
1270      * Unlock the table - it's the last lock so should be gone thereafter
1271      */
1272     MFIB_TEST(((PROTO == FIB_PROTOCOL_IP4 ? 3 : 5) ==
1273                mfib_table_get_n_routes(fib_index, PROTO)),
1274               "1 = %d route left in the FIB",
1275               mfib_table_get_n_routes(fib_index, PROTO));
1276
1277     mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1278
1279     MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1280                mfib_table_find(PROTO, fib_index)),
1281               "MFIB table %d gone", fib_index);
1282
1283     adj_unlock(ai_1);
1284     adj_unlock(ai_2);
1285     adj_unlock(ai_3);
1286     adj_unlock(ai_nbr1);
1287     adj_unlock(ai_nbr2);
1288
1289     /*
1290      * MPLS disable the interface
1291      */
1292     mpls_sw_interface_enable_disable (&mpls_main, tm->hw[0]->sw_if_index, 0);
1293     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1294
1295     /*
1296      * remove the connected
1297      */
1298     fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
1299
1300     /*
1301      * test we've leaked no resources
1302      */
1303     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1304     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1305               n_pls, fib_path_list_pool_size());
1306     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1307               n_reps, pool_elts(replicate_pool));
1308     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1309               " No more entries %d!=%d",
1310               n_entries, pool_elts(mfib_entry_pool));
1311     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1312               " No more Interfaces %d!=%d",
1313               n_itfs, pool_elts(mfib_itf_pool));
1314     vec_free(two_paths);
1315
1316     return (res);
1317 }
1318
1319 static int
1320 mfib_test_v4 (void)
1321 {
1322     const mfib_prefix_t pfx_224_s_8 = {
1323         .fp_len = 8,
1324         .fp_proto = FIB_PROTOCOL_IP4,
1325         .fp_grp_addr = {
1326             .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1327         }
1328     };
1329     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1330         .fp_len = 64,
1331         .fp_proto = FIB_PROTOCOL_IP4,
1332         .fp_grp_addr = {
1333             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1334         },
1335         .fp_src_addr = {
1336             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1337         },
1338     };
1339     const mfib_prefix_t pfx_239_1_1_1 = {
1340         .fp_len = 32,
1341         .fp_proto = FIB_PROTOCOL_IP4,
1342         .fp_grp_addr = {
1343             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1344         },
1345         .fp_src_addr = {
1346             .ip4.as_u32 = 0,
1347         },
1348     };
1349     const mfib_prefix_t pfx_239_1_1_2 = {
1350         .fp_len = 32,
1351         .fp_proto = FIB_PROTOCOL_IP4,
1352         .fp_grp_addr = {
1353             .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1354         },
1355         .fp_src_addr = {
1356             .ip4.as_u32 = 0,
1357         },
1358     };
1359     const mfib_prefix_t pfx_239_1_1_3 = {
1360         .fp_len = 32,
1361         .fp_proto = FIB_PROTOCOL_IP4,
1362         .fp_grp_addr = {
1363             .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1364         },
1365         .fp_src_addr = {
1366             .ip4.as_u32 = 0,
1367         },
1368     };
1369     const mfib_prefix_t pfx_239 = {
1370         .fp_len = 8,
1371         .fp_proto = FIB_PROTOCOL_IP4,
1372         .fp_grp_addr = {
1373             .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1374         },
1375         .fp_src_addr = {
1376             .ip4.as_u32 = 0,
1377         },
1378     };
1379     const fib_prefix_t pfx_itf = {
1380         .fp_len = 24,
1381         .fp_proto = FIB_PROTOCOL_IP4,
1382         .fp_addr = {
1383             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
1384         },
1385     };
1386     const ip46_address_t nbr1 = {
1387         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
1388     };
1389     const ip46_address_t nbr2 = {
1390         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
1391     };
1392     return (mfib_test_i(FIB_PROTOCOL_IP4,
1393                         VNET_LINK_IP4,
1394                         &pfx_224_s_8,
1395                         &pfx_1_1_1_1_c_239_1_1_1,
1396                         &pfx_239_1_1_1,
1397                         &pfx_239_1_1_2,
1398                         &pfx_239_1_1_3,
1399                         &pfx_239,
1400                         &pfx_itf,
1401                         &nbr1,
1402                         &nbr2));
1403 }
1404
1405 static int
1406 mfib_test_v6 (void)
1407 {
1408     const mfib_prefix_t pfx_ffd_s_12 = {
1409         .fp_len = 12,
1410         .fp_proto = FIB_PROTOCOL_IP6,
1411         .fp_grp_addr = {
1412             .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1413         }
1414     };
1415     const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1416         .fp_len = 256,
1417         .fp_proto = FIB_PROTOCOL_IP6,
1418         .fp_grp_addr = {
1419             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1420             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1421         },
1422         .fp_src_addr = {
1423             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1424             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1425         },
1426     };
1427     const mfib_prefix_t pfx_ff_1 = {
1428         .fp_len = 128,
1429         .fp_proto = FIB_PROTOCOL_IP6,
1430         .fp_grp_addr = {
1431             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1432             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1433         },
1434     };
1435     const mfib_prefix_t pfx_ff_2 = {
1436         .fp_len = 128,
1437         .fp_proto = FIB_PROTOCOL_IP6,
1438         .fp_grp_addr = {
1439             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1440             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1441         },
1442     };
1443     const mfib_prefix_t pfx_ff_3 = {
1444         /*
1445          * this is the ALL DHCP routers address
1446          */
1447         .fp_len = 128,
1448         .fp_proto = FIB_PROTOCOL_IP6,
1449         .fp_grp_addr = {
1450             .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1451             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1452         },
1453     };
1454     const mfib_prefix_t pfx_ff = {
1455         .fp_len = 16,
1456         .fp_proto = FIB_PROTOCOL_IP6,
1457         .fp_grp_addr = {
1458             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1459             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1460         },
1461     };
1462     const fib_prefix_t pfx_itf = {
1463         .fp_len = 64,
1464         .fp_proto = FIB_PROTOCOL_IP6,
1465         .fp_addr = {
1466             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1467             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1468         },
1469     };
1470     const ip46_address_t nbr1 = {
1471             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1472             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1473     };
1474     const ip46_address_t nbr2 = {
1475             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1476             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
1477     };
1478
1479     return (mfib_test_i(FIB_PROTOCOL_IP6,
1480                         VNET_LINK_IP6,
1481                         &pfx_ffd_s_12,
1482                         &pfx_2001_1_c_ff_1,
1483                         &pfx_ff_1,
1484                         &pfx_ff_2,
1485                         &pfx_ff_3,
1486                         &pfx_ff,
1487                         &pfx_itf,
1488                         &nbr1,
1489                         &nbr2));
1490 }
1491
1492 static int
1493 mfib_test_rr_i (fib_protocol_t FPROTO,
1494                 dpo_proto_t DPROTO,
1495                 vnet_link_t LINKT,
1496                 const mfib_prefix_t *pfx_cover,
1497                 const mfib_prefix_t *pfx_host1,
1498                 const mfib_prefix_t *pfx_host2)
1499 {
1500     fib_node_index_t mfei_cover, mfei_host1, mfei_host2, ai_1, ai_2;
1501     u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
1502     test_main_t *tm;
1503     int res;
1504
1505     res = 0;
1506     n_entries = pool_elts(mfib_entry_pool);
1507     n_itfs = pool_elts(mfib_itf_pool);
1508     n_reps = pool_elts(replicate_pool);
1509     n_pls = fib_path_list_pool_size();
1510     tm = &test_main;
1511
1512     fib_index = 0;
1513     ai_1 = adj_mcast_add_or_lock(FPROTO,
1514                                  LINKT,
1515                                  tm->hw[1]->sw_if_index);
1516     ai_2 = adj_mcast_add_or_lock(FPROTO,
1517                                  LINKT,
1518                                  tm->hw[2]->sw_if_index);
1519
1520     fib_route_path_t path_via_if0 = {
1521         .frp_proto = DPROTO,
1522         .frp_addr = zero_addr,
1523         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1524         .frp_fib_index = ~0,
1525         .frp_weight = 1,
1526         .frp_flags = 0,
1527         .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
1528     };
1529     fib_route_path_t path_via_if1 = {
1530         .frp_proto = DPROTO,
1531         .frp_addr = zero_addr,
1532         .frp_sw_if_index = tm->hw[1]->sw_if_index,
1533         .frp_fib_index = ~0,
1534         .frp_weight = 1,
1535         .frp_flags = 0,
1536         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1537     };
1538     fib_route_path_t path_via_if2 = {
1539         .frp_proto = DPROTO,
1540         .frp_addr = zero_addr,
1541         .frp_sw_if_index = tm->hw[2]->sw_if_index,
1542         .frp_fib_index = ~0,
1543         .frp_weight = 1,
1544         .frp_flags = 0,
1545         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1546     };
1547     fib_route_path_t path_for_us = {
1548         .frp_proto = DPROTO,
1549         .frp_addr = zero_addr,
1550         .frp_sw_if_index = 0xffffffff,
1551         .frp_fib_index = ~0,
1552         .frp_weight = 1,
1553         .frp_flags = FIB_ROUTE_PATH_LOCAL,
1554         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1555     };
1556
1557     /*
1558      * with only the default in place, recusre thru the /32
1559      */
1560     mfei_host1 = mfib_table_entry_special_add(fib_index, pfx_host1,
1561                                               MFIB_SOURCE_RR,
1562                                               MFIB_ENTRY_FLAG_NONE,
1563                                               INDEX_INVALID);
1564     /*
1565      * expect its forwarding to match the cover's
1566      */
1567     MFIB_TEST(!mfib_test_entry(mfei_host1,
1568                                MFIB_ENTRY_FLAG_DROP,
1569                                0),
1570               "%U no replications OK",
1571               format_mfib_prefix, pfx_host1);
1572
1573     /*
1574      * Insert the less specific /28
1575      */
1576     mfib_table_entry_path_update(fib_index,
1577                                  pfx_cover,
1578                                  MFIB_SOURCE_API,
1579                                  &path_via_if1);
1580
1581     mfei_cover = mfib_table_lookup_exact_match(fib_index, pfx_cover);
1582
1583     MFIB_TEST(!mfib_test_entry(mfei_cover,
1584                                MFIB_ENTRY_FLAG_NONE,
1585                                1,
1586                                DPO_ADJACENCY_MCAST, ai_1),
1587               "%U replicate OK",
1588               format_mfib_prefix, pfx_cover);
1589
1590     /*
1591      * expect the /32 forwarding to match the new cover's
1592      */
1593     MFIB_TEST(!mfib_test_entry(mfei_host1,
1594                                MFIB_ENTRY_FLAG_NONE,
1595                                1,
1596                                DPO_ADJACENCY_MCAST, ai_1),
1597               "%U replicate OK",
1598               format_mfib_prefix, pfx_host1);
1599
1600     /*
1601      * add another path to the cover
1602      */
1603     mfib_table_entry_path_update(fib_index,
1604                                  pfx_cover,
1605                                  MFIB_SOURCE_API,
1606                                  &path_via_if2);
1607
1608     /*
1609      * expect the /32 and /28 to be via both boths
1610      */
1611     MFIB_TEST(!mfib_test_entry(mfei_cover,
1612                                MFIB_ENTRY_FLAG_NONE,
1613                                2,
1614                                DPO_ADJACENCY_MCAST, ai_1,
1615                                DPO_ADJACENCY_MCAST, ai_2),
1616               "%U replicate OK",
1617               format_mfib_prefix, pfx_cover);
1618     MFIB_TEST(!mfib_test_entry(mfei_host1,
1619                                MFIB_ENTRY_FLAG_NONE,
1620                                2,
1621                                DPO_ADJACENCY_MCAST, ai_1,
1622                                DPO_ADJACENCY_MCAST, ai_2),
1623               "%U replicate OK",
1624               format_mfib_prefix, pfx_host1);
1625
1626     /*
1627      * and the other host whilst all is ready
1628      */
1629     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1630                                               MFIB_SOURCE_RR,
1631                                               MFIB_ENTRY_FLAG_NONE,
1632                                               INDEX_INVALID);
1633     MFIB_TEST(!mfib_test_entry(mfei_host2,
1634                                MFIB_ENTRY_FLAG_NONE,
1635                                2,
1636                                DPO_ADJACENCY_MCAST, ai_1,
1637                                DPO_ADJACENCY_MCAST, ai_2),
1638               "%U replicate OK",
1639               format_mfib_prefix, pfx_host2);
1640
1641     /*
1642      * repaet multiple time to simulate multiple recursve children
1643      */
1644     mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1645                                               MFIB_SOURCE_RR,
1646                                               MFIB_ENTRY_FLAG_NONE,
1647                                               INDEX_INVALID);
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
1657     /*
1658      * add an accepting path to the cover
1659      */
1660     mfib_table_entry_path_update(fib_index,
1661                                  pfx_cover,
1662                                  MFIB_SOURCE_API,
1663                                  &path_via_if0);
1664
1665     /*
1666      * expect the /32 and /28 to be via both boths
1667      */
1668     MFIB_TEST(!mfib_test_entry(mfei_cover,
1669                                MFIB_ENTRY_FLAG_NONE,
1670                                2,
1671                                DPO_ADJACENCY_MCAST, ai_1,
1672                                DPO_ADJACENCY_MCAST, ai_2),
1673               "%U replicate OK",
1674               format_mfib_prefix, pfx_cover);
1675     MFIB_TEST(!mfib_test_entry(mfei_host1,
1676                                MFIB_ENTRY_FLAG_NONE,
1677                                2,
1678                                DPO_ADJACENCY_MCAST, ai_1,
1679                                DPO_ADJACENCY_MCAST, ai_2),
1680               "%U replicate OK",
1681               format_mfib_prefix, pfx_cover);
1682     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[0]->sw_if_index,
1683                                       MFIB_ITF_FLAG_ACCEPT));
1684     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[0]->sw_if_index,
1685                                       MFIB_ITF_FLAG_ACCEPT));
1686     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[1]->sw_if_index,
1687                                       MFIB_ITF_FLAG_FORWARD));
1688     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[1]->sw_if_index,
1689                                       MFIB_ITF_FLAG_FORWARD));
1690     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[2]->sw_if_index,
1691                                       MFIB_ITF_FLAG_FORWARD));
1692     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[2]->sw_if_index,
1693                                       MFIB_ITF_FLAG_FORWARD));
1694
1695     /*
1696      * add a for-us path to the cover
1697      */
1698     mfib_table_entry_path_update(fib_index,
1699                                  pfx_cover,
1700                                  MFIB_SOURCE_API,
1701                                  &path_for_us);
1702
1703     /*
1704      * expect the /32 and /28 to be via all three paths
1705      */
1706     MFIB_TEST(!mfib_test_entry(mfei_cover,
1707                                MFIB_ENTRY_FLAG_NONE,
1708                                3,
1709                                DPO_ADJACENCY_MCAST, ai_1,
1710                                DPO_ADJACENCY_MCAST, ai_2,
1711                                DPO_RECEIVE, 0),
1712               "%U replicate OK",
1713               format_mfib_prefix, pfx_cover);
1714     MFIB_TEST(!mfib_test_entry(mfei_host1,
1715                                MFIB_ENTRY_FLAG_NONE,
1716                                3,
1717                                DPO_ADJACENCY_MCAST, ai_1,
1718                                DPO_ADJACENCY_MCAST, ai_2,
1719                                DPO_RECEIVE, 0),
1720               "%U replicate OK",
1721               format_mfib_prefix, pfx_cover);
1722
1723     /*
1724      * get the forwarding chain from the RR prefix
1725      */
1726     replicate_t *rep;
1727     dpo_id_t dpo = DPO_INVALID;
1728
1729     mfib_entry_contribute_forwarding(
1730         mfei_host1,
1731         mfib_forw_chain_type_from_dpo_proto(DPROTO),
1732         MFIB_ENTRY_FWD_FLAG_NONE,
1733         &dpo);
1734
1735     rep = replicate_get(dpo.dpoi_index);
1736     MFIB_TEST((3 == rep->rep_n_buckets),
1737               "%U replicate 3 buckets",
1738               format_mfib_prefix, pfx_host1);
1739
1740     /*
1741      * get the forwarding chain from the RR prefix without local paths
1742      */
1743     mfib_entry_contribute_forwarding(
1744         mfei_host1,
1745         mfib_forw_chain_type_from_dpo_proto(DPROTO),
1746         MFIB_ENTRY_FWD_FLAG_NO_LOCAL,
1747         &dpo);
1748
1749     rep = replicate_get(dpo.dpoi_index);
1750     MFIB_TEST((2 == rep->rep_n_buckets),
1751               "%U no-local replicate 2 buckets",
1752               format_mfib_prefix, pfx_host1);
1753
1754     dpo_reset(&dpo);
1755
1756     /*
1757      * delete the cover, expect the /32 to be via the default
1758      */
1759     mfib_table_entry_delete(fib_index, pfx_cover, MFIB_SOURCE_API);
1760     MFIB_TEST(!mfib_test_entry(mfei_host1,
1761                                MFIB_ENTRY_FLAG_DROP,
1762                                0),
1763               "%U no replications OK",
1764               format_mfib_prefix, pfx_host1);
1765
1766     /*
1767      * source the /32 with its own path
1768      */
1769     mfei_host1 = mfib_table_entry_path_update(fib_index,
1770                                               pfx_host1,
1771                                               MFIB_SOURCE_API,
1772                                               &path_via_if2);
1773     MFIB_TEST(!mfib_test_entry(mfei_host1,
1774                                MFIB_ENTRY_FLAG_NONE,
1775                                1,
1776                                DPO_ADJACENCY_MCAST, ai_2),
1777               "%U replicate OK",
1778               format_mfib_prefix, pfx_host1);
1779
1780     /*
1781      * remove host2 - as many times as it was added
1782      */
1783     mfib_table_entry_delete(fib_index, pfx_host2,
1784                             MFIB_SOURCE_RR);
1785     mfib_table_entry_delete(fib_index, pfx_host2,
1786                             MFIB_SOURCE_RR);
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
1792
1793     /*
1794      * remove the RR source with paths present
1795      */
1796     mfib_table_entry_delete(fib_index, pfx_host1,
1797                             MFIB_SOURCE_RR);
1798
1799     /*
1800      * add the RR back then remove the path and RR
1801      */
1802     mfei_host1 = mfib_table_entry_path_update(fib_index,
1803                                               pfx_host1,
1804                                               MFIB_SOURCE_API,
1805                                               &path_via_if2);
1806     MFIB_TEST(!mfib_test_entry(mfei_host1,
1807                                MFIB_ENTRY_FLAG_NONE,
1808                                1,
1809                                DPO_ADJACENCY_MCAST, ai_2),
1810               "%U replicate OK",
1811               format_mfib_prefix, pfx_host1);
1812
1813     mfib_table_entry_delete(fib_index, pfx_host1,
1814                             MFIB_SOURCE_API);
1815     mfib_table_entry_delete(fib_index, pfx_host1,
1816                             MFIB_SOURCE_RR);
1817
1818     /*
1819      * test we've leaked no resources
1820      */
1821     adj_unlock(ai_1);
1822     adj_unlock(ai_2);
1823     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1824     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1825               n_pls, fib_path_list_pool_size());
1826     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1827               n_reps, pool_elts(replicate_pool));
1828     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1829               " No more entries %d!=%d",
1830               n_entries, pool_elts(mfib_entry_pool));
1831     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1832               " No more Interfaces %d!=%d",
1833               n_itfs, pool_elts(mfib_itf_pool));
1834     return (res);
1835 }
1836
1837 static int
1838 mfib_test_rr_v4 (void)
1839 {
1840     /*
1841      * 2 length of prefix to play with
1842      */
1843     const mfib_prefix_t pfx_host1 = {
1844         .fp_len = 32,
1845         .fp_proto = FIB_PROTOCOL_IP4,
1846         .fp_grp_addr = {
1847             .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1848         },
1849     };
1850     const mfib_prefix_t pfx_host2 = {
1851         .fp_len = 64,
1852         .fp_proto = FIB_PROTOCOL_IP4,
1853         .fp_grp_addr = {
1854             .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1855         },
1856         .fp_src_addr = {
1857             .ip4.as_u32 = clib_host_to_net_u32(0x10101010),
1858         },
1859     };
1860     const mfib_prefix_t pfx_cover = {
1861         .fp_len = 28,
1862         .fp_proto = FIB_PROTOCOL_IP4,
1863         .fp_grp_addr = {
1864             .ip4.as_u32 = clib_host_to_net_u32(0xe0001010),
1865         },
1866     };
1867
1868     return (mfib_test_rr_i(FIB_PROTOCOL_IP4,
1869                            DPO_PROTO_IP4,
1870                            VNET_LINK_IP4,
1871                            &pfx_cover,
1872                            &pfx_host1,
1873                            &pfx_host2));
1874 }
1875
1876 static int
1877 mfib_test_rr_v6 (void)
1878 {
1879     /*
1880      * 2 length of prefix to play with
1881      */
1882     const mfib_prefix_t pfx_host1 = {
1883         .fp_len = 128,
1884         .fp_proto = FIB_PROTOCOL_IP6,
1885         .fp_grp_addr = {
1886             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1887             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1888         },
1889     };
1890     const mfib_prefix_t pfx_host2 = {
1891         .fp_len = 256,
1892         .fp_proto = FIB_PROTOCOL_IP6,
1893         .fp_grp_addr = {
1894             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1895             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1896         },
1897         .fp_src_addr = {
1898             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1899             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1900         },
1901     };
1902     const mfib_prefix_t pfx_cover = {
1903         .fp_len = 64,
1904         .fp_proto = FIB_PROTOCOL_IP6,
1905         .fp_grp_addr = {
1906             .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1907             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1908         },
1909     };
1910
1911     return (mfib_test_rr_i(FIB_PROTOCOL_IP6,
1912                            DPO_PROTO_IP6,
1913                            VNET_LINK_IP6,
1914                            &pfx_cover,
1915                            &pfx_host1,
1916                            &pfx_host2));
1917 }
1918
1919 static clib_error_t *
1920 mfib_test (vlib_main_t * vm,
1921            unformat_input_t * input,
1922            vlib_cli_command_t * cmd_arg)
1923 {
1924     int res = 0;
1925
1926     res += mfib_test_mk_intf(4);
1927     res += mfib_test_rr_v4();
1928
1929     if (res)
1930     {
1931         return clib_error_return(0, "MFIB RR V4 Unit Test Failed");
1932     }
1933
1934     res += mfib_test_rr_v6();
1935
1936     if (res)
1937     {
1938         return clib_error_return(0, "MFIB RR V6 Unit Test Failed");
1939     }
1940
1941     res += mfib_test_v4();
1942
1943     if (res)
1944     {
1945         return clib_error_return(0, "MFIB V4 Unit Test Failed");
1946     }
1947
1948     res += mfib_test_v6();
1949
1950     if (res)
1951     {
1952         return clib_error_return(0, "MFIB V6 Unit Test Failed");
1953     }
1954
1955     return (NULL);
1956 }
1957
1958 VLIB_CLI_COMMAND (test_fib_command, static) = {
1959     .path = "test mfib",
1960     .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1961     .function = mfib_test,
1962 };
1963
1964 clib_error_t *
1965 mfib_test_init (vlib_main_t *vm)
1966 {
1967     return 0;
1968 }
1969
1970 VLIB_INIT_FUNCTION (mfib_test_init);