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