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