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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/fib/fib_entry.h>
17 #include <vnet/fib/fib_table.h>
18 #include <vnet/fib/fib_walk.h>
19 #include <vnet/fib/fib_path_list.h>
21 #include <vnet/bier/bier_table.h>
22 #include <vnet/bier/bier_fmask.h>
23 #include <vnet/bier/bier_bit_string.h>
24 #include <vnet/bier/bier_disp_table.h>
26 #include <vnet/mpls/mpls.h>
27 #include <vnet/dpo/drop_dpo.h>
28 #include <vnet/dpo/load_balance.h>
31 * attributes names for formatting
33 static const char *const bier_fmask_attr_names[] = BIER_FMASK_ATTR_NAMES;
36 * pool of BIER fmask objects
38 bier_fmask_t *bier_fmask_pool;
41 * Stats for each BIER fmask object
43 vlib_combined_counter_main_t bier_fmask_counters;
46 bier_fmask_get_index (const bier_fmask_t *bfm)
48 return (bfm - bier_fmask_pool);
52 bier_fmask_bits_init (bier_fmask_bits_t *bits,
53 bier_hdr_len_id_t hlid)
55 bits->bfmb_refs = clib_mem_alloc(sizeof(bits->bfmb_refs[0]) *
56 bier_hdr_len_id_to_num_bits(hlid));
57 memset(bits->bfmb_refs,
59 (sizeof(bits->bfmb_refs[0]) *
60 bier_hdr_len_id_to_num_bits(hlid)));
62 bits->bfmb_input_reset_string.bbs_len =
63 bier_hdr_len_id_to_num_buckets(hlid);
66 * The buckets are accessed in the switch path
68 bits->bfmb_input_reset_string.bbs_buckets =
69 clib_mem_alloc_aligned(
70 sizeof(bits->bfmb_input_reset_string.bbs_buckets[0]) *
71 bier_hdr_len_id_to_num_buckets(hlid),
72 CLIB_CACHE_LINE_BYTES);
73 memset(bits->bfmb_input_reset_string.bbs_buckets,
75 sizeof(bits->bfmb_input_reset_string.bbs_buckets[0]) *
76 bier_hdr_len_id_to_num_buckets(hlid));
80 bier_fmask_stack (bier_fmask_t *bfm)
82 dpo_id_t via_dpo = DPO_INVALID;
83 fib_forward_chain_type_t fct;
85 if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS)
87 fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
91 fct = FIB_FORW_CHAIN_TYPE_BIER;
94 fib_path_list_contribute_forwarding(bfm->bfm_pl, fct,
95 FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
99 * If the via PL entry provides no forwarding (i.e. a drop)
100 * then neither does this fmask. That way children consider this fmask
101 * unresolved and other ECMP options are used instead.
103 if (dpo_is_drop(&via_dpo))
105 bfm->bfm_flags &= ~BIER_FMASK_FLAG_FORWARDING;
109 bfm->bfm_flags |= BIER_FMASK_FLAG_FORWARDING;
112 dpo_stack(DPO_BIER_FMASK,
120 bier_fmask_contribute_forwarding (index_t bfmi,
125 bfm = bier_fmask_get(bfmi);
127 if (bfm->bfm_flags & BIER_FMASK_FLAG_FORWARDING)
136 dpo_copy(dpo, drop_dpo_get(DPO_PROTO_BIER));
141 bier_fmask_child_add (fib_node_index_t bfmi,
142 fib_node_type_t child_type,
143 fib_node_index_t child_index)
145 return (fib_node_child_add(FIB_NODE_TYPE_BIER_FMASK,
152 bier_fmask_child_remove (fib_node_index_t bfmi,
155 if (INDEX_INVALID == bfmi)
160 fib_node_child_remove(FIB_NODE_TYPE_BIER_FMASK,
166 bier_fmask_init (bier_fmask_t *bfm,
167 const bier_fmask_id_t *fmid,
168 const fib_route_path_t *rpath)
170 const bier_table_id_t *btid;
171 fib_route_path_t *rpaths;
174 memset(bfm, 0, sizeof(*bfm));
176 bfm->bfm_id = clib_mem_alloc(sizeof(*bfm->bfm_id));
178 fib_node_init(&bfm->bfm_node, FIB_NODE_TYPE_BIER_FMASK);
179 *bfm->bfm_id = *fmid;
180 dpo_reset(&bfm->bfm_dpo);
181 btid = bier_table_get_id(bfm->bfm_id->bfmi_bti);
182 bier_fmask_bits_init(&bfm->bfm_bits, btid->bti_hdr_len);
184 if (ip46_address_is_zero(&(bfm->bfm_id->bfmi_nh)))
186 bfm->bfm_flags |= BIER_FMASK_FLAG_DISP;
189 if (!(bfm->bfm_flags & BIER_FMASK_FLAG_DISP))
191 if (NULL != rpath->frp_label_stack)
193 olabel = rpath->frp_label_stack[0].fml_value;
194 vnet_mpls_uc_set_label(&bfm->bfm_label, olabel);
195 vnet_mpls_uc_set_exp(&bfm->bfm_label, 0);
196 vnet_mpls_uc_set_s(&bfm->bfm_label, 1);
197 vnet_mpls_uc_set_ttl(&bfm->bfm_label, 64);
198 bfm->bfm_flags |= BIER_FMASK_FLAG_MPLS;
207 bfm->bfm_flags &= ~BIER_FMASK_FLAG_MPLS;
210 * use a label as encoded for BIFT value
212 id = bier_bift_id_encode(btid->bti_set,
213 btid->bti_sub_domain,
215 vnet_mpls_uc_set_label(&bfm->bfm_label, id);
216 vnet_mpls_uc_set_s(&bfm->bfm_label, 1);
217 vnet_mpls_uc_set_exp(&bfm->bfm_label, 0);
218 vnet_mpls_uc_set_ttl(&bfm->bfm_label, 64);
220 bfm->bfm_label = clib_host_to_net_u32(bfm->bfm_label);
224 vec_add1(rpaths, *rpath);
225 bfm->bfm_pl = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED |
226 FIB_PATH_LIST_FLAG_NO_URPF),
228 bfm->bfm_sibling = fib_path_list_child_add(bfm->bfm_pl,
229 FIB_NODE_TYPE_BIER_FMASK,
230 bier_fmask_get_index(bfm));
232 bier_fmask_stack(bfm);
236 bier_fmask_destroy (bier_fmask_t *bfm)
238 clib_mem_free(bfm->bfm_bits.bfmb_refs);
239 clib_mem_free(bfm->bfm_bits.bfmb_input_reset_string.bbs_buckets);
241 bier_fmask_db_remove(bfm->bfm_id);
242 fib_path_list_child_remove(bfm->bfm_pl,
244 dpo_reset(&bfm->bfm_dpo);
245 clib_mem_free(bfm->bfm_id);
246 pool_put(bier_fmask_pool, bfm);
250 bier_fmask_unlock (index_t bfmi)
254 if (INDEX_INVALID == bfmi)
259 bfm = bier_fmask_get(bfmi);
261 fib_node_unlock(&bfm->bfm_node);
265 bier_fmask_lock (index_t bfmi)
269 if (INDEX_INVALID == bfmi)
274 bfm = bier_fmask_get(bfmi);
276 fib_node_lock(&bfm->bfm_node);
280 bier_fmask_create_and_lock (const bier_fmask_id_t *fmid,
281 const fib_route_path_t *rpath)
286 pool_get_aligned(bier_fmask_pool, bfm, CLIB_CACHE_LINE_BYTES);
287 bfmi = bier_fmask_get_index(bfm);
289 vlib_validate_combined_counter (&(bier_fmask_counters), bfmi);
290 vlib_zero_combined_counter (&(bier_fmask_counters), bfmi);
292 bier_fmask_init(bfm, fmid, rpath);
294 bier_fmask_lock(bfmi);
300 bier_fmask_link (index_t bfmi,
305 bfm = bier_fmask_get(bfmi);
307 if (0 == bfm->bfm_bits.bfmb_refs[BIER_BP_TO_INDEX(bp)])
310 * 0 -> 1 transistion - set the bit in the string
312 bier_bit_string_set_bit(&bfm->bfm_bits.bfmb_input_reset_string, bp);
315 ++bfm->bfm_bits.bfmb_refs[BIER_BP_TO_INDEX(bp)];
316 ++bfm->bfm_bits.bfmb_count;
320 bier_fmask_unlink (index_t bfmi,
325 bfm = bier_fmask_get(bfmi);
327 --bfm->bfm_bits.bfmb_refs[BIER_BP_TO_INDEX(bp)];
328 --bfm->bfm_bits.bfmb_count;
330 if (0 == bfm->bfm_bits.bfmb_refs[BIER_BP_TO_INDEX(bp)])
333 * 1 -> 0 transistion - clear the bit in the string
335 bier_bit_string_clear_bit(&bfm->bfm_bits.bfmb_input_reset_string, bp);
340 format_bier_fmask (u8 *s, va_list *ap)
342 index_t bfmi = va_arg(*ap, index_t);
343 u32 indent = va_arg(*ap, u32);
344 bier_fmask_attributes_t attr;
348 if (pool_is_free_index(bier_fmask_pool, bfmi))
350 return (format(s, "No BIER f-mask %d", bfmi));
353 bfm = bier_fmask_get(bfmi);
355 s = format(s, "fmask: nh:%U bs:%U locks:%d ",
356 format_ip46_address, &bfm->bfm_id->bfmi_nh, IP46_TYPE_ANY,
357 format_bier_bit_string, &bfm->bfm_bits.bfmb_input_reset_string,
358 bfm->bfm_node.fn_locks);
359 s = format(s, "flags:");
360 FOR_EACH_BIER_FMASK_ATTR(attr) {
361 if ((1<<attr) & bfm->bfm_flags) {
362 s = format (s, "%s,", bier_fmask_attr_names[attr]);
365 vlib_get_combined_counter (&(bier_fmask_counters), bfmi, &to);
366 s = format (s, " to:[%Ld:%Ld]]", to.packets, to.bytes);
368 s = fib_path_list_format(bfm->bfm_pl, s);
370 if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS)
372 s = format(s, " output-label:%U",
373 format_mpls_unicast_label,
374 vnet_mpls_uc_get_label(clib_net_to_host_u32(bfm->bfm_label)));
378 s = format(s, " output-bfit:[%U]",
380 vnet_mpls_uc_get_label(clib_net_to_host_u32(bfm->bfm_label)));
382 s = format(s, "\n %U%U",
383 format_white_space, indent,
384 format_dpo_id, &bfm->bfm_dpo, indent+2);
390 bier_fmask_get_stats (index_t bfmi, u64 * packets, u64 * bytes)
394 vlib_get_combined_counter (&(bier_fmask_counters), bfmi, &to);
396 *packets = to.packets;
401 bier_fmask_encode (index_t bfmi,
402 bier_table_id_t *btid,
403 fib_route_path_encode_t *rpath)
407 bfm = bier_fmask_get(bfmi);
408 *btid = *bier_table_get_id(bfm->bfm_id->bfmi_bti);
410 memset(rpath, 0, sizeof(*rpath));
412 rpath->rpath.frp_sw_if_index = ~0;
414 switch (bfm->bfm_id->bfmi_nh_type)
417 rpath->rpath.frp_flags = FIB_ROUTE_PATH_UDP_ENCAP;
418 rpath->rpath.frp_udp_encap_id = bfm->bfm_id->bfmi_id;
421 memcpy(&rpath->rpath.frp_addr, &bfm->bfm_id->bfmi_nh,
422 sizeof(rpath->rpath.frp_addr));
428 bier_fmask_get_node (fib_node_index_t index)
430 bier_fmask_t *bfm = bier_fmask_get(index);
431 return (&(bfm->bfm_node));
435 bier_fmask_get_from_node (fib_node_t *node)
437 return ((bier_fmask_t*)(((char*)node) -
438 STRUCT_OFFSET_OF(bier_fmask_t,
443 * bier_fmask_last_lock_gone
446 bier_fmask_last_lock_gone (fib_node_t *node)
448 bier_fmask_destroy(bier_fmask_get_from_node(node));
452 * bier_fmask_back_walk_notify
454 * A back walk has reached this BIER fmask
456 static fib_node_back_walk_rc_t
457 bier_fmask_back_walk_notify (fib_node_t *node,
458 fib_node_back_walk_ctx_t *ctx)
461 * re-stack the fmask on the n-eos of the via
463 bier_fmask_t *bfm = bier_fmask_get_from_node(node);
465 bier_fmask_stack(bfm);
468 * propagate further up the graph.
469 * we can do this synchronously since the fan out is small.
471 fib_walk_sync(FIB_NODE_TYPE_BIER_FMASK, bier_fmask_get_index(bfm), ctx);
473 return (FIB_NODE_BACK_WALK_CONTINUE);
477 * The BIER fmask's graph node virtual function table
479 static const fib_node_vft_t bier_fmask_vft = {
480 .fnv_get = bier_fmask_get_node,
481 .fnv_last_lock = bier_fmask_last_lock_gone,
482 .fnv_back_walk = bier_fmask_back_walk_notify,
486 bier_fmask_dpo_lock (dpo_id_t *dpo)
491 bier_fmask_dpo_unlock (dpo_id_t *dpo)
496 bier_fmask_dpo_mem_show (void)
498 fib_show_memory_usage("BIER-fmask",
499 pool_elts(bier_fmask_pool),
500 pool_len(bier_fmask_pool),
501 sizeof(bier_fmask_t));
504 const static dpo_vft_t bier_fmask_dpo_vft = {
505 .dv_lock = bier_fmask_dpo_lock,
506 .dv_unlock = bier_fmask_dpo_unlock,
507 .dv_mem_show = bier_fmask_dpo_mem_show,
508 .dv_format = format_bier_fmask,
511 const static char *const bier_fmask_mpls_nodes[] =
516 const static char * const * const bier_fmask_nodes[DPO_PROTO_NUM] =
518 [DPO_PROTO_BIER] = bier_fmask_mpls_nodes,
519 [DPO_PROTO_MPLS] = bier_fmask_mpls_nodes,
523 bier_fmask_module_init (vlib_main_t * vm)
525 fib_node_register_type (FIB_NODE_TYPE_BIER_FMASK, &bier_fmask_vft);
526 dpo_register(DPO_BIER_FMASK, &bier_fmask_dpo_vft, bier_fmask_nodes);
531 VLIB_INIT_FUNCTION (bier_fmask_module_init);
533 static clib_error_t *
534 bier_fmask_show (vlib_main_t * vm,
535 unformat_input_t * input,
536 vlib_cli_command_t * cmd)
541 bfmi = INDEX_INVALID;
543 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
544 if (unformat (input, "%d", &bfmi))
553 if (INDEX_INVALID == bfmi)
555 pool_foreach(bfm, bier_fmask_pool,
557 vlib_cli_output (vm, "[@%d] %U",
558 bier_fmask_get_index(bfm),
559 format_bier_fmask, bier_fmask_get_index(bfm), 0);
564 vlib_cli_output (vm, "%U", format_bier_fmask, bfmi, 0);
570 VLIB_CLI_COMMAND (show_bier_fmask, static) = {
571 .path = "show bier fmask",
572 .short_help = "show bier fmask",
573 .function = bier_fmask_show,