fib: Decouple source from priority and behaviour
[vpp.git] / src / vnet / fib / fib_source.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #include <vnet/fib/fib_source.h>
17
18 static const char *fib_source_names[] = FIB_SOURCES;
19 static const char *fib_source_behaviour_names[] = FIB_SOURCE_BEHAVIOURS;
20
21 static fib_source_t fib_source_id = FIB_SOURCE_LAST+1;
22
23 typedef struct fib_source_prio_t_
24 {
25     fib_source_priority_t fsp_class;
26     fib_source_priority_t fsp_slot;
27 } fib_source_prio_t;
28
29 /**
30  * for each client requested priority count the number pf uses of
31  * that prio so we can asign is usage a slot number, and therefore
32  * each request will have a unique value.
33  */
34 STATIC_ASSERT_SIZEOF(fib_source_priority_t, 1);
35 static fib_source_priority_t fib_source_prio_by_class[0x100];
36
37 typedef struct fib_source_reg_t_
38 {
39     fib_source_t fsr_source;
40     const char *fsr_name;
41     fib_source_behaviour_t fsr_behaviour;
42     fib_source_prio_t fsr_prio;
43 } fib_source_reg_t;
44
45 static fib_source_reg_t *fib_source_regs;
46
47
48 u16
49 fib_source_get_prio (fib_source_t src)
50 {
51     ASSERT(vec_len(fib_source_regs) > src);
52
53     return (((u16)fib_source_regs[src].fsr_prio.fsp_class << 8) |
54             fib_source_regs[src].fsr_prio.fsp_slot);
55 }
56
57 fib_source_behaviour_t
58 fib_source_get_behaviour (fib_source_t src)
59 {
60     ASSERT(vec_len(fib_source_regs) > src);
61
62     return (fib_source_regs[src].fsr_behaviour);
63 }
64
65 u8 *
66 format_fib_source (u8 *s, va_list *a)
67 {
68     fib_source_t src = va_arg(*a, int);
69
70     ASSERT(vec_len(fib_source_regs) > src);
71
72     return (format(s, "%s", fib_source_regs[src].fsr_name));
73 }
74
75 fib_source_priority_cmp_t
76 fib_source_cmp (fib_source_t s1,
77                 fib_source_t s2)
78 {
79     if (fib_source_get_prio(s1) <
80         fib_source_get_prio(s2))
81     {
82         return (FIB_SOURCE_CMP_BETTER);
83     }
84     else if (fib_source_get_prio(s1) >
85              fib_source_get_prio(s2))
86     {
87         return (FIB_SOURCE_CMP_WORSE);
88     }
89     return (FIB_SOURCE_CMP_EQUAL);
90 }
91
92 static void
93 fib_source_reg_init (fib_source_t src,
94                      const char *name,
95                      fib_source_priority_t prio,
96                      fib_source_behaviour_t bh)
97 {
98     fib_source_priority_t slot;
99     fib_source_reg_t *fsr;
100
101     /*
102      * ensure we assign a unique priority to each request
103      * otherwise different source will be treated like ECMP
104      */
105     slot = fib_source_prio_by_class[prio]++;
106
107     vec_validate(fib_source_regs, src);
108
109     fsr = &fib_source_regs[src];
110     fsr->fsr_source = src;
111     fsr->fsr_name = strdup(name);
112     fsr->fsr_prio.fsp_class = prio;
113     fsr->fsr_prio.fsp_slot = slot;
114     fsr->fsr_behaviour = bh;
115 }
116
117 fib_source_t
118 fib_source_allocate (const char *name,
119                      fib_source_priority_t prio,
120                      fib_source_behaviour_t bh)
121 {
122     fib_source_t src;
123
124     // max value range
125     ASSERT(fib_source_id < 255);
126     if (fib_source_id == 255)
127         return (FIB_SOURCE_INVALID);
128
129     src = fib_source_id++;
130
131     fib_source_reg_init(src, name, prio, bh);
132
133     return (src);
134 }
135
136 void
137 fib_source_register (fib_source_t src,
138                      fib_source_priority_t prio,
139                      fib_source_behaviour_t bh)
140 {
141     fib_source_reg_init(src, fib_source_names[src], prio, bh);
142 }
143
144 static u8 *
145 format_fib_source_reg (u8 *s, va_list *a)
146 {
147     fib_source_reg_t *fsr = va_arg(*a, fib_source_reg_t*);
148
149     s = format(s, "[%d] %U prio:%d.%d behaviour:%s",
150                fsr->fsr_source,
151                format_fib_source, fsr->fsr_source,
152                fsr->fsr_prio.fsp_class, fsr->fsr_prio.fsp_slot,
153                fib_source_behaviour_names[fsr->fsr_behaviour]);
154
155     return (s);
156 }
157
158 static int
159 fib_source_reg_cmp_for_sort (void * v1,
160                              void * v2)
161 {
162     fib_source_reg_t *fsr1 = v1, *fsr2 = v2;
163
164     return (fib_source_get_prio(fsr1->fsr_source) -
165             fib_source_get_prio(fsr2->fsr_source));
166 }
167
168 void
169 fib_source_walk (fib_source_walk_t fn,
170                  void *ctx)
171 {
172     fib_source_reg_t *fsr;
173
174     vec_foreach(fsr, fib_source_regs)
175     {
176         if (WALK_STOP == fn(fsr->fsr_source,
177                             fsr->fsr_name,
178                             fsr->fsr_prio.fsp_class,
179                             fsr->fsr_behaviour,
180                             ctx))
181             break;
182     }
183 }
184
185 static clib_error_t *
186 fib_source_show (vlib_main_t * vm,
187                  unformat_input_t * input,
188                  vlib_cli_command_t * cmd)
189 {
190     fib_source_reg_t *fsr, *fsrs;
191
192     fsrs = vec_dup(fib_source_regs);
193
194     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
195     {
196         if (unformat (input, "prio")   ||
197             unformat (input, "priority"))
198             vec_sort_with_function(fsrs, fib_source_reg_cmp_for_sort);
199     }
200     vec_foreach(fsr, fsrs)
201     {
202         vlib_cli_output(vm, "%U", format_fib_source_reg, fsr);
203     }
204     vec_free(fsrs);
205
206     return (NULL);
207 }
208
209 VLIB_CLI_COMMAND (show_fib_sources, static) = {
210     .path = "show fib source",
211     .function = fib_source_show,
212     .short_help = "show fib source [prio]",
213 };
214
215
216 void
217 fib_source_module_init (void)
218 {
219 #define _(s,p,b) fib_source_register(s,p,b);
220     foreach_fib_source
221 #undef _
222 }