ip: Unintialized variables in prefx setup (coverity warning)
[vpp.git] / src / vnet / ip / ip6_ll_table.c
1 /*
2  * Copyright (c) 2018 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 <vlib/vlib.h>
17 #include <vnet/dpo/drop_dpo.h>
18 #include <vnet/fib/ip6_fib.h>
19
20 #include <vnet/ip/ip6_ll_table.h>
21
22 /**
23  * There's only one IP6 link local table
24  */
25 static ip6_ll_table_t ip6_ll_table;
26
27 u32
28 ip6_ll_fib_get (u32 sw_if_index)
29 {
30   ASSERT (vec_len (ip6_ll_table.ilt_fibs) > sw_if_index);
31
32   return (ip6_ll_table.ilt_fibs[sw_if_index]);
33 }
34
35 fib_node_index_t
36 ip6_ll_table_lookup (const ip6_ll_prefix_t * prefix)
37 {
38   return (ip6_fib_table_lookup (ip6_ll_fib_get (prefix->ilp_sw_if_index),
39                                 &prefix->ilp_addr, 128));
40 }
41
42 fib_node_index_t
43 ip6_ll_table_lookup_exact_match (const ip6_ll_prefix_t * prefix)
44 {
45   return (ip6_fib_table_lookup_exact_match
46           (ip6_ll_fib_get (prefix->ilp_sw_if_index), &prefix->ilp_addr, 128));
47 }
48
49 static void
50 ip6_ll_fib_create (u32 sw_if_index)
51 {
52   vnet_main_t *vnm = vnet_get_main ();
53   u8 *desc;
54
55   desc = format (NULL, "IP6-link-local:%U",
56                  format_vnet_sw_interface_name,
57                  vnm, vnet_get_sw_interface (vnm, sw_if_index));
58
59   ip6_ll_table.ilt_fibs[sw_if_index] =
60     ip6_fib_table_create_and_lock (FIB_SOURCE_IP6_ND,
61                                    FIB_TABLE_FLAG_IP6_LL, desc);
62
63   /*
64    * leave the default route as a drop, but fix fe::/10 to be a glean
65    * via the interface.
66    */
67     /* *INDENT-OFF* */
68     fib_prefix_t pfx = {
69         .fp_proto = FIB_PROTOCOL_IP6,
70         .fp_len = 10,
71         .fp_addr = {
72             .ip6 = {
73                 .as_u8 = {
74                     [0] = 0xFE,
75                     [1] = 0x80,
76                 }
77             },
78         }
79     };
80     fib_table_entry_update_one_path(
81         ip6_ll_table.ilt_fibs[sw_if_index],
82         &pfx,
83         FIB_SOURCE_SPECIAL,
84         (FIB_ENTRY_FLAG_ATTACHED |
85          FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT),
86         DPO_PROTO_IP6,
87         NULL,
88         sw_if_index,
89         ~0,
90         1,
91         NULL,
92         FIB_ROUTE_PATH_FLAG_NONE);
93     /* *INDENT-ON* */
94 }
95
96 static void
97 ip6_ll_prefix_to_fib (const ip6_ll_prefix_t * ilp, fib_prefix_t * fp)
98 {
99   fp->fp_proto = FIB_PROTOCOL_IP6;
100   fp->fp_len = 128;
101   fp->fp_addr.ip6 = ilp->ilp_addr;
102   fp->___fp___pad = 0;
103 }
104
105 fib_node_index_t
106 ip6_ll_table_entry_update (const ip6_ll_prefix_t * ilp,
107                            fib_route_path_flags_t flags)
108 {
109   fib_node_index_t ip6_ll_entry_index;
110   fib_route_path_t *rpaths, rpath = {
111     .frp_flags = flags,
112     .frp_sw_if_index = ilp->ilp_sw_if_index,
113     .frp_proto = DPO_PROTO_IP6,
114   };
115   fib_prefix_t fp;
116
117   vec_validate (ip6_ll_table.ilt_fibs, ilp->ilp_sw_if_index);
118
119   if (0 == ip6_ll_fib_get (ilp->ilp_sw_if_index))
120     {
121       ip6_ll_fib_create (ilp->ilp_sw_if_index);
122     }
123
124   rpaths = NULL;
125   vec_add1 (rpaths, rpath);
126
127   ip6_ll_prefix_to_fib (ilp, &fp);
128   ip6_ll_entry_index =
129     fib_table_entry_update (ip6_ll_fib_get (ilp->ilp_sw_if_index), &fp,
130                             FIB_SOURCE_IP6_ND,
131                             (flags & FIB_ROUTE_PATH_LOCAL ?
132                              FIB_ENTRY_FLAG_LOCAL : FIB_ENTRY_FLAG_NONE),
133                             rpaths);
134   vec_free (rpaths);
135
136   return (ip6_ll_entry_index);
137 }
138
139 void
140 ip6_ll_table_entry_delete (const ip6_ll_prefix_t * ilp)
141 {
142   fib_node_index_t ip6_ll_entry_index;
143   u32 fib_index;
144
145   ip6_ll_entry_index = ip6_ll_table_lookup_exact_match (ilp);
146
147   if (FIB_NODE_INDEX_INVALID != ip6_ll_entry_index)
148     fib_table_entry_delete_index (ip6_ll_entry_index, FIB_SOURCE_IP6_ND);
149
150   /*
151    * if there are no ND sourced prefixes left, then we can clean up this FIB
152    */
153   fib_index = ip6_ll_fib_get (ilp->ilp_sw_if_index);
154   if (0 == fib_table_get_num_entries (fib_index,
155                                       FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND))
156     {
157       fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
158       ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = 0;
159     }
160 }
161
162 static void
163 ip6_ll_table_show_one (vlib_main_t * vm, ip6_ll_prefix_t * ilp, int detail)
164 {
165   vlib_cli_output (vm, "%U",
166                    format_fib_entry,
167                    ip6_ll_table_lookup (ilp),
168                    (detail ?
169                     FIB_ENTRY_FORMAT_DETAIL2 : FIB_ENTRY_FORMAT_DETAIL));
170 }
171
172 typedef struct ip6_ll_show_ctx_t_
173 {
174   fib_node_index_t *entries;
175 } ip6_ll_show_ctx_t;
176
177 static fib_table_walk_rc_t
178 ip6_ll_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
179 {
180   ip6_ll_show_ctx_t *ctx = arg;
181
182   vec_add1 (ctx->entries, fib_entry_index);
183
184   return (FIB_TABLE_WALK_CONTINUE);
185 }
186
187 static void
188 ip6_ll_table_show_all (vlib_main_t * vm, u32 fib_index)
189 {
190   fib_node_index_t *fib_entry_index;
191   ip6_ll_show_ctx_t ctx = {
192     .entries = NULL,
193   };
194
195   fib_table_walk (fib_index, FIB_PROTOCOL_IP6, ip6_ll_table_show_walk, &ctx);
196   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
197
198   vec_foreach (fib_entry_index, ctx.entries)
199   {
200     vlib_cli_output (vm, "%U",
201                      format_fib_entry,
202                      *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF);
203   }
204
205   vec_free (ctx.entries);
206 }
207
208 typedef struct
209 {
210   u32 fib_index;
211   u64 count_by_prefix_length[129];
212 } count_routes_in_fib_at_prefix_length_arg_t;
213
214 static int
215 count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp, void *arg)
216 {
217   count_routes_in_fib_at_prefix_length_arg_t *ap = arg;
218   int mask_width;
219
220   if ((kvp->key[2] >> 32) != ap->fib_index)
221     return (BIHASH_WALK_CONTINUE);
222
223   mask_width = kvp->key[2] & 0xFF;
224
225   ap->count_by_prefix_length[mask_width]++;
226
227   return (BIHASH_WALK_CONTINUE);
228 }
229
230 static clib_error_t *
231 ip6_ll_show_fib (vlib_main_t * vm,
232                  unformat_input_t * input, vlib_cli_command_t * cmd)
233 {
234   count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
235   ip6_main_t *im6 = &ip6_main;
236   fib_table_t *fib_table;
237   int verbose, matching;
238   ip6_address_t matching_address;
239   u32 mask_len = 128;
240   u32 sw_if_index = ~0;
241   int detail = 0;
242   vnet_main_t *vnm = vnet_get_main ();
243   u32 fib_index;
244
245   verbose = 1;
246   matching = 0;
247
248   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
249     {
250       if (unformat (input, "brief") ||
251           unformat (input, "summary") || unformat (input, "sum"))
252         verbose = 0;
253
254       else if (unformat (input, "detail") || unformat (input, "det"))
255         detail = 1;
256
257       else if (unformat (input, "%U/%d",
258                          unformat_ip6_address, &matching_address, &mask_len))
259         matching = 1;
260
261       else
262         if (unformat (input, "%U", unformat_ip6_address, &matching_address))
263         matching = 1;
264       else if (unformat (input, "%U",
265                          unformat_vnet_sw_interface, vnm, &sw_if_index))
266         ;
267       else
268         break;
269     }
270
271   vec_foreach_index (sw_if_index, ip6_ll_table.ilt_fibs)
272   {
273     fib_source_t source;
274     u8 *s = NULL;
275
276     fib_index = ip6_ll_table.ilt_fibs[sw_if_index];
277
278     if (0 == fib_index)
279       continue;
280
281     fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
282
283     if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
284       continue;
285
286     s = format (s, "%U, fib_index:%d, locks:[",
287                 format_fib_table_name, fib_index,
288                 FIB_PROTOCOL_IP6, fib_index);
289     vec_foreach_index (source, fib_table->ft_locks)
290     {
291       if (0 != fib_table->ft_locks[source])
292         {
293           s = format (s, "%U:%d, ",
294                       format_fib_source, source, fib_table->ft_locks[source]);
295         }
296     }
297     s = format (s, "]");
298     vlib_cli_output (vm, "%v", s);
299     vec_free (s);
300
301     /* Show summary? */
302     if (!verbose)
303       {
304         clib_bihash_24_8_t *h =
305           &im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
306         int len;
307
308         vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
309
310         clib_memset (ca, 0, sizeof (*ca));
311         ca->fib_index = fib_index;
312
313         clib_bihash_foreach_key_value_pair_24_8
314           (h, count_routes_in_fib_at_prefix_length, ca);
315
316         for (len = 128; len >= 0; len--)
317           {
318             if (ca->count_by_prefix_length[len])
319               vlib_cli_output (vm, "%=20d%=16lld",
320                                len, ca->count_by_prefix_length[len]);
321           }
322         continue;
323       }
324
325     if (!matching)
326       {
327         ip6_ll_table_show_all (vm, fib_index);
328       }
329     else
330       {
331         if (~0 == sw_if_index)
332           {
333             vlib_cli_output (vm, "specify the interface");
334           }
335         else
336           {
337             ip6_ll_prefix_t ilp = {
338               .ilp_addr = matching_address,
339               .ilp_sw_if_index = sw_if_index,
340             };
341             ip6_ll_table_show_one (vm, &ilp, detail);
342           }
343       }
344   };
345
346   return 0;
347 }
348
349 /* *INDENT-OFF* */
350 VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
351     .path = "show ip6-ll",
352     .short_help = "show ip6-ll [summary] [interface] [<ip6-addr>[/<width>]] [detail]",
353     .function = ip6_ll_show_fib,
354 };
355 /* *INDENT-ON* */
356
357 static clib_error_t *
358 ip6_ll_module_init (vlib_main_t * vm)
359 {
360   clib_error_t *error;
361
362   error = vlib_call_init_function (vm, ip6_lookup_init);
363
364   return (error);
365 }
366
367 VLIB_INIT_FUNCTION (ip6_ll_module_init);
368
369 /*
370  * fd.io coding-style-patch-verification: ON
371  *
372  * Local Variables:
373  * eval: (c-set-style "gnu")
374  * End:
375  */