Copying QoS Bits when fragmented, so that marking can happen properly also cleaning...
[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               "%U found via LP match",
547               format_mfib_prefix, pfx_star_g_1);
548
549     MFIB_TEST(!mfib_test_entry(mfei,
550                                MFIB_ENTRY_FLAG_NONE,
551                                1,
552                                DPO_ADJACENCY_MCAST, ai_1),
553               "%U replicate ok",
554               format_mfib_prefix, pfx_star_g_1);
555
556     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
557     MFIB_TEST(mfei == mfei_s_g,
558               "%U found via exact match",
559               format_mfib_prefix, pfx_s_g);
560
561     MFIB_TEST(!mfib_test_entry(mfei,
562                                MFIB_ENTRY_FLAG_NONE,
563                                3,
564                                DPO_ADJACENCY_MCAST, ai_1,
565                                DPO_ADJACENCY_MCAST, ai_2,
566                                DPO_ADJACENCY_MCAST, ai_3),
567               "%U replicate OK",
568               format_mfib_prefix, pfx_s_g);
569     mfei = mfib_table_lookup(fib_index, pfx_s_g);
570     MFIB_TEST(mfei == mfei_s_g,
571               "%U found via LP match",
572               format_mfib_prefix, pfx_s_g);
573
574     MFIB_TEST(!mfib_test_entry(mfei,
575                                MFIB_ENTRY_FLAG_NONE,
576                                3,
577                                DPO_ADJACENCY_MCAST, ai_1,
578                                DPO_ADJACENCY_MCAST, ai_2,
579                                DPO_ADJACENCY_MCAST, ai_3),
580               "%U replicate OK",
581               format_mfib_prefix, pfx_s_g);
582
583     /*
584      * A (*,G/m), which the same root G as the (*,G).
585      * different paths. test our LPM.
586      */
587     mfei_g_m = mfib_table_entry_path_update(fib_index,
588                                             pfx_star_g_slash_m,
589                                             MFIB_SOURCE_API,
590                                             &path_via_if2,
591                                             MFIB_ITF_FLAG_ACCEPT);
592     mfib_table_entry_path_update(fib_index,
593                                  pfx_star_g_slash_m,
594                                  MFIB_SOURCE_API,
595                                  &path_via_if3,
596                                  MFIB_ITF_FLAG_FORWARD);
597
598     /*
599      * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
600      */
601     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
602     MFIB_TEST((mfei_g_1 == mfei),
603               "%U found via DP LPM: %d",
604               format_mfib_prefix, pfx_star_g_1, mfei);
605
606     MFIB_TEST(!mfib_test_entry(mfei,
607                                MFIB_ENTRY_FLAG_NONE,
608                                1,
609                                DPO_ADJACENCY_MCAST, ai_1),
610               "%U replicate ok",
611               format_mfib_prefix, pfx_star_g_1);
612
613     mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
614
615     MFIB_TEST(!mfib_test_entry(mfei,
616                                MFIB_ENTRY_FLAG_NONE,
617                                1,
618                                DPO_ADJACENCY_MCAST, ai_1),
619               "%U replicate ok",
620               format_mfib_prefix, pfx_star_g_1);
621
622     mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
623
624     MFIB_TEST(!mfib_test_entry(mfei,
625                                MFIB_ENTRY_FLAG_NONE,
626                                3,
627                                DPO_ADJACENCY_MCAST, ai_1,
628                                DPO_ADJACENCY_MCAST, ai_2,
629                                DPO_ADJACENCY_MCAST, ai_3),
630               "%U replicate OK",
631               format_mfib_prefix, pfx_s_g);
632     mfei = mfib_table_lookup(fib_index, pfx_s_g);
633
634     MFIB_TEST(!mfib_test_entry(mfei,
635                                MFIB_ENTRY_FLAG_NONE,
636                                3,
637                                DPO_ADJACENCY_MCAST, ai_1,
638                                DPO_ADJACENCY_MCAST, ai_2,
639                                DPO_ADJACENCY_MCAST, ai_3),
640               "%U replicate OK",
641               format_mfib_prefix, pfx_s_g);
642
643     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
644     MFIB_TEST(mfei = mfei_g_m,
645               "%U Found via exact match",
646               format_mfib_prefix, pfx_star_g_slash_m);
647     MFIB_TEST(!mfib_test_entry(mfei,
648                                MFIB_ENTRY_FLAG_NONE,
649                                1,
650                                DPO_ADJACENCY_MCAST, ai_3),
651               "%U replicate OK",
652               format_mfib_prefix, pfx_star_g_slash_m);
653     MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
654               "%U found via LPM",
655               format_mfib_prefix, pfx_star_g_slash_m);
656
657     /*
658      * Add a for-us path
659      */
660     mfei = mfib_table_entry_path_update(fib_index,
661                                         pfx_s_g,
662                                         MFIB_SOURCE_API,
663                                         &path_for_us,
664                                         MFIB_ITF_FLAG_FORWARD);
665
666     MFIB_TEST(!mfib_test_entry(mfei,
667                                MFIB_ENTRY_FLAG_NONE,
668                                4,
669                                DPO_ADJACENCY_MCAST, ai_1,
670                                DPO_ADJACENCY_MCAST, ai_2,
671                                DPO_ADJACENCY_MCAST, ai_3,
672                                DPO_RECEIVE, 0),
673               "%U replicate OK",
674               format_mfib_prefix, pfx_s_g);
675
676     /*
677      * remove a for-us path
678      */
679     mfib_table_entry_path_remove(fib_index,
680                                  pfx_s_g,
681                                  MFIB_SOURCE_API,
682                                  &path_for_us);
683
684     MFIB_TEST(!mfib_test_entry(mfei,
685                                MFIB_ENTRY_FLAG_NONE,
686                                3,
687                                DPO_ADJACENCY_MCAST, ai_1,
688                                DPO_ADJACENCY_MCAST, ai_2,
689                                DPO_ADJACENCY_MCAST, ai_3),
690               "%U replicate OK",
691               format_mfib_prefix, pfx_s_g);
692
693     /*
694      * update an existing forwarding path to be only accepting
695      *   - expect it to be removed from the replication set.
696      */
697     mfib_table_entry_path_update(fib_index,
698                                  pfx_s_g,
699                                  MFIB_SOURCE_API,
700                                  &path_via_if3,
701                                  MFIB_ITF_FLAG_ACCEPT);
702
703     MFIB_TEST(!mfib_test_entry(mfei,
704                                MFIB_ENTRY_FLAG_NONE,
705                                2,
706                                DPO_ADJACENCY_MCAST, ai_1,
707                                DPO_ADJACENCY_MCAST, ai_2),
708               "%U replicate OK",
709               format_mfib_prefix, pfx_s_g);
710     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
711                                       MFIB_ITF_FLAG_ACCEPT));
712     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
713                                       MFIB_ITF_FLAG_FORWARD));
714     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
715                                       MFIB_ITF_FLAG_FORWARD));
716     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
717                                       MFIB_ITF_FLAG_ACCEPT));
718     /*
719      * Make the path forwarding again
720      *  - expect it to be added back to the replication set
721      */
722     mfib_table_entry_path_update(fib_index,
723                                  pfx_s_g,
724                                  MFIB_SOURCE_API,
725                                  &path_via_if3,
726                                  (MFIB_ITF_FLAG_FORWARD |
727                                   MFIB_ITF_FLAG_ACCEPT |
728                                   MFIB_ITF_FLAG_NEGATE_SIGNAL));
729
730     mfei = mfib_table_lookup_exact_match(fib_index,
731                                          pfx_s_g);
732
733     MFIB_TEST(!mfib_test_entry(mfei,
734                                MFIB_ENTRY_FLAG_NONE,
735                                3,
736                                DPO_ADJACENCY_MCAST, ai_1,
737                                DPO_ADJACENCY_MCAST, ai_2,
738                                DPO_ADJACENCY_MCAST, ai_3),
739               "%U replicate OK",
740               format_mfib_prefix, pfx_s_g);
741     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
742                                       MFIB_ITF_FLAG_ACCEPT));
743     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
744                                       MFIB_ITF_FLAG_FORWARD));
745     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
746                                       MFIB_ITF_FLAG_FORWARD));
747     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
748                                       (MFIB_ITF_FLAG_FORWARD |
749                                        MFIB_ITF_FLAG_ACCEPT |
750                                        MFIB_ITF_FLAG_NEGATE_SIGNAL)));
751
752     /*
753      * update flags on the entry
754      */
755     mfib_table_entry_update(fib_index,
756                             pfx_s_g,
757                             MFIB_SOURCE_API,
758                             MFIB_RPF_ID_NONE,
759                             MFIB_ENTRY_FLAG_SIGNAL);
760     MFIB_TEST(!mfib_test_entry(mfei,
761                                MFIB_ENTRY_FLAG_SIGNAL,
762                                3,
763                                DPO_ADJACENCY_MCAST, ai_1,
764                                DPO_ADJACENCY_MCAST, ai_2,
765                                DPO_ADJACENCY_MCAST, ai_3),
766               "%U replicate OK",
767               format_mfib_prefix, pfx_s_g);
768
769     /*
770      * remove paths
771      */
772     mfib_table_entry_path_remove(fib_index,
773                                  pfx_s_g,
774                                  MFIB_SOURCE_API,
775                                  &path_via_if3);
776
777     MFIB_TEST(!mfib_test_entry(mfei,
778                                MFIB_ENTRY_FLAG_SIGNAL,
779                                2,
780                                DPO_ADJACENCY_MCAST, ai_1,
781                                DPO_ADJACENCY_MCAST, ai_2),
782               "%U replicate OK",
783               format_mfib_prefix, pfx_s_g);
784     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
785                                       MFIB_ITF_FLAG_ACCEPT));
786     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
787                                       MFIB_ITF_FLAG_FORWARD));
788     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
789                                       MFIB_ITF_FLAG_FORWARD));
790     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
791
792     mfib_table_entry_path_remove(fib_index,
793                                  pfx_s_g,
794                                  MFIB_SOURCE_API,
795                                  &path_via_if1);
796
797     MFIB_TEST(!mfib_test_entry(mfei,
798                                MFIB_ENTRY_FLAG_SIGNAL,
799                                1,
800                                DPO_ADJACENCY_MCAST, ai_2),
801               "%U replicate OK",
802               format_mfib_prefix, pfx_s_g);
803     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
804                                       MFIB_ITF_FLAG_ACCEPT));
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     /*
810      * remove the accpeting only interface
811      */
812     mfib_table_entry_path_remove(fib_index,
813                                  pfx_s_g,
814                                  MFIB_SOURCE_API,
815                                  &path_via_if0);
816
817     MFIB_TEST(!mfib_test_entry(mfei,
818                                MFIB_ENTRY_FLAG_SIGNAL,
819                                1,
820                                DPO_ADJACENCY_MCAST, ai_2),
821               "%U replicate OK",
822               format_mfib_prefix, pfx_s_g);
823     MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
824                                       MFIB_ITF_FLAG_FORWARD));
825     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index));
826     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index));
827     MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
828
829     /*
830      * remove the last path, the entry still has flags so it remains
831      */
832     mfib_table_entry_path_remove(fib_index,
833                                  pfx_s_g,
834                                  MFIB_SOURCE_API,
835                                  &path_via_if2);
836
837     MFIB_TEST(!mfib_test_entry(mfei,
838                                MFIB_ENTRY_FLAG_SIGNAL,
839                                0),
840               "%U no replications",
841               format_mfib_prefix, pfx_s_g);
842
843     /*
844      * update flags on the entry
845      */
846     mfib_table_entry_update(fib_index,
847                             pfx_s_g,
848                             MFIB_SOURCE_API,
849                             MFIB_RPF_ID_NONE,
850                             (MFIB_ENTRY_FLAG_SIGNAL |
851                              MFIB_ENTRY_FLAG_CONNECTED));
852     MFIB_TEST(!mfib_test_entry(mfei,
853                                (MFIB_ENTRY_FLAG_SIGNAL |
854                                 MFIB_ENTRY_FLAG_CONNECTED),
855                                0),
856               "%U no replications",
857               format_mfib_prefix, pfx_s_g);
858
859     /*
860      * An entry with a NS interface
861      */
862     mfei_g_2 = mfib_table_entry_path_update(fib_index,
863                                             pfx_star_g_2,
864                                             MFIB_SOURCE_API,
865                                             &path_via_if0,
866                                             (MFIB_ITF_FLAG_ACCEPT |
867                                              MFIB_ITF_FLAG_NEGATE_SIGNAL));
868     MFIB_TEST(!mfib_test_entry(mfei_g_2,
869                                MFIB_ENTRY_FLAG_NONE,
870                                0),
871               "%U No replications",
872               format_mfib_prefix, pfx_star_g_2);
873
874     /*
875      * Simulate a signal from the data-plane
876      */
877     {
878         mfib_entry_t *mfe;
879         mfib_itf_t *mfi;
880
881         mfe = mfib_entry_get(mfei_g_2);
882         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
883
884         mfib_signal_push(mfe, mfi, NULL);
885     }
886
887     /*
888      * An entry with a NS interface
889      */
890     mfei_g_3 = mfib_table_entry_path_update(fib_index,
891                                             pfx_star_g_3,
892                                             MFIB_SOURCE_API,
893                                             &path_via_if0,
894                                             (MFIB_ITF_FLAG_ACCEPT |
895                                              MFIB_ITF_NEGATE_SIGNAL));
896     MFIB_TEST(!mfib_test_entry(mfei_g_3,
897                                MFIB_ENTRY_FLAG_NONE,
898                                0),
899               "%U No replications",
900               format_mfib_prefix, pfx_star_g_3);
901
902     /*
903      * Simulate a signal from the data-plane
904      */
905     {
906         mfib_entry_t *mfe;
907         mfib_itf_t *mfi;
908
909         mfe = mfib_entry_get(mfei_g_3);
910         mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
911
912         mfib_signal_push(mfe, mfi, NULL);
913     }
914
915     if (FIB_PROTOCOL_IP6 == PROTO)
916     {
917         /*
918          * All the entries are present. let's ensure we can find them all
919          * via exact and longest prefix matches.
920          */
921         /*
922          * A source address we will never match
923          */
924         ip6_address_t src = {
925             .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
926             .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
927         };
928
929         /*
930          * Find the (*,G/m)
931          */
932         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
933                        ip6_mfib_get(fib_index),
934                        &src,
935                        &pfx_star_g_slash_m->fp_grp_addr.ip6)),
936                   "%U found via DP LPM grp=%U",
937                   format_mfib_prefix, pfx_star_g_slash_m,
938                   format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
939
940         ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
941         tmp.as_u8[15] = 0xff;
942
943         MFIB_TEST((mfei_g_m == ip6_mfib_table_lookup2(
944                        ip6_mfib_get(fib_index),
945                        &pfx_s_g->fp_src_addr.ip6,
946                        &tmp)),
947                   "%U found via DP LPM grp=%U",
948                   format_mfib_prefix, pfx_star_g_slash_m,
949                   format_ip6_address, &tmp);
950
951         /*
952          * Find the (S,G).
953          */
954         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
955                                       &pfx_s_g->fp_src_addr.ip6,
956                                       &pfx_s_g->fp_grp_addr.ip6);
957         MFIB_TEST((mfei_s_g == mfei),
958                   "%U found via DP LPM: %d",
959                   format_mfib_prefix, pfx_s_g, mfei);
960
961         /*
962          * Find the 3 (*,G) s
963          */
964         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
965                                       &src,
966                                       &pfx_star_g_1->fp_grp_addr.ip6);
967         MFIB_TEST((mfei_g_1 == mfei),
968                   "%U found via DP LPM: %d",
969                   format_mfib_prefix, pfx_star_g_1, mfei);
970         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
971                                       &src,
972                                       &pfx_star_g_2->fp_grp_addr.ip6);
973         MFIB_TEST((mfei_g_2 == mfei),
974                   "%U found via DP LPM: %d",
975                   format_mfib_prefix, pfx_star_g_2, mfei);
976         mfei = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index),
977                                       &src,
978                                       &pfx_star_g_3->fp_grp_addr.ip6);
979         MFIB_TEST((mfei_g_3 == mfei),
980                   "%U found via DP LPM: %d",
981                   format_mfib_prefix, pfx_star_g_3, mfei);
982     }
983
984     /*
985      * remove flags on the entry. This is the last of the
986      * state associated with the entry, so now it goes.
987      */
988     mfib_table_entry_update(fib_index,
989                             pfx_s_g,
990                             MFIB_SOURCE_API,
991                             MFIB_RPF_ID_NONE,
992                             MFIB_ENTRY_FLAG_NONE);
993     mfei = mfib_table_lookup_exact_match(fib_index,
994                                          pfx_s_g);
995     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
996               "%U gone",
997               format_mfib_prefix, pfx_s_g);
998
999     /*
1000      * remove the last path on the no forward entry - the last entry
1001      */
1002     mfib_table_entry_path_remove(fib_index,
1003                                  pfx_no_forward,
1004                                  MFIB_SOURCE_API,
1005                                  &path_via_if0);
1006
1007     mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
1008     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1009               "%U gone",
1010               format_mfib_prefix, pfx_no_forward);
1011
1012     /*
1013      * hard delete the (*,232.1.1.1)
1014      */
1015     mfib_table_entry_delete(fib_index,
1016                             pfx_star_g_1,
1017                             MFIB_SOURCE_API);
1018
1019     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1020     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1021               "%U gone",
1022               format_mfib_prefix, pfx_star_g_1);
1023     /*
1024      * remove the entry whilst the signal is pending
1025      */
1026     mfib_table_entry_delete(fib_index,
1027                             pfx_star_g_2,
1028                             MFIB_SOURCE_API);
1029
1030     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1031     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1032               "%U Gone",
1033               format_mfib_prefix, pfx_star_g_2);
1034     mfib_table_entry_delete(fib_index,
1035                             pfx_star_g_3,
1036                             MFIB_SOURCE_API);
1037
1038     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1039     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1040               "%U Gone",
1041               format_mfib_prefix, pfx_star_g_3);
1042
1043     mfib_table_entry_delete(fib_index,
1044                             pfx_star_g_slash_m,
1045                             MFIB_SOURCE_API);
1046
1047     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1048     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1049               "%U Gone",
1050               format_mfib_prefix, pfx_star_g_slash_m);
1051
1052     /*
1053      * Entries with paths via unicast next-hops
1054      */
1055     fib_route_path_t path_via_nbr1 = {
1056         .frp_proto = fib_proto_to_dpo(PROTO),
1057         .frp_addr = *addr_nbr1,
1058         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1059         .frp_fib_index = ~0,
1060         .frp_weight = 0,
1061         .frp_flags = 0,
1062     };
1063     fib_route_path_t path_via_nbr2 = {
1064         .frp_proto = fib_proto_to_dpo(PROTO),
1065         .frp_addr = *addr_nbr2,
1066         .frp_sw_if_index = tm->hw[0]->sw_if_index,
1067         .frp_fib_index = ~0,
1068         .frp_weight = 0,
1069         .frp_flags = 0,
1070     };
1071
1072     mfei_g_1 = mfib_table_entry_path_update(fib_index,
1073                                             pfx_star_g_1,
1074                                             MFIB_SOURCE_API,
1075                                             &path_via_nbr1,
1076                                             (MFIB_ITF_FLAG_FORWARD));
1077     mfei_g_1 = mfib_table_entry_path_update(fib_index,
1078                                             pfx_star_g_1,
1079                                             MFIB_SOURCE_API,
1080                                             &path_via_nbr2,
1081                                             (MFIB_ITF_FLAG_FORWARD));
1082     MFIB_TEST(!mfib_test_entry(mfei_g_1,
1083                                MFIB_ENTRY_FLAG_NONE,
1084                                2,
1085                                DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
1086                                DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1087               "%U replicate OK",
1088               format_mfib_prefix, pfx_star_g_1);
1089     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1090                                       MFIB_ITF_FLAG_FORWARD));
1091
1092     mfib_table_entry_path_remove(fib_index,
1093                                  pfx_star_g_1,
1094                                  MFIB_SOURCE_API,
1095                                  &path_via_nbr1);
1096
1097     MFIB_TEST(!mfib_test_entry(mfei_g_1,
1098                                MFIB_ENTRY_FLAG_NONE,
1099                                1,
1100                                DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1101               "%U replicate OK",
1102               format_mfib_prefix, pfx_star_g_1);
1103     MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1104                                       MFIB_ITF_FLAG_FORWARD));
1105
1106     mfib_table_entry_path_remove(fib_index,
1107                                  pfx_star_g_1,
1108                                  MFIB_SOURCE_API,
1109                                  &path_via_nbr2);
1110     mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1111     MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1112               "%U Gone",
1113               format_mfib_prefix, pfx_star_g_1);
1114
1115     /*
1116      * Add a prefix as a special/exclusive route
1117      */
1118     dpo_id_t td = DPO_INVALID;
1119     index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
1120
1121     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
1122     replicate_set_bucket(repi, 0, &td);
1123
1124     mfei = mfib_table_entry_special_add(fib_index,
1125                                         pfx_star_g_3,
1126                                         MFIB_SOURCE_SRv6,
1127                                         MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1128                                         repi);
1129     MFIB_TEST(!mfib_test_entry(mfei,
1130                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1131                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1132                                1,
1133                                DPO_ADJACENCY_MCAST, ai_2),
1134               "%U exclusive replicate OK",
1135               format_mfib_prefix, pfx_star_g_3);
1136
1137     /*
1138      * update a special/exclusive route
1139      */
1140     index_t repi2 = replicate_create(1, fib_proto_to_dpo(PROTO));
1141
1142     dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1);
1143     replicate_set_bucket(repi2, 0, &td);
1144
1145     mfei = mfib_table_entry_special_add(fib_index,
1146                                         pfx_star_g_3,
1147                                         MFIB_SOURCE_SRv6,
1148                                         MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1149                                         repi2);
1150     MFIB_TEST(!mfib_test_entry(mfei,
1151                                (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1152                                 MFIB_ENTRY_FLAG_EXCLUSIVE),
1153                                1,
1154                                DPO_ADJACENCY_MCAST, ai_1),
1155               "%U exclusive update replicate OK",
1156               format_mfib_prefix, pfx_star_g_3);
1157
1158     mfib_table_entry_delete(fib_index,
1159                             pfx_star_g_3,
1160                             MFIB_SOURCE_SRv6);
1161     dpo_reset(&td);
1162
1163     /*
1164      * A Multicast LSP. This a mLDP head-end
1165      */
1166     fib_node_index_t ai_mpls_10_10_10_1, lfei;
1167     ip46_address_t nh_10_10_10_1 = {
1168         .ip4 = {
1169             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1170         },
1171     };
1172     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1173                                              VNET_LINK_MPLS,
1174                                              &nh_10_10_10_1,
1175                                              tm->hw[0]->sw_if_index);
1176
1177     fib_prefix_t pfx_3500 = {
1178         .fp_len = 21,
1179         .fp_proto = FIB_PROTOCOL_MPLS,
1180         .fp_label = 3500,
1181         .fp_eos = MPLS_EOS,
1182         .fp_payload_proto = DPO_PROTO_IP4,
1183     };
1184     fib_test_rep_bucket_t mc_0 = {
1185         .type = FT_REP_LABEL_O_ADJ,
1186         .label_o_adj = {
1187             .adj = ai_mpls_10_10_10_1,
1188             .label = 3300,
1189             .eos = MPLS_EOS,
1190         },
1191     };
1192     fib_mpls_label_t *l3300 = NULL, fml3300 = {
1193         .fml_value = 3300,
1194     };
1195     vec_add1(l3300, fml3300);
1196
1197     /*
1198      * MPLS enable an interface so we get the MPLS table created
1199      */
1200     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
1201     mpls_sw_interface_enable_disable(&mpls_main,
1202                                      tm->hw[0]->sw_if_index,
1203                                      1, 0);
1204
1205     lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1206                                            &pfx_3500,
1207                                            FIB_SOURCE_API,
1208                                            FIB_ENTRY_FLAG_MULTICAST,
1209                                            DPO_PROTO_IP4,
1210                                            &nh_10_10_10_1,
1211                                            tm->hw[0]->sw_if_index,
1212                                            ~0, // invalid fib index
1213                                            1,
1214                                            l3300,
1215                                            FIB_ROUTE_PATH_FLAG_NONE);
1216     MFIB_TEST(!fib_test_validate_entry(lfei,
1217                                        FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1218                                        1,
1219                                        &mc_0),
1220               "3500 via replicate over 10.10.10.1");
1221
1222     /*
1223      * An (S,G) that resolves via the mLDP head-end
1224      */
1225     fib_route_path_t path_via_mldp = {
1226         .frp_proto = DPO_PROTO_MPLS,
1227         .frp_local_label = pfx_3500.fp_label,
1228         .frp_eos = MPLS_EOS,
1229         .frp_sw_if_index = 0xffffffff,
1230         .frp_fib_index = 0,
1231         .frp_weight = 1,
1232         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1233     };
1234     dpo_id_t mldp_dpo = DPO_INVALID;
1235
1236     fib_entry_contribute_forwarding(lfei,
1237                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1238                                     &mldp_dpo);
1239
1240     mfei = mfib_table_entry_path_update(fib_index,
1241                                         pfx_s_g,
1242                                         MFIB_SOURCE_API,
1243                                         &path_via_mldp,
1244                                         MFIB_ITF_FLAG_FORWARD);
1245
1246     MFIB_TEST(!mfib_test_entry(mfei,
1247                                MFIB_ENTRY_FLAG_NONE,
1248                                1,
1249                                DPO_REPLICATE, mldp_dpo.dpoi_index),
1250               "%U over-mLDP replicate OK",
1251               format_mfib_prefix, pfx_s_g);
1252
1253     /*
1254      * add a for-us path. this tests two types of non-attached paths on one entry
1255      */
1256     mfei = mfib_table_entry_path_update(fib_index,
1257                                         pfx_s_g,
1258                                         MFIB_SOURCE_API,
1259                                         &path_for_us,
1260                                         MFIB_ITF_FLAG_FORWARD);
1261     MFIB_TEST(!mfib_test_entry(mfei,
1262                                MFIB_ENTRY_FLAG_NONE,
1263                                2,
1264                                DPO_REPLICATE, mldp_dpo.dpoi_index,
1265                                DPO_RECEIVE, 0),
1266               "%U mLDP+for-us replicate OK",
1267               format_mfib_prefix, pfx_s_g);
1268
1269     mfib_table_entry_delete(fib_index,
1270                             pfx_s_g,
1271                             MFIB_SOURCE_API);
1272     fib_table_entry_delete(0,
1273                            &pfx_3500,
1274                            FIB_SOURCE_API);
1275     dpo_reset(&mldp_dpo);
1276
1277     /*
1278      * Unlock the table - it's the last lock so should be gone thereafter
1279      */
1280     mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1281
1282     MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1283                mfib_table_find(PROTO, fib_index)),
1284               "MFIB table %d gone", fib_index);
1285
1286     adj_unlock(ai_1);
1287     adj_unlock(ai_2);
1288     adj_unlock(ai_3);
1289     adj_unlock(ai_nbr1);
1290     adj_unlock(ai_nbr2);
1291
1292     /*
1293      * MPLS disable the interface
1294      */
1295     mpls_sw_interface_enable_disable(&mpls_main,
1296                                      tm->hw[0]->sw_if_index,
1297                                      0, 0);
1298     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1299
1300     /*
1301      * remove the connected
1302      */
1303     fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
1304
1305     /*
1306      * test we've leaked no resources
1307      */
1308     MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1309     MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1310               n_pls, fib_path_list_pool_size());
1311     MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1312               n_reps, pool_elts(replicate_pool));
1313     MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1314               " No more entries %d!=%d",
1315               n_entries, pool_elts(mfib_entry_pool));
1316     MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1317               " No more Interfaces %d!=%d",
1318               n_itfs, pool_elts(mfib_itf_pool));
1319
1320     return (res);
1321 }
1322
1323 static int
1324 mfib_test_v4 (void)
1325 {
1326     const mfib_prefix_t pfx_224_s_8 = {
1327         .fp_len = 8,
1328         .fp_proto = FIB_PROTOCOL_IP4,
1329         .fp_grp_addr = {
1330             .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1331         }
1332     };
1333     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1334         .fp_len = 64,
1335         .fp_proto = FIB_PROTOCOL_IP4,
1336         .fp_grp_addr = {
1337             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1338         },
1339         .fp_src_addr = {
1340             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1341         },
1342     };
1343     const mfib_prefix_t pfx_239_1_1_1 = {
1344         .fp_len = 32,
1345         .fp_proto = FIB_PROTOCOL_IP4,
1346         .fp_grp_addr = {
1347             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1348         },
1349         .fp_src_addr = {
1350             .ip4.as_u32 = 0,
1351         },
1352     };
1353     const mfib_prefix_t pfx_239_1_1_2 = {
1354         .fp_len = 32,
1355         .fp_proto = FIB_PROTOCOL_IP4,
1356         .fp_grp_addr = {
1357             .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1358         },
1359         .fp_src_addr = {
1360             .ip4.as_u32 = 0,
1361         },
1362     };
1363     const mfib_prefix_t pfx_239_1_1_3 = {
1364         .fp_len = 32,
1365         .fp_proto = FIB_PROTOCOL_IP4,
1366         .fp_grp_addr = {
1367             .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1368         },
1369         .fp_src_addr = {
1370             .ip4.as_u32 = 0,
1371         },
1372     };
1373     const mfib_prefix_t pfx_239 = {
1374         .fp_len = 8,
1375         .fp_proto = FIB_PROTOCOL_IP4,
1376         .fp_grp_addr = {
1377             .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1378         },
1379         .fp_src_addr = {
1380             .ip4.as_u32 = 0,
1381         },
1382     };
1383     const fib_prefix_t pfx_itf = {
1384         .fp_len = 24,
1385         .fp_proto = FIB_PROTOCOL_IP4,
1386         .fp_addr = {
1387             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
1388         },
1389     };
1390     const ip46_address_t nbr1 = {
1391         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
1392     };
1393     const ip46_address_t nbr2 = {
1394         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
1395     };
1396     return (mfib_test_i(FIB_PROTOCOL_IP4,
1397                         VNET_LINK_IP4,
1398                         &pfx_224_s_8,
1399                         &pfx_1_1_1_1_c_239_1_1_1,
1400                         &pfx_239_1_1_1,
1401                         &pfx_239_1_1_2,
1402                         &pfx_239_1_1_3,
1403                         &pfx_239,
1404                         &pfx_itf,
1405                         &nbr1,
1406                         &nbr2));
1407 }
1408
1409 static int
1410 mfib_test_v6 (void)
1411 {
1412     const mfib_prefix_t pfx_ffd_s_12 = {
1413         .fp_len = 12,
1414         .fp_proto = FIB_PROTOCOL_IP6,
1415         .fp_grp_addr = {
1416             .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1417         }
1418     };
1419     const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1420         .fp_len = 256,
1421         .fp_proto = FIB_PROTOCOL_IP6,
1422         .fp_grp_addr = {
1423             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1424             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1425         },
1426         .fp_src_addr = {
1427             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1428             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1429         },
1430     };
1431     const mfib_prefix_t pfx_ff_1 = {
1432         .fp_len = 128,
1433         .fp_proto = FIB_PROTOCOL_IP6,
1434         .fp_grp_addr = {
1435             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1436             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1437         },
1438     };
1439     const mfib_prefix_t pfx_ff_2 = {
1440         .fp_len = 128,
1441         .fp_proto = FIB_PROTOCOL_IP6,
1442         .fp_grp_addr = {
1443             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1444             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1445         },
1446     };
1447     const mfib_prefix_t pfx_ff_3 = {
1448         /*
1449          * this is the ALL DHCP routers address
1450          */
1451         .fp_len = 128,
1452         .fp_proto = FIB_PROTOCOL_IP6,
1453         .fp_grp_addr = {
1454             .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1455             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1456         },
1457     };
1458     const mfib_prefix_t pfx_ff = {
1459         .fp_len = 16,
1460         .fp_proto = FIB_PROTOCOL_IP6,
1461         .fp_grp_addr = {
1462             .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1463             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1464         },
1465     };
1466     const fib_prefix_t pfx_itf = {
1467         .fp_len = 64,
1468         .fp_proto = FIB_PROTOCOL_IP6,
1469         .fp_addr = {
1470             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1471             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1472         },
1473     };
1474     const ip46_address_t nbr1 = {
1475             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1476             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1477     };
1478     const ip46_address_t nbr2 = {
1479             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1480             .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
1481     };
1482
1483     return (mfib_test_i(FIB_PROTOCOL_IP6,
1484                         VNET_LINK_IP6,
1485                         &pfx_ffd_s_12,
1486                         &pfx_2001_1_c_ff_1,
1487                         &pfx_ff_1,
1488                         &pfx_ff_2,
1489                         &pfx_ff_3,
1490                         &pfx_ff,
1491                         &pfx_itf,
1492                         &nbr1,
1493                         &nbr2));
1494 }
1495
1496 static clib_error_t *
1497 mfib_test (vlib_main_t * vm,
1498            unformat_input_t * input,
1499            vlib_cli_command_t * cmd_arg)
1500 {
1501     int res = 0;
1502
1503     res += mfib_test_mk_intf(4);
1504     res += mfib_test_v4();
1505
1506     if (res)
1507     {
1508         return clib_error_return(0, "MFIB Unit Test Failed");
1509     }
1510
1511     res += mfib_test_v6();
1512
1513     if (res)
1514     {
1515         return clib_error_return(0, "MFIB Unit Test Failed");
1516     }
1517     else
1518     {
1519         return (NULL);
1520     }
1521 }
1522
1523 VLIB_CLI_COMMAND (test_fib_command, static) = {
1524     .path = "test mfib",
1525     .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1526     .function = mfib_test,
1527 };
1528
1529 clib_error_t *
1530 mfib_test_init (vlib_main_t *vm)
1531 {
1532     return 0;
1533 }
1534
1535 VLIB_INIT_FUNCTION (mfib_test_init);