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