fib: add barrier lock for fib_urpf_list_pool and fib_entry_pool
[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     u8 need_barrier_sync = 0;
59     vlib_main_t *vm = vlib_get_main();
60     ASSERT (vm->thread_index == 0);
61
62     pool_get_will_expand (fib_urpf_list_pool, need_barrier_sync );
63     if (need_barrier_sync)
64         vlib_worker_thread_barrier_sync (vm);
65
66     pool_get(fib_urpf_list_pool, urpf);
67
68     if (need_barrier_sync)
69         vlib_worker_thread_barrier_release (vm);
70
71     clib_memset(urpf, 0, sizeof(*urpf));
72
73     urpf->furpf_locks++;
74
75     return (urpf - fib_urpf_list_pool);
76 }
77
78 void
79 fib_urpf_list_unlock (index_t ui)
80 {
81     fib_urpf_list_t *urpf;
82
83     if (INDEX_INVALID == ui)
84         return;
85
86     urpf = fib_urpf_list_get(ui);
87
88     urpf->furpf_locks--;
89
90     if (0 == urpf->furpf_locks)
91     {
92         vec_free(urpf->furpf_itfs);
93         pool_put(fib_urpf_list_pool, urpf);
94     }
95 }
96
97 void
98 fib_urpf_list_lock (index_t ui)
99 {
100     fib_urpf_list_t *urpf;
101
102     urpf = fib_urpf_list_get(ui);
103
104     urpf->furpf_locks++;
105 }
106
107 /**
108  * @brief Append another interface to the list.
109  */
110 void
111 fib_urpf_list_append (index_t ui,
112                       u32 sw_if_index)
113 {
114     fib_urpf_list_t *urpf;
115
116     urpf = fib_urpf_list_get(ui);
117
118     vec_add1(urpf->furpf_itfs, sw_if_index);
119 }
120
121 /**
122  * @brief Combine to interface lists
123  */
124 void
125 fib_urpf_list_combine (index_t ui1,
126                        index_t ui2)
127 {
128     fib_urpf_list_t *urpf1, *urpf2;
129
130     urpf1 = fib_urpf_list_get(ui1);
131     urpf2 = fib_urpf_list_get(ui2);
132
133     vec_append(urpf1->furpf_itfs, urpf2->furpf_itfs);
134 }
135
136 /**
137  * @brief Sort the interface indicies.
138  * The sort is the first step in obtaining a unique list, so the order,
139  * w.r.t. next-hop, interface,etc is not important. So a sort based on the
140  * index is all we need.
141  */
142 static int
143 fib_urpf_itf_cmp_for_sort (void * v1,
144                            void * v2)
145 {
146     const adj_index_t *i1 = v1, *i2 = v2;
147     return (*i2 < *i1);
148 }
149
150 /**
151  * @brief Convert the uRPF list from the itf set obtained during the walk
152  * to a unique list.
153  */
154 void
155 fib_urpf_list_bake (index_t ui)
156 {
157     fib_urpf_list_t *urpf;
158
159     urpf = fib_urpf_list_get(ui);
160
161     ASSERT(!(urpf->furpf_flags & FIB_URPF_LIST_BAKED));
162
163     if (vec_len(urpf->furpf_itfs) > 1)
164       {
165         u32 i, j;
166         /*
167          * cat list | sort | uniq > rpf_list
168          */
169         /* sort */
170         vec_sort_with_function(urpf->furpf_itfs, fib_urpf_itf_cmp_for_sort);
171         /* remove duplicates */
172         i = 0;
173         for (j=1; j<vec_len(urpf->furpf_itfs); j++)
174           if (urpf->furpf_itfs[i] != urpf->furpf_itfs[j])
175             urpf->furpf_itfs[++i] = urpf->furpf_itfs[j];
176         /* set the length of the vector to the number of unique itfs */
177         _vec_len(urpf->furpf_itfs) = i+1;
178       }
179
180     urpf->furpf_flags |= FIB_URPF_LIST_BAKED;
181 }
182
183 void
184 fib_urpf_list_show_mem (void)
185 {
186     fib_show_memory_usage("uRPF-list",
187                           pool_elts(fib_urpf_list_pool),
188                           pool_len(fib_urpf_list_pool),
189                           sizeof(fib_urpf_list_t));
190 }
191
192 static clib_error_t *
193 show_fib_urpf_list_command (vlib_main_t * vm,
194                             unformat_input_t * input,
195                             vlib_cli_command_t * cmd)
196 {
197     index_t ui;
198
199     if (unformat (input, "%d", &ui))
200     {
201         /*
202          * show one in detail
203          */
204         if (!pool_is_free_index(fib_urpf_list_pool, ui))
205         {
206             vlib_cli_output (vm, "%d@%U",
207                              ui,
208                              format_fib_urpf_list, ui);
209         }
210         else
211         {
212             vlib_cli_output (vm, "uRPF %d invalid", ui);
213         }
214     }
215     else
216     {
217         /*
218          * show all
219          */
220         vlib_cli_output (vm, "FIB uRPF Entries:");
221         pool_foreach_index (ui, fib_urpf_list_pool)
222          {
223             vlib_cli_output (vm, "%d@%U",
224                              ui,
225                              format_fib_urpf_list, ui);
226         }
227     }
228
229     return (NULL);
230 }
231
232 /* *INDENT-OFF* */
233 /*?
234  * The '<em>sh fib uRPF [index] </em>' command displays the uRPF lists
235  *
236  * @cliexpar
237  * @cliexstart{show fib uRPF}
238  * FIB uRPF Entries:
239  *  0@uPRF-list:0 len:0 itfs:[]
240  *  1@uPRF-list:1 len:2 itfs:[1, 2, ]
241  *  2@uPRF-list:2 len:1 itfs:[3, ]
242  *  3@uPRF-list:3 len:1 itfs:[9, ]
243  * @cliexend
244 ?*/
245 VLIB_CLI_COMMAND (show_fib_urpf_list, static) = {
246   .path = "show fib uRPF",
247   .function = show_fib_urpf_list_command,
248   .short_help = "show fib uRPF",
249 };
250 /* *INDENT-OFF* */