blob: 2234ea9df37f03e2a59092c600562ace591260ee [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
Benoît Ganne23c48962024-04-05 09:45:29 +0200147 fib_index = ip6_ll_fib_get (ilp->ilp_sw_if_index);
148 if (~0 == fib_index)
149 return;
Neale Ranns53da2212018-02-24 02:11:19 -0800150
Benoît Ganne23c48962024-04-05 09:45:29 +0200151 ip6_ll_entry_index = ip6_ll_table_lookup_exact_match (ilp);
152 if (FIB_NODE_INDEX_INVALID == ip6_ll_entry_index)
153 return;
154
155 fib_table_entry_delete_index (ip6_ll_entry_index, FIB_SOURCE_IP6_ND);
Neale Ranns53da2212018-02-24 02:11:19 -0800156
157 /*
158 * if there are no ND sourced prefixes left, then we can clean up this FIB
159 */
Benoît Ganne23c48962024-04-05 09:45:29 +0200160 if (0 == fib_table_get_num_entries (fib_index, FIB_PROTOCOL_IP6,
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500161 FIB_SOURCE_IP6_ND))
Neale Ranns53da2212018-02-24 02:11:19 -0800162 {
163 fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500164 ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = ~0;
Neale Ranns53da2212018-02-24 02:11:19 -0800165 }
166}
167
168static void
169ip6_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
178typedef struct ip6_ll_show_ctx_t_
179{
180 fib_node_index_t *entries;
181} ip6_ll_show_ctx_t;
182
183static fib_table_walk_rc_t
184ip6_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
193static void
194ip6_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
Neale Ranns53da2212018-02-24 02:11:19 -0800214static clib_error_t *
215ip6_ll_show_fib (vlib_main_t * vm,
216 unformat_input_t * input, vlib_cli_command_t * cmd)
217{
Neale Ranns53da2212018-02-24 02:11:19 -0800218 fib_table_t *fib_table;
219 int verbose, matching;
220 ip6_address_t matching_address;
221 u32 mask_len = 128;
222 u32 sw_if_index = ~0;
223 int detail = 0;
224 vnet_main_t *vnm = vnet_get_main ();
225 u32 fib_index;
226
227 verbose = 1;
228 matching = 0;
229
230 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
231 {
232 if (unformat (input, "brief") ||
233 unformat (input, "summary") || unformat (input, "sum"))
234 verbose = 0;
235
236 else if (unformat (input, "detail") || unformat (input, "det"))
237 detail = 1;
238
239 else if (unformat (input, "%U/%d",
240 unformat_ip6_address, &matching_address, &mask_len))
241 matching = 1;
242
243 else
244 if (unformat (input, "%U", unformat_ip6_address, &matching_address))
245 matching = 1;
246 else if (unformat (input, "%U",
247 unformat_vnet_sw_interface, vnm, &sw_if_index))
248 ;
249 else
250 break;
251 }
252
253 vec_foreach_index (sw_if_index, ip6_ll_table.ilt_fibs)
254 {
Neale Ranns53da2212018-02-24 02:11:19 -0800255 fib_index = ip6_ll_table.ilt_fibs[sw_if_index];
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500256 if (~0 == fib_index)
Neale Ranns53da2212018-02-24 02:11:19 -0800257 continue;
258
259 fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
260
261 if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
262 continue;
263
Benoît Ganne23c48962024-04-05 09:45:29 +0200264 ip6_fib_table_show (vm, fib_table, !verbose);
Neale Ranns53da2212018-02-24 02:11:19 -0800265 if (!verbose)
Benoît Ganne23c48962024-04-05 09:45:29 +0200266 continue;
Neale Ranns53da2212018-02-24 02:11:19 -0800267
268 if (!matching)
269 {
270 ip6_ll_table_show_all (vm, fib_index);
271 }
272 else
273 {
274 if (~0 == sw_if_index)
275 {
276 vlib_cli_output (vm, "specify the interface");
277 }
278 else
279 {
280 ip6_ll_prefix_t ilp = {
281 .ilp_addr = matching_address,
282 .ilp_sw_if_index = sw_if_index,
283 };
284 ip6_ll_table_show_one (vm, &ilp, detail);
285 }
286 }
287 };
288
289 return 0;
290}
291
Neale Ranns53da2212018-02-24 02:11:19 -0800292VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
293 .path = "show ip6-ll",
294 .short_help = "show ip6-ll [summary] [interface] [<ip6-addr>[/<width>]] [detail]",
295 .function = ip6_ll_show_fib,
296};
Neale Ranns53da2212018-02-24 02:11:19 -0800297
298static clib_error_t *
Vladislav Grishenkob9feb612021-11-19 22:53:41 +0500299ip6_ll_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
300{
301 vec_validate_init_empty (ip6_ll_table.ilt_fibs, sw_if_index, ~0);
302
303 return (NULL);
304}
305
306VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_ll_sw_interface_add_del);
307
308static clib_error_t *
Neale Ranns53da2212018-02-24 02:11:19 -0800309ip6_ll_module_init (vlib_main_t * vm)
310{
311 clib_error_t *error;
312
313 error = vlib_call_init_function (vm, ip6_lookup_init);
314
315 return (error);
316}
317
318VLIB_INIT_FUNCTION (ip6_ll_module_init);
319
320/*
321 * fd.io coding-style-patch-verification: ON
322 *
323 * Local Variables:
324 * eval: (c-set-style "gnu")
325 * End:
326 */