blob: f9172f6c50c0cc173743ec481f6b4ae607c6e1e7 [file] [log] [blame]
Neale Ranns53da2212018-02-24 02:11:19 -08001/*
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 */
25static ip6_ll_table_t ip6_ll_table;
26
27u32
28ip6_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
35fib_node_index_t
36ip6_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
42fib_node_index_t
43ip6_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
49static void
50ip6_ll_fib_create (u32 sw_if_index)
51{
52 vnet_main_t *vnm = vnet_get_main ();
53 u8 *desc;
54
Vladislav Grishenkofb9d1ac2022-08-04 20:36:45 +050055 desc = format (NULL, "IP6-link-local:%U", format_vnet_sw_if_index_name, vnm,
56 sw_if_index);
Neale Ranns53da2212018-02-24 02:11:19 -080057
58 ip6_ll_table.ilt_fibs[sw_if_index] =
59 ip6_fib_table_create_and_lock (FIB_SOURCE_IP6_ND,
60 FIB_TABLE_FLAG_IP6_LL, desc);
61
62 /*
63 * leave the default route as a drop, but fix fe::/10 to be a glean
64 * via the interface.
65 */
Neale Ranns53da2212018-02-24 02:11:19 -080066 fib_prefix_t pfx = {
67 .fp_proto = FIB_PROTOCOL_IP6,
68 .fp_len = 10,
69 .fp_addr = {
70 .ip6 = {
71 .as_u8 = {
72 [0] = 0xFE,
73 [1] = 0x80,
74 }
75 },
76 }
77 };
78 fib_table_entry_update_one_path(
79 ip6_ll_table.ilt_fibs[sw_if_index],
80 &pfx,
81 FIB_SOURCE_SPECIAL,
82 (FIB_ENTRY_FLAG_ATTACHED |
83 FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT),
84 DPO_PROTO_IP6,
85 NULL,
86 sw_if_index,
87 ~0,
88 1,
89 NULL,
90 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns53da2212018-02-24 02:11:19 -080091}
92
93static void
94ip6_ll_prefix_to_fib (const ip6_ll_prefix_t * ilp, fib_prefix_t * fp)
95{
96 fp->fp_proto = FIB_PROTOCOL_IP6;
97 fp->fp_len = 128;
98 fp->fp_addr.ip6 = ilp->ilp_addr;
Neale Ranns39a233a2020-02-20 13:13:45 +000099 fp->___fp___pad = 0;
Neale Ranns53da2212018-02-24 02:11:19 -0800100}
101
102fib_node_index_t
103ip6_ll_table_entry_update (const ip6_ll_prefix_t * ilp,
104 fib_route_path_flags_t flags)
105{
106 fib_node_index_t ip6_ll_entry_index;
107 fib_route_path_t *rpaths, rpath = {
108 .frp_flags = flags,
109 .frp_sw_if_index = ilp->ilp_sw_if_index,
110 .frp_proto = DPO_PROTO_IP6,
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +0500111 .frp_fib_index = ~0,
112 .frp_weight = 1,
Neale Ranns53da2212018-02-24 02:11:19 -0800113 };
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +0500114 fib_prefix_t fp = { 0 };
115
116 if (flags & FIB_ROUTE_PATH_LOCAL)
117 rpath.frp_addr.ip6 = ilp->ilp_addr;
Neale Ranns53da2212018-02-24 02:11:19 -0800118
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500119 vec_validate_init_empty (ip6_ll_table.ilt_fibs, ilp->ilp_sw_if_index, ~0);
Neale Ranns53da2212018-02-24 02:11:19 -0800120
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500121 if (~0 == ip6_ll_fib_get (ilp->ilp_sw_if_index))
Neale Ranns53da2212018-02-24 02:11:19 -0800122 {
123 ip6_ll_fib_create (ilp->ilp_sw_if_index);
124 }
125
126 rpaths = NULL;
127 vec_add1 (rpaths, rpath);
128
129 ip6_ll_prefix_to_fib (ilp, &fp);
130 ip6_ll_entry_index =
131 fib_table_entry_update (ip6_ll_fib_get (ilp->ilp_sw_if_index), &fp,
132 FIB_SOURCE_IP6_ND,
133 (flags & FIB_ROUTE_PATH_LOCAL ?
134 FIB_ENTRY_FLAG_LOCAL : FIB_ENTRY_FLAG_NONE),
135 rpaths);
136 vec_free (rpaths);
137
138 return (ip6_ll_entry_index);
139}
140
141void
142ip6_ll_table_entry_delete (const ip6_ll_prefix_t * ilp)
143{
144 fib_node_index_t ip6_ll_entry_index;
145 u32 fib_index;
146
147 ip6_ll_entry_index = ip6_ll_table_lookup_exact_match (ilp);
148
149 if (FIB_NODE_INDEX_INVALID != ip6_ll_entry_index)
150 fib_table_entry_delete_index (ip6_ll_entry_index, FIB_SOURCE_IP6_ND);
151
152 /*
153 * if there are no ND sourced prefixes left, then we can clean up this FIB
154 */
155 fib_index = ip6_ll_fib_get (ilp->ilp_sw_if_index);
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500156 if (~0 != fib_index &&
157 0 == fib_table_get_num_entries (fib_index, FIB_PROTOCOL_IP6,
158 FIB_SOURCE_IP6_ND))
Neale Ranns53da2212018-02-24 02:11:19 -0800159 {
160 fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500161 ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = ~0;
Neale Ranns53da2212018-02-24 02:11:19 -0800162 }
163}
164
165static void
166ip6_ll_table_show_one (vlib_main_t * vm, ip6_ll_prefix_t * ilp, int detail)
167{
168 vlib_cli_output (vm, "%U",
169 format_fib_entry,
170 ip6_ll_table_lookup (ilp),
171 (detail ?
172 FIB_ENTRY_FORMAT_DETAIL2 : FIB_ENTRY_FORMAT_DETAIL));
173}
174
175typedef struct ip6_ll_show_ctx_t_
176{
177 fib_node_index_t *entries;
178} ip6_ll_show_ctx_t;
179
180static fib_table_walk_rc_t
181ip6_ll_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
182{
183 ip6_ll_show_ctx_t *ctx = arg;
184
185 vec_add1 (ctx->entries, fib_entry_index);
186
187 return (FIB_TABLE_WALK_CONTINUE);
188}
189
190static void
191ip6_ll_table_show_all (vlib_main_t * vm, u32 fib_index)
192{
193 fib_node_index_t *fib_entry_index;
194 ip6_ll_show_ctx_t ctx = {
195 .entries = NULL,
196 };
197
198 fib_table_walk (fib_index, FIB_PROTOCOL_IP6, ip6_ll_table_show_walk, &ctx);
199 vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
200
201 vec_foreach (fib_entry_index, ctx.entries)
202 {
203 vlib_cli_output (vm, "%U",
204 format_fib_entry,
205 *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF);
206 }
207
208 vec_free (ctx.entries);
209}
210
211typedef struct
212{
213 u32 fib_index;
214 u64 count_by_prefix_length[129];
215} count_routes_in_fib_at_prefix_length_arg_t;
216
Neale Rannsf50bac12019-12-06 05:53:17 +0000217static int
218count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp, void *arg)
Neale Ranns53da2212018-02-24 02:11:19 -0800219{
220 count_routes_in_fib_at_prefix_length_arg_t *ap = arg;
221 int mask_width;
222
223 if ((kvp->key[2] >> 32) != ap->fib_index)
Neale Rannsf50bac12019-12-06 05:53:17 +0000224 return (BIHASH_WALK_CONTINUE);
Neale Ranns53da2212018-02-24 02:11:19 -0800225
226 mask_width = kvp->key[2] & 0xFF;
227
228 ap->count_by_prefix_length[mask_width]++;
Neale Rannsf50bac12019-12-06 05:53:17 +0000229
230 return (BIHASH_WALK_CONTINUE);
Neale Ranns53da2212018-02-24 02:11:19 -0800231}
232
233static clib_error_t *
234ip6_ll_show_fib (vlib_main_t * vm,
235 unformat_input_t * input, vlib_cli_command_t * cmd)
236{
237 count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
Neale Ranns53da2212018-02-24 02:11:19 -0800238 fib_table_t *fib_table;
239 int verbose, matching;
240 ip6_address_t matching_address;
241 u32 mask_len = 128;
242 u32 sw_if_index = ~0;
243 int detail = 0;
244 vnet_main_t *vnm = vnet_get_main ();
245 u32 fib_index;
246
247 verbose = 1;
248 matching = 0;
249
250 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
251 {
252 if (unformat (input, "brief") ||
253 unformat (input, "summary") || unformat (input, "sum"))
254 verbose = 0;
255
256 else if (unformat (input, "detail") || unformat (input, "det"))
257 detail = 1;
258
259 else if (unformat (input, "%U/%d",
260 unformat_ip6_address, &matching_address, &mask_len))
261 matching = 1;
262
263 else
264 if (unformat (input, "%U", unformat_ip6_address, &matching_address))
265 matching = 1;
266 else if (unformat (input, "%U",
267 unformat_vnet_sw_interface, vnm, &sw_if_index))
268 ;
269 else
270 break;
271 }
272
273 vec_foreach_index (sw_if_index, ip6_ll_table.ilt_fibs)
274 {
275 fib_source_t source;
276 u8 *s = NULL;
277
278 fib_index = ip6_ll_table.ilt_fibs[sw_if_index];
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500279 if (~0 == fib_index)
Neale Ranns53da2212018-02-24 02:11:19 -0800280 continue;
281
282 fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
283
284 if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
285 continue;
286
287 s = format (s, "%U, fib_index:%d, locks:[",
288 format_fib_table_name, fib_index,
289 FIB_PROTOCOL_IP6, fib_index);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000290 vec_foreach_index (source, fib_table->ft_locks)
Neale Ranns53da2212018-02-24 02:11:19 -0800291 {
292 if (0 != fib_table->ft_locks[source])
293 {
294 s = format (s, "%U:%d, ",
295 format_fib_source, source, fib_table->ft_locks[source]);
296 }
297 }
298 s = format (s, "]");
299 vlib_cli_output (vm, "%v", s);
300 vec_free (s);
301
302 /* Show summary? */
303 if (!verbose)
304 {
Neale Rannsae809832018-11-23 09:00:27 -0800305 clib_bihash_24_8_t *h =
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000306 &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
Neale Ranns53da2212018-02-24 02:11:19 -0800307 int len;
308
309 vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
310
Dave Barachb7b92992018-10-17 10:38:51 -0400311 clib_memset (ca, 0, sizeof (*ca));
Neale Ranns53da2212018-02-24 02:11:19 -0800312 ca->fib_index = fib_index;
313
Neale Rannsae809832018-11-23 09:00:27 -0800314 clib_bihash_foreach_key_value_pair_24_8
Neale Ranns53da2212018-02-24 02:11:19 -0800315 (h, count_routes_in_fib_at_prefix_length, ca);
316
317 for (len = 128; len >= 0; len--)
318 {
319 if (ca->count_by_prefix_length[len])
320 vlib_cli_output (vm, "%=20d%=16lld",
321 len, ca->count_by_prefix_length[len]);
322 }
323 continue;
324 }
325
326 if (!matching)
327 {
328 ip6_ll_table_show_all (vm, fib_index);
329 }
330 else
331 {
332 if (~0 == sw_if_index)
333 {
334 vlib_cli_output (vm, "specify the interface");
335 }
336 else
337 {
338 ip6_ll_prefix_t ilp = {
339 .ilp_addr = matching_address,
340 .ilp_sw_if_index = sw_if_index,
341 };
342 ip6_ll_table_show_one (vm, &ilp, detail);
343 }
344 }
345 };
346
347 return 0;
348}
349
Neale Ranns53da2212018-02-24 02:11:19 -0800350VLIB_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};
Neale Ranns53da2212018-02-24 02:11:19 -0800355
356static clib_error_t *
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500357ip6_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
364VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_ll_sw_interface_add_del);
365
366static clib_error_t *
Neale Ranns53da2212018-02-24 02:11:19 -0800367ip6_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
376VLIB_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 */