diff options
Diffstat (limited to 'src/vnet/fib/fib_source.c')
-rw-r--r-- | src/vnet/fib/fib_source.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/vnet/fib/fib_source.c b/src/vnet/fib/fib_source.c new file mode 100644 index 00000000000..0aeecae545f --- /dev/null +++ b/src/vnet/fib/fib_source.c @@ -0,0 +1,222 @@ +/* + * 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 _ +} |