FIB Interpose Source
[vpp.git] / src / vnet / mfib / 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     } else {                                                    \
38         fformat(stderr, "PASS:%d: " _comment "\n",              \
39                 __LINE__, ##_args);                             \
40     }                                                           \
41     res;                                                        \
42 })
43 #define MFIB_TEST(_cond, _comment, _args...)                    \
44 {                                                               \
45     if (MFIB_TEST_I(_cond, _comment, ##_args)) {                \
46         return 1;                                               \
47         ASSERT(!("FAIL: " _comment));                           \
48     }                                                           \
49 }
50 #define MFIB_TEST_NS(_cond)                                     \
51 {                                                               \
52     if (MFIB_TEST_I(_cond, "")) {                               \
53         return 1;                                               \
54         ASSERT(!("FAIL: "));                                    \
55     }                                                           \
56 }
57
58 /**
59  * A 'i'm not fussed is this is not efficient' store of test data
60  */
61 typedef struct test_main_t_ {
62     /**
63      * HW if indicies
64      */
65     u32 hw_if_indicies[4];
66     /**
67      * HW interfaces
68      */
69     vnet_hw_interface_t * hw[4];
70
71 } test_main_t;
72 static test_main_t test_main;
73
74 /* fake ethernet device class, distinct from "fake-ethX" */
75 static u8 * format_test_interface_name (u8 * s, va_list * args)
76 {
77   u32 dev_instance = va_arg (*args, u32);
78   return format (s, "test-eth%d", dev_instance);
79 }
80
81 static uword dummy_interface_tx (vlib_main_t * vm,
82                                  vlib_node_runtime_t * node,
83                                  vlib_frame_t * frame)
84 {
85   clib_warning ("you shouldn't be here, leaking buffers...");
86   return frame->n_vectors;
87 }
88
89 static clib_error_t *
90 test_interface_admin_up_down (vnet_main_t * vnm,
91                               u32 hw_if_index,
92                               u32 flags)
93 {
94   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
95     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
96   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
97   return 0;
98 }
99
100 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
101   .name = "Test interface",
102   .format_device_name = format_test_interface_name,
103   .tx_function = dummy_interface_tx,
104   .admin_up_down_function = test_interface_admin_up_down,
105 };
106
107 static u8 *hw_address;
108
109 static int
110 mfib_test_mk_intf (u32 ninterfaces)
111 {
112     clib_error_t * error = NULL;
113     test_main_t *tm = &test_main;
114     u8 byte;
115     int res;
116     u32 i;
117
118     res = 0;
119     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
120
121     for (i=0; i<6; i++)
122     {
123         byte = 0xd0+i;
124         vec_add1(hw_address, byte);
125     }
126
127     for (i = 0; i < ninterfaces; i++)
128     {
129         hw_address[5] = i;
130
131         error = ethernet_register_interface(vnet_get_main(),
132                                             test_interface_device_class.index,
133                                             i /* instance */,
134                                             hw_address,
135                                             &tm->hw_if_indicies[i],
136                                             /* flag change */ 0);
137
138         MFIB_TEST((NULL == error), "ADD interface %d", i);
139
140         error = vnet_hw_interface_set_flags(vnet_get_main(),
141                                             tm->hw_if_indicies[i],
142                                             VNET_HW_INTERFACE_FLAG_LINK_UP);
143         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
144                                           tm->hw_if_indicies[i]);
145         vec_validate (ip4_main.fib_index_by_sw_if_index,
146                       tm->hw[i]->sw_if_index);
147         vec_validate (ip6_main.fib_index_by_sw_if_index,
148                       tm->hw[i]->sw_if_index);
149         ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
150         ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
151
152         vec_validate (ip4_main.mfib_index_by_sw_if_index,
153                       tm->hw[i]->sw_if_index);
154         vec_validate (ip6_main.mfib_index_by_sw_if_index,
155                       tm->hw[i]->sw_if_index);
156         ip4_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
157         ip6_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
158
159         error = vnet_sw_interface_set_flags(vnet_get_main(),
160                                             tm->hw[i]->sw_if_index,
161                                             VNET_SW_INTERFACE_FLAG_ADMIN_UP);
162         MFIB_TEST((NULL == error), "UP interface %d", i);
163     }
164     /*
165      * re-eval after the inevitable realloc
166      */
167     for (i = 0; i < ninterfaces; i++)
168     {
169         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
170                                           tm->hw_if_indicies[i]);
171     }
172
173     return (res);
174 }
175
176 #define MFIB_TEST_REP(_cond, _comment, _args...)                \
177 {                                                               \
178     if (MFIB_TEST_I(_cond, _comment, ##_args)) {                \
179         return (1);                                             \
180     }                                                           \
181 }
182
183 static int
184 mfib_test_validate_rep_v (const replicate_t *rep,
185                           u16 n_buckets,
186                           va_list *ap)
187 {
188     const dpo_id_t *dpo;
189     adj_index_t ai;
190     dpo_type_t dt;
191     int bucket;
192     int res;
193
194     res = 0;
195     MFIB_TEST_REP((n_buckets == rep->rep_n_buckets),
196                   "n_buckets = %d", rep->rep_n_buckets);
197
198     for (bucket = 0; bucket < n_buckets; bucket++)
199     {
200         dt = va_arg(*ap, int);  // type promotion
201         ai = va_arg(*ap, adj_index_t);
202         dpo = replicate_get_bucket_i(rep, bucket);
203
204         MFIB_TEST_REP((dt == dpo->dpoi_type),
205                       "bucket %d stacks on %U",
206                       bucket,
207                       format_dpo_type, dpo->dpoi_type);
208
209         if (DPO_RECEIVE != dt)
210         {
211             MFIB_TEST_REP((ai == dpo->dpoi_index),
212                           "bucket %d [exp:%d] stacks on %U",
213                           bucket, ai,
214                           format_dpo_id, dpo, 0);
215         }
216     }
217     return (res);
218 }
219
220 static fib_forward_chain_type_t
221 fib_forw_chain_type_from_fib_proto (fib_protocol_t proto)
222 {
223     switch (proto)
224     {
225     case FIB_PROTOCOL_IP4:
226         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
227     case FIB_PROTOCOL_IP6:
228         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
229     default:
230         break;
231     }
232     ASSERT(0);
233     return (0);
234 }
235
236
237 static int
238 mfib_test_entry (fib_node_index_t fei,
239                  mfib_entry_flags_t eflags,
240                  int n_buckets,
241                  ...)
242 {
243     const mfib_entry_t *mfe;
244     const replicate_t *rep;
245     mfib_prefix_t pfx;
246     va_list ap;
247     int res;
248
249     va_start(ap, n_buckets);
250
251     res = 0;
252     mfe = mfib_entry_get(fei);
253     mfib_entry_get_prefix(fei, &pfx);
254
255     MFIB_TEST_REP((eflags == mfe->mfe_flags),
256                   "%U has %U expect %U",
257                   format_mfib_prefix, &pfx,
258                   format_mfib_entry_flags, mfe->mfe_flags,
259                   format_mfib_entry_flags, eflags);
260
261     if (0 == n_buckets)
262     {
263         MFIB_TEST_REP((DPO_DROP == mfe->mfe_rep.dpoi_type),
264                       "%U links to %U",
265                       format_mfib_prefix, &pfx,
266                       format_dpo_id, &mfe->mfe_rep, 0);
267     }
268     else
269     {
270         dpo_id_t tmp = DPO_INVALID;
271
272         mfib_entry_contribute_forwarding(
273             fei,
274             fib_forw_chain_type_from_fib_proto(pfx.fp_proto),
275             &tmp);
276         rep = replicate_get(tmp.dpoi_index);
277
278         MFIB_TEST_REP((DPO_REPLICATE == tmp.dpoi_type),
279                       "%U links to %U",
280                       format_mfib_prefix, &pfx,
281                       format_dpo_type, tmp.dpoi_type);
282
283         res = mfib_test_validate_rep_v(rep, n_buckets, &ap);
284
285         dpo_reset(&tmp);
286     }
287
288     va_end(ap);
289
290     return (res);
291 }
292
293 static int
294 mfib_test_entry_itf (fib_node_index_t fei,
295                      u32 sw_if_index,
296                      mfib_itf_flags_t flags)
297 {
298     const mfib_entry_t *mfe;
299     const mfib_itf_t *mfi;
300     mfib_prefix_t pfx;
301     int res;
302
303     res = 0;
304     mfe = mfib_entry_get(fei);
305     mfi = mfib_entry_get_itf(mfe, sw_if_index);
306     mfib_entry_get_prefix(fei, &pfx);
307
308     MFIB_TEST_REP((NULL != mfi),
309                   "%U has interface %d",
310                   format_mfib_prefix, &pfx, sw_if_index);
311
312     MFIB_TEST_REP((flags == mfi->mfi_flags),
313                   "%U interface %d has flags %U expect %U",
314                   format_mfib_prefix, &pfx, sw_if_index,
315                   format_mfib_itf_flags, flags,
316                   format_mfib_itf_flags, mfi->mfi_flags);
317
318     return (res);
319 }
320
321 static int
322 mfib_test_entry_no_itf (fib_node_index_t fei,
323                         u32 sw_if_index)
324 {
325     const mfib_entry_t *mfe;
326     const mfib_itf_t *mfi;
327     mfib_prefix_t pfx;
328     int res;
329
330     res = 0;
331     mfe = mfib_entry_get(fei);
332     mfi = mfib_entry_get_itf(mfe, sw_if_index);
333     mfib_entry_get_prefix(fei, &pfx);
334
335     MFIB_TEST_REP((NULL == mfi),
336                   "%U has no interface %d",
337                   format_mfib_prefix, &pfx, sw_if_index);
338
339     return (res);
340 }
341
342 static int
343 mfib_test_i (fib_protocol_t PROTO,
344              vnet_link_t LINKT,
345              const mfib_prefix_t *pfx_no_forward,
346              const mfib_prefix_t *pfx_s_g,
347              const mfib_prefix_t *pfx_star_g_1,
348              const mfib_prefix_t *pfx_star_g_2,
349              const mfib_prefix_t *pfx_star_g_3,
350              const mfib_prefix_t *pfx_star_g_slash_m)
351 {
352     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;
353     u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
354     fib_node_index_t ai_1, ai_2, ai_3;
355     test_main_t *tm;
356     int res;
357
358     mfib_prefix_t all_1s;
359     memset(&all_1s, 0xfd, sizeof(all_1s));
360
361     res = 0;
362     n_entries = pool_elts(mfib_entry_pool);
363     n_itfs = pool_elts(mfib_itf_pool);
364     n_reps = pool_elts(replicate_pool);
365     n_pls = fib_path_list_pool_size();
366     tm = &test_main;
367
368     ai_1 = adj_mcast_add_or_lock(PROTO,
369                                  LINKT,
370                                  tm->hw[1]->sw_if_index);
371     ai_2 = adj_mcast_add_or_lock(PROTO,
372                                  LINKT,
373                                  tm->hw[2]->sw_if_index);
374     ai_3 = adj_mcast_add_or_lock(PROTO,
375                                  LINKT,
376                                  tm->hw[3]->sw_if_index);
377
378     MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
379
380     /* Find or create FIB table 11 */
381     fib_index = mfib_table_find_or_create_and_lock(PROTO, 11, MFIB_SOURCE_API);
382
383     mfib_prefix_t pfx_dft = {
384         .fp_len = 0,
385         .fp_proto = PROTO,
386     };
387     mfei_dflt = mfib_table_lookup_exact_match(fib_index, &pfx_dft);
388     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
389     MFIB_TEST(!mfib_test_entry(mfei_dflt,
390                                MFIB_ENTRY_FLAG_DROP,
391                                0),
392               "(*,*) no replcaitions");
393
394     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
395     MFIB_TEST(!mfib_test_entry(mfei_dflt,
396                                MFIB_ENTRY_FLAG_DROP,
397                                0),
398               "(*,*) no replcaitions");
399
400
401     fib_route_path_t path_via_if0 = {
402         .frp_proto = fib_proto_to_dpo(PROTO),
403         .frp_addr = zero_addr,
404         .frp_sw_if_index = tm->hw[0]->sw_if_index,
405         .frp_fib_index = ~0,
406         .frp_weight = 0,
407         .frp_flags = 0,
408     };
409
410     mfib_table_entry_path_update(fib_index,
411                                  pfx_no_forward,
412                                  MFIB_SOURCE_API,
413                                  &path_via_if0,
414                                  MFIB_ITF_FLAG_ACCEPT);
415
416     mfei_no_f = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
417     MFIB_TEST(!mfib_test_entry(mfei_no_f,
418                                MFIB_ENTRY_FLAG_NONE,
419                                0),
420               "%U no replcaitions",
421               format_mfib_prefix, pfx_no_forward);
422     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_no_f, tm->hw[0]->sw_if_index,
423                                       MFIB_ITF_FLAG_ACCEPT));
424
425     fib_route_path_t path_via_if1 = {
426         .frp_proto = fib_proto_to_dpo(PROTO),
427         .frp_addr = zero_addr,
428         .frp_sw_if_index = tm->hw[1]->sw_if_index,
429         .frp_fib_index = ~0,
430         .frp_weight = 0,
431         .frp_flags = 0,
432     };
433     fib_route_path_t path_via_if2 = {
434         .frp_proto = fib_proto_to_dpo(PROTO),
435         .frp_addr = zero_addr,
436         .frp_sw_if_index = tm->hw[2]->sw_if_index,
437         .frp_fib_index = ~0,
438         .frp_weight = 0,
439         .frp_flags = 0,
440     };
441     fib_route_path_t path_via_if3 = {
442         .frp_proto = fib_proto_to_dpo(PROTO),
443         .frp_addr = zero_addr,
444         .frp_sw_if_index = tm->hw[3]->sw_if_index,
445         .frp_fib_index = ~0,
446         .frp_weight = 0,
447         .frp_flags = 0,
448     };
449     fib_route_path_t path_for_us = {
450         .frp_proto = fib_proto_to_dpo(PROTO),
451         .frp_addr = zero_addr,
452         .frp_sw_if_index = 0xffffffff,
453         .frp_fib_index = ~0,
454         .frp_weight = 0,
455         .frp_flags = FIB_ROUTE_PATH_LOCAL,
456     };
457
458     /*
459      * An (S,G) with 1 accepting and 3 forwarding paths
460      */
461     mfib_table_entry_path_update(fib_index,
462                                  pfx_s_g,
463                                  MFIB_SOURCE_API,
464                                  &path_via_if0,
465                                  MFIB_ITF_FLAG_ACCEPT);
466     mfib_table_entry_path_update(fib_index,
467                                  pfx_s_g,
468                                  MFIB_SOURCE_API,
469                                  &path_via_if1,
470                                  MFIB_ITF_FLAG_FORWARD);
471     mfib_table_entry_path_update(fib_index,
472                                  pfx_s_g,
473                                  MFIB_SOURCE_API,
474                                  &path_via_if2,
475                                  MFIB_ITF_FLAG_FORWARD);
476     mfib_table_entry_path_update(fib_index,
477                                  pfx_s_g,
478                                  MFIB_SOURCE_API,
479                                  &path_via_if3,
480                                  (MFIB_ITF_FLAG_FORWARD |
481                                   MFIB_ITF_FLAG_NEGATE_SIGNAL));
482
483     mfei_s_g = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
484
485     MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_s_g,
486               "%U present",
487               format_mfib_prefix, pfx_s_g);
488     MFIB_TEST(!mfib_test_entry(mfei_s_g,
489                                MFIB_ENTRY_FLAG_NONE,
490                                3,
491                                DPO_ADJACENCY_MCAST, ai_1,
492                                DPO_ADJACENCY_MCAST, ai_2,
493                                DPO_ADJACENCY_MCAST, ai_3),
494               "%U replicate ok",
495               format_mfib_prefix, pfx_s_g);
496     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[0]->sw_if_index,
497                                       MFIB_ITF_FLAG_ACCEPT));
498     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[1]->sw_if_index,
499                                       MFIB_ITF_FLAG_FORWARD));
500     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[2]->sw_if_index,
501                                       MFIB_ITF_FLAG_FORWARD));
502     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[3]->sw_if_index,
503                                       (MFIB_ITF_FLAG_FORWARD |
504                                        MFIB_ITF_FLAG_NEGATE_SIGNAL)));
505
506     /*
507      * A (*,G), which the same G as the (S,G).
508      * different paths. test our LPM.
509      */
510     mfei_g_1 = mfib_table_entry_path_update(fib_index,
511                                             pfx_star_g_1,
512                                             MFIB_SOURCE_API,
513                                             &path_via_if0,
514                                             MFIB_ITF_FLAG_ACCEPT);
515     mfib_table_entry_path_update(fib_index,
516                                  pfx_star_g_1,
517                                  MFIB_SOURCE_API,
518                                  &path_via_if1,
519                                  MFIB_ITF_FLAG_FORWARD);
520
521     /*
522      * test we find the *,G and S,G via LPM and exact matches
523      */
524     mfei = mfib_table_lookup_exact_match(fib_index,
525                                          pfx_star_g_1);
526     MFIB_TEST(mfei == mfei_g_1,
527               "%U found via exact match",
528               format_mfib_prefix, pfx_star_g_1);
529     MFIB_TEST(!mfib_test_entry(mfei,
530                                MFIB_ENTRY_FLAG_NONE,
531                                1,
532                                DPO_ADJACENCY_MCAST, ai_1),
533               "%U replicate ok",
534               format_mfib_prefix, pfx_star_g_1);
535
536     mfei = mfib_table_lookup(fib_index,
537                              pfx_star_g_1);
538     MFIB_TEST(mfei == mfei_g_1,
539               "%U found via LP match",
540               format_mfib_prefix, pfx_star_g_1);
541
542     MFIB_TEST(!mfib_test_entry(mfei,
543                                MFIB_ENTRY_FLAG_NONE,
544                                1,
545                                DPO_ADJACENCY_MCAST, ai_1),
546               "%U replicate ok",
547               format_mfib_prefix, pfx_star_g_1);
548
549     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
550     MFIB_TEST(mfei == mfei_s_g,
551               "%U found via exact match",
552               format_mfib_prefix, pfx_s_g);
553
554     MFIB_TEST(!mfib_test_entry(mfei,
555                                MFIB_ENTRY_FLAG_NONE,
556                                3,
557                                DPO_ADJACENCY_MCAST, ai_1,
558                                DPO_ADJACENCY_MCAST, ai_2,
559                                DPO_ADJACENCY_MCAST, ai_3),
560               "%U replicate OK",
561               format_mfib_prefix, pfx_s_g);
562     mfei = mfib_table_lookup(fib_index, pfx_s_g);
563     MFIB_TEST(mfei == mfei_s_g,
564               "%U found via LP match",
565               format_mfib_prefix, pfx_s_g);
566
567     MFIB_TEST(!mfib_test_entry(mfei,
568                                MFIB_ENTRY_FLAG_NONE,
569                                3,
570                                DPO_ADJACENCY_MCAST, ai_1,
571                                DPO_ADJACENCY_MCAST, ai_2,
572                                DPO_ADJACENCY_MCAST, ai_3),
573               "%U replicate OK",
574               format_mfib_prefix, pfx_s_g);
575
576     /*
577      * A (*,G/m), which the same root G as the (*,G).
578      * different paths. test our LPM.
579      */
580     mfei_g_m = mfib_table_entry_path_update(fib_index,
581                                             pfx_star_g_slash_m,
582                                             MFIB_SOURCE_API,
583                                             &path_via_if2,
584                                             MFIB_ITF_FLAG_ACCEPT);
585     mfib_table_entry_path_update(fib_index,
586                                  pfx_star_g_slash_m,
587                                  MFIB_SOURCE_API,
588                                  &path_via_if3,
589                                  MFIB_ITF_FLAG_FORWARD);
590
591     /*
592      * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
593      */
594     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
595     MFIB_TEST((mfei_g_1 == mfei),
596               "%U found via DP LPM: %d",
597               format_mfib_prefix, pfx_star_g_1, mfei);
598
599     MFIB_TEST(!mfib_test_entry(mfei,
600                                MFIB_ENTRY_FLAG_NONE,
601                                1,
602                                DPO_ADJACENCY_MCAST, ai_1),
603               "%U replicate ok",
604               format_mfib_prefix, pfx_star_g_1);
605
606     mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
607
608     MFIB_TEST(!mfib_test_entry(mfei,
609                                MFIB_ENTRY_FLAG_NONE,
610                                1,
611                                DPO_ADJACENCY_MCAST, ai_1),
612               "%U replicate ok",
613               format_mfib_prefix, pfx_star_g_1);
614
615     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
616
617     MFIB_TEST(!mfib_test_entry(mfei,
618                                MFIB_ENTRY_FLAG_NONE,
619                                3,
620                                DPO_ADJACENCY_MCAST, ai_1,
621                                DPO_ADJACENCY_MCAST, ai_2,
622                                DPO_ADJACENCY_MCAST, ai_3),
623               "%U replicate OK",
624               format_mfib_prefix, pfx_s_g);
625     mfei = mfib_table_lookup(fib_index, pfx_s_g);
626
627     MFIB_TEST(!mfib_test_entry(mfei,
628                                MFIB_ENTRY_FLAG_NONE,
629                                3,
630                                DPO_ADJACENCY_MCAST, ai_1,
631                                DPO_ADJACENCY_MCAST, ai_2,
632                                DPO_ADJACENCY_MCAST, ai_3),
633               "%U replicate OK",
634               format_mfib_prefix, pfx_s_g);
635
636     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
637     MFIB_TEST(mfei = mfei_g_m,
638               "%U Found via exact match",
639               format_mfib_prefix, pfx_star_g_slash_m);
640     MFIB_TEST(!mfib_test_entry(mfei,
641                                MFIB_ENTRY_FLAG_NONE,
642                                1,
643                                DPO_ADJACENCY_MCAST, ai_3),
644               "%U replicate OK",
645               format_mfib_prefix, pfx_star_g_slash_m);
646     MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
647               "%U found via LPM",
648               format_mfib_prefix, pfx_star_g_slash_m);
649
650     /*
651      * Add a for-us path
652      */
653     mfei = mfib_table_entry_path_update(fib_index,
654                                         pfx_s_g,
655                                         MFIB_SOURCE_API,
656                                         &path_for_us,
657                                         MFIB_ITF_FLAG_FORWARD);
658
659     MFIB_TEST(!mfib_test_entry(mfei,
660                                MFIB_ENTRY_FLAG_NONE,
661                                4,
662                                DPO_ADJACENCY_MCAST, ai_1,
663                                DPO_ADJACENCY_MCAST, ai_2,
664                                DPO_ADJACENCY_MCAST, ai_3,
665                                DPO_RECEIVE, 0),
666               "%U replicate OK",
667               format_mfib_prefix, pfx_s_g);
668
669     /*
670      * remove a for-us path
671      */
672     mfib_table_entry_path_remove(fib_index,
673                                  pfx_s_g,
674                                  MFIB_SOURCE_API,
675                                  &path_for_us);
676
677     MFIB_TEST(!mfib_test_entry(mfei,
678                                MFIB_ENTRY_FLAG_NONE,
679                                3,
680                                DPO_ADJACENCY_MCAST, ai_1,
681                                DPO_ADJACENCY_MCAST, ai_2,
682                                DPO_ADJACENCY_MCAST, ai_3),
683               "%U replicate OK",
684               format_mfib_prefix, pfx_s_g);
685
686     /*
687      * update an existing forwarding path to be only accepting
688      *   - expect it to be removed from the replication set.
689      */
690     mfib_table_entry_path_update(fib_index,
691                                  pfx_s_g,
692                                  MFIB_SOURCE_API,
693                                  &path_via_if3,
694                                  MFIB_ITF_FLAG_ACCEPT);
695
696     MFIB_TEST(!mfib_test_entry(mfei,
697                                MFIB_ENTRY_FLAG_NONE,
698                                2,
699                                DPO_ADJACENCY_MCAST, ai_1,
700                                DPO_ADJACENCY_MCAST, ai_2),
701               "%U replicate OK",
702               format_mfib_prefix, pfx_s_g);
703     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
704                                       MFIB_ITF_FLAG_ACCEPT));
705     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
706                                       MFIB_ITF_FLAG_FORWARD));
707     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
708                                       MFIB_ITF_FLAG_FORWARD));
709     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
710                                       MFIB_ITF_FLAG_ACCEPT));
711     /*
712      * Make the path forwarding again
713      *  - expect it to be added back to the replication set
714      */
715     mfib_table_entry_path_update(fib_index,
716                                  pfx_s_g,
717                                  MFIB_SOURCE_API,
718                                  &path_via_if3,
719                                  (MFIB_ITF_FLAG_FORWARD |
720                                   MFIB_ITF_FLAG_ACCEPT |
721                                   MFIB_ITF_FLAG_NEGATE_SIGNAL));
722
723     mfei = mfib_table_lookup_exact_match(fib_index,
724                                          pfx_s_g);
725
726     MFIB_TEST(!mfib_test_entry(mfei,
727                                MFIB_ENTRY_FLAG_NONE,
728                                3,
729                                DPO_ADJACENCY_MCAST, ai_1,
730                                DPO_ADJACENCY_MCAST, ai_2,
731                                DPO_ADJACENCY_MCAST, ai_3),
732               "%U replicate OK",
733               format_mfib_prefix, pfx_s_g);
734     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
735                                       MFIB_ITF_FLAG_ACCEPT));
736     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
737                                       MFIB_ITF_FLAG_FORWARD));
738     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
739                                       MFIB_ITF_FLAG_FORWARD));
740     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
741                                       (MFIB_ITF_FLAG_FORWARD |
742                                        MFIB_ITF_FLAG_ACCEPT |
743                                        MFIB_ITF_FLAG_NEGATE_SIGNAL)));
744
745     /*
746      * update flags on the entry
747      */
748     mfib_table_entry_update(fib_index,
749                             pfx_s_g,
750                             MFIB_SOURCE_API,
751                             MFIB_RPF_ID_NONE,
752                             MFIB_ENTRY_FLAG_SIGNAL);
753     MFIB_TEST(!mfib_test_entry(mfei,
754                                MFIB_ENTRY_FLAG_SIGNAL,
755                                3,
756                                DPO_ADJACENCY_MCAST, ai_1,
757                                DPO_ADJACENCY_MCAST, ai_2,
758                                DPO_ADJACENCY_MCAST, ai_3),
759               "%U replicate OK",
760               format_mfib_prefix, pfx_s_g);
761
762     /*
763      * remove paths
764      */
765     mfib_table_entry_path_remove(fib_index,
766                                  pfx_s_g,
767                                  MFIB_SOURCE_API,
768                                  &path_via_if3);
769
770     MFIB_TEST(!mfib_test_entry(mfei,
771                                MFIB_ENTRY_FLAG_SIGNAL,
772                                2,
773                                DPO_ADJACENCY_MCAST, ai_1,
774                                DPO_ADJACENCY_MCAST, ai_2),
775               "%U replicate OK",
776               format_mfib_prefix, pfx_s_g);
777     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
778                                       MFIB_ITF_FLAG_ACCEPT));
779     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
780                                       MFIB_ITF_FLAG_FORWARD));
781     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
782                                       MFIB_ITF_FLAG_FORWARD));
783     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
784
785     mfib_table_entry_path_remove(fib_index,
786                                  pfx_s_g,
787                                  MFIB_SOURCE_API,
788                                  &path_via_if1);
789
790     MFIB_TEST(!mfib_test_entry(mfei,
791                                MFIB_ENTRY_FLAG_SIGNAL,
792                                1,
793                                DPO_ADJACENCY_MCAST, ai_2),
794               "%U replicate OK",
795               format_mfib_prefix, pfx_s_g);
796     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
797                                       MFIB_ITF_FLAG_ACCEPT));
798     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
799                                       MFIB_ITF_FLAG_FORWARD));
800     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
801
802     /*
803      * remove the accpeting only interface
804      */
805     mfib_table_entry_path_remove(fib_index,
806                                  pfx_s_g,
807                                  MFIB_SOURCE_API,
808                                  &path_via_if0);
809
810     MFIB_TEST(!mfib_test_entry(mfei,
811                                MFIB_ENTRY_FLAG_SIGNAL,
812                                1,
813                                DPO_ADJACENCY_MCAST, ai_2),
814               "%U replicate OK",
815               format_mfib_prefix, pfx_s_g);
816     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
817                                       MFIB_ITF_FLAG_FORWARD));
818     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index));
819     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index));
820     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
821
822     /*
823      * remove the last path, the entry still has flags so it remains
824      */
825     mfib_table_entry_path_remove(fib_index,
826                                  pfx_s_g,
827                                  MFIB_SOURCE_API,
828                                  &path_via_if2);
829
830     MFIB_TEST(!mfib_test_entry(mfei,
831                                MFIB_ENTRY_FLAG_SIGNAL,
832                                0),
833               "%U no replications",
834               format_mfib_prefix, pfx_s_g);
835
836     /*
837      * update flags on the entry
838      */
839     mfib_table_entry_update(fib_index,
840                             pfx_s_g,
841                             MFIB_SOURCE_API,
842                             MFIB_RPF_ID_NONE,
843                             (MFIB_ENTRY_FLAG_SIGNAL |
844                              MFIB_ENTRY_FLAG_CONNECTED));
845     MFIB_TEST(!mfib_test_entry(mfei,
846                                (MFIB_ENTRY_FLAG_SIGNAL |
847                                 MFIB_ENTRY_FLAG_CONNECTED),
848                                0),
849               "%U no replications",
850               format_mfib_prefix, pfx_s_g);
851
852     /*
853      * An entry with a NS interface
854      */
855     mfei_g_2 = mfib_table_entry_path_update(fib_index,
856                                             pfx_star_g_2,
857                                             MFIB_SOURCE_API,
858                                             &path_via_if0,
859                                             (MFIB_ITF_FLAG_ACCEPT |
860                                              MFIB_ITF_FLAG_NEGATE_SIGNAL));
861     MFIB_TEST(!mfib_test_entry(mfei_g_2,
862                                MFIB_ENTRY_FLAG_NONE,
863                                0),
864               "%U No replications",
865               format_mfib_prefix, pfx_star_g_2);
866
867     /*
868      * Simulate a signal from the data-plane
869      */
870     {
871         mfib_entry_t *mfe;
872         mfib_itf_t *mfi;
873
874         mfe = mfib_entry_get(mfei_g_2);
875         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
876
877         mfib_signal_push(mfe, mfi, NULL);
878     }
879
880     /*
881      * An entry with a NS interface
882      */
883     mfei_g_3 = mfib_table_entry_path_update(fib_index,
884                                             pfx_star_g_3,
885                                             MFIB_SOURCE_API,
886                                             &path_via_if0,
887                                             (MFIB_ITF_FLAG_ACCEPT |
888                                              MFIB_ITF_NEGATE_SIGNAL));
889     MFIB_TEST(!mfib_test_entry(mfei_g_3,
890                                MFIB_ENTRY_FLAG_NONE,
891                                0),
892               "%U No replications",
893               format_mfib_prefix, pfx_star_g_3);
894
895     /*
896      * Simulate a signal from the data-plane
897      */
898     {
899         mfib_entry_t *mfe;
900         mfib_itf_t *mfi;
901
902         mfe = mfib_entry_get(mfei_g_3);
903         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
904
905         mfib_signal_push(mfe, mfi, NULL);
906     }
907
908     if (FIB_PROTOCOL_IP6 == PROTO)
909     {
910         /*
911          * All the entries are present. let's ensure we can find them all
912          * via exact and longest prefix matches.
913          */
914         /*
915          * A source address we will never match
916          */
917         ip6_address_t src = {
918             .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
919             .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
920         };
921
922         /*
923          * Find the (*,G/m)
924          */
925         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
926                        ip6_mfib_get(fib_index),
927                        &src,
928                        &pfx_star_g_slash_m->fp_grp_addr.ip6)),
929                   "%U found via DP LPM grp=%U",
930                   format_mfib_prefix, pfx_star_g_slash_m,
931                   format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
932
933         ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
934         tmp.as_u8[15] = 0xff;
935
936         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
937                        ip6_mfib_get(fib_index),
938                        &pfx_s_g->fp_src_addr.ip6,
939                        &tmp)),
940                   "%U found via DP LPM grp=%U",
941                   format_mfib_prefix, pfx_star_g_slash_m,
942                   format_ip6_address, &tmp);
943
944         /*
945          * Find the (S,G).
946          */
947         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
948                                       &pfx_s_g->fp_src_addr.ip6,
949                                       &pfx_s_g->fp_grp_addr.ip6);
950         MFIB_TEST((mfei_s_g == mfei),
951                   "%U found via DP LPM: %d",
952                   format_mfib_prefix, pfx_s_g, mfei);
953
954         /*
955          * Find the 3 (*,G) s
956          */
957         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
958                                       &src,
959                                       &pfx_star_g_1->fp_grp_addr.ip6);
960         MFIB_TEST((mfei_g_1 == mfei),
961                   "%U found via DP LPM: %d",
962                   format_mfib_prefix, pfx_star_g_1, mfei);
963         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
964                                       &src,
965                                       &pfx_star_g_2->fp_grp_addr.ip6);
966         MFIB_TEST((mfei_g_2 == mfei),
967                   "%U found via DP LPM: %d",
968                   format_mfib_prefix, pfx_star_g_2, mfei);
969         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
970                                       &src,
971                                       &pfx_star_g_3->fp_grp_addr.ip6);
972         MFIB_TEST((mfei_g_3 == mfei),
973                   "%U found via DP LPM: %d",
974                   format_mfib_prefix, pfx_star_g_3, mfei);
975     }
976
977     /*
978      * remove flags on the entry. This is the last of the
979      * state associated with the entry, so now it goes.
980      */
981     mfib_table_entry_update(fib_index,
982                             pfx_s_g,
983                             MFIB_SOURCE_API,
984                             MFIB_RPF_ID_NONE,
985                             MFIB_ENTRY_FLAG_NONE);
986     mfei = mfib_table_lookup_exact_match(fib_index,
987                                          pfx_s_g);
988     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
989               "%U gone",
990               format_mfib_prefix, pfx_s_g);
991
992     /*
993      * remove the last path on the no forward entry - the last entry
994      */
995     mfib_table_entry_path_remove(fib_index,
996                                  pfx_no_forward,
997                                  MFIB_SOURCE_API,
998                                  &path_via_if0);
999
1000     mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
1001     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1002               "%U gone",
1003               format_mfib_prefix, pfx_no_forward);
1004
1005     /*
1006      * hard delete the (*,232.1.1.1)
1007      */
1008     mfib_table_entry_delete(fib_index,
1009                             pfx_star_g_1,
1010                             MFIB_SOURCE_API);
1011
1012     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1013     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1014               "%U gone",
1015               format_mfib_prefix, pfx_star_g_1);
1016     /*
1017      * remove the entry whilst the signal is pending
1018      */
1019     mfib_table_entry_delete(fib_index,
1020                             pfx_star_g_2,
1021                             MFIB_SOURCE_API);
1022
1023     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1024     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1025               "%U Gone",
1026               format_mfib_prefix, pfx_star_g_2);
1027     mfib_table_entry_delete(fib_index,
1028                             pfx_star_g_3,
1029                             MFIB_SOURCE_API);
1030
1031     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1032     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1033               "%U Gone",
1034               format_mfib_prefix, pfx_star_g_3);
1035
1036     mfib_table_entry_delete(fib_index,
1037                             pfx_star_g_slash_m,
1038                             MFIB_SOURCE_API);
1039
1040     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1041     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1042               "%U Gone",
1043               format_mfib_prefix, pfx_star_g_slash_m);
1044
1045     /*
1046      * Add a prefix as a special/exclusive route
1047      */
1048     dpo_id_t td = DPO_INVALID;
1049     index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
1050
1051     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
1052     replicate_set_bucket(repi, 0, &td);
1053
1054     mfei = mfib_table_entry_special_add(fib_index,
1055                                         pfx_star_g_3,
1056                                         MFIB_SOURCE_SRv6,
1057                                         MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1058                                         repi);
1059     MFIB_TEST(!mfib_test_entry(mfei,
1060                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1061                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1062                                1,
1063                                DPO_ADJACENCY_MCAST, ai_2),
1064               "%U exclusive replicate OK",
1065               format_mfib_prefix, pfx_star_g_3);
1066
1067     /*
1068      * update a special/exclusive route
1069      */
1070     index_t repi2 = replicate_create(1, fib_proto_to_dpo(PROTO));
1071
1072     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1);
1073     replicate_set_bucket(repi2, 0, &td);
1074
1075     mfei = mfib_table_entry_special_add(fib_index,
1076                                         pfx_star_g_3,
1077                                         MFIB_SOURCE_SRv6,
1078                                         MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1079                                         repi2);
1080     MFIB_TEST(!mfib_test_entry(mfei,
1081                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1082                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1083                                1,
1084                                DPO_ADJACENCY_MCAST, ai_1),
1085               "%U exclusive update replicate OK",
1086               format_mfib_prefix, pfx_star_g_3);
1087
1088     mfib_table_entry_delete(fib_index,
1089                             pfx_star_g_3,
1090                             MFIB_SOURCE_SRv6);
1091     dpo_reset(&td);
1092
1093     /*
1094      * A Multicast LSP. This a mLDP head-end
1095      */
1096     fib_node_index_t ai_mpls_10_10_10_1, lfei;
1097     ip46_address_t nh_10_10_10_1 = {
1098         .ip4 = {
1099             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1100         },
1101     };
1102     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1103                                              VNET_LINK_MPLS,
1104                                              &nh_10_10_10_1,
1105                                              tm->hw[0]->sw_if_index);
1106
1107     fib_prefix_t pfx_3500 = {
1108         .fp_len = 21,
1109         .fp_proto = FIB_PROTOCOL_MPLS,
1110         .fp_label = 3500,
1111         .fp_eos = MPLS_EOS,
1112         .fp_payload_proto = DPO_PROTO_IP4,
1113     };
1114     fib_test_rep_bucket_t mc_0 = {
1115         .type = FT_REP_LABEL_O_ADJ,
1116         .label_o_adj = {
1117             .adj = ai_mpls_10_10_10_1,
1118             .label = 3300,
1119             .eos = MPLS_EOS,
1120         },
1121     };
1122     fib_mpls_label_t *l3300 = NULL, fml3300 = {
1123         .fml_value = 3300,
1124     };
1125     vec_add1(l3300, fml3300);
1126
1127     /*
1128      * MPLS enable an interface so we get the MPLS table created
1129      */
1130     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
1131     mpls_sw_interface_enable_disable(&mpls_main,
1132                                      tm->hw[0]->sw_if_index,
1133                                      1, 0);
1134
1135     lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1136                                            &pfx_3500,
1137                                            FIB_SOURCE_API,
1138                                            FIB_ENTRY_FLAG_MULTICAST,
1139                                            DPO_PROTO_IP4,
1140                                            &nh_10_10_10_1,
1141                                            tm->hw[0]->sw_if_index,
1142                                            ~0, // invalid fib index
1143                                            1,
1144                                            l3300,
1145                                            FIB_ROUTE_PATH_FLAG_NONE);
1146     MFIB_TEST(!fib_test_validate_entry(lfei,
1147                                        FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1148                                        1,
1149                                        &mc_0),
1150               "3500 via replicate over 10.10.10.1");
1151
1152     /*
1153      * An (S,G) that resolves via the mLDP head-end
1154      */
1155     fib_route_path_t path_via_mldp = {
1156         .frp_proto = DPO_PROTO_MPLS,
1157         .frp_local_label = pfx_3500.fp_label,
1158         .frp_eos = MPLS_EOS,
1159         .frp_sw_if_index = 0xffffffff,
1160         .frp_fib_index = 0,
1161         .frp_weight = 1,
1162         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1163     };
1164     dpo_id_t mldp_dpo = DPO_INVALID;
1165
1166     fib_entry_contribute_forwarding(lfei,
1167                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1168                                     &mldp_dpo);
1169
1170     mfei = mfib_table_entry_path_update(fib_index,
1171                                         pfx_s_g,
1172                                         MFIB_SOURCE_API,
1173                                         &path_via_mldp,
1174                                         MFIB_ITF_FLAG_FORWARD);
1175
1176     MFIB_TEST(!mfib_test_entry(mfei,
1177                                MFIB_ENTRY_FLAG_NONE,
1178                                1,
1179                                DPO_REPLICATE, mldp_dpo.dpoi_index),
1180               "%U over-mLDP replicate OK",
1181               format_mfib_prefix, pfx_s_g);
1182
1183     /*
1184      * add a for-us path. this tests two types of non-attached paths on one entry
1185      */
1186     mfei = mfib_table_entry_path_update(fib_index,
1187                                         pfx_s_g,
1188                                         MFIB_SOURCE_API,
1189                                         &path_for_us,
1190                                         MFIB_ITF_FLAG_FORWARD);
1191     MFIB_TEST(!mfib_test_entry(mfei,
1192                                MFIB_ENTRY_FLAG_NONE,
1193                                2,
1194                                DPO_REPLICATE, mldp_dpo.dpoi_index,
1195                                DPO_RECEIVE, 0),
1196               "%U mLDP+for-us replicate OK",
1197               format_mfib_prefix, pfx_s_g);
1198
1199     mfib_table_entry_delete(fib_index,
1200                             pfx_s_g,
1201                             MFIB_SOURCE_API);
1202     fib_table_entry_delete(0,
1203                            &pfx_3500,
1204                            FIB_SOURCE_API);
1205     dpo_reset(&mldp_dpo);
1206
1207     /*
1208      * Unlock the table - it's the last lock so should be gone thereafter
1209      */
1210     mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1211
1212     MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1213                mfib_table_find(PROTO, fib_index)),
1214               "MFIB table %d gone", fib_index);
1215
1216     adj_unlock(ai_1);
1217     adj_unlock(ai_2);
1218     adj_unlock(ai_3);
1219
1220     /*
1221      * MPLS disable the interface
1222      */
1223     mpls_sw_interface_enable_disable(&mpls_main,
1224                                      tm->hw[0]->sw_if_index,
1225                                      0, 0);
1226     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1227
1228     /*
1229      * test we've leaked no resources
1230      */
1231     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1232     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1233               n_pls, fib_path_list_pool_size());
1234     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1235               n_reps, pool_elts(replicate_pool));
1236     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1237               " No more entries %d!=%d",
1238               n_entries, pool_elts(mfib_entry_pool));
1239     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1240               " No more Interfaces %d!=%d",
1241               n_itfs, pool_elts(mfib_itf_pool));
1242
1243     return (res);
1244 }
1245
1246 static int
1247 mfib_test_v4 (void)
1248 {
1249     const mfib_prefix_t pfx_224_s_8 = {
1250         .fp_len = 8,
1251         .fp_proto = FIB_PROTOCOL_IP4,
1252         .fp_grp_addr = {
1253             .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1254         }
1255     };
1256     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1257         .fp_len = 64,
1258         .fp_proto = FIB_PROTOCOL_IP4,
1259         .fp_grp_addr = {
1260             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1261         },
1262         .fp_src_addr = {
1263             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1264         },
1265     };
1266     const mfib_prefix_t pfx_239_1_1_1 = {
1267         .fp_len = 32,
1268         .fp_proto = FIB_PROTOCOL_IP4,
1269         .fp_grp_addr = {
1270             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1271         },
1272         .fp_src_addr = {
1273             .ip4.as_u32 = 0,
1274         },
1275     };
1276     const mfib_prefix_t pfx_239_1_1_2 = {
1277         .fp_len = 32,
1278         .fp_proto = FIB_PROTOCOL_IP4,
1279         .fp_grp_addr = {
1280             .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1281         },
1282         .fp_src_addr = {
1283             .ip4.as_u32 = 0,
1284         },
1285     };
1286     const mfib_prefix_t pfx_239_1_1_3 = {
1287         .fp_len = 32,
1288         .fp_proto = FIB_PROTOCOL_IP4,
1289         .fp_grp_addr = {
1290             .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1291         },
1292         .fp_src_addr = {
1293             .ip4.as_u32 = 0,
1294         },
1295     };
1296     const mfib_prefix_t pfx_239 = {
1297         .fp_len = 8,
1298         .fp_proto = FIB_PROTOCOL_IP4,
1299         .fp_grp_addr = {
1300             .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1301         },
1302         .fp_src_addr = {
1303             .ip4.as_u32 = 0,
1304         },
1305     };
1306
1307     return (mfib_test_i(FIB_PROTOCOL_IP4,
1308                         VNET_LINK_IP4,
1309                         &pfx_224_s_8,
1310                         &pfx_1_1_1_1_c_239_1_1_1,
1311                         &pfx_239_1_1_1,
1312                         &pfx_239_1_1_2,
1313                         &pfx_239_1_1_3,
1314                         &pfx_239));
1315 }
1316
1317 static int
1318 mfib_test_v6 (void)
1319 {
1320     const mfib_prefix_t pfx_ffd_s_12 = {
1321         .fp_len = 12,
1322         .fp_proto = FIB_PROTOCOL_IP6,
1323         .fp_grp_addr = {
1324             .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1325         }
1326     };
1327     const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1328         .fp_len = 256,
1329         .fp_proto = FIB_PROTOCOL_IP6,
1330         .fp_grp_addr = {
1331             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1332             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1333         },
1334         .fp_src_addr = {
1335             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1336             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1337         },
1338     };
1339     const mfib_prefix_t pfx_ff_1 = {
1340         .fp_len = 128,
1341         .fp_proto = FIB_PROTOCOL_IP6,
1342         .fp_grp_addr = {
1343             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1344             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1345         },
1346     };
1347     const mfib_prefix_t pfx_ff_2 = {
1348         .fp_len = 128,
1349         .fp_proto = FIB_PROTOCOL_IP6,
1350         .fp_grp_addr = {
1351             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1352             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1353         },
1354     };
1355     const mfib_prefix_t pfx_ff_3 = {
1356         /*
1357          * this is the ALL DHCP routers address
1358          */
1359         .fp_len = 128,
1360         .fp_proto = FIB_PROTOCOL_IP6,
1361         .fp_grp_addr = {
1362             .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1363             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1364         },
1365     };
1366     const mfib_prefix_t pfx_ff = {
1367         .fp_len = 16,
1368         .fp_proto = FIB_PROTOCOL_IP6,
1369         .fp_grp_addr = {
1370             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1371             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1372         },
1373     };
1374
1375     return (mfib_test_i(FIB_PROTOCOL_IP6,
1376                         VNET_LINK_IP6,
1377                         &pfx_ffd_s_12,
1378                         &pfx_2001_1_c_ff_1,
1379                         &pfx_ff_1,
1380                         &pfx_ff_2,
1381                         &pfx_ff_3,
1382                         &pfx_ff));
1383 }
1384
1385 static clib_error_t *
1386 mfib_test (vlib_main_t * vm,
1387            unformat_input_t * input,
1388            vlib_cli_command_t * cmd_arg)
1389 {
1390     int res = 0;
1391
1392     res += mfib_test_mk_intf(4);
1393     res += mfib_test_v4();
1394     res += mfib_test_v6();
1395
1396     if (res)
1397     {
1398         return clib_error_return(0, "MFIB Unit Test Failed");
1399     }
1400     else
1401     {
1402         return (NULL);
1403     }
1404 }
1405
1406 VLIB_CLI_COMMAND (test_fib_command, static) = {
1407     .path = "test mfib",
1408     .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1409     .function = mfib_test,
1410 };
1411
1412 clib_error_t *
1413 mfib_test_init (vlib_main_t *vm)
1414 {
1415     return 0;
1416 }
1417
1418 VLIB_INIT_FUNCTION (mfib_test_init);