fib: fix urpf_itfs vector overflow
[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     clib_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     const adj_index_t *i1 = v1, *i2 = v2;
136     return (*i2 < *i1);
137 }
138
139 /**
140  * @brief Convert the uRPF list from the itf set obtained during the walk
141  * to a unique list.
142  */
143 void
144 fib_urpf_list_bake (index_t ui)
145 {
146     fib_urpf_list_t *urpf;
147
148     urpf = fib_urpf_list_get(ui);
149
150     ASSERT(!(urpf->furpf_flags & FIB_URPF_LIST_BAKED));
151
152     if (vec_len(urpf->furpf_itfs) > 1)
153       {
154         u32 i, j;
155         /*
156          * cat list | sort | uniq > rpf_list
157          */
158         /* sort */
159         vec_sort_with_function(urpf->furpf_itfs, fib_urpf_itf_cmp_for_sort);
160         /* remove duplicates */
161         i = 0;
162         for (j=1; j<vec_len(urpf->furpf_itfs); j++)
163           if (urpf->furpf_itfs[i] != urpf->furpf_itfs[j])
164             urpf->furpf_itfs[++i] = urpf->furpf_itfs[j];
165         /* set the length of the vector to the number of unique itfs */
166         _vec_len(urpf->furpf_itfs) = i+1;
167       }
168
169     urpf->furpf_flags |= FIB_URPF_LIST_BAKED;
170 }
171
172 void
173 fib_urpf_list_show_mem (void)
174 {
175     fib_show_memory_usage("uRPF-list",
176                           pool_elts(fib_urpf_list_pool),
177                           pool_len(fib_urpf_list_pool),
178                           sizeof(fib_urpf_list_t));
179 }
180
181 static clib_error_t *
182 show_fib_urpf_list_command (vlib_main_t * vm,
183                             unformat_input_t * input,
184                             vlib_cli_command_t * cmd)
185 {
186     index_t ui;
187
188     if (unformat (input, "%d", &ui))
189     {
190         /*
191          * show one in detail
192          */
193         if (!pool_is_free_index(fib_urpf_list_pool, ui))
194         {
195             vlib_cli_output (vm, "%d@%U",
196                              ui,
197                              format_fib_urpf_list, ui);
198         }
199         else
200         {
201             vlib_cli_output (vm, "uRPF %d invalid", ui);
202         }
203     }
204     else
205     {
206         /*
207          * show all
208          */
209         vlib_cli_output (vm, "FIB uRPF Entries:");
210         pool_foreach_index(ui, fib_urpf_list_pool,
211         ({
212             vlib_cli_output (vm, "%d@%U",
213                              ui,
214                              format_fib_urpf_list, ui);
215         }));
216     }
217
218     return (NULL);
219 }
220
221 /* *INDENT-OFF* */
222 /*?
223  * The '<em>sh fib uRPF [index] </em>' command displays the uRPF lists
224  *
225  * @cliexpar
226  * @cliexstart{show fib uRPF}
227  * FIB uRPF Entries:
228  *  0@uPRF-list:0 len:0 itfs:[]
229  *  1@uPRF-list:1 len:2 itfs:[1, 2, ]
230  *  2@uPRF-list:2 len:1 itfs:[3, ]
231  *  3@uPRF-list:3 len:1 itfs:[9, ]
232  * @cliexend
233 ?*/
234 VLIB_CLI_COMMAND (show_fib_urpf_list, static) = {
235   .path = "show fib uRPF",
236   .function = show_fib_urpf_list_command,
237   .short_help = "show fib uRPF",
238 };
239 /* *INDENT-OFF* */