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