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