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