Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * ip/ip_lookup.c: ip4/6 adjacency and lookup table management
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vnet/ip/ip.h>
41 : #include <vnet/adj/adj.h>
42 : #include <vnet/fib/fib_table.h>
43 : #include <vnet/fib/ip4_fib.h>
44 : #include <vnet/fib/ip6_fib.h>
45 : #include <vnet/mpls/mpls.h>
46 : #include <vnet/mfib/mfib_table.h>
47 : #include <vnet/dpo/drop_dpo.h>
48 : #include <vnet/dpo/classify_dpo.h>
49 : #include <vnet/dpo/punt_dpo.h>
50 : #include <vnet/dpo/receive_dpo.h>
51 : #include <vnet/dpo/ip_null_dpo.h>
52 :
53 : /**
54 : * @file
55 : * @brief IPv4 and IPv6 adjacency and lookup table management.
56 : *
57 : */
58 :
59 : static clib_error_t *
60 11597 : ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
61 : {
62 15494 : vec_validate_init_empty (ip4_main.
63 : lookup_main.if_address_pool_index_by_sw_if_index,
64 : sw_if_index, ~0);
65 15494 : vec_validate_init_empty (ip6_main.
66 : lookup_main.if_address_pool_index_by_sw_if_index,
67 : sw_if_index, ~0);
68 :
69 11597 : return (NULL);
70 : }
71 :
72 3363 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
73 :
74 : void
75 1118 : ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
76 : {
77 1118 : if (!lm->fib_result_n_bytes)
78 1118 : lm->fib_result_n_bytes = sizeof (uword);
79 :
80 1118 : lm->is_ip6 = is_ip6;
81 1118 : mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword),
82 : sizeof (ip_interface_prefix_key_t));
83 1118 : if (is_ip6)
84 : {
85 559 : lm->format_address_and_length = format_ip6_address_and_length;
86 559 : mhash_init (&lm->address_to_if_address_index, sizeof (uword),
87 : sizeof (ip6_address_fib_t));
88 : }
89 : else
90 : {
91 559 : lm->format_address_and_length = format_ip4_address_and_length;
92 559 : mhash_init (&lm->address_to_if_address_index, sizeof (uword),
93 : sizeof (ip4_address_fib_t));
94 : }
95 :
96 : {
97 : int i;
98 :
99 : /* Setup all IP protocols to be punted and builtin-unknown. */
100 287326 : for (i = 0; i < 256; i++)
101 : {
102 286208 : lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
103 286208 : lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
104 : }
105 :
106 1118 : lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
107 1118 : lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
108 1118 : IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
109 1118 : lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
110 : IP_BUILTIN_PROTOCOL_UDP;
111 1118 : lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
112 1118 : IP_PROTOCOL_ICMP] =
113 : IP_BUILTIN_PROTOCOL_ICMP;
114 : }
115 1118 : }
116 :
117 : u8 *
118 572 : format_ip_flow_hash_config (u8 * s, va_list * args)
119 : {
120 572 : flow_hash_config_t flow_hash_config = va_arg (*args, u32);
121 :
122 : #define _(n, b, v) \
123 : if (flow_hash_config & v) \
124 : s = format (s, "%s ", #n);
125 572 : foreach_flow_hash_bit;
126 : #undef _
127 :
128 572 : return s;
129 : }
130 :
131 : uword
132 0 : unformat_ip_flow_hash_config (unformat_input_t *input, va_list *args)
133 : {
134 0 : flow_hash_config_t *flow_hash_config = va_arg (*args, flow_hash_config_t *);
135 0 : uword start_index = unformat_check_input (input);
136 0 : int matched_once = 0;
137 :
138 0 : if (unformat (input, "default"))
139 : {
140 0 : *flow_hash_config = IP_FLOW_HASH_DEFAULT;
141 0 : return 1;
142 : }
143 0 : while (!unformat_is_eof (input) &&
144 0 : !is_white_space (unformat_peek_input (input)))
145 : {
146 0 : if (unformat (input, "%_,"))
147 : ;
148 : #define _(a, b, c) \
149 : else if (unformat (input, "%_" #a)) \
150 : { \
151 : *flow_hash_config |= c; \
152 : matched_once = 1; \
153 : }
154 0 : foreach_flow_hash_bit
155 : #undef _
156 : else
157 : {
158 : /* Roll back to our start */
159 0 : input->index = start_index;
160 0 : return 0;
161 : }
162 : }
163 :
164 0 : return matched_once;
165 : }
166 :
167 : u8 *
168 306113 : format_ip_adjacency_packet_data (u8 * s, va_list * args)
169 : {
170 306113 : u8 *packet_data = va_arg (*args, u8 *);
171 306113 : u32 n_packet_data_bytes = va_arg (*args, u32);
172 :
173 306113 : s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
174 :
175 306113 : return s;
176 : }
177 :
178 : static uword
179 2 : unformat_dpo (unformat_input_t * input, va_list * args)
180 : {
181 2 : dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
182 2 : fib_protocol_t fp = va_arg (*args, int);
183 : dpo_proto_t proto;
184 :
185 2 : proto = fib_proto_to_dpo (fp);
186 :
187 2 : if (unformat (input, "drop"))
188 2 : dpo_copy (dpo, drop_dpo_get (proto));
189 0 : else if (unformat (input, "punt"))
190 0 : dpo_copy (dpo, punt_dpo_get (proto));
191 0 : else if (unformat (input, "local"))
192 0 : receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
193 0 : else if (unformat (input, "null-send-unreach"))
194 0 : ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
195 0 : else if (unformat (input, "null-send-prohibit"))
196 0 : ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
197 0 : else if (unformat (input, "null"))
198 0 : ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
199 0 : else if (unformat (input, "classify"))
200 : {
201 : u32 classify_table_index;
202 :
203 0 : if (!unformat (input, "%d", &classify_table_index))
204 : {
205 0 : clib_warning ("classify adj must specify table index");
206 0 : return 0;
207 : }
208 :
209 0 : dpo_set (dpo, DPO_CLASSIFY, proto,
210 : classify_dpo_create (proto, classify_table_index));
211 : }
212 : else
213 0 : return 0;
214 :
215 2 : return 1;
216 : }
217 :
218 : const ip46_address_t zero_addr = {
219 : .as_u64 = {
220 : 0, 0},
221 : };
222 :
223 : static clib_error_t *
224 11 : vnet_ip_route_cmd (vlib_main_t * vm,
225 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
226 : {
227 11 : unformat_input_t _line_input, *line_input = &_line_input;
228 : u32 table_id, is_del, fib_index, payload_proto;
229 11 : dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
230 11 : fib_route_path_t *rpaths = NULL, rpath;
231 11 : fib_prefix_t *prefixs = NULL, pfx;
232 11 : clib_error_t *error = NULL;
233 : f64 count;
234 : int i;
235 :
236 11 : is_del = 0;
237 11 : table_id = 0;
238 11 : count = 1;
239 11 : clib_memset (&pfx, 0, sizeof (pfx));
240 :
241 : /* Get a line of input. */
242 11 : if (!unformat_user (main_input, unformat_line_input, line_input))
243 0 : return 0;
244 :
245 46 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
246 : {
247 35 : clib_memset (&rpath, 0, sizeof (rpath));
248 :
249 35 : if (unformat (line_input, "table %d", &table_id))
250 : ;
251 33 : else if (unformat (line_input, "count %f", &count))
252 : ;
253 :
254 33 : else if (unformat (line_input, "%U/%d",
255 : unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
256 : {
257 2 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
258 2 : vec_add1 (prefixs, pfx);
259 : }
260 31 : else if (unformat (line_input, "%U/%d",
261 : unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
262 : {
263 9 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
264 9 : vec_add1 (prefixs, pfx);
265 : }
266 22 : else if (unformat (line_input, "via %U",
267 : unformat_fib_route_path, &rpath, &payload_proto))
268 : {
269 9 : vec_add1 (rpaths, rpath);
270 : }
271 15 : else if (vec_len (prefixs) > 0 &&
272 2 : unformat (line_input, "via %U",
273 2 : unformat_dpo, &dpo, prefixs[0].fp_proto))
274 : {
275 2 : vec_add1 (dpos, dpo);
276 : }
277 11 : else if (unformat (line_input, "del"))
278 0 : is_del = 1;
279 11 : else if (unformat (line_input, "add"))
280 11 : is_del = 0;
281 : else
282 : {
283 0 : error = unformat_parse_error (line_input);
284 0 : goto done;
285 : }
286 : }
287 :
288 11 : if (vec_len (prefixs) == 0)
289 : {
290 : error =
291 0 : clib_error_return (0, "expected ip4/ip6 destination address/length.");
292 0 : goto done;
293 : }
294 :
295 11 : if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
296 : {
297 0 : error = clib_error_return (0, "expected paths.");
298 0 : goto done;
299 : }
300 :
301 11 : if (~0 == table_id)
302 : {
303 : /*
304 : * if no table_id is passed we will manipulate the default
305 : */
306 0 : fib_index = 0;
307 : }
308 : else
309 : {
310 11 : fib_index = fib_table_find (prefixs[0].fp_proto, table_id);
311 :
312 11 : if (~0 == fib_index)
313 : {
314 0 : error = clib_error_return (0, "Nonexistent table id %d", table_id);
315 0 : goto done;
316 : }
317 : }
318 :
319 22 : for (i = 0; i < vec_len (prefixs); i++)
320 : {
321 11 : if (is_del && 0 == vec_len (rpaths))
322 : {
323 0 : fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
324 : }
325 11 : else if (!is_del && 1 == vec_len (dpos))
326 : {
327 2 : fib_table_entry_special_dpo_add (fib_index,
328 2 : &prefixs[i],
329 : FIB_SOURCE_CLI,
330 : FIB_ENTRY_FLAG_EXCLUSIVE,
331 : &dpos[0]);
332 2 : dpo_reset (&dpos[0]);
333 : }
334 9 : else if (vec_len (dpos) > 0)
335 : {
336 : error =
337 0 : clib_error_return (0,
338 : "Load-balancing over multiple special adjacencies is unsupported");
339 0 : goto done;
340 : }
341 9 : else if (0 < vec_len (rpaths))
342 9 : {
343 : u32 k, n;
344 : f64 t[2];
345 9 : n = count;
346 9 : t[0] = vlib_time_now (vm);
347 :
348 18 : for (k = 0; k < n; k++)
349 : {
350 9 : fib_prefix_t rpfx = {
351 9 : .fp_len = prefixs[i].fp_len,
352 9 : .fp_proto = prefixs[i].fp_proto,
353 9 : .fp_addr = prefixs[i].fp_addr,
354 : };
355 :
356 9 : if (is_del)
357 0 : fib_table_entry_path_remove2 (fib_index,
358 : &rpfx, FIB_SOURCE_CLI, rpaths);
359 : else
360 9 : fib_table_entry_path_add2 (fib_index,
361 : &rpfx,
362 : FIB_SOURCE_CLI,
363 : FIB_ENTRY_FLAG_NONE, rpaths);
364 :
365 9 : fib_prefix_increment (&prefixs[i]);
366 : }
367 :
368 9 : t[1] = vlib_time_now (vm);
369 9 : if (count > 1)
370 0 : vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
371 : }
372 : else
373 : {
374 0 : error = clib_error_return (0, "Don't understand what you want...");
375 0 : goto done;
376 : }
377 : }
378 :
379 11 : done:
380 11 : vec_free (dpos);
381 11 : vec_free (prefixs);
382 11 : vec_free (rpaths);
383 11 : unformat_free (line_input);
384 11 : return error;
385 : }
386 :
387 : clib_error_t *
388 3 : vnet_ip_table_cmd (vlib_main_t * vm,
389 : unformat_input_t * main_input,
390 : vlib_cli_command_t * cmd, fib_protocol_t fproto)
391 : {
392 3 : unformat_input_t _line_input, *line_input = &_line_input;
393 3 : clib_error_t *error = NULL;
394 : u32 table_id, is_add;
395 3 : u8 *name = NULL;
396 :
397 3 : is_add = 1;
398 3 : table_id = ~0;
399 :
400 : /* Get a line of input. */
401 3 : if (!unformat_user (main_input, unformat_line_input, line_input))
402 0 : return 0;
403 :
404 7 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
405 : {
406 4 : if (unformat (line_input, "%d", &table_id))
407 : ;
408 1 : else if (unformat (line_input, "del"))
409 0 : is_add = 0;
410 1 : else if (unformat (line_input, "add"))
411 1 : is_add = 1;
412 0 : else if (unformat (line_input, "name %s", &name))
413 : ;
414 : else
415 : {
416 0 : error = unformat_parse_error (line_input);
417 0 : goto done;
418 : }
419 : }
420 :
421 3 : if (0 == table_id)
422 : {
423 0 : error = clib_error_return (0, "Can't change the default table");
424 0 : goto done;
425 : }
426 : else
427 : {
428 3 : if (is_add)
429 : {
430 3 : if (~0 == table_id)
431 : {
432 0 : table_id = ip_table_get_unused_id (fproto);
433 0 : vlib_cli_output (vm, "%u\n", table_id);
434 : }
435 3 : ip_table_create (fproto, table_id, 0, name);
436 : }
437 : else
438 : {
439 0 : if (~0 == table_id)
440 : {
441 0 : error = clib_error_return (0, "No table id");
442 0 : goto done;
443 : }
444 0 : ip_table_delete (fproto, table_id, 0);
445 : }
446 : }
447 :
448 3 : done:
449 3 : vec_free (name);
450 3 : unformat_free (line_input);
451 3 : return error;
452 : }
453 :
454 : clib_error_t *
455 2 : vnet_ip4_table_cmd (vlib_main_t * vm,
456 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
457 : {
458 2 : return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
459 : }
460 :
461 : clib_error_t *
462 1 : vnet_ip6_table_cmd (vlib_main_t * vm,
463 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
464 : {
465 1 : return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
466 : }
467 :
468 : clib_error_t *
469 0 : vnet_show_ip_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
470 : vlib_cli_command_t *cmd, fib_protocol_t fproto)
471 : {
472 0 : unformat_input_t _line_input, *line_input = &_line_input;
473 : fib_table_t *fib, *fibs;
474 0 : clib_error_t *error = NULL;
475 0 : u32 table_id = ~0, fib_index;
476 : /* Get a line of input. */
477 0 : if (unformat_user (main_input, unformat_line_input, line_input))
478 : {
479 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
480 : {
481 0 : if (unformat (line_input, "%d", &table_id))
482 : ;
483 : else
484 : {
485 0 : error = unformat_parse_error (line_input);
486 0 : goto done;
487 : }
488 : }
489 0 : unformat_free (line_input);
490 : }
491 :
492 0 : fibs = (fproto == FIB_PROTOCOL_IP4) ? ip4_main.fibs : ip6_main.fibs;
493 :
494 0 : if (table_id != (u32) ~0)
495 : {
496 0 : fib_index = fib_table_find (fproto, table_id);
497 0 : if (fib_index == (u32) ~0)
498 : {
499 0 : error = clib_error_return (0, "Couldn't find table with table_id %u",
500 : table_id);
501 0 : goto done;
502 : }
503 :
504 0 : fib = fib_table_get (fib_index, fproto);
505 0 : vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
506 : fib->ft_table_id, fib->ft_desc);
507 : }
508 : else
509 : {
510 0 : pool_foreach (fib, fibs)
511 0 : vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
512 : fib->ft_table_id, fib->ft_desc);
513 : }
514 :
515 0 : done:
516 0 : return error;
517 : }
518 :
519 : clib_error_t *
520 0 : vnet_show_ip4_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
521 : vlib_cli_command_t *cmd)
522 : {
523 0 : return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
524 : }
525 :
526 : clib_error_t *
527 0 : vnet_show_ip6_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
528 : vlib_cli_command_t *cmd)
529 : {
530 0 : return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
531 : }
532 :
533 : /* *INDENT-OFF* */
534 272887 : VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
535 : .path = "ip",
536 : .short_help = "Internet protocol (IP) commands",
537 : };
538 : /* *INDENT-ON* */
539 :
540 : /* *INDENT-OFF* */
541 272887 : VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
542 : .path = "ip6",
543 : .short_help = "Internet protocol version 6 (IPv6) commands",
544 : };
545 : /* *INDENT-ON* */
546 :
547 : /* *INDENT-OFF* */
548 272887 : VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
549 : .path = "show ip",
550 : .short_help = "Internet protocol (IP) show commands",
551 : };
552 : /* *INDENT-ON* */
553 :
554 : /* *INDENT-OFF* */
555 272887 : VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
556 : .path = "show ip6",
557 : .short_help = "Internet protocol version 6 (IPv6) show commands",
558 : };
559 : /* *INDENT-ON* */
560 :
561 : /*?
562 : * This command is used to add or delete IPv4 or IPv6 routes. All
563 : * IP Addresses ('<em><dst-ip-addr>/<width></em>',
564 : * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
565 : * can be IPv4 or IPv6, but all must be of the same form in a single
566 : * command. To display the current set of routes, use the commands
567 : * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
568 : *
569 : * @cliexpar
570 : * Example of how to add a straight forward static route:
571 : * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
572 : * Example of how to delete a straight forward static route:
573 : * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
574 : * Mainly for route add/del performance testing, one can add or delete
575 : * multiple routes by adding 'count N' to the previous item:
576 : * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
577 : * Add multiple routes for the same destination to create equal-cost multipath:
578 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
579 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
580 : * For unequal-cost multipath, specify the desired weights. This
581 : * combination of weights results in 3/4 of the traffic following the
582 : * second path, 1/4 following the first path:
583 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
584 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
585 : * To add a route to a particular FIB table (VRF), use:
586 : * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
587 : ?*/
588 : /* *INDENT-OFF* */
589 272887 : VLIB_CLI_COMMAND (ip_route_command, static) = {
590 : .path = "ip route",
591 : .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table "
592 : "<table-id>] via [next-hop-address] [next-hop-interface] "
593 : "[next-hop-table <value>] [weight <value>] [preference "
594 : "<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] "
595 : "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
596 : "[resolve-via-host] [resolve-via-connected] [rx-ip4 "
597 : "<interface>] [out-labels <value value value>]",
598 : .function = vnet_ip_route_cmd,
599 : .is_mp_safe = 1,
600 : };
601 :
602 : /* *INDENT-ON* */
603 : /*?
604 : * This command is used to add or delete IPv4 Tables. All
605 : * Tables must be explicitly added before that can be used. Creating a
606 : * table will add both unicast and multicast FIBs
607 : *
608 : ?*/
609 : /* *INDENT-OFF* */
610 272887 : VLIB_CLI_COMMAND (ip4_table_command, static) = {
611 : .path = "ip table",
612 : .short_help = "ip table [add|del] <table-id>",
613 : .function = vnet_ip4_table_cmd,
614 : };
615 : /* *INDENT-ON* */
616 :
617 : /* *INDENT-ON* */
618 : /*?
619 : * This command is used to add or delete IPv4 Tables. All
620 : * Tables must be explicitly added before that can be used. Creating a
621 : * table will add both unicast and multicast FIBs
622 : *
623 : ?*/
624 : /* *INDENT-OFF* */
625 272887 : VLIB_CLI_COMMAND (ip6_table_command, static) = {
626 : .path = "ip6 table",
627 : .short_help = "ip6 table [add|del] <table-id>",
628 : .function = vnet_ip6_table_cmd,
629 : };
630 :
631 272887 : VLIB_CLI_COMMAND (show_ip4_table_command, static) = {
632 : .path = "show ip table",
633 : .short_help = "show ip table <table-id>",
634 : .function = vnet_show_ip4_table_cmd,
635 : };
636 :
637 272887 : VLIB_CLI_COMMAND (show_ip6_table_command, static) = {
638 : .path = "show ip6 table",
639 : .short_help = "show ip6 table <table-id>",
640 : .function = vnet_show_ip6_table_cmd,
641 : };
642 :
643 : static clib_error_t *
644 2 : ip_table_bind_cmd (vlib_main_t * vm,
645 : unformat_input_t * input,
646 : vlib_cli_command_t * cmd,
647 : fib_protocol_t fproto)
648 : {
649 2 : vnet_main_t *vnm = vnet_get_main ();
650 2 : clib_error_t *error = 0;
651 : u32 sw_if_index, table_id;
652 : int rv;
653 :
654 2 : sw_if_index = ~0;
655 :
656 2 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
657 : {
658 0 : error = clib_error_return (0, "unknown interface `%U'",
659 : format_unformat_error, input);
660 0 : goto done;
661 : }
662 :
663 2 : if (unformat (input, "%d", &table_id))
664 : ;
665 : else
666 : {
667 0 : error = clib_error_return (0, "expected table id `%U'",
668 : format_unformat_error, input);
669 0 : goto done;
670 : }
671 :
672 2 : rv = ip_table_bind (fproto, sw_if_index, table_id);
673 :
674 2 : if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv)
675 : {
676 0 : error = clib_error_return (0, "IP addresses are still present on %U",
677 : format_vnet_sw_if_index_name,
678 : vnet_get_main(),
679 : sw_if_index);
680 : }
681 2 : else if (VNET_API_ERROR_NO_SUCH_FIB == rv)
682 : {
683 0 : error = clib_error_return (0, "no such table %d", table_id);
684 : }
685 2 : else if (0 != rv)
686 : {
687 0 : error = clib_error_return (0, "unknown error");
688 : }
689 :
690 2 : done:
691 2 : return error;
692 : }
693 :
694 : static clib_error_t *
695 1 : ip4_table_bind_cmd (vlib_main_t * vm,
696 : unformat_input_t * input,
697 : vlib_cli_command_t * cmd)
698 : {
699 1 : return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP4));
700 : }
701 :
702 : static clib_error_t *
703 1 : ip6_table_bind_cmd (vlib_main_t * vm,
704 : unformat_input_t * input,
705 : vlib_cli_command_t * cmd)
706 : {
707 1 : return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP6));
708 : }
709 :
710 : /*?
711 : * Place the indicated interface into the supplied IPv4 FIB table (also known
712 : * as a VRF). The FIB table must be created using "ip table add" already. To
713 : * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
714 : * FIB table will only be displayed if a route has been added to the table, or
715 : * an IP Address is assigned to an interface in the table (which adds a route
716 : * automatically).
717 : *
718 : * @note IP addresses added after setting the interface IP table are added to
719 : * the indicated FIB table. If an IP address is added prior to changing the
720 : * table then this is an error. The control plane must remove these addresses
721 : * first and then change the table. VPP will not automatically move the
722 : * addresses from the old to the new table as it does not know the validity
723 : * of such a change.
724 : *
725 : * @cliexpar
726 : * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
727 : * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
728 : ?*/
729 : /* *INDENT-OFF* */
730 272887 : VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
731 : {
732 : .path = "set interface ip table",
733 : .function = ip4_table_bind_cmd,
734 : .short_help = "set interface ip table <interface> <table-id>",
735 : };
736 : /* *INDENT-ON* */
737 :
738 : /*?
739 : * Place the indicated interface into the supplied IPv6 FIB table (also known
740 : * as a VRF). The FIB table must be created using "ip6 table add" already. To
741 : * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
742 : * FIB table will only be displayed if a route has been added to the table, or
743 : * an IP Address is assigned to an interface in the table (which adds a route
744 : * automatically).
745 : *
746 : * @note IP addresses added after setting the interface IP table are added to
747 : * the indicated FIB table. If an IP address is added prior to changing the
748 : * table then this is an error. The control plane must remove these addresses
749 : * first and then change the table. VPP will not automatically move the
750 : * addresses from the old to the new table as it does not know the validity
751 : * of such a change.
752 : *
753 : * @cliexpar
754 : * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
755 : * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
756 : ?*/
757 : /* *INDENT-OFF* */
758 272887 : VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
759 : {
760 : .path = "set interface ip6 table",
761 : .function = ip6_table_bind_cmd,
762 : .short_help = "set interface ip6 table <interface> <table-id>"
763 : };
764 : /* *INDENT-ON* */
765 :
766 : clib_error_t *
767 0 : vnet_ip_mroute_cmd (vlib_main_t * vm,
768 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
769 : {
770 0 : unformat_input_t _line_input, *line_input = &_line_input;
771 0 : fib_route_path_t rpath, *rpaths = NULL;
772 0 : clib_error_t *error = NULL;
773 : u32 table_id, is_del, payload_proto;
774 : mfib_prefix_t pfx;
775 : u32 fib_index;
776 0 : mfib_entry_flags_t eflags = 0;
777 : u32 gcount, scount, ss, gg, incr;
778 : f64 timet[2];
779 0 : u32 rpf_id = MFIB_RPF_ID_NONE;
780 :
781 0 : gcount = scount = 1;
782 0 : is_del = 0;
783 0 : table_id = 0;
784 0 : clib_memset (&pfx, 0, sizeof (pfx));
785 0 : clib_memset (&rpath, 0, sizeof (rpath));
786 0 : rpath.frp_sw_if_index = ~0;
787 :
788 : /* Get a line of input. */
789 0 : if (!unformat_user (main_input, unformat_line_input, line_input))
790 0 : return 0;
791 :
792 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
793 : {
794 0 : if (unformat (line_input, "table %d", &table_id))
795 : ;
796 0 : else if (unformat (line_input, "del"))
797 0 : is_del = 1;
798 0 : else if (unformat (line_input, "add"))
799 0 : is_del = 0;
800 0 : else if (unformat (line_input, "rpf-id %d", &rpf_id))
801 : ;
802 0 : else if (unformat (line_input, "scount %d", &scount))
803 : ;
804 0 : else if (unformat (line_input, "gcount %d", &gcount))
805 : ;
806 0 : else if (unformat (line_input, "%U %U",
807 : unformat_ip4_address,
808 : &pfx.fp_src_addr.ip4,
809 : unformat_ip4_address, &pfx.fp_grp_addr.ip4))
810 : {
811 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
812 0 : pfx.fp_len = 64;
813 : }
814 0 : else if (unformat (line_input, "%U %U",
815 : unformat_ip6_address,
816 : &pfx.fp_src_addr.ip6,
817 : unformat_ip6_address, &pfx.fp_grp_addr.ip6))
818 : {
819 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
820 0 : pfx.fp_len = 256;
821 : }
822 0 : else if (unformat (line_input, "%U/%d",
823 : unformat_ip4_address,
824 : &pfx.fp_grp_addr.ip4, &pfx.fp_len))
825 : {
826 0 : clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
827 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
828 : }
829 0 : else if (unformat (line_input, "%U/%d",
830 : unformat_ip6_address,
831 : &pfx.fp_grp_addr.ip6, &pfx.fp_len))
832 : {
833 0 : clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
834 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
835 : }
836 0 : else if (unformat (line_input, "%U",
837 : unformat_ip4_address, &pfx.fp_grp_addr.ip4))
838 : {
839 0 : clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
840 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
841 0 : pfx.fp_len = 32;
842 : }
843 0 : else if (unformat (line_input, "%U",
844 : unformat_ip6_address, &pfx.fp_grp_addr.ip6))
845 : {
846 0 : clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
847 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
848 0 : pfx.fp_len = 128;
849 : }
850 0 : else if (unformat (line_input, "via local Forward"))
851 : {
852 0 : clib_memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr));
853 0 : rpath.frp_sw_if_index = ~0;
854 0 : rpath.frp_weight = 1;
855 0 : rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL;
856 : /*
857 : * set the path proto appropriately for the prefix
858 : */
859 0 : rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto);
860 0 : rpath.frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
861 :
862 0 : vec_add1 (rpaths, rpath);
863 : }
864 0 : else if (unformat (line_input, "via %U",
865 : unformat_fib_route_path, &rpath, &payload_proto))
866 : {
867 0 : vec_add1 (rpaths, rpath);
868 : }
869 0 : else if (unformat (line_input, "%U",
870 : unformat_mfib_entry_flags, &eflags))
871 : ;
872 : else
873 : {
874 0 : error = unformat_parse_error (line_input);
875 0 : goto done;
876 : }
877 : }
878 :
879 0 : if (~0 == table_id)
880 : {
881 : /*
882 : * if no table_id is passed we will manipulate the default
883 : */
884 0 : fib_index = 0;
885 : }
886 : else
887 : {
888 0 : fib_index = mfib_table_find (pfx.fp_proto, table_id);
889 :
890 0 : if (~0 == fib_index)
891 : {
892 0 : error = clib_error_return (0, "Nonexistent table id %d", table_id);
893 0 : goto done;
894 : }
895 : }
896 :
897 0 : timet[0] = vlib_time_now (vm);
898 :
899 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
900 : {
901 0 : incr = 1 << (32 - (pfx.fp_len % 32));
902 : }
903 : else
904 : {
905 0 : incr = 1 << (128 - (pfx.fp_len % 128));
906 : }
907 :
908 0 : for (ss = 0; ss < scount; ss++)
909 : {
910 0 : for (gg = 0; gg < gcount; gg++)
911 : {
912 0 : if (is_del && 0 == vec_len (rpaths))
913 : {
914 : /* no path provided => route delete */
915 0 : mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
916 : }
917 0 : else if (eflags || (MFIB_RPF_ID_NONE != rpf_id))
918 : {
919 0 : mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
920 : rpf_id, eflags);
921 : }
922 : else
923 : {
924 0 : if (is_del)
925 0 : mfib_table_entry_path_remove (fib_index,
926 : &pfx, MFIB_SOURCE_CLI, rpaths);
927 : else
928 0 : mfib_table_entry_path_update (fib_index, &pfx, MFIB_SOURCE_CLI,
929 : MFIB_ENTRY_FLAG_NONE, rpaths);
930 : }
931 :
932 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
933 : {
934 0 : pfx.fp_grp_addr.ip4.as_u32 =
935 0 : clib_host_to_net_u32 (incr +
936 0 : clib_net_to_host_u32 (pfx.
937 : fp_grp_addr.ip4.
938 : as_u32));
939 : }
940 : else
941 : {
942 0 : int bucket = (incr < 64 ? 0 : 1);
943 0 : pfx.fp_grp_addr.ip6.as_u64[bucket] =
944 0 : clib_host_to_net_u64 (incr +
945 0 : clib_net_to_host_u64 (pfx.
946 : fp_grp_addr.ip6.as_u64
947 : [bucket]));
948 :
949 : }
950 : }
951 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
952 : {
953 0 : pfx.fp_src_addr.ip4.as_u32 =
954 0 : clib_host_to_net_u32 (1 +
955 0 : clib_net_to_host_u32 (pfx.fp_src_addr.
956 : ip4.as_u32));
957 : }
958 : else
959 : {
960 0 : pfx.fp_src_addr.ip6.as_u64[1] =
961 0 : clib_host_to_net_u64 (1 +
962 0 : clib_net_to_host_u64 (pfx.fp_src_addr.
963 : ip6.as_u64[1]));
964 : }
965 : }
966 :
967 0 : timet[1] = vlib_time_now (vm);
968 :
969 0 : if (scount > 1 || gcount > 1)
970 0 : vlib_cli_output (vm, "%.6e routes/sec",
971 0 : (scount * gcount) / (timet[1] - timet[0]));
972 :
973 0 : done:
974 0 : vec_free (rpaths);
975 0 : unformat_free (line_input);
976 :
977 0 : return error;
978 : }
979 :
980 : /*?
981 : * This command is used to add or delete IPv4 or IPv6 multicast routes. All
982 : * IP Addresses ('<em><dst-ip-addr>/<width></em>',
983 : * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
984 : * can be IPv4 or IPv6, but all must be of the same form in a single
985 : * command. To display the current set of routes, use the commands
986 : * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
987 : * The full set of support flags for interfaces and route is shown via;
988 : * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
989 : * respectively.
990 : * @cliexpar
991 : * Example of how to add a forwarding interface to a route (and create the
992 : * route if it does not exist)
993 : * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
994 : * Example of how to add an accepting interface to a route (and create the
995 : * route if it does not exist)
996 : * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
997 : * Example of changing the route's flags to send signals via the API
998 : * @cliexcmd{ip mroute add 232.1.1.1 Signal}
999 :
1000 : ?*/
1001 : /* *INDENT-OFF* */
1002 272887 : VLIB_CLI_COMMAND (ip_mroute_command, static) =
1003 : {
1004 : .path = "ip mroute",
1005 : .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [rpf-id <ID>] [via <next-hop-ip-addr> [<interface>],",
1006 : .function = vnet_ip_mroute_cmd,
1007 : .is_mp_safe = 1,
1008 : };
1009 : /* *INDENT-ON* */
1010 :
1011 : /*
1012 : * fd.io coding-style-patch-verification: ON
1013 : *
1014 : * Local Variables:
1015 : * eval: (c-set-style "gnu")
1016 : * End:
1017 : */
|