Line data Source code
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 : } \
38 : res; \
39 : })
40 : #define MFIB_TEST(_cond, _comment, _args...) \
41 : { \
42 : if (MFIB_TEST_I(_cond, _comment, ##_args)) { \
43 : return 1; \
44 : ASSERT(!("FAIL: " _comment)); \
45 : } \
46 : }
47 : #define MFIB_TEST_NS(_cond) \
48 : { \
49 : if (MFIB_TEST_I(_cond, "")) { \
50 : return 1; \
51 : ASSERT(!("FAIL: ")); \
52 : } \
53 : }
54 :
55 : /**
56 : * A 'i'm not fussed is this is not efficient' store of test data
57 : */
58 : typedef struct test_main_t_ {
59 : /**
60 : * HW if indicies
61 : */
62 : u32 hw_if_indicies[4];
63 : /**
64 : * HW interfaces
65 : */
66 : vnet_hw_interface_t * hw[4];
67 :
68 : } test_main_t;
69 : static test_main_t test_main;
70 :
71 : /* fake ethernet device class, distinct from "fake-ethX" */
72 8 : static u8 * format_test_interface_name (u8 * s, va_list * args)
73 : {
74 8 : u32 dev_instance = va_arg (*args, u32);
75 8 : return format (s, "test-eth%d", dev_instance);
76 : }
77 :
78 1 : static uword placeholder_interface_tx (vlib_main_t * vm,
79 : vlib_node_runtime_t * node,
80 : vlib_frame_t * frame)
81 : {
82 1 : clib_warning ("you shouldn't be here, leaking buffers...");
83 1 : return frame->n_vectors;
84 : }
85 :
86 : static clib_error_t *
87 4 : test_interface_admin_up_down (vnet_main_t * vnm,
88 : u32 hw_if_index,
89 : u32 flags)
90 : {
91 4 : u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
92 : VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
93 4 : vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
94 4 : return 0;
95 : }
96 :
97 2799 : VNET_DEVICE_CLASS (test_interface_device_class,static) = {
98 : .name = "Test interface",
99 : .format_device_name = format_test_interface_name,
100 : .tx_function = placeholder_interface_tx,
101 : .admin_up_down_function = test_interface_admin_up_down,
102 : };
103 :
104 : static u8 *hw_address;
105 :
106 : static int
107 1 : mfib_test_mk_intf (u32 ninterfaces)
108 : {
109 1 : clib_error_t * error = NULL;
110 1 : test_main_t *tm = &test_main;
111 : u8 byte;
112 : int res;
113 : u32 i;
114 :
115 1 : res = 0;
116 1 : ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
117 :
118 7 : for (i=0; i<6; i++)
119 : {
120 6 : byte = 0xd0+i;
121 6 : vec_add1(hw_address, byte);
122 : }
123 :
124 5 : for (i = 0; i < ninterfaces; i++)
125 : {
126 4 : vnet_eth_interface_registration_t eir = {};
127 4 : vnet_main_t *vnm = vnet_get_main ();
128 :
129 4 : hw_address[5] = i;
130 :
131 4 : eir.dev_class_index = test_interface_device_class.index;
132 4 : eir.dev_instance = i;
133 4 : eir.address = hw_address;
134 4 : tm->hw_if_indicies[i] = vnet_eth_register_interface (vnm, &eir);
135 :
136 : error =
137 4 : vnet_hw_interface_set_flags (vnet_get_main (), tm->hw_if_indicies[i],
138 : VNET_HW_INTERFACE_FLAG_LINK_UP);
139 4 : tm->hw[i] =
140 4 : vnet_get_hw_interface (vnet_get_main (), tm->hw_if_indicies[i]);
141 4 : ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
142 4 : ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
143 :
144 4 : ip4_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
145 4 : ip6_main.mfib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
146 :
147 : error =
148 4 : vnet_sw_interface_set_flags (vnet_get_main (), tm->hw[i]->sw_if_index,
149 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
150 4 : MFIB_TEST ((NULL == error), "UP interface %d", i);
151 : }
152 : /*
153 : * re-eval after the inevitable realloc
154 : */
155 5 : for (i = 0; i < ninterfaces; i++)
156 : {
157 4 : tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
158 : tm->hw_if_indicies[i]);
159 : }
160 :
161 1 : return (res);
162 : }
163 :
164 : #define MFIB_TEST_REP(_cond, _comment, _args...) \
165 : { \
166 : if (MFIB_TEST_I(_cond, _comment, ##_args)) { \
167 : return (1); \
168 : } \
169 : }
170 :
171 : static int
172 68 : mfib_test_validate_rep_v (const replicate_t *rep,
173 : u16 n_buckets,
174 : va_list *ap)
175 : {
176 : const dpo_id_t *dpo;
177 : adj_index_t ai;
178 : dpo_type_t dt;
179 : int bucket;
180 : int res;
181 :
182 68 : res = 0;
183 68 : MFIB_TEST_REP((n_buckets == rep->rep_n_buckets),
184 : "n_buckets = %d", rep->rep_n_buckets);
185 :
186 200 : for (bucket = 0; bucket < n_buckets; bucket++)
187 : {
188 132 : dt = va_arg(*ap, int); // type promotion
189 132 : ai = va_arg(*ap, adj_index_t);
190 132 : dpo = replicate_get_bucket_i(rep, bucket);
191 :
192 132 : MFIB_TEST_REP((dt == dpo->dpoi_type),
193 : "bucket %d stacks on %U",
194 : bucket,
195 : format_dpo_type, dpo->dpoi_type);
196 :
197 132 : if (DPO_RECEIVE != dt)
198 : {
199 124 : MFIB_TEST_REP((ai == dpo->dpoi_index),
200 : "bucket %d [exp:%d] stacks on %U",
201 : bucket, ai,
202 : format_dpo_id, dpo, 0);
203 : }
204 : }
205 68 : return (res);
206 : }
207 :
208 : static int
209 86 : mfib_test_entry (fib_node_index_t fei,
210 : mfib_entry_flags_t eflags,
211 : int n_buckets,
212 : ...)
213 : {
214 : const mfib_prefix_t *pfx;
215 : const mfib_entry_t *mfe;
216 : const replicate_t *rep;
217 : va_list ap;
218 : int res;
219 :
220 :
221 86 : res = 0;
222 86 : mfe = mfib_entry_get(fei);
223 86 : pfx = mfib_entry_get_prefix(fei);
224 :
225 86 : MFIB_TEST_REP((eflags == mfe->mfe_flags),
226 : "%U has %U expect %U",
227 : format_mfib_prefix, pfx,
228 : format_mfib_entry_flags, mfe->mfe_flags,
229 : format_mfib_entry_flags, eflags);
230 :
231 86 : if (0 == n_buckets)
232 : {
233 18 : MFIB_TEST_REP((DPO_DROP == mfe->mfe_rep.dpoi_type),
234 : "%U links to %U",
235 : format_mfib_prefix, pfx,
236 : format_dpo_id, &mfe->mfe_rep, 0);
237 : }
238 : else
239 : {
240 68 : dpo_id_t tmp = DPO_INVALID;
241 :
242 68 : mfib_entry_contribute_forwarding(
243 : fei,
244 68 : mfib_forw_chain_type_from_fib_proto(pfx->fp_proto),
245 : MFIB_ENTRY_FWD_FLAG_NONE,
246 : &tmp);
247 68 : rep = replicate_get(tmp.dpoi_index);
248 :
249 68 : MFIB_TEST_REP((DPO_REPLICATE == tmp.dpoi_type),
250 : "%U links to %U",
251 : format_mfib_prefix, pfx,
252 : format_dpo_type, tmp.dpoi_type);
253 :
254 68 : va_start(ap, n_buckets);
255 68 : res = mfib_test_validate_rep_v(rep, n_buckets, &ap);
256 68 : va_end(ap);
257 :
258 68 : dpo_reset(&tmp);
259 : }
260 :
261 :
262 86 : return (res);
263 : }
264 :
265 : static int
266 52 : mfib_test_entry_itf (fib_node_index_t fei,
267 : u32 sw_if_index,
268 : mfib_itf_flags_t flags)
269 : {
270 : const mfib_prefix_t *pfx;
271 : const mfib_entry_t *mfe;
272 : const mfib_itf_t *mfi;
273 : int res;
274 :
275 52 : res = 0;
276 52 : mfe = mfib_entry_get(fei);
277 52 : mfi = mfib_entry_get_itf(mfe, sw_if_index);
278 52 : pfx = mfib_entry_get_prefix(fei);
279 :
280 52 : MFIB_TEST_REP((NULL != mfi),
281 : "%U has interface %d",
282 : format_mfib_prefix, pfx, sw_if_index);
283 :
284 52 : MFIB_TEST_REP((flags == mfi->mfi_flags),
285 : "%U interface %d has flags %U expect %U",
286 : format_mfib_prefix, pfx, sw_if_index,
287 : format_mfib_itf_flags, flags,
288 : format_mfib_itf_flags, mfi->mfi_flags);
289 :
290 52 : return (res);
291 : }
292 :
293 : static int
294 4 : mfib_test_entry_no_itf (fib_node_index_t fei,
295 : u32 sw_if_index)
296 : {
297 : const mfib_prefix_t *pfx;
298 : const mfib_entry_t *mfe;
299 : const mfib_itf_t *mfi;
300 : int res;
301 :
302 4 : res = 0;
303 4 : mfe = mfib_entry_get(fei);
304 4 : mfi = mfib_entry_get_itf(mfe, sw_if_index);
305 4 : pfx = mfib_entry_get_prefix(fei);
306 :
307 4 : MFIB_TEST_REP((NULL == mfi),
308 : "%U has no interface %d",
309 : format_mfib_prefix, pfx, sw_if_index);
310 :
311 4 : return (res);
312 : }
313 :
314 : static int
315 2 : mfib_test_i (fib_protocol_t PROTO,
316 : vnet_link_t LINKT,
317 : const mfib_prefix_t *pfx_no_forward,
318 : const mfib_prefix_t *pfx_s_g,
319 : const mfib_prefix_t *pfx_star_g_1,
320 : const mfib_prefix_t *pfx_star_g_2,
321 : const mfib_prefix_t *pfx_star_g_3,
322 : const mfib_prefix_t *pfx_star_g_slash_m,
323 : const fib_prefix_t *pfx_itf,
324 : const ip46_address_t *addr_nbr1,
325 : const ip46_address_t *addr_nbr2)
326 : {
327 : 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;
328 : u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
329 : fib_node_index_t ai_1, ai_2, ai_3, ai_nbr1, ai_nbr2;
330 : test_main_t *tm;
331 : int res;
332 :
333 : mfib_prefix_t all_1s;
334 2 : clib_memset(&all_1s, 0xfd, sizeof(all_1s));
335 :
336 2 : res = 0;
337 2 : n_entries = pool_elts(mfib_entry_pool);
338 2 : n_itfs = pool_elts(mfib_itf_pool);
339 2 : n_reps = pool_elts(replicate_pool);
340 2 : n_pls = fib_path_list_pool_size();
341 2 : tm = &test_main;
342 :
343 2 : ai_1 = adj_mcast_add_or_lock(PROTO,
344 : LINKT,
345 2 : tm->hw[1]->sw_if_index);
346 2 : ai_2 = adj_mcast_add_or_lock(PROTO,
347 : LINKT,
348 2 : tm->hw[2]->sw_if_index);
349 2 : ai_3 = adj_mcast_add_or_lock(PROTO,
350 : LINKT,
351 2 : tm->hw[3]->sw_if_index);
352 2 : ai_nbr1 = adj_nbr_add_or_lock(PROTO,
353 : LINKT,
354 : addr_nbr1,
355 2 : tm->hw[0]->sw_if_index);
356 2 : ai_nbr2 = adj_nbr_add_or_lock(PROTO,
357 : LINKT,
358 : addr_nbr2,
359 2 : tm->hw[0]->sw_if_index);
360 :
361 2 : MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
362 :
363 : /* Find or create FIB table 11 */
364 2 : fib_index = mfib_table_find_or_create_and_lock(PROTO, 11, MFIB_SOURCE_API);
365 :
366 2 : fib_table_entry_update_one_path(0,
367 : pfx_itf,
368 : FIB_SOURCE_INTERFACE,
369 : (FIB_ENTRY_FLAG_CONNECTED |
370 : FIB_ENTRY_FLAG_ATTACHED),
371 : DPO_PROTO_IP4,
372 : NULL,
373 2 : tm->hw[0]->sw_if_index,
374 : ~0, // invalid fib index
375 : 1, // weight
376 : NULL,
377 : FIB_ROUTE_PATH_FLAG_NONE);
378 :
379 2 : mfib_prefix_t pfx_dft = {
380 : .fp_len = 0,
381 : .fp_proto = PROTO,
382 : };
383 2 : mfei_dflt = mfib_table_lookup_exact_match(fib_index, &pfx_dft);
384 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
385 2 : MFIB_TEST(!mfib_test_entry(mfei_dflt,
386 : MFIB_ENTRY_FLAG_DROP,
387 : 0),
388 : "(*,*) no replcaitions");
389 :
390 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_dflt, "(*,*) presnet");
391 2 : MFIB_TEST(!mfib_test_entry(mfei_dflt,
392 : MFIB_ENTRY_FLAG_DROP,
393 : 0),
394 : "(*,*) no replcaitions");
395 :
396 :
397 4 : fib_route_path_t path_via_if0 = {
398 2 : .frp_proto = fib_proto_to_dpo(PROTO),
399 : .frp_addr = zero_addr,
400 2 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
401 : .frp_fib_index = ~0,
402 : .frp_weight = 1,
403 : .frp_flags = 0,
404 : .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
405 : };
406 :
407 2 : mfib_table_entry_path_update (fib_index, pfx_no_forward, MFIB_SOURCE_API,
408 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
409 :
410 2 : mfei_no_f = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
411 2 : MFIB_TEST(!mfib_test_entry(mfei_no_f,
412 : MFIB_ENTRY_FLAG_NONE,
413 : 0),
414 : "%U no replcaitions",
415 : format_mfib_prefix, pfx_no_forward);
416 2 : MFIB_TEST(!mfib_test_entry_itf(mfei_no_f, tm->hw[0]->sw_if_index,
417 : MFIB_ITF_FLAG_ACCEPT),
418 : "%U interface not accepting",
419 : format_mfib_prefix, pfx_no_forward);
420 :
421 4 : fib_route_path_t path_via_if1 = {
422 2 : .frp_proto = fib_proto_to_dpo(PROTO),
423 : .frp_addr = zero_addr,
424 2 : .frp_sw_if_index = tm->hw[1]->sw_if_index,
425 : .frp_fib_index = ~0,
426 : .frp_weight = 1,
427 : .frp_flags = 0,
428 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
429 : };
430 4 : fib_route_path_t path_via_if2 = {
431 2 : .frp_proto = fib_proto_to_dpo(PROTO),
432 : .frp_addr = zero_addr,
433 2 : .frp_sw_if_index = tm->hw[2]->sw_if_index,
434 : .frp_fib_index = ~0,
435 : .frp_weight = 1,
436 : .frp_flags = 0,
437 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
438 : };
439 4 : fib_route_path_t path_via_if3 = {
440 2 : .frp_proto = fib_proto_to_dpo(PROTO),
441 : .frp_addr = zero_addr,
442 2 : .frp_sw_if_index = tm->hw[3]->sw_if_index,
443 : .frp_fib_index = ~0,
444 : .frp_weight = 1,
445 : .frp_flags = 0,
446 : .frp_mitf_flags = (MFIB_ITF_FLAG_FORWARD |
447 : MFIB_ITF_FLAG_NEGATE_SIGNAL),
448 : };
449 2 : fib_route_path_t *two_paths = NULL;
450 2 : vec_add1(two_paths, path_via_if2);
451 2 : vec_add1(two_paths, path_via_if3);
452 :
453 : /*
454 : * An (S,G) with 1 accepting and 3 forwarding paths
455 : */
456 2 : mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
457 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
458 2 : mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
459 : MFIB_ENTRY_FLAG_NONE, &path_via_if1);
460 2 : mfib_table_entry_paths_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
461 : MFIB_ENTRY_FLAG_NONE, two_paths);
462 :
463 2 : mfei_s_g = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
464 :
465 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID != mfei_s_g,
466 : "%U present",
467 : format_mfib_prefix, pfx_s_g);
468 2 : MFIB_TEST(!mfib_test_entry(mfei_s_g,
469 : MFIB_ENTRY_FLAG_NONE,
470 : 3,
471 : DPO_ADJACENCY_MCAST, ai_1,
472 : DPO_ADJACENCY_MCAST, ai_2,
473 : DPO_ADJACENCY_MCAST, ai_3),
474 : "%U replicate ok",
475 : format_mfib_prefix, pfx_s_g);
476 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[0]->sw_if_index,
477 : MFIB_ITF_FLAG_ACCEPT));
478 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[1]->sw_if_index,
479 : MFIB_ITF_FLAG_FORWARD));
480 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[2]->sw_if_index,
481 : MFIB_ITF_FLAG_FORWARD));
482 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_s_g, tm->hw[3]->sw_if_index,
483 : (MFIB_ITF_FLAG_FORWARD |
484 : MFIB_ITF_FLAG_NEGATE_SIGNAL)));
485 :
486 : /*
487 : * A (*,G), which the same G as the (S,G).
488 : * different paths. test our LPM.
489 : */
490 : mfei_g_1 =
491 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_1, MFIB_SOURCE_API,
492 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
493 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_1, MFIB_SOURCE_API,
494 : MFIB_ENTRY_FLAG_NONE, &path_via_if1);
495 :
496 : /*
497 : * test we find the *,G and S,G via LPM and exact matches
498 : */
499 2 : mfei = mfib_table_lookup_exact_match(fib_index,
500 : pfx_star_g_1);
501 2 : MFIB_TEST(mfei == mfei_g_1,
502 : "%U found via exact match",
503 : format_mfib_prefix, pfx_star_g_1);
504 2 : MFIB_TEST(!mfib_test_entry(mfei,
505 : MFIB_ENTRY_FLAG_NONE,
506 : 1,
507 : DPO_ADJACENCY_MCAST, ai_1),
508 : "%U replicate ok",
509 : format_mfib_prefix, pfx_star_g_1);
510 :
511 2 : mfei = mfib_table_lookup(fib_index,
512 : pfx_star_g_1);
513 2 : MFIB_TEST(mfei == mfei_g_1,
514 : "[e:%d a:%d] %U found via LP match",
515 : mfei, mfei_g_1,
516 : format_mfib_prefix, pfx_star_g_1);
517 :
518 2 : MFIB_TEST(!mfib_test_entry(mfei,
519 : MFIB_ENTRY_FLAG_NONE,
520 : 1,
521 : DPO_ADJACENCY_MCAST, ai_1),
522 : "%U replicate ok",
523 : format_mfib_prefix, pfx_star_g_1);
524 :
525 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
526 2 : MFIB_TEST(mfei == mfei_s_g,
527 : "%U found via exact match",
528 : format_mfib_prefix, pfx_s_g);
529 :
530 2 : MFIB_TEST(!mfib_test_entry(mfei,
531 : MFIB_ENTRY_FLAG_NONE,
532 : 3,
533 : DPO_ADJACENCY_MCAST, ai_1,
534 : DPO_ADJACENCY_MCAST, ai_2,
535 : DPO_ADJACENCY_MCAST, ai_3),
536 : "%U replicate OK",
537 : format_mfib_prefix, pfx_s_g);
538 2 : mfei = mfib_table_lookup(fib_index, pfx_s_g);
539 2 : MFIB_TEST(mfei == mfei_s_g,
540 : "%U found via LP match",
541 : format_mfib_prefix, pfx_s_g);
542 :
543 2 : MFIB_TEST(!mfib_test_entry(mfei,
544 : MFIB_ENTRY_FLAG_NONE,
545 : 3,
546 : DPO_ADJACENCY_MCAST, ai_1,
547 : DPO_ADJACENCY_MCAST, ai_2,
548 : DPO_ADJACENCY_MCAST, ai_3),
549 : "%U replicate OK",
550 : format_mfib_prefix, pfx_s_g);
551 :
552 : /*
553 : * A (*,G/m), which the same root G as the (*,G).
554 : * different paths. test our LPM.
555 : */
556 2 : path_via_if2.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
557 2 : mfei_g_m = mfib_table_entry_path_update (
558 : fib_index, pfx_star_g_slash_m, MFIB_SOURCE_API, MFIB_ENTRY_FLAG_NONE,
559 : &path_via_if2);
560 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_slash_m,
561 : MFIB_SOURCE_API, MFIB_ENTRY_FLAG_NONE,
562 : &path_via_if3);
563 :
564 : /*
565 : * test we find the (*,G/m), (*,G) and (S,G) via LPM and exact matches
566 : */
567 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
568 2 : MFIB_TEST((mfei_g_1 == mfei),
569 : "%U found via DP LPM: %d",
570 : format_mfib_prefix, pfx_star_g_1, mfei);
571 :
572 2 : MFIB_TEST(!mfib_test_entry(mfei,
573 : MFIB_ENTRY_FLAG_NONE,
574 : 1,
575 : DPO_ADJACENCY_MCAST, ai_1),
576 : "%U replicate ok",
577 : format_mfib_prefix, pfx_star_g_1);
578 :
579 2 : mfei = mfib_table_lookup(fib_index, pfx_star_g_1);
580 :
581 2 : 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 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_s_g);
589 :
590 2 : MFIB_TEST(!mfib_test_entry(mfei,
591 : MFIB_ENTRY_FLAG_NONE,
592 : 3,
593 : DPO_ADJACENCY_MCAST, ai_1,
594 : DPO_ADJACENCY_MCAST, ai_2,
595 : DPO_ADJACENCY_MCAST, ai_3),
596 : "%U replicate OK",
597 : format_mfib_prefix, pfx_s_g);
598 2 : mfei = mfib_table_lookup(fib_index, pfx_s_g);
599 :
600 2 : MFIB_TEST(!mfib_test_entry(mfei,
601 : MFIB_ENTRY_FLAG_NONE,
602 : 3,
603 : DPO_ADJACENCY_MCAST, ai_1,
604 : DPO_ADJACENCY_MCAST, ai_2,
605 : DPO_ADJACENCY_MCAST, ai_3),
606 : "%U replicate OK",
607 : format_mfib_prefix, pfx_s_g);
608 :
609 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
610 2 : MFIB_TEST(mfei = mfei_g_m,
611 : "%U Found via exact match",
612 : format_mfib_prefix, pfx_star_g_slash_m);
613 2 : MFIB_TEST(!mfib_test_entry(mfei,
614 : MFIB_ENTRY_FLAG_NONE,
615 : 1,
616 : DPO_ADJACENCY_MCAST, ai_3),
617 : "%U replicate OK",
618 : format_mfib_prefix, pfx_star_g_slash_m);
619 2 : MFIB_TEST(mfei_g_m == mfib_table_lookup(fib_index, pfx_star_g_slash_m),
620 : "%U found via LPM",
621 : format_mfib_prefix, pfx_star_g_slash_m);
622 :
623 : /*
624 : * Add a for-us path
625 : */
626 4 : fib_route_path_t path_for_us = {
627 2 : .frp_proto = fib_proto_to_dpo(PROTO),
628 : .frp_addr = zero_addr,
629 : .frp_sw_if_index = 0xffffffff,
630 : .frp_fib_index = ~0,
631 : .frp_weight = 1,
632 : .frp_flags = FIB_ROUTE_PATH_LOCAL,
633 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
634 : };
635 :
636 2 : mfei = mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
637 : MFIB_ENTRY_FLAG_NONE, &path_for_us);
638 :
639 2 : MFIB_TEST(!mfib_test_entry(mfei,
640 : MFIB_ENTRY_FLAG_NONE,
641 : 4,
642 : DPO_ADJACENCY_MCAST, ai_1,
643 : DPO_ADJACENCY_MCAST, ai_2,
644 : DPO_ADJACENCY_MCAST, ai_3,
645 : DPO_RECEIVE, 0),
646 : "%U replicate OK",
647 : format_mfib_prefix, pfx_s_g);
648 :
649 : /*
650 : * remove a for-us path
651 : */
652 2 : mfib_table_entry_path_remove(fib_index,
653 : pfx_s_g,
654 : MFIB_SOURCE_API,
655 : &path_for_us);
656 :
657 2 : MFIB_TEST(!mfib_test_entry(mfei,
658 : MFIB_ENTRY_FLAG_NONE,
659 : 3,
660 : DPO_ADJACENCY_MCAST, ai_1,
661 : DPO_ADJACENCY_MCAST, ai_2,
662 : DPO_ADJACENCY_MCAST, ai_3),
663 : "%U replicate OK",
664 : format_mfib_prefix, pfx_s_g);
665 :
666 : /*
667 : * update an existing forwarding path to be only accepting
668 : * - expect it to be removed from the replication set.
669 : */
670 2 : path_via_if3.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
671 2 : mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
672 : MFIB_ENTRY_FLAG_NONE, &path_via_if3);
673 :
674 2 : MFIB_TEST(!mfib_test_entry(mfei,
675 : MFIB_ENTRY_FLAG_NONE,
676 : 2,
677 : DPO_ADJACENCY_MCAST, ai_1,
678 : DPO_ADJACENCY_MCAST, ai_2),
679 : "%U replicate OK",
680 : format_mfib_prefix, pfx_s_g);
681 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
682 : MFIB_ITF_FLAG_ACCEPT));
683 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
684 : MFIB_ITF_FLAG_FORWARD));
685 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
686 : MFIB_ITF_FLAG_FORWARD));
687 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
688 : MFIB_ITF_FLAG_ACCEPT));
689 : /*
690 : * Make the path forwarding again
691 : * - expect it to be added back to the replication set
692 : */
693 2 : path_via_if3.frp_mitf_flags = (MFIB_ITF_FLAG_FORWARD |
694 : MFIB_ITF_FLAG_ACCEPT |
695 : MFIB_ITF_FLAG_NEGATE_SIGNAL);
696 2 : mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
697 : MFIB_ENTRY_FLAG_NONE, &path_via_if3);
698 :
699 2 : mfei = mfib_table_lookup_exact_match(fib_index,
700 : pfx_s_g);
701 :
702 2 : MFIB_TEST(!mfib_test_entry(mfei,
703 : MFIB_ENTRY_FLAG_NONE,
704 : 3,
705 : DPO_ADJACENCY_MCAST, ai_1,
706 : DPO_ADJACENCY_MCAST, ai_2,
707 : DPO_ADJACENCY_MCAST, ai_3),
708 : "%U replicate OK",
709 : format_mfib_prefix, pfx_s_g);
710 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
711 : MFIB_ITF_FLAG_ACCEPT));
712 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
713 : MFIB_ITF_FLAG_FORWARD));
714 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
715 : MFIB_ITF_FLAG_FORWARD));
716 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[3]->sw_if_index,
717 : (MFIB_ITF_FLAG_FORWARD |
718 : MFIB_ITF_FLAG_ACCEPT |
719 : MFIB_ITF_FLAG_NEGATE_SIGNAL)));
720 :
721 : /*
722 : * update flags on the entry
723 : */
724 2 : mfib_table_entry_update(fib_index,
725 : pfx_s_g,
726 : MFIB_SOURCE_API,
727 : MFIB_RPF_ID_NONE,
728 : MFIB_ENTRY_FLAG_SIGNAL);
729 2 : MFIB_TEST(!mfib_test_entry(mfei,
730 : MFIB_ENTRY_FLAG_SIGNAL,
731 : 3,
732 : DPO_ADJACENCY_MCAST, ai_1,
733 : DPO_ADJACENCY_MCAST, ai_2,
734 : DPO_ADJACENCY_MCAST, ai_3),
735 : "%U replicate OK",
736 : format_mfib_prefix, pfx_s_g);
737 :
738 : /*
739 : * remove paths
740 : */
741 2 : mfib_table_entry_path_remove(fib_index,
742 : pfx_s_g,
743 : MFIB_SOURCE_API,
744 : &path_via_if3);
745 :
746 2 : MFIB_TEST(!mfib_test_entry(mfei,
747 : MFIB_ENTRY_FLAG_SIGNAL,
748 : 2,
749 : DPO_ADJACENCY_MCAST, ai_1,
750 : DPO_ADJACENCY_MCAST, ai_2),
751 : "%U replicate OK",
752 : format_mfib_prefix, pfx_s_g);
753 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
754 : MFIB_ITF_FLAG_ACCEPT));
755 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[1]->sw_if_index,
756 : MFIB_ITF_FLAG_FORWARD));
757 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
758 : MFIB_ITF_FLAG_FORWARD));
759 2 : MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
760 :
761 2 : mfib_table_entry_path_remove(fib_index,
762 : pfx_s_g,
763 : MFIB_SOURCE_API,
764 : &path_via_if1);
765 :
766 2 : MFIB_TEST(!mfib_test_entry(mfei,
767 : MFIB_ENTRY_FLAG_SIGNAL,
768 : 1,
769 : DPO_ADJACENCY_MCAST, ai_2),
770 : "%U replicate OK",
771 : format_mfib_prefix, pfx_s_g);
772 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[0]->sw_if_index,
773 : MFIB_ITF_FLAG_ACCEPT));
774 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index,
775 : MFIB_ITF_FLAG_FORWARD));
776 2 : MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index));
777 :
778 : /*
779 : * remove
780 : */
781 : /* mfib_table_entry_path_remove(fib_index, */
782 : /* pfx_s_g, */
783 : /* MFIB_SOURCE_API, */
784 : /* &path_via_if0); */
785 :
786 : /* MFIB_TEST(!mfib_test_entry(mfei, */
787 : /* MFIB_ENTRY_FLAG_SIGNAL, */
788 : /* 1, */
789 : /* DPO_ADJACENCY_MCAST, ai_2), */
790 : /* "%U replicate OK", */
791 : /* format_mfib_prefix, pfx_s_g); */
792 : /* MFIB_TEST_NS(!mfib_test_entry_itf(mfei, tm->hw[2]->sw_if_index, */
793 : /* MFIB_ITF_FLAG_FORWARD)); */
794 : /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[0]->sw_if_index)); */
795 : /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[1]->sw_if_index)); */
796 : /* MFIB_TEST_NS(!mfib_test_entry_no_itf(mfei, tm->hw[3]->sw_if_index)); */
797 :
798 : /*
799 : * remove the last path and the accepting only interface,
800 : * the entry still has flags so it remains
801 : */
802 2 : vec_reset_length(two_paths);
803 2 : vec_add1(two_paths, path_via_if0);
804 2 : vec_add1(two_paths, path_via_if2);
805 :
806 2 : mfib_table_entry_paths_remove(fib_index,
807 : pfx_s_g,
808 : MFIB_SOURCE_API,
809 : two_paths);
810 :
811 2 : 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 2 : mfib_table_entry_update(fib_index,
821 : pfx_s_g,
822 : MFIB_SOURCE_API,
823 : MFIB_RPF_ID_NONE,
824 : (MFIB_ENTRY_FLAG_SIGNAL |
825 : MFIB_ENTRY_FLAG_CONNECTED));
826 2 : MFIB_TEST(!mfib_test_entry(mfei,
827 : (MFIB_ENTRY_FLAG_SIGNAL |
828 : MFIB_ENTRY_FLAG_CONNECTED),
829 : 0),
830 : "%U no replications",
831 : format_mfib_prefix, pfx_s_g);
832 :
833 : /*
834 : * An entry with a NS interface
835 : */
836 2 : path_via_if0.frp_mitf_flags = (MFIB_ITF_FLAG_ACCEPT |
837 : MFIB_ITF_FLAG_NEGATE_SIGNAL);
838 : mfei_g_2 =
839 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_2, MFIB_SOURCE_API,
840 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
841 2 : 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 2 : mfe = mfib_entry_get(mfei_g_2);
855 2 : mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
856 :
857 2 : mfib_signal_push(mfe, mfi, NULL);
858 : }
859 :
860 : /*
861 : * An entry with a NS interface
862 : */
863 2 : path_via_if0.frp_mitf_flags = (MFIB_ITF_FLAG_ACCEPT |
864 : MFIB_ITF_FLAG_NEGATE_SIGNAL);
865 : mfei_g_3 =
866 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_3, MFIB_SOURCE_API,
867 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
868 2 : MFIB_TEST(!mfib_test_entry(mfei_g_3,
869 : MFIB_ENTRY_FLAG_NONE,
870 : 0),
871 : "%U No replications",
872 : format_mfib_prefix, pfx_star_g_3);
873 :
874 : /*
875 : * Simulate a signal from the data-plane
876 : */
877 : {
878 : mfib_entry_t *mfe;
879 : mfib_itf_t *mfi;
880 :
881 2 : mfe = mfib_entry_get(mfei_g_3);
882 2 : mfi = mfib_entry_get_itf(mfe, path_via_if0.frp_sw_if_index);
883 :
884 2 : mfib_signal_push(mfe, mfi, NULL);
885 : }
886 :
887 2 : if (FIB_PROTOCOL_IP6 == PROTO)
888 : {
889 : /*
890 : * All the entries are present. let's ensure we can find them all
891 : * via exact and longest prefix matches.
892 : */
893 : /*
894 : * A source address we will never match
895 : */
896 2 : ip6_address_t src = {
897 1 : .as_u64[0] = clib_host_to_net_u64(0x3001000000000000),
898 1 : .as_u64[1] = clib_host_to_net_u64(0xffffffffffffffff),
899 : };
900 :
901 : /*
902 : * Find the (*,G/m)
903 : */
904 1 : MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
905 : ip6_mfib_get(fib_index),
906 : &src,
907 : &pfx_star_g_slash_m->fp_grp_addr.ip6)),
908 : "%U found via DP LPM grp=%U",
909 : format_mfib_prefix, pfx_star_g_slash_m,
910 : format_ip6_address, &pfx_star_g_slash_m->fp_grp_addr.ip6);
911 :
912 1 : ip6_address_t tmp = pfx_star_g_slash_m->fp_grp_addr.ip6;
913 1 : tmp.as_u8[15] = 0xff;
914 :
915 1 : MFIB_TEST((mfei_g_m == ip6_mfib_table_fwd_lookup(
916 : ip6_mfib_get(fib_index),
917 : &pfx_s_g->fp_src_addr.ip6,
918 : &tmp)),
919 : "%U found via DP LPM grp=%U",
920 : format_mfib_prefix, pfx_star_g_slash_m,
921 : format_ip6_address, &tmp);
922 :
923 : /*
924 : * Find the (S,G).
925 : */
926 1 : mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
927 : &pfx_s_g->fp_src_addr.ip6,
928 : &pfx_s_g->fp_grp_addr.ip6);
929 1 : MFIB_TEST((mfei_s_g == mfei),
930 : "%U found via DP LPM: %d",
931 : format_mfib_prefix, pfx_s_g, mfei);
932 :
933 : /*
934 : * Find the 3 (*,G) s
935 : */
936 1 : mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
937 : &src,
938 : &pfx_star_g_1->fp_grp_addr.ip6);
939 1 : MFIB_TEST((mfei_g_1 == mfei),
940 : "%U found via DP LPM: %d",
941 : format_mfib_prefix, pfx_star_g_1, mfei);
942 1 : mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
943 : &src,
944 : &pfx_star_g_2->fp_grp_addr.ip6);
945 1 : MFIB_TEST((mfei_g_2 == mfei),
946 : "%U found via DP LPM: %d",
947 : format_mfib_prefix, pfx_star_g_2, mfei);
948 1 : mfei = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index),
949 : &src,
950 : &pfx_star_g_3->fp_grp_addr.ip6);
951 1 : MFIB_TEST((mfei_g_3 == mfei),
952 : "%U found via DP LPM: %d",
953 : format_mfib_prefix, pfx_star_g_3, mfei);
954 : }
955 :
956 : /*
957 : * remove flags on the entry. This is the last of the
958 : * state associated with the entry, so now it goes.
959 : */
960 2 : mfib_table_entry_update(fib_index,
961 : pfx_s_g,
962 : MFIB_SOURCE_API,
963 : MFIB_RPF_ID_NONE,
964 : MFIB_ENTRY_FLAG_NONE);
965 2 : mfei = mfib_table_lookup_exact_match(fib_index,
966 : pfx_s_g);
967 2 : 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 2 : mfib_table_entry_path_remove(fib_index,
975 : pfx_no_forward,
976 : MFIB_SOURCE_API,
977 : &path_via_if0);
978 :
979 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_no_forward);
980 2 : 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 2 : mfib_table_entry_delete(fib_index,
988 : pfx_star_g_1,
989 : MFIB_SOURCE_API);
990 :
991 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
992 2 : 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 2 : mfib_table_entry_delete(fib_index,
999 : pfx_star_g_2,
1000 : MFIB_SOURCE_API);
1001 :
1002 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_2);
1003 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1004 : "%U Gone",
1005 : format_mfib_prefix, pfx_star_g_2);
1006 2 : mfib_table_entry_delete(fib_index,
1007 : pfx_star_g_3,
1008 : MFIB_SOURCE_API);
1009 :
1010 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_3);
1011 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1012 : "%U Gone",
1013 : format_mfib_prefix, pfx_star_g_3);
1014 :
1015 2 : mfib_table_entry_delete(fib_index,
1016 : pfx_star_g_slash_m,
1017 : MFIB_SOURCE_API);
1018 :
1019 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_slash_m);
1020 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1021 : "%U Gone",
1022 : format_mfib_prefix, pfx_star_g_slash_m);
1023 :
1024 : /*
1025 : * Entries with paths via unicast next-hops
1026 : */
1027 4 : fib_route_path_t path_via_nbr1 = {
1028 2 : .frp_proto = fib_proto_to_dpo(PROTO),
1029 : .frp_addr = *addr_nbr1,
1030 2 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
1031 : .frp_fib_index = ~0,
1032 : .frp_weight = 1,
1033 : .frp_flags = 0,
1034 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1035 : };
1036 4 : fib_route_path_t path_via_nbr2 = {
1037 2 : .frp_proto = fib_proto_to_dpo(PROTO),
1038 : .frp_addr = *addr_nbr2,
1039 2 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
1040 : .frp_fib_index = ~0,
1041 : .frp_weight = 1,
1042 : .frp_flags = 0,
1043 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1044 : };
1045 :
1046 : mfei_g_1 =
1047 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_1, MFIB_SOURCE_API,
1048 : MFIB_ENTRY_FLAG_NONE, &path_via_nbr1);
1049 : mfei_g_1 =
1050 2 : mfib_table_entry_path_update (fib_index, pfx_star_g_1, MFIB_SOURCE_API,
1051 : MFIB_ENTRY_FLAG_NONE, &path_via_nbr2);
1052 2 : MFIB_TEST(!mfib_test_entry(mfei_g_1,
1053 : MFIB_ENTRY_FLAG_NONE,
1054 : 2,
1055 : DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
1056 : DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1057 : "%U replicate OK",
1058 : format_mfib_prefix, pfx_star_g_1);
1059 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1060 : MFIB_ITF_FLAG_FORWARD));
1061 :
1062 2 : mfib_table_entry_path_remove(fib_index,
1063 : pfx_star_g_1,
1064 : MFIB_SOURCE_API,
1065 : &path_via_nbr1);
1066 :
1067 2 : MFIB_TEST(!mfib_test_entry(mfei_g_1,
1068 : MFIB_ENTRY_FLAG_NONE,
1069 : 1,
1070 : DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
1071 : "%U replicate OK",
1072 : format_mfib_prefix, pfx_star_g_1);
1073 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
1074 : MFIB_ITF_FLAG_FORWARD));
1075 :
1076 2 : mfib_table_entry_path_remove(fib_index,
1077 : pfx_star_g_1,
1078 : MFIB_SOURCE_API,
1079 : &path_via_nbr2);
1080 2 : mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
1081 2 : MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
1082 : "%U Gone",
1083 : format_mfib_prefix, pfx_star_g_1);
1084 :
1085 : /*
1086 : * Add a prefix as a special/exclusive route
1087 : */
1088 2 : dpo_id_t td = DPO_INVALID;
1089 2 : index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
1090 :
1091 2 : dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
1092 2 : replicate_set_bucket(repi, 0, &td);
1093 :
1094 2 : mfei = mfib_table_entry_special_add(fib_index,
1095 : pfx_star_g_3,
1096 : MFIB_SOURCE_SRv6,
1097 : MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
1098 : repi);
1099 2 : MFIB_TEST(!mfib_test_entry(mfei,
1100 : (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1101 : MFIB_ENTRY_FLAG_EXCLUSIVE),
1102 : 1,
1103 : DPO_ADJACENCY_MCAST, ai_2),
1104 : "%U exclusive replicate OK",
1105 : format_mfib_prefix, pfx_star_g_3);
1106 :
1107 : /*
1108 : * update a special/exclusive route
1109 : */
1110 2 : index_t repi2 = replicate_create(1, fib_proto_to_dpo(PROTO));
1111 :
1112 2 : dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1);
1113 2 : replicate_set_bucket(repi2, 0, &td);
1114 :
1115 2 : mfib_entry_update(mfei,
1116 : MFIB_SOURCE_SRv6,
1117 : (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1118 : MFIB_ENTRY_FLAG_EXCLUSIVE),
1119 : MFIB_RPF_ID_NONE,
1120 : repi2);
1121 2 : MFIB_TEST(!mfib_test_entry(mfei,
1122 : (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
1123 : MFIB_ENTRY_FLAG_EXCLUSIVE),
1124 : 1,
1125 : DPO_ADJACENCY_MCAST, ai_1),
1126 : "%U exclusive update replicate OK",
1127 : format_mfib_prefix, pfx_star_g_3);
1128 :
1129 2 : mfib_table_entry_delete(fib_index,
1130 : pfx_star_g_3,
1131 : MFIB_SOURCE_SRv6);
1132 2 : dpo_reset(&td);
1133 :
1134 : /*
1135 : * A Multicast LSP. This a mLDP head-end
1136 : */
1137 : fib_node_index_t ai_mpls_10_10_10_1, lfei;
1138 4 : ip46_address_t nh_10_10_10_1 = {
1139 : .ip4 = {
1140 2 : .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1141 : },
1142 : };
1143 2 : ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1144 : VNET_LINK_MPLS,
1145 : &nh_10_10_10_1,
1146 2 : tm->hw[0]->sw_if_index);
1147 :
1148 2 : fib_prefix_t pfx_3500 = {
1149 : .fp_len = 21,
1150 : .fp_proto = FIB_PROTOCOL_MPLS,
1151 : .fp_label = 3500,
1152 : .fp_eos = MPLS_EOS,
1153 : .fp_payload_proto = DPO_PROTO_IP4,
1154 : };
1155 2 : fib_test_rep_bucket_t mc_0 = {
1156 : .type = FT_REP_LABEL_O_ADJ,
1157 : .label_o_adj = {
1158 : .adj = ai_mpls_10_10_10_1,
1159 : .label = 3300,
1160 : .eos = MPLS_EOS,
1161 : },
1162 : };
1163 2 : fib_mpls_label_t *l3300 = NULL, fml3300 = {
1164 : .fml_value = 3300,
1165 : };
1166 2 : vec_add1(l3300, fml3300);
1167 :
1168 : /*
1169 : * MPLS enable an interface so we get the MPLS table created
1170 : */
1171 2 : mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
1172 2 : mpls_sw_interface_enable_disable (&mpls_main, tm->hw[0]->sw_if_index, 1);
1173 :
1174 2 : lfei = fib_table_entry_update_one_path(0, // default MPLS Table
1175 : &pfx_3500,
1176 : FIB_SOURCE_API,
1177 : FIB_ENTRY_FLAG_MULTICAST,
1178 : DPO_PROTO_IP4,
1179 : &nh_10_10_10_1,
1180 2 : tm->hw[0]->sw_if_index,
1181 : ~0, // invalid fib index
1182 : 1,
1183 : l3300,
1184 : FIB_ROUTE_PATH_FLAG_NONE);
1185 2 : MFIB_TEST(!fib_test_validate_entry(lfei,
1186 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1187 : 1,
1188 : &mc_0),
1189 : "3500 via replicate over 10.10.10.1");
1190 :
1191 : /*
1192 : * An (S,G) that resolves via the mLDP head-end
1193 : */
1194 2 : fib_route_path_t path_via_mldp = {
1195 : .frp_proto = DPO_PROTO_MPLS,
1196 2 : .frp_local_label = pfx_3500.fp_label,
1197 : .frp_eos = MPLS_EOS,
1198 : .frp_sw_if_index = 0xffffffff,
1199 : .frp_fib_index = 0,
1200 : .frp_weight = 1,
1201 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
1202 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1203 : };
1204 2 : dpo_id_t mldp_dpo = DPO_INVALID;
1205 :
1206 2 : fib_entry_contribute_forwarding(lfei,
1207 : FIB_FORW_CHAIN_TYPE_MPLS_EOS,
1208 : &mldp_dpo);
1209 :
1210 2 : mfei = mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
1211 : MFIB_ENTRY_FLAG_NONE, &path_via_mldp);
1212 :
1213 2 : MFIB_TEST(!mfib_test_entry(mfei,
1214 : MFIB_ENTRY_FLAG_NONE,
1215 : 1,
1216 : DPO_REPLICATE, mldp_dpo.dpoi_index),
1217 : "%U over-mLDP replicate OK",
1218 : format_mfib_prefix, pfx_s_g);
1219 :
1220 : /*
1221 : * add a for-us path. this tests two types of non-attached paths on one entry
1222 : */
1223 2 : mfei = mfib_table_entry_path_update (fib_index, pfx_s_g, MFIB_SOURCE_API,
1224 : MFIB_ENTRY_FLAG_NONE, &path_for_us);
1225 2 : MFIB_TEST(!mfib_test_entry(mfei,
1226 : MFIB_ENTRY_FLAG_NONE,
1227 : 2,
1228 : DPO_REPLICATE, mldp_dpo.dpoi_index,
1229 : DPO_RECEIVE, 0),
1230 : "%U mLDP+for-us replicate OK",
1231 : format_mfib_prefix, pfx_s_g);
1232 :
1233 2 : mfib_table_entry_delete(fib_index,
1234 : pfx_s_g,
1235 : MFIB_SOURCE_API);
1236 2 : fib_table_entry_delete(0,
1237 : &pfx_3500,
1238 : FIB_SOURCE_API);
1239 2 : dpo_reset(&mldp_dpo);
1240 :
1241 : /*
1242 : * Unlock the table - it's the last lock so should be gone thereafter
1243 : */
1244 2 : MFIB_TEST(((PROTO == FIB_PROTOCOL_IP4 ? 3 : 5) ==
1245 : mfib_table_get_n_routes(fib_index, PROTO)),
1246 : "1 = %d route left in the FIB",
1247 : mfib_table_get_n_routes(fib_index, PROTO));
1248 :
1249 2 : mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API);
1250 :
1251 2 : MFIB_TEST((FIB_NODE_INDEX_INVALID ==
1252 : mfib_table_find(PROTO, fib_index)),
1253 : "MFIB table %d gone", fib_index);
1254 :
1255 2 : adj_unlock(ai_1);
1256 2 : adj_unlock(ai_2);
1257 2 : adj_unlock(ai_3);
1258 2 : adj_unlock(ai_nbr1);
1259 2 : adj_unlock(ai_nbr2);
1260 :
1261 : /*
1262 : * MPLS disable the interface
1263 : */
1264 2 : mpls_sw_interface_enable_disable (&mpls_main, tm->hw[0]->sw_if_index, 0);
1265 2 : mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
1266 :
1267 : /*
1268 : * remove the connected
1269 : */
1270 2 : fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
1271 :
1272 : /*
1273 : * test we've leaked no resources
1274 : */
1275 2 : MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1276 2 : MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1277 : n_pls, fib_path_list_pool_size());
1278 2 : MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1279 : n_reps, pool_elts(replicate_pool));
1280 2 : MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1281 : " No more entries %d!=%d",
1282 : n_entries, pool_elts(mfib_entry_pool));
1283 2 : MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1284 : " No more Interfaces %d!=%d",
1285 : n_itfs, pool_elts(mfib_itf_pool));
1286 2 : vec_free(two_paths);
1287 :
1288 2 : return (res);
1289 : }
1290 :
1291 : static int
1292 1 : mfib_test_v4 (void)
1293 : {
1294 2 : const mfib_prefix_t pfx_224_s_8 = {
1295 : .fp_len = 8,
1296 : .fp_proto = FIB_PROTOCOL_IP4,
1297 : .fp_grp_addr = {
1298 1 : .ip4.as_u32 = clib_host_to_net_u32(0xe0000000),
1299 : }
1300 : };
1301 3 : const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
1302 : .fp_len = 64,
1303 : .fp_proto = FIB_PROTOCOL_IP4,
1304 : .fp_grp_addr = {
1305 1 : .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1306 : },
1307 : .fp_src_addr = {
1308 1 : .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1309 : },
1310 : };
1311 2 : const mfib_prefix_t pfx_239_1_1_1 = {
1312 : .fp_len = 32,
1313 : .fp_proto = FIB_PROTOCOL_IP4,
1314 : .fp_grp_addr = {
1315 1 : .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
1316 : },
1317 : .fp_src_addr = {
1318 : .ip4.as_u32 = 0,
1319 : },
1320 : };
1321 2 : const mfib_prefix_t pfx_239_1_1_2 = {
1322 : .fp_len = 32,
1323 : .fp_proto = FIB_PROTOCOL_IP4,
1324 : .fp_grp_addr = {
1325 1 : .ip4.as_u32 = clib_host_to_net_u32(0xef010102),
1326 : },
1327 : .fp_src_addr = {
1328 : .ip4.as_u32 = 0,
1329 : },
1330 : };
1331 2 : const mfib_prefix_t pfx_239_1_1_3 = {
1332 : .fp_len = 32,
1333 : .fp_proto = FIB_PROTOCOL_IP4,
1334 : .fp_grp_addr = {
1335 1 : .ip4.as_u32 = clib_host_to_net_u32(0xef010103),
1336 : },
1337 : .fp_src_addr = {
1338 : .ip4.as_u32 = 0,
1339 : },
1340 : };
1341 2 : const mfib_prefix_t pfx_239 = {
1342 : .fp_len = 8,
1343 : .fp_proto = FIB_PROTOCOL_IP4,
1344 : .fp_grp_addr = {
1345 1 : .ip4.as_u32 = clib_host_to_net_u32(0xef000000),
1346 : },
1347 : .fp_src_addr = {
1348 : .ip4.as_u32 = 0,
1349 : },
1350 : };
1351 2 : const fib_prefix_t pfx_itf = {
1352 : .fp_len = 24,
1353 : .fp_proto = FIB_PROTOCOL_IP4,
1354 : .fp_addr = {
1355 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
1356 : },
1357 : };
1358 2 : const ip46_address_t nbr1 = {
1359 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
1360 : };
1361 2 : const ip46_address_t nbr2 = {
1362 1 : .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
1363 : };
1364 1 : return (mfib_test_i(FIB_PROTOCOL_IP4,
1365 : VNET_LINK_IP4,
1366 : &pfx_224_s_8,
1367 : &pfx_1_1_1_1_c_239_1_1_1,
1368 : &pfx_239_1_1_1,
1369 : &pfx_239_1_1_2,
1370 : &pfx_239_1_1_3,
1371 : &pfx_239,
1372 : &pfx_itf,
1373 : &nbr1,
1374 : &nbr2));
1375 : }
1376 :
1377 : static int
1378 1 : mfib_test_v6 (void)
1379 : {
1380 2 : const mfib_prefix_t pfx_ffd_s_12 = {
1381 : .fp_len = 12,
1382 : .fp_proto = FIB_PROTOCOL_IP6,
1383 : .fp_grp_addr = {
1384 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xffd0000000000000),
1385 : }
1386 : };
1387 5 : const mfib_prefix_t pfx_2001_1_c_ff_1 = {
1388 : .fp_len = 256,
1389 : .fp_proto = FIB_PROTOCOL_IP6,
1390 : .fp_grp_addr = {
1391 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1392 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1393 : },
1394 : .fp_src_addr = {
1395 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1396 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1397 : },
1398 : };
1399 3 : const mfib_prefix_t pfx_ff_1 = {
1400 : .fp_len = 128,
1401 : .fp_proto = FIB_PROTOCOL_IP6,
1402 : .fp_grp_addr = {
1403 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1404 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1405 : },
1406 : };
1407 3 : const mfib_prefix_t pfx_ff_2 = {
1408 : .fp_len = 128,
1409 : .fp_proto = FIB_PROTOCOL_IP6,
1410 : .fp_grp_addr = {
1411 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1412 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1413 : },
1414 : };
1415 3 : const mfib_prefix_t pfx_ff_3 = {
1416 : /*
1417 : * this is the ALL DHCP routers address
1418 : */
1419 : .fp_len = 128,
1420 : .fp_proto = FIB_PROTOCOL_IP6,
1421 : .fp_grp_addr = {
1422 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff02000100000000),
1423 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1424 : },
1425 : };
1426 3 : const mfib_prefix_t pfx_ff = {
1427 : .fp_len = 16,
1428 : .fp_proto = FIB_PROTOCOL_IP6,
1429 : .fp_grp_addr = {
1430 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff01000000000000),
1431 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1432 : },
1433 : };
1434 3 : const fib_prefix_t pfx_itf = {
1435 : .fp_len = 64,
1436 : .fp_proto = FIB_PROTOCOL_IP6,
1437 : .fp_addr = {
1438 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1439 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1440 : },
1441 : };
1442 2 : const ip46_address_t nbr1 = {
1443 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1444 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
1445 : };
1446 2 : const ip46_address_t nbr2 = {
1447 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1448 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
1449 : };
1450 :
1451 1 : return (mfib_test_i(FIB_PROTOCOL_IP6,
1452 : VNET_LINK_IP6,
1453 : &pfx_ffd_s_12,
1454 : &pfx_2001_1_c_ff_1,
1455 : &pfx_ff_1,
1456 : &pfx_ff_2,
1457 : &pfx_ff_3,
1458 : &pfx_ff,
1459 : &pfx_itf,
1460 : &nbr1,
1461 : &nbr2));
1462 : }
1463 :
1464 : static int
1465 2 : mfib_test_rr_i (fib_protocol_t FPROTO,
1466 : dpo_proto_t DPROTO,
1467 : vnet_link_t LINKT,
1468 : const mfib_prefix_t *pfx_cover,
1469 : const mfib_prefix_t *pfx_host1,
1470 : const mfib_prefix_t *pfx_host2)
1471 : {
1472 : fib_node_index_t mfei_cover, mfei_host1, mfei_host2, ai_1, ai_2;
1473 : u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
1474 : test_main_t *tm;
1475 : int res;
1476 :
1477 2 : res = 0;
1478 2 : n_entries = pool_elts(mfib_entry_pool);
1479 2 : n_itfs = pool_elts(mfib_itf_pool);
1480 2 : n_reps = pool_elts(replicate_pool);
1481 2 : n_pls = fib_path_list_pool_size();
1482 2 : tm = &test_main;
1483 :
1484 2 : fib_index = 0;
1485 2 : ai_1 = adj_mcast_add_or_lock(FPROTO,
1486 : LINKT,
1487 2 : tm->hw[1]->sw_if_index);
1488 2 : ai_2 = adj_mcast_add_or_lock(FPROTO,
1489 : LINKT,
1490 2 : tm->hw[2]->sw_if_index);
1491 :
1492 2 : fib_route_path_t path_via_if0 = {
1493 : .frp_proto = DPROTO,
1494 : .frp_addr = zero_addr,
1495 2 : .frp_sw_if_index = tm->hw[0]->sw_if_index,
1496 : .frp_fib_index = ~0,
1497 : .frp_weight = 1,
1498 : .frp_flags = 0,
1499 : .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
1500 : };
1501 2 : fib_route_path_t path_via_if1 = {
1502 : .frp_proto = DPROTO,
1503 : .frp_addr = zero_addr,
1504 2 : .frp_sw_if_index = tm->hw[1]->sw_if_index,
1505 : .frp_fib_index = ~0,
1506 : .frp_weight = 1,
1507 : .frp_flags = 0,
1508 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1509 : };
1510 2 : fib_route_path_t path_via_if2 = {
1511 : .frp_proto = DPROTO,
1512 : .frp_addr = zero_addr,
1513 2 : .frp_sw_if_index = tm->hw[2]->sw_if_index,
1514 : .frp_fib_index = ~0,
1515 : .frp_weight = 1,
1516 : .frp_flags = 0,
1517 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1518 : };
1519 2 : fib_route_path_t path_for_us = {
1520 : .frp_proto = DPROTO,
1521 : .frp_addr = zero_addr,
1522 : .frp_sw_if_index = 0xffffffff,
1523 : .frp_fib_index = ~0,
1524 : .frp_weight = 1,
1525 : .frp_flags = FIB_ROUTE_PATH_LOCAL,
1526 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
1527 : };
1528 :
1529 : /*
1530 : * with only the default in place, recusre thru the /32
1531 : */
1532 2 : mfei_host1 = mfib_table_entry_special_add(fib_index, pfx_host1,
1533 : MFIB_SOURCE_RR,
1534 : MFIB_ENTRY_FLAG_NONE,
1535 : INDEX_INVALID);
1536 : /*
1537 : * expect its forwarding to match the cover's
1538 : */
1539 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1540 : MFIB_ENTRY_FLAG_DROP,
1541 : 0),
1542 : "%U no replications OK",
1543 : format_mfib_prefix, pfx_host1);
1544 :
1545 : /*
1546 : * Insert the less specific /28
1547 : */
1548 2 : mfib_table_entry_path_update (fib_index, pfx_cover, MFIB_SOURCE_API,
1549 : MFIB_ENTRY_FLAG_NONE, &path_via_if1);
1550 :
1551 2 : mfei_cover = mfib_table_lookup_exact_match(fib_index, pfx_cover);
1552 :
1553 2 : MFIB_TEST(!mfib_test_entry(mfei_cover,
1554 : MFIB_ENTRY_FLAG_NONE,
1555 : 1,
1556 : DPO_ADJACENCY_MCAST, ai_1),
1557 : "%U replicate OK",
1558 : format_mfib_prefix, pfx_cover);
1559 :
1560 : /*
1561 : * expect the /32 forwarding to match the new cover's
1562 : */
1563 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1564 : MFIB_ENTRY_FLAG_NONE,
1565 : 1,
1566 : DPO_ADJACENCY_MCAST, ai_1),
1567 : "%U replicate OK",
1568 : format_mfib_prefix, pfx_host1);
1569 :
1570 : /*
1571 : * add another path to the cover
1572 : */
1573 2 : mfib_table_entry_path_update (fib_index, pfx_cover, MFIB_SOURCE_API,
1574 : MFIB_ENTRY_FLAG_NONE, &path_via_if2);
1575 :
1576 : /*
1577 : * expect the /32 and /28 to be via both boths
1578 : */
1579 2 : MFIB_TEST(!mfib_test_entry(mfei_cover,
1580 : MFIB_ENTRY_FLAG_NONE,
1581 : 2,
1582 : DPO_ADJACENCY_MCAST, ai_1,
1583 : DPO_ADJACENCY_MCAST, ai_2),
1584 : "%U replicate OK",
1585 : format_mfib_prefix, pfx_cover);
1586 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1587 : MFIB_ENTRY_FLAG_NONE,
1588 : 2,
1589 : DPO_ADJACENCY_MCAST, ai_1,
1590 : DPO_ADJACENCY_MCAST, ai_2),
1591 : "%U replicate OK",
1592 : format_mfib_prefix, pfx_host1);
1593 :
1594 : /*
1595 : * and the other host whilst all is ready
1596 : */
1597 2 : mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1598 : MFIB_SOURCE_RR,
1599 : MFIB_ENTRY_FLAG_NONE,
1600 : INDEX_INVALID);
1601 2 : MFIB_TEST(!mfib_test_entry(mfei_host2,
1602 : MFIB_ENTRY_FLAG_NONE,
1603 : 2,
1604 : DPO_ADJACENCY_MCAST, ai_1,
1605 : DPO_ADJACENCY_MCAST, ai_2),
1606 : "%U replicate OK",
1607 : format_mfib_prefix, pfx_host2);
1608 :
1609 : /*
1610 : * repaet multiple time to simulate multiple recursve children
1611 : */
1612 2 : mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1613 : MFIB_SOURCE_RR,
1614 : MFIB_ENTRY_FLAG_NONE,
1615 : INDEX_INVALID);
1616 2 : mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1617 : MFIB_SOURCE_RR,
1618 : MFIB_ENTRY_FLAG_NONE,
1619 : INDEX_INVALID);
1620 2 : mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2,
1621 : MFIB_SOURCE_RR,
1622 : MFIB_ENTRY_FLAG_NONE,
1623 : INDEX_INVALID);
1624 :
1625 : /*
1626 : * add an accepting path to the cover
1627 : */
1628 2 : mfib_table_entry_path_update (fib_index, pfx_cover, MFIB_SOURCE_API,
1629 : MFIB_ENTRY_FLAG_NONE, &path_via_if0);
1630 :
1631 : /*
1632 : * expect the /32 and /28 to be via both boths
1633 : */
1634 2 : MFIB_TEST(!mfib_test_entry(mfei_cover,
1635 : MFIB_ENTRY_FLAG_NONE,
1636 : 2,
1637 : DPO_ADJACENCY_MCAST, ai_1,
1638 : DPO_ADJACENCY_MCAST, ai_2),
1639 : "%U replicate OK",
1640 : format_mfib_prefix, pfx_cover);
1641 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1642 : MFIB_ENTRY_FLAG_NONE,
1643 : 2,
1644 : DPO_ADJACENCY_MCAST, ai_1,
1645 : DPO_ADJACENCY_MCAST, ai_2),
1646 : "%U replicate OK",
1647 : format_mfib_prefix, pfx_cover);
1648 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[0]->sw_if_index,
1649 : MFIB_ITF_FLAG_ACCEPT));
1650 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[0]->sw_if_index,
1651 : MFIB_ITF_FLAG_ACCEPT));
1652 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[1]->sw_if_index,
1653 : MFIB_ITF_FLAG_FORWARD));
1654 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[1]->sw_if_index,
1655 : MFIB_ITF_FLAG_FORWARD));
1656 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[2]->sw_if_index,
1657 : MFIB_ITF_FLAG_FORWARD));
1658 2 : MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[2]->sw_if_index,
1659 : MFIB_ITF_FLAG_FORWARD));
1660 :
1661 : /*
1662 : * add a for-us path to the cover
1663 : */
1664 2 : mfib_table_entry_path_update (fib_index, pfx_cover, MFIB_SOURCE_API,
1665 : MFIB_ENTRY_FLAG_NONE, &path_for_us);
1666 :
1667 : /*
1668 : * expect the /32 and /28 to be via all three paths
1669 : */
1670 2 : MFIB_TEST(!mfib_test_entry(mfei_cover,
1671 : MFIB_ENTRY_FLAG_NONE,
1672 : 3,
1673 : DPO_ADJACENCY_MCAST, ai_1,
1674 : DPO_ADJACENCY_MCAST, ai_2,
1675 : DPO_RECEIVE, 0),
1676 : "%U replicate OK",
1677 : format_mfib_prefix, pfx_cover);
1678 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1679 : MFIB_ENTRY_FLAG_NONE,
1680 : 3,
1681 : DPO_ADJACENCY_MCAST, ai_1,
1682 : DPO_ADJACENCY_MCAST, ai_2,
1683 : DPO_RECEIVE, 0),
1684 : "%U replicate OK",
1685 : format_mfib_prefix, pfx_cover);
1686 :
1687 : /*
1688 : * get the forwarding chain from the RR prefix
1689 : */
1690 : replicate_t *rep;
1691 2 : dpo_id_t dpo = DPO_INVALID;
1692 :
1693 2 : mfib_entry_contribute_forwarding(
1694 : mfei_host1,
1695 2 : mfib_forw_chain_type_from_dpo_proto(DPROTO),
1696 : MFIB_ENTRY_FWD_FLAG_NONE,
1697 : &dpo);
1698 :
1699 2 : rep = replicate_get(dpo.dpoi_index);
1700 2 : MFIB_TEST((3 == rep->rep_n_buckets),
1701 : "%U replicate 3 buckets",
1702 : format_mfib_prefix, pfx_host1);
1703 :
1704 : /*
1705 : * get the forwarding chain from the RR prefix without local paths
1706 : */
1707 2 : mfib_entry_contribute_forwarding(
1708 : mfei_host1,
1709 2 : mfib_forw_chain_type_from_dpo_proto(DPROTO),
1710 : MFIB_ENTRY_FWD_FLAG_NO_LOCAL,
1711 : &dpo);
1712 :
1713 2 : rep = replicate_get(dpo.dpoi_index);
1714 2 : MFIB_TEST((2 == rep->rep_n_buckets),
1715 : "%U no-local replicate 2 buckets",
1716 : format_mfib_prefix, pfx_host1);
1717 :
1718 2 : dpo_reset(&dpo);
1719 :
1720 : /*
1721 : * delete the cover, expect the /32 to be via the default
1722 : */
1723 2 : mfib_table_entry_delete(fib_index, pfx_cover, MFIB_SOURCE_API);
1724 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1725 : MFIB_ENTRY_FLAG_DROP,
1726 : 0),
1727 : "%U no replications OK",
1728 : format_mfib_prefix, pfx_host1);
1729 :
1730 : /*
1731 : * source the /32 with its own path
1732 : */
1733 : mfei_host1 =
1734 2 : mfib_table_entry_path_update (fib_index, pfx_host1, MFIB_SOURCE_API,
1735 : MFIB_ENTRY_FLAG_NONE, &path_via_if2);
1736 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1737 : MFIB_ENTRY_FLAG_NONE,
1738 : 1,
1739 : DPO_ADJACENCY_MCAST, ai_2),
1740 : "%U replicate OK",
1741 : format_mfib_prefix, pfx_host1);
1742 :
1743 : /*
1744 : * remove host2 - as many times as it was added
1745 : */
1746 2 : mfib_table_entry_delete(fib_index, pfx_host2,
1747 : MFIB_SOURCE_RR);
1748 2 : mfib_table_entry_delete(fib_index, pfx_host2,
1749 : MFIB_SOURCE_RR);
1750 2 : mfib_table_entry_delete(fib_index, pfx_host2,
1751 : MFIB_SOURCE_RR);
1752 2 : mfib_table_entry_delete(fib_index, pfx_host2,
1753 : MFIB_SOURCE_RR);
1754 :
1755 :
1756 : /*
1757 : * remove the RR source with paths present
1758 : */
1759 2 : mfib_table_entry_delete(fib_index, pfx_host1,
1760 : MFIB_SOURCE_RR);
1761 :
1762 : /*
1763 : * add the RR back then remove the path and RR
1764 : */
1765 : mfei_host1 =
1766 2 : mfib_table_entry_path_update (fib_index, pfx_host1, MFIB_SOURCE_API,
1767 : MFIB_ENTRY_FLAG_NONE, &path_via_if2);
1768 2 : MFIB_TEST(!mfib_test_entry(mfei_host1,
1769 : MFIB_ENTRY_FLAG_NONE,
1770 : 1,
1771 : DPO_ADJACENCY_MCAST, ai_2),
1772 : "%U replicate OK",
1773 : format_mfib_prefix, pfx_host1);
1774 :
1775 2 : mfib_table_entry_delete(fib_index, pfx_host1,
1776 : MFIB_SOURCE_API);
1777 2 : mfib_table_entry_delete(fib_index, pfx_host1,
1778 : MFIB_SOURCE_RR);
1779 :
1780 : /*
1781 : * test we've leaked no resources
1782 : */
1783 2 : adj_unlock(ai_1);
1784 2 : adj_unlock(ai_2);
1785 2 : MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
1786 2 : MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists",
1787 : n_pls, fib_path_list_pool_size());
1788 2 : MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates",
1789 : n_reps, pool_elts(replicate_pool));
1790 2 : MFIB_TEST(n_entries == pool_elts(mfib_entry_pool),
1791 : " No more entries %d!=%d",
1792 : n_entries, pool_elts(mfib_entry_pool));
1793 2 : MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool),
1794 : " No more Interfaces %d!=%d",
1795 : n_itfs, pool_elts(mfib_itf_pool));
1796 2 : return (res);
1797 : }
1798 :
1799 : static int
1800 1 : mfib_test_rr_v4 (void)
1801 : {
1802 : /*
1803 : * 2 length of prefix to play with
1804 : */
1805 2 : const mfib_prefix_t pfx_host1 = {
1806 : .fp_len = 32,
1807 : .fp_proto = FIB_PROTOCOL_IP4,
1808 : .fp_grp_addr = {
1809 1 : .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1810 : },
1811 : };
1812 3 : const mfib_prefix_t pfx_host2 = {
1813 : .fp_len = 64,
1814 : .fp_proto = FIB_PROTOCOL_IP4,
1815 : .fp_grp_addr = {
1816 1 : .ip4.as_u32 = clib_host_to_net_u32(0xe0001011),
1817 : },
1818 : .fp_src_addr = {
1819 1 : .ip4.as_u32 = clib_host_to_net_u32(0x10101010),
1820 : },
1821 : };
1822 2 : const mfib_prefix_t pfx_cover = {
1823 : .fp_len = 28,
1824 : .fp_proto = FIB_PROTOCOL_IP4,
1825 : .fp_grp_addr = {
1826 1 : .ip4.as_u32 = clib_host_to_net_u32(0xe0001010),
1827 : },
1828 : };
1829 :
1830 1 : return (mfib_test_rr_i(FIB_PROTOCOL_IP4,
1831 : DPO_PROTO_IP4,
1832 : VNET_LINK_IP4,
1833 : &pfx_cover,
1834 : &pfx_host1,
1835 : &pfx_host2));
1836 : }
1837 :
1838 : static int
1839 1 : mfib_test_rr_v6 (void)
1840 : {
1841 : /*
1842 : * 2 length of prefix to play with
1843 : */
1844 3 : const mfib_prefix_t pfx_host1 = {
1845 : .fp_len = 128,
1846 : .fp_proto = FIB_PROTOCOL_IP6,
1847 : .fp_grp_addr = {
1848 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1849 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1850 : },
1851 : };
1852 5 : const mfib_prefix_t pfx_host2 = {
1853 : .fp_len = 256,
1854 : .fp_proto = FIB_PROTOCOL_IP6,
1855 : .fp_grp_addr = {
1856 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1857 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1858 : },
1859 : .fp_src_addr = {
1860 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
1861 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
1862 : },
1863 : };
1864 3 : const mfib_prefix_t pfx_cover = {
1865 : .fp_len = 64,
1866 : .fp_proto = FIB_PROTOCOL_IP6,
1867 : .fp_grp_addr = {
1868 1 : .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000),
1869 1 : .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
1870 : },
1871 : };
1872 :
1873 1 : return (mfib_test_rr_i(FIB_PROTOCOL_IP6,
1874 : DPO_PROTO_IP6,
1875 : VNET_LINK_IP6,
1876 : &pfx_cover,
1877 : &pfx_host1,
1878 : &pfx_host2));
1879 : }
1880 :
1881 : static clib_error_t *
1882 1 : mfib_test (vlib_main_t * vm,
1883 : unformat_input_t * input,
1884 : vlib_cli_command_t * cmd_arg)
1885 : {
1886 1 : int res = 0;
1887 :
1888 1 : res += mfib_test_mk_intf(4);
1889 1 : res += mfib_test_rr_v4();
1890 :
1891 1 : if (res)
1892 : {
1893 0 : return clib_error_return(0, "MFIB RR V4 Unit Test Failed");
1894 : }
1895 :
1896 1 : res += mfib_test_rr_v6();
1897 :
1898 1 : if (res)
1899 : {
1900 0 : return clib_error_return(0, "MFIB RR V6 Unit Test Failed");
1901 : }
1902 :
1903 1 : res += mfib_test_v4();
1904 :
1905 1 : if (res)
1906 : {
1907 0 : return clib_error_return(0, "MFIB V4 Unit Test Failed");
1908 : }
1909 :
1910 1 : res += mfib_test_v6();
1911 :
1912 1 : if (res)
1913 : {
1914 0 : return clib_error_return(0, "MFIB V6 Unit Test Failed");
1915 : }
1916 :
1917 1 : return (NULL);
1918 : }
1919 :
1920 16239 : VLIB_CLI_COMMAND (test_fib_command, static) = {
1921 : .path = "test mfib",
1922 : .short_help = "mfib unit tests - DO NOT RUN ON A LIVE SYSTEM",
1923 : .function = mfib_test,
1924 : };
1925 :
1926 : clib_error_t *
1927 559 : mfib_test_init (vlib_main_t *vm)
1928 : {
1929 559 : return 0;
1930 : }
1931 :
1932 4479 : VLIB_INIT_FUNCTION (mfib_test_init);
|