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 11798 : ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
61 : {
62 15752 : vec_validate_init_empty (ip4_main.
63 : lookup_main.if_address_pool_index_by_sw_if_index,
64 : sw_if_index, ~0);
65 15752 : vec_validate_init_empty (ip6_main.
66 : lookup_main.if_address_pool_index_by_sw_if_index,
67 : sw_if_index, ~0);
68 :
69 11798 : return (NULL);
70 : }
71 :
72 3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
73 :
74 : void
75 1150 : ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
76 : {
77 1150 : if (!lm->fib_result_n_bytes)
78 1150 : lm->fib_result_n_bytes = sizeof (uword);
79 :
80 1150 : lm->is_ip6 = is_ip6;
81 1150 : mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword),
82 : sizeof (ip_interface_prefix_key_t));
83 1150 : if (is_ip6)
84 : {
85 575 : lm->format_address_and_length = format_ip6_address_and_length;
86 575 : mhash_init (&lm->address_to_if_address_index, sizeof (uword),
87 : sizeof (ip6_address_fib_t));
88 : }
89 : else
90 : {
91 575 : lm->format_address_and_length = format_ip4_address_and_length;
92 575 : 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 295550 : for (i = 0; i < 256; i++)
101 : {
102 294400 : lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
103 294400 : lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
104 : }
105 :
106 1150 : lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
107 1150 : lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
108 1150 : IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
109 1150 : lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
110 : IP_BUILTIN_PROTOCOL_UDP;
111 1150 : lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
112 1150 : IP_PROTOCOL_ICMP] =
113 : IP_BUILTIN_PROTOCOL_ICMP;
114 : }
115 1150 : }
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 335953 : format_ip_adjacency_packet_data (u8 * s, va_list * args)
169 : {
170 335953 : u8 *packet_data = va_arg (*args, u8 *);
171 335953 : u32 n_packet_data_bytes = va_arg (*args, u32);
172 :
173 335953 : s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
174 :
175 335953 : 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 : bool
224 7453 : fib_prefix_validate (const fib_prefix_t *prefix)
225 : {
226 7453 : if (FIB_PROTOCOL_IP4 == prefix->fp_proto)
227 : {
228 4469 : if (prefix->fp_len > 32)
229 : {
230 0 : return false;
231 : }
232 : }
233 :
234 7453 : if (FIB_PROTOCOL_IP6 == prefix->fp_proto)
235 : {
236 2918 : if (prefix->fp_len > 128)
237 : {
238 0 : return false;
239 : }
240 : }
241 7453 : return true;
242 : }
243 :
244 : static clib_error_t *
245 19 : vnet_ip_route_cmd (vlib_main_t * vm,
246 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
247 : {
248 19 : unformat_input_t _line_input, *line_input = &_line_input;
249 : u32 table_id, is_del, fib_index, payload_proto;
250 19 : dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
251 19 : fib_route_path_t *rpaths = NULL, rpath;
252 19 : fib_prefix_t *prefixs = NULL, pfx;
253 19 : clib_error_t *error = NULL;
254 : f64 count;
255 : int i;
256 :
257 19 : is_del = 0;
258 19 : table_id = 0;
259 19 : count = 1;
260 19 : clib_memset (&pfx, 0, sizeof (pfx));
261 :
262 : /* Get a line of input. */
263 19 : if (!unformat_user (main_input, unformat_line_input, line_input))
264 0 : return 0;
265 :
266 78 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
267 : {
268 59 : clib_memset (&rpath, 0, sizeof (rpath));
269 :
270 59 : if (unformat (line_input, "table %d", &table_id))
271 : ;
272 57 : else if (unformat (line_input, "count %f", &count))
273 : ;
274 :
275 57 : else if (unformat (line_input, "%U/%d",
276 : unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
277 : {
278 2 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
279 2 : vec_add1 (prefixs, pfx);
280 : }
281 55 : else if (unformat (line_input, "%U/%d",
282 : unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
283 : {
284 17 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
285 17 : vec_add1 (prefixs, pfx);
286 : }
287 38 : else if (unformat (line_input, "via %U",
288 : unformat_fib_route_path, &rpath, &payload_proto))
289 : {
290 17 : vec_add1 (rpaths, rpath);
291 : }
292 23 : else if (vec_len (prefixs) > 0 &&
293 2 : unformat (line_input, "via %U",
294 2 : unformat_dpo, &dpo, prefixs[0].fp_proto))
295 : {
296 2 : vec_add1 (dpos, dpo);
297 : }
298 19 : else if (unformat (line_input, "del"))
299 0 : is_del = 1;
300 19 : else if (unformat (line_input, "add"))
301 19 : is_del = 0;
302 : else
303 : {
304 0 : error = unformat_parse_error (line_input);
305 0 : goto done;
306 : }
307 : }
308 :
309 19 : if (vec_len (prefixs) == 0)
310 : {
311 : error =
312 0 : clib_error_return (0, "expected ip4/ip6 destination address/length.");
313 0 : goto done;
314 : }
315 :
316 19 : if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
317 : {
318 0 : error = clib_error_return (0, "expected paths.");
319 0 : goto done;
320 : }
321 :
322 19 : if (~0 == table_id)
323 : {
324 : /*
325 : * if no table_id is passed we will manipulate the default
326 : */
327 0 : fib_index = 0;
328 : }
329 : else
330 : {
331 19 : fib_index = fib_table_find (prefixs[0].fp_proto, table_id);
332 :
333 19 : if (~0 == fib_index)
334 : {
335 0 : error = clib_error_return (0, "Nonexistent table id %d", table_id);
336 0 : goto done;
337 : }
338 : }
339 :
340 38 : for (i = 0; i < vec_len (prefixs); i++)
341 : {
342 19 : if (is_del && 0 == vec_len (rpaths))
343 : {
344 0 : fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
345 : }
346 19 : else if (!is_del && 1 == vec_len (dpos))
347 : {
348 2 : fib_table_entry_special_dpo_add (fib_index,
349 2 : &prefixs[i],
350 : FIB_SOURCE_CLI,
351 : FIB_ENTRY_FLAG_EXCLUSIVE,
352 : &dpos[0]);
353 2 : dpo_reset (&dpos[0]);
354 : }
355 17 : else if (vec_len (dpos) > 0)
356 : {
357 : error =
358 0 : clib_error_return (0,
359 : "Load-balancing over multiple special adjacencies is unsupported");
360 0 : goto done;
361 : }
362 17 : else if (0 < vec_len (rpaths))
363 17 : {
364 : u32 k, n;
365 : f64 t[2];
366 17 : n = count;
367 17 : t[0] = vlib_time_now (vm);
368 :
369 34 : for (k = 0; k < n; k++)
370 : {
371 17 : fib_prefix_t rpfx = {
372 17 : .fp_len = prefixs[i].fp_len,
373 17 : .fp_proto = prefixs[i].fp_proto,
374 17 : .fp_addr = prefixs[i].fp_addr,
375 : };
376 :
377 17 : if (!fib_prefix_validate (&rpfx))
378 : {
379 0 : vlib_cli_output (vm, "Invalid prefix len: %d", rpfx.fp_len);
380 0 : continue;
381 : }
382 :
383 17 : if (is_del)
384 0 : fib_table_entry_path_remove2 (fib_index,
385 : &rpfx, FIB_SOURCE_CLI, rpaths);
386 : else
387 17 : fib_table_entry_path_add2 (fib_index,
388 : &rpfx,
389 : FIB_SOURCE_CLI,
390 : FIB_ENTRY_FLAG_NONE, rpaths);
391 :
392 17 : fib_prefix_increment (&prefixs[i]);
393 : }
394 :
395 17 : t[1] = vlib_time_now (vm);
396 17 : if (count > 1)
397 0 : vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
398 : }
399 : else
400 : {
401 0 : error = clib_error_return (0, "Don't understand what you want...");
402 0 : goto done;
403 : }
404 : }
405 :
406 19 : done:
407 19 : vec_free (dpos);
408 19 : vec_free (prefixs);
409 19 : vec_free (rpaths);
410 19 : unformat_free (line_input);
411 19 : return error;
412 : }
413 :
414 : clib_error_t *
415 3 : vnet_ip_table_cmd (vlib_main_t * vm,
416 : unformat_input_t * main_input,
417 : vlib_cli_command_t * cmd, fib_protocol_t fproto)
418 : {
419 3 : unformat_input_t _line_input, *line_input = &_line_input;
420 3 : clib_error_t *error = NULL;
421 : u32 table_id, is_add;
422 3 : u8 *name = NULL;
423 :
424 3 : is_add = 1;
425 3 : table_id = ~0;
426 :
427 : /* Get a line of input. */
428 3 : if (!unformat_user (main_input, unformat_line_input, line_input))
429 0 : return 0;
430 :
431 7 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
432 : {
433 4 : if (unformat (line_input, "%d", &table_id))
434 : ;
435 1 : else if (unformat (line_input, "del"))
436 0 : is_add = 0;
437 1 : else if (unformat (line_input, "add"))
438 1 : is_add = 1;
439 0 : else if (unformat (line_input, "name %s", &name))
440 : ;
441 : else
442 : {
443 0 : error = unformat_parse_error (line_input);
444 0 : goto done;
445 : }
446 : }
447 :
448 3 : if (0 == table_id)
449 : {
450 0 : error = clib_error_return (0, "Can't change the default table");
451 0 : goto done;
452 : }
453 : else
454 : {
455 3 : if (is_add)
456 : {
457 3 : if (~0 == table_id)
458 : {
459 0 : table_id = ip_table_get_unused_id (fproto);
460 0 : vlib_cli_output (vm, "%u\n", table_id);
461 : }
462 3 : ip_table_create (fproto, table_id, 0, name);
463 : }
464 : else
465 : {
466 0 : if (~0 == table_id)
467 : {
468 0 : error = clib_error_return (0, "No table id");
469 0 : goto done;
470 : }
471 0 : ip_table_delete (fproto, table_id, 0);
472 : }
473 : }
474 :
475 3 : done:
476 3 : vec_free (name);
477 3 : unformat_free (line_input);
478 3 : return error;
479 : }
480 :
481 : clib_error_t *
482 2 : vnet_ip4_table_cmd (vlib_main_t * vm,
483 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
484 : {
485 2 : return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
486 : }
487 :
488 : clib_error_t *
489 1 : vnet_ip6_table_cmd (vlib_main_t * vm,
490 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
491 : {
492 1 : return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
493 : }
494 :
495 : clib_error_t *
496 0 : vnet_show_ip_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
497 : vlib_cli_command_t *cmd, fib_protocol_t fproto)
498 : {
499 0 : unformat_input_t _line_input, *line_input = &_line_input;
500 : fib_table_t *fib, *fibs;
501 0 : clib_error_t *error = NULL;
502 0 : u32 table_id = ~0, fib_index;
503 : /* Get a line of input. */
504 0 : if (unformat_user (main_input, unformat_line_input, line_input))
505 : {
506 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
507 : {
508 0 : if (unformat (line_input, "%d", &table_id))
509 : ;
510 : else
511 : {
512 0 : error = unformat_parse_error (line_input);
513 0 : goto done;
514 : }
515 : }
516 0 : unformat_free (line_input);
517 : }
518 :
519 0 : fibs = (fproto == FIB_PROTOCOL_IP4) ? ip4_main.fibs : ip6_main.fibs;
520 :
521 0 : if (table_id != (u32) ~0)
522 : {
523 0 : fib_index = fib_table_find (fproto, table_id);
524 0 : if (fib_index == (u32) ~0)
525 : {
526 0 : error = clib_error_return (0, "Couldn't find table with table_id %u",
527 : table_id);
528 0 : goto done;
529 : }
530 :
531 0 : fib = fib_table_get (fib_index, fproto);
532 0 : vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
533 : fib->ft_table_id, fib->ft_desc);
534 : }
535 : else
536 : {
537 0 : pool_foreach (fib, fibs)
538 0 : vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
539 : fib->ft_table_id, fib->ft_desc);
540 : }
541 :
542 0 : done:
543 0 : return error;
544 : }
545 :
546 : clib_error_t *
547 0 : vnet_show_ip4_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
548 : vlib_cli_command_t *cmd)
549 : {
550 0 : return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
551 : }
552 :
553 : clib_error_t *
554 0 : vnet_show_ip6_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
555 : vlib_cli_command_t *cmd)
556 : {
557 0 : return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
558 : }
559 :
560 : /* *INDENT-OFF* */
561 285289 : VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
562 : .path = "ip",
563 : .short_help = "Internet protocol (IP) commands",
564 : };
565 : /* *INDENT-ON* */
566 :
567 : /* *INDENT-OFF* */
568 285289 : VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
569 : .path = "ip6",
570 : .short_help = "Internet protocol version 6 (IPv6) commands",
571 : };
572 : /* *INDENT-ON* */
573 :
574 : /* *INDENT-OFF* */
575 285289 : VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
576 : .path = "show ip",
577 : .short_help = "Internet protocol (IP) show commands",
578 : };
579 : /* *INDENT-ON* */
580 :
581 : /* *INDENT-OFF* */
582 285289 : VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
583 : .path = "show ip6",
584 : .short_help = "Internet protocol version 6 (IPv6) show commands",
585 : };
586 : /* *INDENT-ON* */
587 :
588 : /*?
589 : * This command is used to add or delete IPv4 or IPv6 routes. All
590 : * IP Addresses ('<em><dst-ip-addr>/<width></em>',
591 : * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
592 : * can be IPv4 or IPv6, but all must be of the same form in a single
593 : * command. To display the current set of routes, use the commands
594 : * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
595 : *
596 : * @cliexpar
597 : * Example of how to add a straight forward static route:
598 : * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
599 : * Example of how to delete a straight forward static route:
600 : * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
601 : * Mainly for route add/del performance testing, one can add or delete
602 : * multiple routes by adding 'count N' to the previous item:
603 : * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
604 : * Add multiple routes for the same destination to create equal-cost multipath:
605 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
606 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
607 : * For unequal-cost multipath, specify the desired weights. This
608 : * combination of weights results in 3/4 of the traffic following the
609 : * second path, 1/4 following the first path:
610 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
611 : * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
612 : * To add a route to a particular FIB table (VRF), use:
613 : * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
614 : ?*/
615 : /* *INDENT-OFF* */
616 285289 : VLIB_CLI_COMMAND (ip_route_command, static) = {
617 : .path = "ip route",
618 : .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table "
619 : "<table-id>] via [next-hop-address] [next-hop-interface] "
620 : "[next-hop-table <value>] [weight <value>] [preference "
621 : "<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] "
622 : "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
623 : "[resolve-via-host] [resolve-via-connected] [rx-ip4 "
624 : "<interface>] [out-labels <value value value>]",
625 : .function = vnet_ip_route_cmd,
626 : .is_mp_safe = 1,
627 : };
628 :
629 : /* *INDENT-ON* */
630 : /*?
631 : * This command is used to add or delete IPv4 Tables. All
632 : * Tables must be explicitly added before that can be used. Creating a
633 : * table will add both unicast and multicast FIBs
634 : *
635 : ?*/
636 : /* *INDENT-OFF* */
637 285289 : VLIB_CLI_COMMAND (ip4_table_command, static) = {
638 : .path = "ip table",
639 : .short_help = "ip table [add|del] <table-id>",
640 : .function = vnet_ip4_table_cmd,
641 : };
642 : /* *INDENT-ON* */
643 :
644 : /* *INDENT-ON* */
645 : /*?
646 : * This command is used to add or delete IPv4 Tables. All
647 : * Tables must be explicitly added before that can be used. Creating a
648 : * table will add both unicast and multicast FIBs
649 : *
650 : ?*/
651 : /* *INDENT-OFF* */
652 285289 : VLIB_CLI_COMMAND (ip6_table_command, static) = {
653 : .path = "ip6 table",
654 : .short_help = "ip6 table [add|del] <table-id>",
655 : .function = vnet_ip6_table_cmd,
656 : };
657 :
658 285289 : VLIB_CLI_COMMAND (show_ip4_table_command, static) = {
659 : .path = "show ip table",
660 : .short_help = "show ip table <table-id>",
661 : .function = vnet_show_ip4_table_cmd,
662 : };
663 :
664 285289 : VLIB_CLI_COMMAND (show_ip6_table_command, static) = {
665 : .path = "show ip6 table",
666 : .short_help = "show ip6 table <table-id>",
667 : .function = vnet_show_ip6_table_cmd,
668 : };
669 :
670 : static clib_error_t *
671 2 : ip_table_bind_cmd (vlib_main_t * vm,
672 : unformat_input_t * input,
673 : vlib_cli_command_t * cmd,
674 : fib_protocol_t fproto)
675 : {
676 2 : vnet_main_t *vnm = vnet_get_main ();
677 2 : clib_error_t *error = 0;
678 : u32 sw_if_index, table_id;
679 : int rv;
680 :
681 2 : sw_if_index = ~0;
682 :
683 2 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
684 : {
685 0 : error = clib_error_return (0, "unknown interface `%U'",
686 : format_unformat_error, input);
687 0 : goto done;
688 : }
689 :
690 2 : if (unformat (input, "%d", &table_id))
691 : ;
692 : else
693 : {
694 0 : error = clib_error_return (0, "expected table id `%U'",
695 : format_unformat_error, input);
696 0 : goto done;
697 : }
698 :
699 2 : rv = ip_table_bind (fproto, sw_if_index, table_id);
700 :
701 2 : if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv)
702 : {
703 0 : error = clib_error_return (0, "IP addresses are still present on %U",
704 : format_vnet_sw_if_index_name,
705 : vnet_get_main(),
706 : sw_if_index);
707 : }
708 2 : else if (VNET_API_ERROR_NO_SUCH_FIB == rv)
709 : {
710 0 : error = clib_error_return (0, "no such table %d", table_id);
711 : }
712 2 : else if (0 != rv)
713 : {
714 0 : error = clib_error_return (0, "unknown error");
715 : }
716 :
717 2 : done:
718 2 : return error;
719 : }
720 :
721 : static clib_error_t *
722 1 : ip4_table_bind_cmd (vlib_main_t * vm,
723 : unformat_input_t * input,
724 : vlib_cli_command_t * cmd)
725 : {
726 1 : return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP4));
727 : }
728 :
729 : static clib_error_t *
730 1 : ip6_table_bind_cmd (vlib_main_t * vm,
731 : unformat_input_t * input,
732 : vlib_cli_command_t * cmd)
733 : {
734 1 : return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP6));
735 : }
736 :
737 : /*?
738 : * Place the indicated interface into the supplied IPv4 FIB table (also known
739 : * as a VRF). The FIB table must be created using "ip table add" already. To
740 : * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
741 : * FIB table will only be displayed if a route has been added to the table, or
742 : * an IP Address is assigned to an interface in the table (which adds a route
743 : * automatically).
744 : *
745 : * @note IP addresses added after setting the interface IP table are added to
746 : * the indicated FIB table. If an IP address is added prior to changing the
747 : * table then this is an error. The control plane must remove these addresses
748 : * first and then change the table. VPP will not automatically move the
749 : * addresses from the old to the new table as it does not know the validity
750 : * of such a change.
751 : *
752 : * @cliexpar
753 : * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
754 : * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
755 : ?*/
756 : /* *INDENT-OFF* */
757 285289 : VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
758 : {
759 : .path = "set interface ip table",
760 : .function = ip4_table_bind_cmd,
761 : .short_help = "set interface ip table <interface> <table-id>",
762 : };
763 : /* *INDENT-ON* */
764 :
765 : /*?
766 : * Place the indicated interface into the supplied IPv6 FIB table (also known
767 : * as a VRF). The FIB table must be created using "ip6 table add" already. To
768 : * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
769 : * FIB table will only be displayed if a route has been added to the table, or
770 : * an IP Address is assigned to an interface in the table (which adds a route
771 : * automatically).
772 : *
773 : * @note IP addresses added after setting the interface IP table are added to
774 : * the indicated FIB table. If an IP address is added prior to changing the
775 : * table then this is an error. The control plane must remove these addresses
776 : * first and then change the table. VPP will not automatically move the
777 : * addresses from the old to the new table as it does not know the validity
778 : * of such a change.
779 : *
780 : * @cliexpar
781 : * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
782 : * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
783 : ?*/
784 : /* *INDENT-OFF* */
785 285289 : VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
786 : {
787 : .path = "set interface ip6 table",
788 : .function = ip6_table_bind_cmd,
789 : .short_help = "set interface ip6 table <interface> <table-id>"
790 : };
791 : /* *INDENT-ON* */
792 :
793 : clib_error_t *
794 0 : vnet_ip_mroute_cmd (vlib_main_t * vm,
795 : unformat_input_t * main_input, vlib_cli_command_t * cmd)
796 : {
797 0 : unformat_input_t _line_input, *line_input = &_line_input;
798 0 : fib_route_path_t rpath, *rpaths = NULL;
799 0 : clib_error_t *error = NULL;
800 : u32 table_id, is_del, payload_proto;
801 : mfib_prefix_t pfx;
802 : u32 fib_index;
803 0 : mfib_entry_flags_t eflags = 0;
804 : u32 gcount, scount, ss, gg, incr;
805 : f64 timet[2];
806 0 : u32 rpf_id = MFIB_RPF_ID_NONE;
807 :
808 0 : gcount = scount = 1;
809 0 : is_del = 0;
810 0 : table_id = 0;
811 0 : clib_memset (&pfx, 0, sizeof (pfx));
812 0 : clib_memset (&rpath, 0, sizeof (rpath));
813 0 : rpath.frp_sw_if_index = ~0;
814 :
815 : /* Get a line of input. */
816 0 : if (!unformat_user (main_input, unformat_line_input, line_input))
817 0 : return 0;
818 :
819 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
820 : {
821 0 : if (unformat (line_input, "table %d", &table_id))
822 : ;
823 0 : else if (unformat (line_input, "del"))
824 0 : is_del = 1;
825 0 : else if (unformat (line_input, "add"))
826 0 : is_del = 0;
827 0 : else if (unformat (line_input, "rpf-id %d", &rpf_id))
828 : ;
829 0 : else if (unformat (line_input, "scount %d", &scount))
830 : ;
831 0 : else if (unformat (line_input, "gcount %d", &gcount))
832 : ;
833 0 : else if (unformat (line_input, "%U %U",
834 : unformat_ip4_address,
835 : &pfx.fp_src_addr.ip4,
836 : unformat_ip4_address, &pfx.fp_grp_addr.ip4))
837 : {
838 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
839 0 : pfx.fp_len = 64;
840 : }
841 0 : else if (unformat (line_input, "%U %U",
842 : unformat_ip6_address,
843 : &pfx.fp_src_addr.ip6,
844 : unformat_ip6_address, &pfx.fp_grp_addr.ip6))
845 : {
846 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
847 0 : pfx.fp_len = 256;
848 : }
849 0 : else if (unformat (line_input, "%U/%d",
850 : unformat_ip4_address,
851 : &pfx.fp_grp_addr.ip4, &pfx.fp_len))
852 : {
853 0 : clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
854 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
855 : }
856 0 : else if (unformat (line_input, "%U/%d",
857 : unformat_ip6_address,
858 : &pfx.fp_grp_addr.ip6, &pfx.fp_len))
859 : {
860 0 : clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
861 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
862 : }
863 0 : else if (unformat (line_input, "%U",
864 : unformat_ip4_address, &pfx.fp_grp_addr.ip4))
865 : {
866 0 : clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
867 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
868 0 : pfx.fp_len = 32;
869 : }
870 0 : else if (unformat (line_input, "%U",
871 : unformat_ip6_address, &pfx.fp_grp_addr.ip6))
872 : {
873 0 : clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
874 0 : payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
875 0 : pfx.fp_len = 128;
876 : }
877 0 : else if (unformat (line_input, "via local Forward"))
878 : {
879 0 : clib_memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr));
880 0 : rpath.frp_sw_if_index = ~0;
881 0 : rpath.frp_weight = 1;
882 0 : rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL;
883 : /*
884 : * set the path proto appropriately for the prefix
885 : */
886 0 : rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto);
887 0 : rpath.frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
888 :
889 0 : vec_add1 (rpaths, rpath);
890 : }
891 0 : else if (unformat (line_input, "via %U",
892 : unformat_fib_route_path, &rpath, &payload_proto))
893 : {
894 0 : vec_add1 (rpaths, rpath);
895 : }
896 0 : else if (unformat (line_input, "%U",
897 : unformat_mfib_entry_flags, &eflags))
898 : ;
899 : else
900 : {
901 0 : error = unformat_parse_error (line_input);
902 0 : goto done;
903 : }
904 : }
905 :
906 0 : if (~0 == table_id)
907 : {
908 : /*
909 : * if no table_id is passed we will manipulate the default
910 : */
911 0 : fib_index = 0;
912 : }
913 : else
914 : {
915 0 : fib_index = mfib_table_find (pfx.fp_proto, table_id);
916 :
917 0 : if (~0 == fib_index)
918 : {
919 0 : error = clib_error_return (0, "Nonexistent table id %d", table_id);
920 0 : goto done;
921 : }
922 : }
923 :
924 0 : timet[0] = vlib_time_now (vm);
925 :
926 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
927 : {
928 0 : incr = 1 << (32 - (pfx.fp_len % 32));
929 : }
930 : else
931 : {
932 0 : incr = 1 << (128 - (pfx.fp_len % 128));
933 : }
934 :
935 0 : for (ss = 0; ss < scount; ss++)
936 : {
937 0 : for (gg = 0; gg < gcount; gg++)
938 : {
939 0 : if (is_del && 0 == vec_len (rpaths))
940 : {
941 : /* no path provided => route delete */
942 0 : mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
943 : }
944 0 : else if (eflags || (MFIB_RPF_ID_NONE != rpf_id))
945 : {
946 0 : mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
947 : rpf_id, eflags);
948 : }
949 : else
950 : {
951 0 : if (is_del)
952 0 : mfib_table_entry_path_remove (fib_index,
953 : &pfx, MFIB_SOURCE_CLI, rpaths);
954 : else
955 0 : mfib_table_entry_path_update (fib_index, &pfx, MFIB_SOURCE_CLI,
956 : MFIB_ENTRY_FLAG_NONE, rpaths);
957 : }
958 :
959 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
960 : {
961 0 : pfx.fp_grp_addr.ip4.as_u32 =
962 0 : clib_host_to_net_u32 (incr +
963 0 : clib_net_to_host_u32 (pfx.
964 : fp_grp_addr.ip4.
965 : as_u32));
966 : }
967 : else
968 : {
969 0 : int bucket = (incr < 64 ? 0 : 1);
970 0 : pfx.fp_grp_addr.ip6.as_u64[bucket] =
971 0 : clib_host_to_net_u64 (incr +
972 0 : clib_net_to_host_u64 (pfx.
973 : fp_grp_addr.ip6.as_u64
974 : [bucket]));
975 :
976 : }
977 : }
978 0 : if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
979 : {
980 0 : pfx.fp_src_addr.ip4.as_u32 =
981 0 : clib_host_to_net_u32 (1 +
982 0 : clib_net_to_host_u32 (pfx.fp_src_addr.
983 : ip4.as_u32));
984 : }
985 : else
986 : {
987 0 : pfx.fp_src_addr.ip6.as_u64[1] =
988 0 : clib_host_to_net_u64 (1 +
989 0 : clib_net_to_host_u64 (pfx.fp_src_addr.
990 : ip6.as_u64[1]));
991 : }
992 : }
993 :
994 0 : timet[1] = vlib_time_now (vm);
995 :
996 0 : if (scount > 1 || gcount > 1)
997 0 : vlib_cli_output (vm, "%.6e routes/sec",
998 0 : (scount * gcount) / (timet[1] - timet[0]));
999 :
1000 0 : done:
1001 0 : vec_free (rpaths);
1002 0 : unformat_free (line_input);
1003 :
1004 0 : return error;
1005 : }
1006 :
1007 : /*?
1008 : * This command is used to add or delete IPv4 or IPv6 multicast routes. All
1009 : * IP Addresses ('<em><dst-ip-addr>/<width></em>',
1010 : * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
1011 : * can be IPv4 or IPv6, but all must be of the same form in a single
1012 : * command. To display the current set of routes, use the commands
1013 : * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
1014 : * The full set of support flags for interfaces and route is shown via;
1015 : * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
1016 : * respectively.
1017 : * @cliexpar
1018 : * Example of how to add a forwarding interface to a route (and create the
1019 : * route if it does not exist)
1020 : * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
1021 : * Example of how to add an accepting interface to a route (and create the
1022 : * route if it does not exist)
1023 : * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
1024 : * Example of changing the route's flags to send signals via the API
1025 : * @cliexcmd{ip mroute add 232.1.1.1 Signal}
1026 :
1027 : ?*/
1028 : /* *INDENT-OFF* */
1029 285289 : VLIB_CLI_COMMAND (ip_mroute_command, static) =
1030 : {
1031 : .path = "ip mroute",
1032 : .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [rpf-id <ID>] [via <next-hop-ip-addr> [<interface>],",
1033 : .function = vnet_ip_mroute_cmd,
1034 : .is_mp_safe = 1,
1035 : };
1036 : /* *INDENT-ON* */
1037 :
1038 : /*
1039 : * fd.io coding-style-patch-verification: ON
1040 : *
1041 : * Local Variables:
1042 : * eval: (c-set-style "gnu")
1043 : * End:
1044 : */
|