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