/* * 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_source.h> static const char *fib_source_names[] = FIB_SOURCES; static const char *fib_source_behaviour_names[] = FIB_SOURCE_BEHAVIOURS; static fib_source_t fib_source_id = FIB_SOURCE_LAST+1; typedef struct fib_source_prio_t_ { fib_source_priority_t fsp_class; fib_source_priority_t fsp_slot; } fib_source_prio_t; /** * for each client requested priority count the number pf uses of * that prio so we can asign is usage a slot number, and therefore * each request will have a unique value. */ STATIC_ASSERT_SIZEOF(fib_source_priority_t, 1); static fib_source_priority_t fib_source_prio_by_class[0x100]; typedef struct fib_source_reg_t_ { fib_source_t fsr_source; const char *fsr_name; fib_source_behaviour_t fsr_behaviour; fib_source_prio_t fsr_prio; } fib_source_reg_t; static fib_source_reg_t *fib_source_regs; u16 fib_source_get_prio (fib_source_t src) { ASSERT(vec_len(fib_source_regs) > src); return (((u16)fib_source_regs[src].fsr_prio.fsp_class << 8) | fib_source_regs[src].fsr_prio.fsp_slot); } fib_source_behaviour_t fib_source_get_behaviour (fib_source_t src) { ASSERT(vec_len(fib_source_regs) > src); return (fib_source_regs[src].fsr_behaviour); } u8 * format_fib_source (u8 *s, va_list *a) { fib_source_t src = va_arg(*a, int); ASSERT(vec_len(fib_source_regs) > src); return (format(s, "%s", fib_source_regs[src].fsr_name)); } fib_source_priority_cmp_t fib_source_cmp (fib_source_t s1, fib_source_t s2) { if (fib_source_get_prio(s1) < fib_source_get_prio(s2)) { return (FIB_SOURCE_CMP_BETTER); } else if (fib_source_get_prio(s1) > fib_source_get_prio(s2)) { return (FIB_SOURCE_CMP_WORSE); } return (FIB_SOURCE_CMP_EQUAL); } static void fib_source_reg_init (fib_source_t src, const char *name, fib_source_priority_t prio, fib_source_behaviour_t bh) { fib_source_priority_t slot; fib_source_reg_t *fsr; /* * ensure we assign a unique priority to each request * otherwise different source will be treated like ECMP */ slot = fib_source_prio_by_class[prio]++; vec_validate(fib_source_regs, src); fsr = &fib_source_regs[src]; fsr->fsr_source = src; fsr->fsr_name = strdup(name); fsr->fsr_prio.fsp_class = prio; fsr->fsr_prio.fsp_slot = slot; fsr->fsr_behaviour = bh; } fib_source_t fib_source_allocate (const char *name, fib_source_priority_t prio, fib_source_behaviour_t bh) { fib_source_t src; // max value range ASSERT(fib_source_id < 255); if (fib_source_id == 255) return (FIB_SOURCE_INVALID); src = fib_source_id++; fib_source_reg_init(src, name, prio, bh); return (src); } void fib_source_register (fib_source_t src, fib_source_priority_t prio, fib_source_behaviour_t bh) { fib_source_reg_init(src, fib_source_names[src], prio, bh); } static u8 * format_fib_source_reg (u8 *s, va_list *a) { fib_source_reg_t *fsr = va_arg(*a, fib_source_reg_t*); s = format(s, "[%d] %U prio:%d.%d behaviour:%s", fsr->fsr_source, format_fib_source, fsr->fsr_source, fsr->fsr_prio.fsp_class, fsr->fsr_prio.fsp_slot, fib_source_behaviour_names[fsr->fsr_behaviour]); return (s); } static int fib_source_reg_cmp_for_sort (void * v1, void * v2) { fib_source_reg_t *fsr1 = v1, *fsr2 = v2; return (fib_source_get_prio(fsr1->fsr_source) - fib_source_get_prio(fsr2->fsr_source)); } void fib_source_walk (fib_source_walk_t fn, void *ctx) { fib_source_reg_t *fsr; vec_foreach(fsr, fib_source_regs) { if (WALK_STOP == fn(fsr->fsr_source, fsr->fsr_name, fsr->fsr_prio.fsp_class, fsr->fsr_behaviour, ctx)) break; } } static clib_error_t * fib_source_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { fib_source_reg_t *fsr, *fsrs; fsrs = vec_dup(fib_source_regs); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "prio") || unformat (input, "priority")) vec_sort_with_function(fsrs, fib_source_reg_cmp_for_sort); } vec_foreach(fsr, fsrs) { vlib_cli_output(vm, "%U", format_fib_source_reg, fsr); } vec_free(fsrs); return (NULL); } VLIB_CLI_COMMAND (show_fib_sources, static) = { .path = "show fib source", .function = fib_source_show, .short_help = "show fib source [prio]", }; void fib_source_module_init (void) { #define _(s,p,b) fib_source_register(s,p,b); foreach_fib_source #undef _ }