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