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