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