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