c11 safe string handling support
[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 }
103
104 fib_node_index_t
105 ip6_ll_table_entry_update (const ip6_ll_prefix_t * ilp,
106                            fib_route_path_flags_t flags)
107 {
108   fib_node_index_t ip6_ll_entry_index;
109   fib_route_path_t *rpaths, rpath = {
110     .frp_flags = flags,
111     .frp_sw_if_index = ilp->ilp_sw_if_index,
112     .frp_proto = DPO_PROTO_IP6,
113   };
114   fib_prefix_t fp;
115
116   vec_validate (ip6_ll_table.ilt_fibs, ilp->ilp_sw_if_index);
117
118   if (0 == ip6_ll_fib_get (ilp->ilp_sw_if_index))
119     {
120       ip6_ll_fib_create (ilp->ilp_sw_if_index);
121     }
122
123   rpaths = NULL;
124   vec_add1 (rpaths, rpath);
125
126   ip6_ll_prefix_to_fib (ilp, &fp);
127   ip6_ll_entry_index =
128     fib_table_entry_update (ip6_ll_fib_get (ilp->ilp_sw_if_index), &fp,
129                             FIB_SOURCE_IP6_ND,
130                             (flags & FIB_ROUTE_PATH_LOCAL ?
131                              FIB_ENTRY_FLAG_LOCAL : FIB_ENTRY_FLAG_NONE),
132                             rpaths);
133   vec_free (rpaths);
134
135   return (ip6_ll_entry_index);
136 }
137
138 void
139 ip6_ll_table_entry_delete (const ip6_ll_prefix_t * ilp)
140 {
141   fib_node_index_t ip6_ll_entry_index;
142   u32 fib_index;
143
144   ip6_ll_entry_index = ip6_ll_table_lookup_exact_match (ilp);
145
146   if (FIB_NODE_INDEX_INVALID != ip6_ll_entry_index)
147     fib_table_entry_delete_index (ip6_ll_entry_index, FIB_SOURCE_IP6_ND);
148
149   /*
150    * if there are no ND sourced prefixes left, then we can clean up this FIB
151    */
152   fib_index = ip6_ll_fib_get (ilp->ilp_sw_if_index);
153   if (0 == fib_table_get_num_entries (fib_index,
154                                       FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND))
155     {
156       fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
157       ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = 0;
158     }
159 }
160
161 static void
162 ip6_ll_table_show_one (vlib_main_t * vm, ip6_ll_prefix_t * ilp, int detail)
163 {
164   vlib_cli_output (vm, "%U",
165                    format_fib_entry,
166                    ip6_ll_table_lookup (ilp),
167                    (detail ?
168                     FIB_ENTRY_FORMAT_DETAIL2 : FIB_ENTRY_FORMAT_DETAIL));
169 }
170
171 typedef struct ip6_ll_show_ctx_t_
172 {
173   fib_node_index_t *entries;
174 } ip6_ll_show_ctx_t;
175
176 static fib_table_walk_rc_t
177 ip6_ll_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
178 {
179   ip6_ll_show_ctx_t *ctx = arg;
180
181   vec_add1 (ctx->entries, fib_entry_index);
182
183   return (FIB_TABLE_WALK_CONTINUE);
184 }
185
186 static void
187 ip6_ll_table_show_all (vlib_main_t * vm, u32 fib_index)
188 {
189   fib_node_index_t *fib_entry_index;
190   ip6_ll_show_ctx_t ctx = {
191     .entries = NULL,
192   };
193
194   fib_table_walk (fib_index, FIB_PROTOCOL_IP6, ip6_ll_table_show_walk, &ctx);
195   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
196
197   vec_foreach (fib_entry_index, ctx.entries)
198   {
199     vlib_cli_output (vm, "%U",
200                      format_fib_entry,
201                      *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF);
202   }
203
204   vec_free (ctx.entries);
205 }
206
207 typedef struct
208 {
209   u32 fib_index;
210   u64 count_by_prefix_length[129];
211 } count_routes_in_fib_at_prefix_length_arg_t;
212
213 static void
214 count_routes_in_fib_at_prefix_length (BVT (clib_bihash_kv) * kvp, void *arg)
215 {
216   count_routes_in_fib_at_prefix_length_arg_t *ap = arg;
217   int mask_width;
218
219   if ((kvp->key[2] >> 32) != ap->fib_index)
220     return;
221
222   mask_width = kvp->key[2] & 0xFF;
223
224   ap->count_by_prefix_length[mask_width]++;
225 }
226
227 static clib_error_t *
228 ip6_ll_show_fib (vlib_main_t * vm,
229                  unformat_input_t * input, vlib_cli_command_t * cmd)
230 {
231   count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
232   ip6_main_t *im6 = &ip6_main;
233   fib_table_t *fib_table;
234   int verbose, matching;
235   ip6_address_t matching_address;
236   u32 mask_len = 128;
237   u32 sw_if_index = ~0;
238   int detail = 0;
239   vnet_main_t *vnm = vnet_get_main ();
240   u32 fib_index;
241
242   verbose = 1;
243   matching = 0;
244
245   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
246     {
247       if (unformat (input, "brief") ||
248           unformat (input, "summary") || unformat (input, "sum"))
249         verbose = 0;
250
251       else if (unformat (input, "detail") || unformat (input, "det"))
252         detail = 1;
253
254       else if (unformat (input, "%U/%d",
255                          unformat_ip6_address, &matching_address, &mask_len))
256         matching = 1;
257
258       else
259         if (unformat (input, "%U", unformat_ip6_address, &matching_address))
260         matching = 1;
261       else if (unformat (input, "%U",
262                          unformat_vnet_sw_interface, vnm, &sw_if_index))
263         ;
264       else
265         break;
266     }
267
268   vec_foreach_index (sw_if_index, ip6_ll_table.ilt_fibs)
269   {
270     fib_source_t source;
271     u8 *s = NULL;
272
273     fib_index = ip6_ll_table.ilt_fibs[sw_if_index];
274
275     if (0 == fib_index)
276       continue;
277
278     fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
279
280     if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
281       continue;
282
283     s = format (s, "%U, fib_index:%d, locks:[",
284                 format_fib_table_name, fib_index,
285                 FIB_PROTOCOL_IP6, fib_index);
286     FOR_EACH_FIB_SOURCE (source)
287     {
288       if (0 != fib_table->ft_locks[source])
289         {
290           s = format (s, "%U:%d, ",
291                       format_fib_source, source, fib_table->ft_locks[source]);
292         }
293     }
294     s = format (s, "]");
295     vlib_cli_output (vm, "%v", s);
296     vec_free (s);
297
298     /* Show summary? */
299     if (!verbose)
300       {
301         BVT (clib_bihash) * h =
302           &im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
303         int len;
304
305         vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
306
307         clib_memset (ca, 0, sizeof (*ca));
308         ca->fib_index = fib_index;
309
310         BV (clib_bihash_foreach_key_value_pair)
311           (h, count_routes_in_fib_at_prefix_length, ca);
312
313         for (len = 128; len >= 0; len--)
314           {
315             if (ca->count_by_prefix_length[len])
316               vlib_cli_output (vm, "%=20d%=16lld",
317                                len, ca->count_by_prefix_length[len]);
318           }
319         continue;
320       }
321
322     if (!matching)
323       {
324         ip6_ll_table_show_all (vm, fib_index);
325       }
326     else
327       {
328         if (~0 == sw_if_index)
329           {
330             vlib_cli_output (vm, "specify the interface");
331           }
332         else
333           {
334             ip6_ll_prefix_t ilp = {
335               .ilp_addr = matching_address,
336               .ilp_sw_if_index = sw_if_index,
337             };
338             ip6_ll_table_show_one (vm, &ilp, detail);
339           }
340       }
341   };
342
343   return 0;
344 }
345
346 /* *INDENT-OFF* */
347 VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
348     .path = "show ip6-ll",
349     .short_help = "show ip6-ll [summary] [interface] [<ip6-addr>[/<width>]] [detail]",
350     .function = ip6_ll_show_fib,
351 };
352 /* *INDENT-ON* */
353
354 static clib_error_t *
355 ip6_ll_module_init (vlib_main_t * vm)
356 {
357   clib_error_t *error;
358
359   error = vlib_call_init_function (vm, ip6_lookup_init);
360
361   return (error);
362 }
363
364 VLIB_INIT_FUNCTION (ip6_ll_module_init);
365
366 /*
367  * fd.io coding-style-patch-verification: ON
368  *
369  * Local Variables:
370  * eval: (c-set-style "gnu")
371  * End:
372  */