blob: b356b278e01456f2026523d52275626a8bec1c39 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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/*
Paul Vinciguerra5b755e22019-10-26 19:34:40 -040016 * ip/ip_lookup.c: ip4/6 adjacency and lookup table management
Ed Warnickecb9cada2015-12-08 15:45:58 -070017 *
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
Ed Warnickecb9cada2015-12-08 15:45:58 -070040#include <vnet/ip/ip.h>
Neale Ranns6c3ebcc2016-10-02 21:20:15 +010041#include <vnet/adj/adj.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010042#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>
Neale Ranns32e1c012016-11-22 17:07:28 +000046#include <vnet/mfib/mfib_table.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#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>
Neale Ranns948e00f2016-10-20 13:39:34 +010051#include <vnet/dpo/ip_null_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Billy McFall0683c9c2016-10-13 08:27:31 -040053/**
54 * @file
Paul Vinciguerra5b755e22019-10-26 19:34:40 -040055 * @brief IPv4 and IPv6 adjacency and lookup table management.
Billy McFall0683c9c2016-10-13 08:27:31 -040056 *
57 */
58
Neale Rannsd96bad82017-03-08 01:12:54 -080059static clib_error_t *
60ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
61{
62 vec_validate_init_empty (ip4_main.
63 lookup_main.if_address_pool_index_by_sw_if_index,
64 sw_if_index, ~0);
65 vec_validate_init_empty (ip6_main.
66 lookup_main.if_address_pool_index_by_sw_if_index,
67 sw_if_index, ~0);
68
69 return (NULL);
70}
71
72VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
73
Dave Barachd7cb1b52016-12-09 09:52:16 -050074void
75ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
Dave Barachd7cb1b52016-12-09 09:52:16 -050077 if (!lm->fib_result_n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 lm->fib_result_n_bytes = sizeof (uword);
79
Ed Warnickecb9cada2015-12-08 15:45:58 -070080 lm->is_ip6 = is_ip6;
Matthew Smith6c92f5b2019-08-07 11:46:30 -050081 mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword),
82 sizeof (ip_interface_prefix_key_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -070083 if (is_ip6)
84 {
85 lm->format_address_and_length = format_ip6_address_and_length;
86 mhash_init (&lm->address_to_if_address_index, sizeof (uword),
87 sizeof (ip6_address_fib_t));
88 }
89 else
90 {
91 lm->format_address_and_length = format_ip4_address_and_length;
92 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 for (i = 0; i < 256; i++)
101 {
102 lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
103 lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
104 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
106 lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107 lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
108 IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
109 lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
110 IP_BUILTIN_PROTOCOL_UDP;
111 lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
112 IP_PROTOCOL_ICMP] =
113 IP_BUILTIN_PROTOCOL_ICMP;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 }
115}
116
Dave Barachd7cb1b52016-12-09 09:52:16 -0500117u8 *
118format_ip_flow_hash_config (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120 flow_hash_config_t flow_hash_config = va_arg (*args, u32);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122#define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
123 foreach_flow_hash_bit;
124#undef _
125
126 return s;
127}
128
Dave Barachd7cb1b52016-12-09 09:52:16 -0500129u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130format_ip_adjacency_packet_data (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 u8 *packet_data = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133 u32 n_packet_data_bytes = va_arg (*args, u32);
BenoƮt Ganne138c37a2019-07-18 17:34:28 +0200134
Neale Ranns0b6a8572019-10-30 17:34:14 +0000135 s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
137 return s;
138}
139
Dave Barachd7cb1b52016-12-09 09:52:16 -0500140static uword
141unformat_dpo (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100143 dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
144 fib_protocol_t fp = va_arg (*args, int);
145 dpo_proto_t proto;
146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 proto = fib_proto_to_dpo (fp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148
149 if (unformat (input, "drop"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500150 dpo_copy (dpo, drop_dpo_get (proto));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 else if (unformat (input, "punt"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 dpo_copy (dpo, punt_dpo_get (proto));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 else if (unformat (input, "local"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500154 receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100155 else if (unformat (input, "null-send-unreach"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500156 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100157 else if (unformat (input, "null-send-prohibit"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500158 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100159 else if (unformat (input, "null"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500160 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161 else if (unformat (input, "classify"))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162 {
163 u32 classify_table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100165 if (!unformat (input, "%d", &classify_table_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500166 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100167 clib_warning ("classify adj must specify table index");
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 return 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100169 }
170
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 dpo_set (dpo, DPO_CLASSIFY, proto,
172 classify_dpo_create (proto, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100173 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 else
175 return 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100176
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 return 1;
178}
179
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180const ip46_address_t zero_addr = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 .as_u64 = {
182 0, 0},
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100183};
184
Neale Ranns039cbfe2018-02-27 03:45:38 -0800185static clib_error_t *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100186vnet_ip_route_cmd (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 unformat_input_t * main_input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 unformat_input_t _line_input, *line_input = &_line_input;
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800190 u32 table_id, is_del, fib_index, payload_proto;
Neale Ranns948e00f2016-10-20 13:39:34 +0100191 dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800192 fib_route_path_t *rpaths = NULL, rpath;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100193 fib_prefix_t *prefixs = NULL, pfx;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500194 clib_error_t *error = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 f64 count;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100196 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
198 is_del = 0;
199 table_id = 0;
200 count = 1;
Dave Barachb7b92992018-10-17 10:38:51 -0400201 clib_memset (&pfx, 0, sizeof (pfx));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202
203 /* Get a line of input. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500204 if (!unformat_user (main_input, unformat_line_input, line_input))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 return 0;
206
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
208 {
Dave Barachb7b92992018-10-17 10:38:51 -0400209 clib_memset (&rpath, 0, sizeof (rpath));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100210
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 if (unformat (line_input, "table %d", &table_id))
212 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 else if (unformat (line_input, "count %f", &count))
214 ;
215
216 else if (unformat (line_input, "%U/%d",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500217 unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
218 {
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800219 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500220 vec_add1 (prefixs, pfx);
221 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 else if (unformat (line_input, "%U/%d",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500223 unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
224 {
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800225 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500226 vec_add1 (prefixs, pfx);
227 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 else if (unformat (line_input, "via %U",
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800229 unformat_fib_route_path, &rpath, &payload_proto))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500230 {
Neale Ranns8c2f05c2016-12-12 19:35:58 +0000231 vec_add1 (rpaths, rpath);
232 }
233 else if (vec_len (prefixs) > 0 &&
234 unformat (line_input, "via %U",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100235 unformat_dpo, &dpo, prefixs[0].fp_proto))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500236 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100237 vec_add1 (dpos, dpo);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500238 }
pragash352829f2017-08-17 22:53:24 -0400239 else if (unformat (line_input, "del"))
240 is_del = 1;
241 else if (unformat (line_input, "add"))
242 is_del = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500244 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 error = unformat_parse_error (line_input);
246 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500247 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500249
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100250 if (vec_len (prefixs) == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500251 {
252 error =
253 clib_error_return (0, "expected ip4/ip6 destination address/length.");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 goto done;
255 }
256
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257 if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100259 error = clib_error_return (0, "expected paths.");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 goto done;
261 }
262
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263 if (~0 == table_id)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500264 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100265 /*
266 * if no table_id is passed we will manipulate the default
267 */
268 fib_index = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500269 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100270 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500271 {
Neale Ranns107e7d42017-04-11 09:55:19 -0700272 fib_index = fib_table_find (prefixs[0].fp_proto, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100274 if (~0 == fib_index)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500275 {
276 error = clib_error_return (0, "Nonexistent table id %d", table_id);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500278 }
279 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281 for (i = 0; i < vec_len (prefixs); i++)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500282 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100283 if (is_del && 0 == vec_len (rpaths))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500284 {
285 fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
286 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100287 else if (!is_del && 1 == vec_len (dpos))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500288 {
289 fib_table_entry_special_dpo_add (fib_index,
290 &prefixs[i],
291 FIB_SOURCE_CLI,
292 FIB_ENTRY_FLAG_EXCLUSIVE,
293 &dpos[0]);
294 dpo_reset (&dpos[0]);
295 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 else if (vec_len (dpos) > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500297 {
298 error =
299 clib_error_return (0,
300 "Load-balancing over multiple special adjacencies is unsupported");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100301 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500302 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100303 else if (0 < vec_len (rpaths))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 {
Neale Ranns097fa662018-05-01 05:17:55 -0700305 u32 k, n, incr;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100306 ip46_address_t dst = prefixs[i].fp_addr;
307 f64 t[2];
308 n = count;
309 t[0] = vlib_time_now (vm);
310 incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
311 prefixs[i].fp_len);
312
313 for (k = 0; k < n; k++)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500314 {
Neale Ranns097fa662018-05-01 05:17:55 -0700315 fib_prefix_t rpfx = {
316 .fp_len = prefixs[i].fp_len,
317 .fp_proto = prefixs[i].fp_proto,
318 .fp_addr = dst,
319 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100320
Neale Ranns097fa662018-05-01 05:17:55 -0700321 if (is_del)
322 fib_table_entry_path_remove2 (fib_index,
323 &rpfx, FIB_SOURCE_CLI, rpaths);
324 else
325 fib_table_entry_path_add2 (fib_index,
326 &rpfx,
327 FIB_SOURCE_CLI,
328 FIB_ENTRY_FLAG_NONE, rpaths);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329
330 if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500331 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100332 dst.ip4.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 clib_host_to_net_u32 (incr +
334 clib_net_to_host_u32 (dst.
335 ip4.as_u32));
336 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100337 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500338 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100339 int bucket = (incr < 64 ? 0 : 1);
340 dst.ip6.as_u64[bucket] =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500341 clib_host_to_net_u64 (incr +
342 clib_net_to_host_u64 (dst.ip6.as_u64
343 [bucket]));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500344 }
345 }
Neale Ranns097fa662018-05-01 05:17:55 -0700346
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100347 t[1] = vlib_time_now (vm);
348 if (count > 1)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500349 vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
350 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100351 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500352 {
353 error = clib_error_return (0, "Don't understand what you want...");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100354 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500355 }
356 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100357
Dave Barachd7cb1b52016-12-09 09:52:16 -0500358done:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100359 vec_free (dpos);
360 vec_free (prefixs);
361 vec_free (rpaths);
Billy McFalla9a20e72017-02-15 11:39:12 -0500362 unformat_free (line_input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363 return error;
364}
365
Neale Ranns15002542017-09-10 04:39:11 -0700366clib_error_t *
367vnet_ip_table_cmd (vlib_main_t * vm,
368 unformat_input_t * main_input,
369 vlib_cli_command_t * cmd, fib_protocol_t fproto)
370{
371 unformat_input_t _line_input, *line_input = &_line_input;
372 clib_error_t *error = NULL;
373 u32 table_id, is_add;
Neale Ranns2297af02017-09-12 09:45:04 -0700374 u8 *name = NULL;
Neale Ranns15002542017-09-10 04:39:11 -0700375
376 is_add = 1;
377 table_id = ~0;
378
379 /* Get a line of input. */
380 if (!unformat_user (main_input, unformat_line_input, line_input))
381 return 0;
382
383 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
384 {
385 if (unformat (line_input, "%d", &table_id))
386 ;
387 else if (unformat (line_input, "del"))
388 is_add = 0;
389 else if (unformat (line_input, "add"))
390 is_add = 1;
Neale Ranns2297af02017-09-12 09:45:04 -0700391 else if (unformat (line_input, "name %s", &name))
392 ;
Neale Ranns15002542017-09-10 04:39:11 -0700393 else
394 {
395 error = unformat_parse_error (line_input);
396 goto done;
397 }
398 }
399
400 if (~0 == table_id)
401 {
402 error = clib_error_return (0, "No table id");
403 goto done;
404 }
405 else if (0 == table_id)
406 {
407 error = clib_error_return (0, "Can't change the default table");
408 goto done;
409 }
410 else
411 {
412 if (is_add)
413 {
Neale Ranns2297af02017-09-12 09:45:04 -0700414 ip_table_create (fproto, table_id, 0, name);
Neale Ranns15002542017-09-10 04:39:11 -0700415 }
416 else
417 {
418 ip_table_delete (fproto, table_id, 0);
419 }
420 }
421
422done:
423 unformat_free (line_input);
424 return error;
425}
426
427clib_error_t *
428vnet_ip4_table_cmd (vlib_main_t * vm,
429 unformat_input_t * main_input, vlib_cli_command_t * cmd)
430{
431 return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
432}
433
434clib_error_t *
435vnet_ip6_table_cmd (vlib_main_t * vm,
436 unformat_input_t * main_input, vlib_cli_command_t * cmd)
437{
438 return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
439}
440
Dave Barachd7cb1b52016-12-09 09:52:16 -0500441/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
443 .path = "ip",
444 .short_help = "Internet protocol (IP) commands",
445};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500446/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447
Dave Barachd7cb1b52016-12-09 09:52:16 -0500448/* *INDENT-OFF* */
Billy McFall0683c9c2016-10-13 08:27:31 -0400449VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
450 .path = "ip6",
451 .short_help = "Internet protocol version 6 (IPv6) commands",
452};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453/* *INDENT-ON* */
Billy McFall0683c9c2016-10-13 08:27:31 -0400454
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
457 .path = "show ip",
458 .short_help = "Internet protocol (IP) show commands",
459};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
464 .path = "show ip6",
Billy McFall0683c9c2016-10-13 08:27:31 -0400465 .short_help = "Internet protocol version 6 (IPv6) show commands",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700469/*?
Billy McFall0683c9c2016-10-13 08:27:31 -0400470 * This command is used to add or delete IPv4 or IPv6 routes. All
471 * IP Addresses ('<em><dst-ip-addr>/<width></em>',
472 * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
473 * can be IPv4 or IPv6, but all must be of the same form in a single
474 * command. To display the current set of routes, use the commands
475 * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
476 *
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700477 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -0400478 * Example of how to add a straight forward static route:
479 * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
480 * Example of how to delete a straight forward static route:
481 * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700482 * Mainly for route add/del performance testing, one can add or delete
483 * multiple routes by adding 'count N' to the previous item:
Billy McFall0683c9c2016-10-13 08:27:31 -0400484 * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700485 * Add multiple routes for the same destination to create equal-cost multipath:
Billy McFall0683c9c2016-10-13 08:27:31 -0400486 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
487 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
488 * For unequal-cost multipath, specify the desired weights. This
489 * combination of weights results in 3/4 of the traffic following the
490 * second path, 1/4 following the first path:
491 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
492 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
493 * To add a route to a particular FIB table (VRF), use:
494 * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700495 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -0400496/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497VLIB_CLI_COMMAND (ip_route_command, static) = {
498 .path = "ip route",
Neale Ranns70ed8ae2017-11-15 12:54:46 -0800499 .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table <table-id>] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500 .function = vnet_ip_route_cmd,
Dave Barachb2ef4dd2016-03-23 08:56:01 -0400501 .is_mp_safe = 1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502};
Neale Ranns15002542017-09-10 04:39:11 -0700503
504/* *INDENT-ON* */
505/*?
506 * This command is used to add or delete IPv4 Tables. All
507 * Tables must be explicitly added before that can be used. Creating a
508 * table will add both unicast and multicast FIBs
509 *
510 ?*/
511/* *INDENT-OFF* */
512VLIB_CLI_COMMAND (ip4_table_command, static) = {
513 .path = "ip table",
514 .short_help = "ip table [add|del] <table-id>",
515 .function = vnet_ip4_table_cmd,
Neale Ranns15002542017-09-10 04:39:11 -0700516};
517/* *INDENT-ON* */
518
519/* *INDENT-ON* */
520/*?
521 * This command is used to add or delete IPv4 Tables. All
522 * Tables must be explicitly added before that can be used. Creating a
523 * table will add both unicast and multicast FIBs
524 *
525 ?*/
526/* *INDENT-OFF* */
527VLIB_CLI_COMMAND (ip6_table_command, static) = {
528 .path = "ip6 table",
529 .short_help = "ip6 table [add|del] <table-id>",
530 .function = vnet_ip6_table_cmd,
Neale Ranns15002542017-09-10 04:39:11 -0700531};
532
533static clib_error_t *
534ip_table_bind_cmd (vlib_main_t * vm,
535 unformat_input_t * input,
536 vlib_cli_command_t * cmd,
537 fib_protocol_t fproto)
538{
539 vnet_main_t *vnm = vnet_get_main ();
540 clib_error_t *error = 0;
541 u32 sw_if_index, table_id;
542 int rv;
543
544 sw_if_index = ~0;
545
546 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
547 {
548 error = clib_error_return (0, "unknown interface `%U'",
549 format_unformat_error, input);
550 goto done;
551 }
552
553 if (unformat (input, "%d", &table_id))
554 ;
555 else
556 {
557 error = clib_error_return (0, "expected table id `%U'",
558 format_unformat_error, input);
559 goto done;
560 }
561
562 rv = ip_table_bind (fproto, sw_if_index, table_id, 0);
563
564 if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv)
565 {
566 error = clib_error_return (0, "IP addresses are still present on %U",
567 format_vnet_sw_if_index_name,
568 vnet_get_main(),
569 sw_if_index);
570 }
571 else if (VNET_API_ERROR_NO_SUCH_FIB == rv)
572 {
573 error = clib_error_return (0, "no such table %d", table_id);
574 }
575 else if (0 != rv)
576 {
577 error = clib_error_return (0, "unknown error");
578 }
579
580 done:
581 return error;
582}
583
584static clib_error_t *
585ip4_table_bind_cmd (vlib_main_t * vm,
586 unformat_input_t * input,
587 vlib_cli_command_t * cmd)
588{
589 return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP4));
590}
591
592static clib_error_t *
593ip6_table_bind_cmd (vlib_main_t * vm,
594 unformat_input_t * input,
595 vlib_cli_command_t * cmd)
596{
597 return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP6));
598}
599
600/*?
601 * Place the indicated interface into the supplied IPv4 FIB table (also known
Yichen Wang5c482a92018-08-02 17:12:01 -0700602 * as a VRF). The FIB table must be created using "ip table add" already. To
Neale Ranns15002542017-09-10 04:39:11 -0700603 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
604 * FIB table will only be displayed if a route has been added to the table, or
605 * an IP Address is assigned to an interface in the table (which adds a route
606 * automatically).
607 *
608 * @note IP addresses added after setting the interface IP table are added to
609 * the indicated FIB table. If an IP address is added prior to changing the
610 * table then this is an error. The control plane must remove these addresses
611 * first and then change the table. VPP will not automatically move the
612 * addresses from the old to the new table as it does not know the validity
613 * of such a change.
614 *
615 * @cliexpar
616 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
617 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
618 ?*/
619/* *INDENT-OFF* */
620VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
621{
622 .path = "set interface ip table",
623 .function = ip4_table_bind_cmd,
624 .short_help = "set interface ip table <interface> <table-id>",
625};
626/* *INDENT-ON* */
627
628/*?
629 * Place the indicated interface into the supplied IPv6 FIB table (also known
Yichen Wang5c482a92018-08-02 17:12:01 -0700630 * as a VRF). The FIB table must be created using "ip6 table add" already. To
Neale Ranns15002542017-09-10 04:39:11 -0700631 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
632 * FIB table will only be displayed if a route has been added to the table, or
633 * an IP Address is assigned to an interface in the table (which adds a route
634 * automatically).
635 *
636 * @note IP addresses added after setting the interface IP table are added to
637 * the indicated FIB table. If an IP address is added prior to changing the
638 * table then this is an error. The control plane must remove these addresses
639 * first and then change the table. VPP will not automatically move the
640 * addresses from the old to the new table as it does not know the validity
641 * of such a change.
642 *
643 * @cliexpar
644 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
645 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
646 ?*/
647/* *INDENT-OFF* */
648VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
649{
650 .path = "set interface ip6 table",
651 .function = ip6_table_bind_cmd,
652 .short_help = "set interface ip6 table <interface> <table-id>"
653};
Billy McFall0683c9c2016-10-13 08:27:31 -0400654/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655
Neale Ranns32e1c012016-11-22 17:07:28 +0000656clib_error_t *
657vnet_ip_mroute_cmd (vlib_main_t * vm,
658 unformat_input_t * main_input, vlib_cli_command_t * cmd)
659{
660 unformat_input_t _line_input, *line_input = &_line_input;
Neale Ranns097fa662018-05-01 05:17:55 -0700661 fib_route_path_t rpath, *rpaths = NULL;
Neale Ranns32e1c012016-11-22 17:07:28 +0000662 clib_error_t *error = NULL;
Neale Ranns097fa662018-05-01 05:17:55 -0700663 u32 table_id, is_del, payload_proto;
Neale Ranns32e1c012016-11-22 17:07:28 +0000664 mfib_prefix_t pfx;
665 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +0000666 mfib_entry_flags_t eflags = 0;
Neale Ranns52456fc2017-02-15 00:38:27 -0800667 u32 gcount, scount, ss, gg, incr;
668 f64 timet[2];
Neale Rannsad69c1f2018-12-05 16:39:45 +0000669 u32 rpf_id = MFIB_RPF_ID_NONE;
Neale Ranns32e1c012016-11-22 17:07:28 +0000670
Neale Ranns52456fc2017-02-15 00:38:27 -0800671 gcount = scount = 1;
Neale Ranns32e1c012016-11-22 17:07:28 +0000672 is_del = 0;
673 table_id = 0;
Dave Barachb7b92992018-10-17 10:38:51 -0400674 clib_memset (&pfx, 0, sizeof (pfx));
675 clib_memset (&rpath, 0, sizeof (rpath));
Neale Ranns32e1c012016-11-22 17:07:28 +0000676 rpath.frp_sw_if_index = ~0;
677
678 /* Get a line of input. */
679 if (!unformat_user (main_input, unformat_line_input, line_input))
680 return 0;
681
682 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
683 {
684 if (unformat (line_input, "table %d", &table_id))
685 ;
686 else if (unformat (line_input, "del"))
687 is_del = 1;
688 else if (unformat (line_input, "add"))
689 is_del = 0;
Neale Rannsad69c1f2018-12-05 16:39:45 +0000690 else if (unformat (line_input, "rpf-id %d", &rpf_id))
691 ;
Neale Ranns52456fc2017-02-15 00:38:27 -0800692 else if (unformat (line_input, "scount %d", &scount))
693 ;
694 else if (unformat (line_input, "gcount %d", &gcount))
695 ;
Neale Ranns32e1c012016-11-22 17:07:28 +0000696 else if (unformat (line_input, "%U %U",
697 unformat_ip4_address,
698 &pfx.fp_src_addr.ip4,
699 unformat_ip4_address, &pfx.fp_grp_addr.ip4))
700 {
Elias Rudberg224735b2020-06-04 00:15:45 +0200701 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
Neale Ranns32e1c012016-11-22 17:07:28 +0000702 pfx.fp_len = 64;
703 }
704 else if (unformat (line_input, "%U %U",
705 unformat_ip6_address,
706 &pfx.fp_src_addr.ip6,
707 unformat_ip6_address, &pfx.fp_grp_addr.ip6))
708 {
Elias Rudberg224735b2020-06-04 00:15:45 +0200709 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
Neale Ranns32e1c012016-11-22 17:07:28 +0000710 pfx.fp_len = 256;
711 }
712 else if (unformat (line_input, "%U/%d",
713 unformat_ip4_address,
714 &pfx.fp_grp_addr.ip4, &pfx.fp_len))
715 {
Dave Barachb7b92992018-10-17 10:38:51 -0400716 clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
Elias Rudberg224735b2020-06-04 00:15:45 +0200717 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
Neale Ranns32e1c012016-11-22 17:07:28 +0000718 }
719 else if (unformat (line_input, "%U/%d",
720 unformat_ip6_address,
721 &pfx.fp_grp_addr.ip6, &pfx.fp_len))
722 {
Dave Barachb7b92992018-10-17 10:38:51 -0400723 clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
Elias Rudberg224735b2020-06-04 00:15:45 +0200724 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
Neale Ranns32e1c012016-11-22 17:07:28 +0000725 }
726 else if (unformat (line_input, "%U",
727 unformat_ip4_address, &pfx.fp_grp_addr.ip4))
728 {
Dave Barachb7b92992018-10-17 10:38:51 -0400729 clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
Elias Rudberg224735b2020-06-04 00:15:45 +0200730 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
Neale Ranns32e1c012016-11-22 17:07:28 +0000731 pfx.fp_len = 32;
732 }
733 else if (unformat (line_input, "%U",
734 unformat_ip6_address, &pfx.fp_grp_addr.ip6))
735 {
Dave Barachb7b92992018-10-17 10:38:51 -0400736 clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
Elias Rudberg224735b2020-06-04 00:15:45 +0200737 payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
Neale Ranns32e1c012016-11-22 17:07:28 +0000738 pfx.fp_len = 128;
739 }
Neale Rannsad69c1f2018-12-05 16:39:45 +0000740 else if (unformat (line_input, "via local Forward"))
Neale Ranns5d85f2d2017-05-02 10:17:17 -0700741 {
Dave Barachb7b92992018-10-17 10:38:51 -0400742 clib_memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr));
Neale Ranns5d85f2d2017-05-02 10:17:17 -0700743 rpath.frp_sw_if_index = ~0;
744 rpath.frp_weight = 1;
745 rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL;
Neale Ranns37439992018-05-30 02:08:32 -0400746 /*
747 * set the path proto appropriately for the prefix
748 */
749 rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto);
Neale Ranns097fa662018-05-01 05:17:55 -0700750 rpath.frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
Neale Rannseacc8c52019-10-01 09:49:53 -0700751
752 vec_add1 (rpaths, rpath);
Neale Ranns32e1c012016-11-22 17:07:28 +0000753 }
Neale Ranns097fa662018-05-01 05:17:55 -0700754 else if (unformat (line_input, "via %U",
755 unformat_fib_route_path, &rpath, &payload_proto))
756 {
757 vec_add1 (rpaths, rpath);
758 }
759 else if (unformat (line_input, "%U",
Neale Ranns32e1c012016-11-22 17:07:28 +0000760 unformat_mfib_entry_flags, &eflags))
761 ;
762 else
763 {
764 error = unformat_parse_error (line_input);
765 goto done;
766 }
767 }
768
Neale Ranns32e1c012016-11-22 17:07:28 +0000769 if (~0 == table_id)
770 {
771 /*
772 * if no table_id is passed we will manipulate the default
773 */
774 fib_index = 0;
775 }
776 else
777 {
778 fib_index = mfib_table_find (pfx.fp_proto, table_id);
779
780 if (~0 == fib_index)
781 {
782 error = clib_error_return (0, "Nonexistent table id %d", table_id);
783 goto done;
784 }
785 }
786
Neale Ranns52456fc2017-02-15 00:38:27 -0800787 timet[0] = vlib_time_now (vm);
788
789 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
Neale Ranns32e1c012016-11-22 17:07:28 +0000790 {
Neale Ranns52456fc2017-02-15 00:38:27 -0800791 incr = 1 << (32 - (pfx.fp_len % 32));
Neale Ranns32e1c012016-11-22 17:07:28 +0000792 }
793 else
794 {
Neale Ranns52456fc2017-02-15 00:38:27 -0800795 incr = 1 << (128 - (pfx.fp_len % 128));
Neale Ranns32e1c012016-11-22 17:07:28 +0000796 }
797
Neale Ranns52456fc2017-02-15 00:38:27 -0800798 for (ss = 0; ss < scount; ss++)
799 {
800 for (gg = 0; gg < gcount; gg++)
801 {
Neale Ranns097fa662018-05-01 05:17:55 -0700802 if (is_del && 0 == vec_len (rpaths))
Neale Ranns52456fc2017-02-15 00:38:27 -0800803 {
804 /* no path provided => route delete */
805 mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
806 }
Neale Rannsad69c1f2018-12-05 16:39:45 +0000807 else if (eflags || (MFIB_RPF_ID_NONE != rpf_id))
Neale Ranns52456fc2017-02-15 00:38:27 -0800808 {
809 mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
Neale Rannsad69c1f2018-12-05 16:39:45 +0000810 rpf_id, eflags);
Neale Ranns52456fc2017-02-15 00:38:27 -0800811 }
812 else
813 {
814 if (is_del)
815 mfib_table_entry_path_remove (fib_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700816 &pfx, MFIB_SOURCE_CLI, rpaths);
Neale Ranns52456fc2017-02-15 00:38:27 -0800817 else
818 mfib_table_entry_path_update (fib_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700819 &pfx, MFIB_SOURCE_CLI, rpaths);
Neale Ranns52456fc2017-02-15 00:38:27 -0800820 }
821
822 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
823 {
824 pfx.fp_grp_addr.ip4.as_u32 =
825 clib_host_to_net_u32 (incr +
826 clib_net_to_host_u32 (pfx.
827 fp_grp_addr.ip4.
828 as_u32));
829 }
830 else
831 {
832 int bucket = (incr < 64 ? 0 : 1);
833 pfx.fp_grp_addr.ip6.as_u64[bucket] =
834 clib_host_to_net_u64 (incr +
835 clib_net_to_host_u64 (pfx.
836 fp_grp_addr.ip6.as_u64
837 [bucket]));
838
839 }
840 }
841 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
842 {
843 pfx.fp_src_addr.ip4.as_u32 =
844 clib_host_to_net_u32 (1 +
845 clib_net_to_host_u32 (pfx.fp_src_addr.
846 ip4.as_u32));
847 }
848 else
849 {
850 pfx.fp_src_addr.ip6.as_u64[1] =
851 clib_host_to_net_u64 (1 +
852 clib_net_to_host_u64 (pfx.fp_src_addr.
853 ip6.as_u64[1]));
854 }
855 }
856
857 timet[1] = vlib_time_now (vm);
858
859 if (scount > 1 || gcount > 1)
860 vlib_cli_output (vm, "%.6e routes/sec",
861 (scount * gcount) / (timet[1] - timet[0]));
862
Neale Ranns32e1c012016-11-22 17:07:28 +0000863done:
Neale Ranns097fa662018-05-01 05:17:55 -0700864 vec_free (rpaths);
Billy McFalla9a20e72017-02-15 11:39:12 -0500865 unformat_free (line_input);
866
Neale Ranns32e1c012016-11-22 17:07:28 +0000867 return error;
868}
869
870/*?
Paul Vinciguerra5b755e22019-10-26 19:34:40 -0400871 * This command is used to add or delete IPv4 or IPv6 multicast routes. All
Neale Ranns32e1c012016-11-22 17:07:28 +0000872 * IP Addresses ('<em><dst-ip-addr>/<width></em>',
873 * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
874 * can be IPv4 or IPv6, but all must be of the same form in a single
875 * command. To display the current set of routes, use the commands
876 * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
877 * The full set of support flags for interfaces and route is shown via;
878 * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
879 * respectively.
880 * @cliexpar
881 * Example of how to add a forwarding interface to a route (and create the
882 * route if it does not exist)
883 * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
884 * Example of how to add an accepting interface to a route (and create the
885 * route if it does not exist)
886 * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
887 * Example of changing the route's flags to send signals via the API
888 * @cliexcmd{ip mroute add 232.1.1.1 Signal}
889
890 ?*/
891/* *INDENT-OFF* */
892VLIB_CLI_COMMAND (ip_mroute_command, static) =
893{
894 .path = "ip mroute",
Neale Rannsad69c1f2018-12-05 16:39:45 +0000895 .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [rpf-id <ID>] [via <next-hop-ip-addr> [<interface>],",
Neale Ranns32e1c012016-11-22 17:07:28 +0000896 .function = vnet_ip_mroute_cmd,
897 .is_mp_safe = 1,
898};
899/* *INDENT-ON* */
900
Dave Barachd7cb1b52016-12-09 09:52:16 -0500901/*
902 * fd.io coding-style-patch-verification: ON
903 *
904 * Local Variables:
905 * eval: (c-set-style "gnu")
906 * End:
907 */