ip: Use .api declared error counters
[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_init_empty (ip6_ll_table.ilt_fibs, ilp->ilp_sw_if_index, ~0);
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_index &&
155       0 == fib_table_get_num_entries (fib_index, FIB_PROTOCOL_IP6,
156                                       FIB_SOURCE_IP6_ND))
157     {
158       fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
159       ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = ~0;
160     }
161 }
162
163 static void
164 ip6_ll_table_show_one (vlib_main_t * vm, ip6_ll_prefix_t * ilp, int detail)
165 {
166   vlib_cli_output (vm, "%U",
167                    format_fib_entry,
168                    ip6_ll_table_lookup (ilp),
169                    (detail ?
170                     FIB_ENTRY_FORMAT_DETAIL2 : FIB_ENTRY_FORMAT_DETAIL));
171 }
172
173 typedef struct ip6_ll_show_ctx_t_
174 {
175   fib_node_index_t *entries;
176 } ip6_ll_show_ctx_t;
177
178 static fib_table_walk_rc_t
179 ip6_ll_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
180 {
181   ip6_ll_show_ctx_t *ctx = arg;
182
183   vec_add1 (ctx->entries, fib_entry_index);
184
185   return (FIB_TABLE_WALK_CONTINUE);
186 }
187
188 static void
189 ip6_ll_table_show_all (vlib_main_t * vm, u32 fib_index)
190 {
191   fib_node_index_t *fib_entry_index;
192   ip6_ll_show_ctx_t ctx = {
193     .entries = NULL,
194   };
195
196   fib_table_walk (fib_index, FIB_PROTOCOL_IP6, ip6_ll_table_show_walk, &ctx);
197   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
198
199   vec_foreach (fib_entry_index, ctx.entries)
200   {
201     vlib_cli_output (vm, "%U",
202                      format_fib_entry,
203                      *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF);
204   }
205
206   vec_free (ctx.entries);
207 }
208
209 typedef struct
210 {
211   u32 fib_index;
212   u64 count_by_prefix_length[129];
213 } count_routes_in_fib_at_prefix_length_arg_t;
214
215 static int
216 count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp, void *arg)
217 {
218   count_routes_in_fib_at_prefix_length_arg_t *ap = arg;
219   int mask_width;
220
221   if ((kvp->key[2] >> 32) != ap->fib_index)
222     return (BIHASH_WALK_CONTINUE);
223
224   mask_width = kvp->key[2] & 0xFF;
225
226   ap->count_by_prefix_length[mask_width]++;
227
228   return (BIHASH_WALK_CONTINUE);
229 }
230
231 static clib_error_t *
232 ip6_ll_show_fib (vlib_main_t * vm,
233                  unformat_input_t * input, vlib_cli_command_t * cmd)
234 {
235   count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
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     if (~0 == fib_index)
278       continue;
279
280     fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
281
282     if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
283       continue;
284
285     s = format (s, "%U, fib_index:%d, locks:[",
286                 format_fib_table_name, fib_index,
287                 FIB_PROTOCOL_IP6, fib_index);
288     vec_foreach_index (source, fib_table->ft_locks)
289     {
290       if (0 != fib_table->ft_locks[source])
291         {
292           s = format (s, "%U:%d, ",
293                       format_fib_source, source, fib_table->ft_locks[source]);
294         }
295     }
296     s = format (s, "]");
297     vlib_cli_output (vm, "%v", s);
298     vec_free (s);
299
300     /* Show summary? */
301     if (!verbose)
302       {
303         clib_bihash_24_8_t *h =
304           &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
305         int len;
306
307         vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
308
309         clib_memset (ca, 0, sizeof (*ca));
310         ca->fib_index = fib_index;
311
312         clib_bihash_foreach_key_value_pair_24_8
313           (h, count_routes_in_fib_at_prefix_length, ca);
314
315         for (len = 128; len >= 0; len--)
316           {
317             if (ca->count_by_prefix_length[len])
318               vlib_cli_output (vm, "%=20d%=16lld",
319                                len, ca->count_by_prefix_length[len]);
320           }
321         continue;
322       }
323
324     if (!matching)
325       {
326         ip6_ll_table_show_all (vm, fib_index);
327       }
328     else
329       {
330         if (~0 == sw_if_index)
331           {
332             vlib_cli_output (vm, "specify the interface");
333           }
334         else
335           {
336             ip6_ll_prefix_t ilp = {
337               .ilp_addr = matching_address,
338               .ilp_sw_if_index = sw_if_index,
339             };
340             ip6_ll_table_show_one (vm, &ilp, detail);
341           }
342       }
343   };
344
345   return 0;
346 }
347
348 /* *INDENT-OFF* */
349 VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
350     .path = "show ip6-ll",
351     .short_help = "show ip6-ll [summary] [interface] [<ip6-addr>[/<width>]] [detail]",
352     .function = ip6_ll_show_fib,
353 };
354 /* *INDENT-ON* */
355
356 static clib_error_t *
357 ip6_ll_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
358 {
359   vec_validate_init_empty (ip6_ll_table.ilt_fibs, sw_if_index, ~0);
360
361   return (NULL);
362 }
363
364 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_ll_sw_interface_add_del);
365
366 static clib_error_t *
367 ip6_ll_module_init (vlib_main_t * vm)
368 {
369   clib_error_t *error;
370
371   error = vlib_call_init_function (vm, ip6_lookup_init);
372
373   return (error);
374 }
375
376 VLIB_INIT_FUNCTION (ip6_ll_module_init);
377
378 /*
379  * fd.io coding-style-patch-verification: ON
380  *
381  * Local Variables:
382  * eval: (c-set-style "gnu")
383  * End:
384  */