| /* |
| * 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 _ |
| } |