d5a406e6191608d71ab756bbe127abeb604fb4a8
[vpp.git] / src / vnet / fib / fib_urpf_list.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_urpf_list.h>
17 #include <vnet/adj/adj.h>
18
19 /**
20  * @brief pool of all fib_urpf_list
21  */
22 fib_urpf_list_t *fib_urpf_list_pool;
23
24 u8 *
25 format_fib_urpf_list (u8 *s, va_list *args)
26 {
27     fib_urpf_list_t *urpf;
28     index_t ui;
29     u32 *swi;
30
31     ui = va_arg(*args, index_t);
32
33     if (INDEX_INVALID != ui)
34     {
35         urpf = fib_urpf_list_get(ui);
36
37         s = format(s, "uPRF-list:%d len:%d itfs:[",
38                    ui, vec_len(urpf->furpf_itfs));
39
40         vec_foreach(swi, urpf->furpf_itfs)
41         {
42             s = format(s, "%d, ", *swi);
43         }
44         s = format(s, "]");
45     }
46     else
47     {
48         s = format(s, "uRPF-list: None");
49     }
50
51     return (s);
52 }
53
54 index_t
55 fib_urpf_list_alloc_and_lock (void)
56 {
57     fib_urpf_list_t *urpf;
58
59     pool_get(fib_urpf_list_pool, urpf);
60     memset(urpf, 0, sizeof(*urpf));
61
62     urpf->furpf_locks++;
63
64     return (urpf - fib_urpf_list_pool);
65 }
66
67 void
68 fib_urpf_list_unlock (index_t ui)
69 {
70     fib_urpf_list_t *urpf;
71
72     if (INDEX_INVALID == ui)
73         return;
74
75     urpf = fib_urpf_list_get(ui);
76
77     urpf->furpf_locks--;
78
79     if (0 == urpf->furpf_locks)
80     {
81         vec_free(urpf->furpf_itfs);
82         pool_put(fib_urpf_list_pool, urpf);
83     }
84 }
85
86 void
87 fib_urpf_list_lock (index_t ui)
88 {
89     fib_urpf_list_t *urpf;
90
91     urpf = fib_urpf_list_get(ui);
92
93     urpf->furpf_locks++;
94 }
95
96 /**
97  * @brief Append another interface to the list.
98  */
99 void
100 fib_urpf_list_append (index_t ui,
101                       u32 sw_if_index)
102 {
103     fib_urpf_list_t *urpf;
104
105     urpf = fib_urpf_list_get(ui);
106
107     vec_add1(urpf->furpf_itfs, sw_if_index);
108 }
109
110 /**
111  * @brief Combine to interface lists
112  */
113 void
114 fib_urpf_list_combine (index_t ui1,
115                        index_t ui2)
116 {
117     fib_urpf_list_t *urpf1, *urpf2;
118
119     urpf1 = fib_urpf_list_get(ui1);
120     urpf2 = fib_urpf_list_get(ui2);
121
122     vec_append(urpf1->furpf_itfs, urpf2->furpf_itfs);
123 }
124
125 /**
126  * @brief Sort the interface indicies.
127  * The sort is the first step in obtaining a unique list, so the order,
128  * w.r.t. next-hop, interface,etc is not important. So a sort based on the
129  * index is all we need.
130  */
131 static int
132 fib_urpf_itf_cmp_for_sort (void * v1,
133                            void * v2)
134 {
135     fib_node_index_t *i1 = v1, *i2 = v2;
136
137     return (*i2 < *i1);
138 }
139
140 /**
141  * @brief Convert the uRPF list from the itf set obtained during the walk
142  * to a unique list.
143  */
144 void
145 fib_urpf_list_bake (index_t ui)
146 {
147     fib_urpf_list_t *urpf;
148
149     urpf = fib_urpf_list_get(ui);
150
151     ASSERT(!(urpf->furpf_flags & FIB_URPF_LIST_BAKED));
152
153     if (vec_len(urpf->furpf_itfs) > 1)
154     {
155         u32 i,j;
156
157         /*
158          * cat list | sort | uniq > rpf_list
159          */
160         vec_sort_with_function(urpf->furpf_itfs, fib_urpf_itf_cmp_for_sort);
161
162         i = 0, j = 1;
163         while (j < vec_len(urpf->furpf_itfs))
164         {
165             if (urpf->furpf_itfs[i] == urpf->furpf_itfs[j])
166             {
167                 /*
168                  * the itfacenct entries are the same.
169                  * search forward for a unique one
170                  */
171                 while (urpf->furpf_itfs[i] == urpf->furpf_itfs[j] &&
172                        j < vec_len(urpf->furpf_itfs))
173                 {
174                     j++;
175                 }
176                 if (j == vec_len(urpf->furpf_itfs))
177                 {
178                     /*
179                      * ran off the end without finding a unique index.
180                      * we are done.
181                      */
182                     break;
183                 }
184                 else
185                 {
186                     urpf->furpf_itfs[i+1] = urpf->furpf_itfs[j];
187                 }
188             }
189             i++, j++;
190         }
191
192         /*
193          * set the length of the vector to the number of unique itfs
194          */
195         _vec_len(urpf->furpf_itfs) = i+1;
196     }
197
198     urpf->furpf_flags |= FIB_URPF_LIST_BAKED;
199 }
200
201 void
202 fib_urpf_list_show_mem (void)
203 {
204     fib_show_memory_usage("uRPF-list",
205                           pool_elts(fib_urpf_list_pool),
206                           pool_len(fib_urpf_list_pool),
207                           sizeof(fib_urpf_list_t));
208 }
209
210 static clib_error_t *
211 show_fib_urpf_list_command (vlib_main_t * vm,
212                             unformat_input_t * input,
213                             vlib_cli_command_t * cmd)
214 {
215     index_t ui;
216
217     if (unformat (input, "%d", &ui))
218     {
219         /*
220          * show one in detail
221          */
222         if (!pool_is_free_index(fib_urpf_list_pool, ui))
223         {
224             vlib_cli_output (vm, "%d@%U",
225                              ui,
226                              format_fib_urpf_list, ui);
227         }
228         else
229         {
230             vlib_cli_output (vm, "uRPF %d invalid", ui);
231         }
232     }
233     else
234     {
235         /*
236          * show all
237          */
238         vlib_cli_output (vm, "FIB uRPF Entries:");
239         pool_foreach_index(ui, fib_urpf_list_pool,
240         ({
241             vlib_cli_output (vm, "%d@%U",
242                              ui,
243                              format_fib_urpf_list, ui);
244         }));
245     }
246
247     return (NULL);
248 }
249
250 /* *INDENT-OFF* */
251 /*?
252  * The '<em>sh fib uRPF [index] </em>' command displays the uRPF lists
253  *
254  * @cliexpar
255  * @cliexstart{show fib uRPF}
256  * FIB uRPF Entries:
257  *  0@uPRF-list:0 len:0 itfs:[]
258  *  1@uPRF-list:1 len:2 itfs:[1, 2, ]
259  *  2@uPRF-list:2 len:1 itfs:[3, ]
260  *  3@uPRF-list:3 len:1 itfs:[9, ]
261  * @cliexend
262 ?*/
263 VLIB_CLI_COMMAND (show_fib_urpf_list, static) = {
264   .path = "show fib uRPF",
265   .function = show_fib_urpf_list_command,
266   .short_help = "show fib uRPF",
267 };
268 /* *INDENT-OFF* */