blob: e668c4fc51ff84617edf12eb0b5d8590b544b2be [file] [log] [blame]
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/fib/fib_node.h>
#include <vnet/fib/fib_node_list.h>
#include <vnet/fib/fib_table.h>
#include <vnet/mfib/mfib_table.h>
/*
* The per-type vector of virtual function tables
*/
static fib_node_vft_t *fn_vfts;
/**
* The last registered new type
*/
static fib_node_type_t last_new_type = FIB_NODE_TYPE_LAST;
/*
* the node type names
*/
static const char *fn_type_builtin_names[] = FIB_NODE_TYPES;
static const char **fn_type_names;
const char*
fib_node_type_get_name (fib_node_type_t type)
{
if ((type < vec_len(fn_type_names)) &&
(NULL != fn_type_names[type]))
{
return (fn_type_names[type]);
}
else
{
return ("unknown");
}
}
/**
* fib_node_register_type
*
* Register the function table for a given type
*/
static void
fib_node_register_type_i (fib_node_type_t type,
const char *name,
const fib_node_vft_t *vft)
{
/*
* assert that one only registration is made per-node type
*/
if (vec_len(fn_vfts) > type)
ASSERT(NULL == fn_vfts[type].fnv_get);
/*
* Assert that we are getting each of the required functions
*/
ASSERT(NULL != vft->fnv_get);
ASSERT(NULL != vft->fnv_last_lock);
vec_validate(fn_vfts, type);
fn_vfts[type] = *vft;
vec_validate(fn_type_names, type);
fn_type_names[type] = name;
}
/**
* fib_node_register_type
*
* Register the function table for a given type
*/
void
fib_node_register_type (fib_node_type_t type,
const fib_node_vft_t *vft)
{
fib_node_register_type_i(type, fn_type_builtin_names[type], vft);
}
fib_node_type_t
fib_node_register_new_type (const char *name,
const fib_node_vft_t *vft)
{
fib_node_type_t new_type;
new_type = ++last_new_type;
fib_node_register_type_i(new_type, name, vft);
return (new_type);
}
static u8*
fib_node_format (fib_node_ptr_t *fnp, u8*s)
{
return (format(s, "{%s:%d}", fn_type_names[fnp->fnp_type], fnp->fnp_index));
}
u32
fib_node_child_add (fib_node_type_t parent_type,
fib_node_index_t parent_index,
fib_node_type_t type,
fib_node_index_t index)
{
fib_node_t *parent;
parent = fn_vfts[parent_type].fnv_get(parent_index);
/*
* return the index of the sibling in the child list
*/
fib_node_lock(parent);
if (FIB_NODE_INDEX_INVALID == parent->fn_children)
{
parent->fn_children = fib_node_list_create();
}
return (fib_node_list_push_front(parent->fn_children,
0, type,
index));
}
void
fib_node_child_remove (fib_node_type_t parent_type,
fib_node_index_t parent_index,
fib_node_index_t sibling_index)
{
fib_node_t *parent;
parent = fn_vfts[parent_type].fnv_get(parent_index);
fib_node_list_remove(parent->fn_children, sibling_index);
if (0 == fib_node_list_get_size(parent->fn_children))
{
fib_node_list_destroy(&parent->fn_children);
}
fib_node_unlock(parent);
}
u32
fib_node_get_n_children (fib_node_type_t parent_type,
fib_node_index_t parent_index)
{
fib_node_t *parent;
parent = fn_vfts[parent_type].fnv_get(parent_index);
return (fib_node_list_get_size(parent->fn_children));
}
fib_node_back_walk_rc_t
fib_node_back_walk_one (fib_node_ptr_t *ptr,
fib_node_back_walk_ctx_t *ctx)
{
fib_node_t *node;
node = fn_vfts[ptr->fnp_type].fnv_get(ptr->fnp_index);
return (fn_vfts[ptr->fnp_type].fnv_back_walk(node, ctx));
}
static walk_rc_t
fib_node_ptr_format_one_child (fib_node_ptr_t *ptr,
void *arg)
{
u8 **s = (u8**) arg;
*s = fib_node_format(ptr, *s);
return (WALK_CONTINUE);
}
u8*
fib_node_children_format (fib_node_list_t list,
u8 *s)
{
fib_node_list_walk(list, fib_node_ptr_format_one_child, (void*)&s);
return (s);
}
void
fib_node_init (fib_node_t *node,
fib_node_type_t type)
{
/**
* The node's type. used to retrieve the VFT.
*/
node->fn_type = type;
node->fn_locks = 0;
node->fn_children = FIB_NODE_INDEX_INVALID;
}
void
fib_node_deinit (fib_node_t *node)
{
fib_node_list_destroy(&node->fn_children);
}
void
fib_node_lock (fib_node_t *node)
{
node->fn_locks++;
}
void
fib_node_unlock (fib_node_t *node)
{
node->fn_locks--;
if (0 == node->fn_locks)
{
fn_vfts[node->fn_type].fnv_last_lock(node);
}
}
void
fib_show_memory_usage (const char *name,
u32 in_use_elts,
u32 allocd_elts,
size_t size_elt)
{
vlib_cli_output (vlib_get_main(), "%=30s %=5d %=8d/%=9d %d/%d ",
name, size_elt,
in_use_elts, allocd_elts,
in_use_elts*size_elt, allocd_elts*size_elt);
}
static clib_error_t *
fib_memory_show (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
fib_node_vft_t *vft;
vlib_cli_output (vm, "FIB memory");
vlib_cli_output (vm, " Tables:");
vlib_cli_output (vm, "%=30s %=6s %=12s", "SAFI", "Number", "Bytes");
vlib_cli_output (vm, "%U", format_fib_table_memory);
vlib_cli_output (vm, "%U", format_mfib_table_memory);
vlib_cli_output (vm, " Nodes:");
vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s totals",
"Name","Size", "in-use", "allocated");
vec_foreach(vft, fn_vfts)
{
if (NULL != vft->fnv_mem_show)
vft->fnv_mem_show();
}
fib_node_list_memory_show();
return (NULL);
}
/*?
* The '<em>sh fib memory </em>' command displays the memory usage for each
* FIB object type.
*
* @cliexpar
* @cliexstart{show fib memory}
*FIB memory
* Tables:
* SAFI Number Bytes
* IPv4 unicast 2 673066
* IPv6 unicast 2 1054608
* MPLS 1 4194312
* IPv4 multicast 2 2322
* IPv6 multicast 2 ???
* Nodes:
* Name Size in-use /allocated totals
* Entry 96 20 / 20 1920/1920
* Entry Source 32 0 / 0 0/0
* Entry Path-Extensions 60 0 / 0 0/0
* multicast-Entry 192 12 / 12 2304/2304
* Path-list 40 28 / 28 1120/1120
* uRPF-list 16 20 / 20 320/320
* Path 72 28 / 28 2016/2016
* Node-list elements 20 28 / 28 560/560
* Node-list heads 8 30 / 30 240/240
* @cliexend
?*/
VLIB_CLI_COMMAND (show_fib_memory, static) = {
.path = "show fib memory",
.function = fib_memory_show,
.short_help = "show fib memory",
};