blob: 9ae269cc20511248ba30640dc1b2e9e5b4a3716a [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/*
16 * ip/ip_lookup.c: ip4/6 adjacency and lookup table managment
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
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>
Neale Ranns3f844d02017-02-18 00:03:54 -080052#include <vnet/ip/ip6_neighbor.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070053
Billy McFall0683c9c2016-10-13 08:27:31 -040054/**
55 * @file
56 * @brief IPv4 and IPv6 adjacency and lookup table managment.
57 *
58 */
59
Ed Warnickecb9cada2015-12-08 15:45:58 -070060clib_error_t *
61ip_interface_address_add_del (ip_lookup_main_t * lm,
62 u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -050063 void *addr_fib,
Ed Warnickecb9cada2015-12-08 15:45:58 -070064 u32 address_length,
Dave Barachd7cb1b52016-12-09 09:52:16 -050065 u32 is_del, u32 * result_if_address_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -070066{
Dave Barachd7cb1b52016-12-09 09:52:16 -050067 vnet_main_t *vnm = vnet_get_main ();
68 ip_interface_address_t *a, *prev, *next;
69 uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib);
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Dave Barachd7cb1b52016-12-09 09:52:16 -050071 vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
72 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073 a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0;
74
75 /* Verify given length. */
76 if ((a && (address_length != a->address_length)) || (address_length == 0))
77 {
78 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
Dave Barachd7cb1b52016-12-09 09:52:16 -050079 return clib_error_create
80 ("%U wrong length (expected %d) for interface %U",
81 lm->format_address_and_length, addr_fib,
82 address_length, a ? a->address_length : -1,
83 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -070084 }
85
86 if (is_del)
87 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050088 if (!a)
89 {
90 vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
91 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
92 return clib_error_create ("%U not found for interface %U",
93 lm->format_address_and_length,
94 addr_fib, address_length,
95 format_vnet_sw_interface_name, vnm, si);
96 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
98 if (a->prev_this_sw_interface != ~0)
99 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500100 prev =
101 pool_elt_at_index (lm->if_address_pool,
102 a->prev_this_sw_interface);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103 prev->next_this_sw_interface = a->next_this_sw_interface;
104 }
105 if (a->next_this_sw_interface != ~0)
106 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107 next =
108 pool_elt_at_index (lm->if_address_pool,
109 a->next_this_sw_interface);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110 next->prev_this_sw_interface = a->prev_this_sw_interface;
111
Dave Barachd7cb1b52016-12-09 09:52:16 -0500112 if (a->prev_this_sw_interface == ~0)
113 lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
114 a->next_this_sw_interface;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115 }
116
Dave Barachd7cb1b52016-12-09 09:52:16 -0500117 if ((a->next_this_sw_interface == ~0)
118 && (a->prev_this_sw_interface == ~0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119 lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0;
120
121 mhash_unset (&lm->address_to_if_address_index, addr_fib,
122 /* old_value */ 0);
123 pool_put (lm->if_address_pool, a);
124
125 if (result_if_address_index)
126 *result_if_address_index = ~0;
127 }
128
Dave Barachd7cb1b52016-12-09 09:52:16 -0500129 else if (!a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 u32 pi; /* previous index */
132 u32 ai;
133 u32 hi; /* head index */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
135 pool_get (lm->if_address_pool, a);
136 memset (a, ~0, sizeof (a[0]));
137 ai = a - lm->if_address_pool;
138
139 hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
140 prev = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 while (pi != (u32) ~ 0)
142 {
143 prev = pool_elt_at_index (lm->if_address_pool, pi);
144 pi = prev->next_this_sw_interface;
145 }
146 pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147
148 a->address_key = mhash_set (&lm->address_to_if_address_index,
149 addr_fib, ai, /* old_value */ 0);
150 a->address_length = address_length;
151 a->sw_if_index = sw_if_index;
152 a->flags = 0;
153 a->prev_this_sw_interface = pi;
154 a->next_this_sw_interface = ~0;
155 if (prev)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500156 prev->next_this_sw_interface = ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157
Dave Barachd7cb1b52016-12-09 09:52:16 -0500158 lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
159 (hi != ~0) ? hi : ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 if (result_if_address_index)
161 *result_if_address_index = ai;
162 }
163 else
164 {
165 if (result_if_address_index)
166 *result_if_address_index = a - lm->if_address_pool;
167 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
170 return /* no error */ 0;
171}
172
Neale Rannsd96bad82017-03-08 01:12:54 -0800173static clib_error_t *
174ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
175{
176 vec_validate_init_empty (ip4_main.
177 lookup_main.if_address_pool_index_by_sw_if_index,
178 sw_if_index, ~0);
179 vec_validate_init_empty (ip6_main.
180 lookup_main.if_address_pool_index_by_sw_if_index,
181 sw_if_index, ~0);
182
183 return (NULL);
184}
185
186VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
187
Dave Barachd7cb1b52016-12-09 09:52:16 -0500188void
189ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190{
Dave Barachdbf19ca2016-03-15 10:21:54 +0100191 /* ensure that adjacency is cacheline aligned and sized */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500192 STATIC_ASSERT (STRUCT_OFFSET_OF (ip_adjacency_t, cacheline0) == 0,
193 "Cache line marker must be 1st element in struct");
194 STATIC_ASSERT (STRUCT_OFFSET_OF (ip_adjacency_t, cacheline1) ==
195 CLIB_CACHE_LINE_BYTES,
196 "Data in cache line 0 is bigger than cache line size");
Dave Barachdbf19ca2016-03-15 10:21:54 +0100197
Dave Barachb2ef4dd2016-03-23 08:56:01 -0400198 /* Preallocate three "special" adjacencies */
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100199 lm->adjacency_heap = adj_pool;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 if (!lm->fib_result_n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 lm->fib_result_n_bytes = sizeof (uword);
203
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 lm->is_ip6 = is_ip6;
205 if (is_ip6)
206 {
207 lm->format_address_and_length = format_ip6_address_and_length;
208 mhash_init (&lm->address_to_if_address_index, sizeof (uword),
209 sizeof (ip6_address_fib_t));
210 }
211 else
212 {
213 lm->format_address_and_length = format_ip4_address_and_length;
214 mhash_init (&lm->address_to_if_address_index, sizeof (uword),
215 sizeof (ip4_address_fib_t));
216 }
217
218 {
219 int i;
220
221 /* Setup all IP protocols to be punted and builtin-unknown. */
222 for (i = 0; i < 256; i++)
223 {
224 lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
225 lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
226 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
228 lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500229 lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
230 IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
231 lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
232 IP_BUILTIN_PROTOCOL_UDP;
233 lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
234 IP_PROTOCOL_ICMP] =
235 IP_BUILTIN_PROTOCOL_ICMP;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 }
237}
238
Dave Barachd7cb1b52016-12-09 09:52:16 -0500239u8 *
240format_ip_flow_hash_config (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100242 flow_hash_config_t flow_hash_config = va_arg (*args, u32);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500243
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244#define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
245 foreach_flow_hash_bit;
246#undef _
247
248 return s;
249}
250
Dave Barachd7cb1b52016-12-09 09:52:16 -0500251u8 *
252format_ip_lookup_next (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100254 ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500255 char *t = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256
257 switch (n)
258 {
259 default:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100260 s = format (s, "unknown %d", n);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 return s;
262
Dave Barachd7cb1b52016-12-09 09:52:16 -0500263 case IP_LOOKUP_NEXT_DROP:
264 t = "drop";
265 break;
266 case IP_LOOKUP_NEXT_PUNT:
267 t = "punt";
268 break;
269 case IP_LOOKUP_NEXT_ARP:
270 t = "arp";
271 break;
272 case IP_LOOKUP_NEXT_MIDCHAIN:
273 t = "midchain";
274 break;
275 case IP_LOOKUP_NEXT_GLEAN:
276 t = "glean";
277 break;
Neale Ranns32e1c012016-11-22 17:07:28 +0000278 case IP_LOOKUP_NEXT_MCAST:
279 t = "mcast";
280 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 case IP_LOOKUP_NEXT_REWRITE:
282 break;
283 }
284
285 if (t)
286 vec_add (s, t, strlen (t));
287
288 return s;
289}
290
Dave Barachd7cb1b52016-12-09 09:52:16 -0500291u8 *
292format_ip_adjacency_packet_data (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500294 vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 u32 adj_index = va_arg (*args, u32);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500296 u8 *packet_data = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 u32 n_packet_data_bytes = va_arg (*args, u32);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500298 ip_adjacency_t *adj = adj_get (adj_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299
300 switch (adj->lookup_next_index)
301 {
302 case IP_LOOKUP_NEXT_REWRITE:
303 s = format (s, "%U",
304 format_vnet_rewrite_header,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500305 vnm->vlib_main, &adj->rewrite_header, packet_data,
306 n_packet_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307 break;
308
309 default:
310 break;
311 }
312
313 return s;
314}
315
Dave Barachd7cb1b52016-12-09 09:52:16 -0500316static uword
317unformat_dpo (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100319 dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
320 fib_protocol_t fp = va_arg (*args, int);
321 dpo_proto_t proto;
322
Dave Barachd7cb1b52016-12-09 09:52:16 -0500323 proto = fib_proto_to_dpo (fp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324
325 if (unformat (input, "drop"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500326 dpo_copy (dpo, drop_dpo_get (proto));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327 else if (unformat (input, "punt"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500328 dpo_copy (dpo, punt_dpo_get (proto));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329 else if (unformat (input, "local"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500330 receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100331 else if (unformat (input, "null-send-unreach"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500332 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100333 else if (unformat (input, "null-send-prohibit"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500334 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
Neale Ranns948e00f2016-10-20 13:39:34 +0100335 else if (unformat (input, "null"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500336 ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337 else if (unformat (input, "classify"))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100338 {
339 u32 classify_table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100341 if (!unformat (input, "%d", &classify_table_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500342 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100343 clib_warning ("classify adj must specify table index");
Dave Barachd7cb1b52016-12-09 09:52:16 -0500344 return 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100345 }
346
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 dpo_set (dpo, DPO_CLASSIFY, proto,
348 classify_dpo_create (proto, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100349 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 else
351 return 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100352
Ed Warnickecb9cada2015-12-08 15:45:58 -0700353 return 1;
354}
355
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100356const ip46_address_t zero_addr = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500357 .as_u64 = {
358 0, 0},
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100359};
360
361u32
Dave Barachd7cb1b52016-12-09 09:52:16 -0500362fib_table_id_find_fib_index (fib_protocol_t proto, u32 table_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500364 ip4_main_t *im4 = &ip4_main;
365 ip6_main_t *im6 = &ip6_main;
366 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367
Dave Barachd7cb1b52016-12-09 09:52:16 -0500368 switch (proto)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370 case FIB_PROTOCOL_IP4:
Dave Barachd7cb1b52016-12-09 09:52:16 -0500371 p = hash_get (im4->fib_index_by_table_id, table_id);
372 break;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100373 case FIB_PROTOCOL_IP6:
Dave Barachd7cb1b52016-12-09 09:52:16 -0500374 p = hash_get (im6->fib_index_by_table_id, table_id);
375 break;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100376 default:
Dave Barachd7cb1b52016-12-09 09:52:16 -0500377 p = NULL;
378 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700379 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500380 if (NULL != p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500382 return (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500384 return (~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385}
386
387clib_error_t *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100388vnet_ip_route_cmd (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500389 unformat_input_t * main_input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500391 unformat_input_t _line_input, *line_input = &_line_input;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100392 fib_route_path_t *rpaths = NULL, rpath;
Neale Ranns948e00f2016-10-20 13:39:34 +0100393 dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100394 fib_prefix_t *prefixs = NULL, pfx;
Neale Rannsad422ed2016-11-02 14:20:04 +0000395 mpls_label_t out_label, via_label;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 clib_error_t *error = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100397 u32 table_id, is_del;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500398 vnet_main_t *vnm;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100399 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400 f64 count;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100401 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
Dave Barachd7cb1b52016-12-09 09:52:16 -0500403 vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404 is_del = 0;
405 table_id = 0;
406 count = 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500407 memset (&pfx, 0, sizeof (pfx));
Neale Rannsad422ed2016-11-02 14:20:04 +0000408 out_label = via_label = MPLS_LABEL_INVALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
410 /* Get a line of input. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 if (!unformat_user (main_input, unformat_line_input, line_input))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 return 0;
413
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
415 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416 memset (&rpath, 0, sizeof (rpath));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418 if (unformat (line_input, "table %d", &table_id))
419 ;
420 else if (unformat (line_input, "del"))
421 is_del = 1;
422 else if (unformat (line_input, "add"))
423 is_del = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100424 else if (unformat (line_input, "resolve-via-host"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500425 {
426 if (vec_len (rpaths) == 0)
427 {
428 error = clib_error_return (0, "Paths then flags");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500430 }
431 rpaths[vec_len (rpaths) - 1].frp_flags |=
432 FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
433 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434 else if (unformat (line_input, "resolve-via-attached"))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500435 {
436 if (vec_len (rpaths) == 0)
437 {
438 error = clib_error_return (0, "Paths then flags");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100439 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500440 }
441 rpaths[vec_len (rpaths) - 1].frp_flags |=
442 FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
443 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444 else if (unformat (line_input, "out-label %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500445 unformat_mpls_unicast_label, &out_label))
446 {
447 if (vec_len (rpaths) == 0)
448 {
449 error = clib_error_return (0, "Paths then labels");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500451 }
452 vec_add1 (rpaths[vec_len (rpaths) - 1].frp_label_stack, out_label);
453 }
Neale Rannsad422ed2016-11-02 14:20:04 +0000454 else if (unformat (line_input, "via-label %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455 unformat_mpls_unicast_label, &rpath.frp_local_label))
456 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000457 rpath.frp_weight = 1;
458 rpath.frp_proto = FIB_PROTOCOL_MPLS;
459 rpath.frp_sw_if_index = ~0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 vec_add1 (rpaths, rpath);
461 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 else if (unformat (line_input, "count %f", &count))
463 ;
464
465 else if (unformat (line_input, "%U/%d",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500466 unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
467 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100468 pfx.fp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500469 vec_add1 (prefixs, pfx);
470 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 else if (unformat (line_input, "%U/%d",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
473 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100474 pfx.fp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500475 vec_add1 (prefixs, pfx);
476 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100477 else if (unformat (line_input, "via %U %U weight %u",
478 unformat_ip4_address,
479 &rpath.frp_addr.ip4,
480 unformat_vnet_sw_interface, vnm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500481 &rpath.frp_sw_if_index, &rpath.frp_weight))
482 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100483 rpath.frp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500484 vec_add1 (rpaths, rpath);
485 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486
487 else if (unformat (line_input, "via %U %U weight %u",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100488 unformat_ip6_address,
489 &rpath.frp_addr.ip6,
490 unformat_vnet_sw_interface, vnm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500491 &rpath.frp_sw_if_index, &rpath.frp_weight))
492 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100493 rpath.frp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500494 vec_add1 (rpaths, rpath);
495 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496
497 else if (unformat (line_input, "via %U %U",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100498 unformat_ip4_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500499 &rpath.frp_addr.ip4,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100500 unformat_vnet_sw_interface, vnm,
501 &rpath.frp_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100503 rpath.frp_weight = 1;
504 rpath.frp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 vec_add1 (rpaths, rpath);
506 }
507
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 else if (unformat (line_input, "via %U %U",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100509 unformat_ip6_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500510 &rpath.frp_addr.ip6,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100511 unformat_vnet_sw_interface, vnm,
512 &rpath.frp_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500513 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100514 rpath.frp_weight = 1;
515 rpath.frp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500516 vec_add1 (rpaths, rpath);
517 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518 else if (unformat (line_input, "via %U next-hop-table %d",
519 unformat_ip4_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 &rpath.frp_addr.ip4, &rpath.frp_fib_index))
521 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100522 rpath.frp_weight = 1;
523 rpath.frp_sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100524 rpath.frp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525 vec_add1 (rpaths, rpath);
526 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527 else if (unformat (line_input, "via %U next-hop-table %d",
528 unformat_ip6_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529 &rpath.frp_addr.ip6, &rpath.frp_fib_index))
530 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100531 rpath.frp_weight = 1;
532 rpath.frp_sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100533 rpath.frp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 vec_add1 (rpaths, rpath);
535 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 else if (unformat (line_input, "via %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500537 unformat_ip4_address, &rpath.frp_addr.ip4))
538 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100539 /*
540 * the recursive next-hops are by default in the same table
541 * as the prefix
542 */
543 rpath.frp_fib_index = table_id;
544 rpath.frp_weight = 1;
545 rpath.frp_sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100546 rpath.frp_proto = FIB_PROTOCOL_IP4;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 vec_add1 (rpaths, rpath);
548 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 else if (unformat (line_input, "via %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 unformat_ip6_address, &rpath.frp_addr.ip6))
551 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100552 rpath.frp_fib_index = table_id;
553 rpath.frp_weight = 1;
554 rpath.frp_sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100555 rpath.frp_proto = FIB_PROTOCOL_IP6;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500556 vec_add1 (rpaths, rpath);
557 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100558 else if (unformat (line_input,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500559 "lookup in table %d", &rpath.frp_fib_index))
560 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100561 rpath.frp_proto = pfx.fp_proto;
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100562 rpath.frp_sw_if_index = ~0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500563 vec_add1 (rpaths, rpath);
564 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100565 else if (vec_len (prefixs) > 0 &&
566 unformat (line_input, "via %U",
Neale Ranns8c2f05c2016-12-12 19:35:58 +0000567 unformat_vnet_sw_interface, vnm,
568 &rpath.frp_sw_if_index))
569 {
570 rpath.frp_weight = 1;
571 rpath.frp_proto = prefixs[0].fp_proto;
572 vec_add1 (rpaths, rpath);
573 }
574 else if (vec_len (prefixs) > 0 &&
575 unformat (line_input, "via %U",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100576 unformat_dpo, &dpo, prefixs[0].fp_proto))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500577 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100578 vec_add1 (dpos, dpo);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500579 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500581 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 error = unformat_parse_error (line_input);
583 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500584 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500586
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100587 if (vec_len (prefixs) == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 {
589 error =
590 clib_error_return (0, "expected ip4/ip6 destination address/length.");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700591 goto done;
592 }
593
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100594 if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100596 error = clib_error_return (0, "expected paths.");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597 goto done;
598 }
599
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100600 if (~0 == table_id)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500601 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100602 /*
603 * if no table_id is passed we will manipulate the default
604 */
605 fib_index = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500606 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100607 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500608 {
609 fib_index = fib_table_id_find_fib_index (prefixs[0].fp_proto, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100611 if (~0 == fib_index)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500612 {
613 error = clib_error_return (0, "Nonexistent table id %d", table_id);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100614 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500615 }
616 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100618 for (i = 0; i < vec_len (prefixs); i++)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500619 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100620 if (is_del && 0 == vec_len (rpaths))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500621 {
622 fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
623 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624 else if (!is_del && 1 == vec_len (dpos))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500625 {
626 fib_table_entry_special_dpo_add (fib_index,
627 &prefixs[i],
628 FIB_SOURCE_CLI,
629 FIB_ENTRY_FLAG_EXCLUSIVE,
630 &dpos[0]);
631 dpo_reset (&dpos[0]);
632 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100633 else if (vec_len (dpos) > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 {
635 error =
636 clib_error_return (0,
637 "Load-balancing over multiple special adjacencies is unsupported");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100640 else if (0 < vec_len (rpaths))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500641 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642 u32 k, j, n, incr;
643 ip46_address_t dst = prefixs[i].fp_addr;
644 f64 t[2];
645 n = count;
646 t[0] = vlib_time_now (vm);
647 incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
648 prefixs[i].fp_len);
649
650 for (k = 0; k < n; k++)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100652 for (j = 0; j < vec_len (rpaths); j++)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500653 {
Neale Ranns3ee44042016-10-03 13:05:48 +0100654 u32 fi;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100655 /*
656 * the CLI parsing stored table Ids, swap to FIB indicies
657 */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500658 fi = fib_table_id_find_fib_index (prefixs[i].fp_proto,
659 rpaths[i].frp_fib_index);
Neale Ranns3ee44042016-10-03 13:05:48 +0100660
661 if (~0 == fi)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500662 {
663 error =
664 clib_error_return (0, "Via table %d does not exist",
665 rpaths[i].frp_fib_index);
Neale Ranns3ee44042016-10-03 13:05:48 +0100666 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500667 }
Neale Ranns3ee44042016-10-03 13:05:48 +0100668 rpaths[i].frp_fib_index = fi;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669
670 fib_prefix_t rpfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500671 .fp_len = prefixs[i].fp_len,
672 .fp_proto = prefixs[i].fp_proto,
673 .fp_addr = dst,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100674 };
675
Dave Barachd7cb1b52016-12-09 09:52:16 -0500676 if (is_del)
677 fib_table_entry_path_remove2 (fib_index,
678 &rpfx,
679 FIB_SOURCE_CLI, &rpaths[j]);
680 else
681 fib_table_entry_path_add2 (fib_index,
682 &rpfx,
683 FIB_SOURCE_CLI,
684 FIB_ENTRY_FLAG_NONE,
685 &rpaths[j]);
686 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100687
688 if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500689 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690 dst.ip4.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500691 clib_host_to_net_u32 (incr +
692 clib_net_to_host_u32 (dst.
693 ip4.as_u32));
694 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100695 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500696 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 int bucket = (incr < 64 ? 0 : 1);
698 dst.ip6.as_u64[bucket] =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500699 clib_host_to_net_u64 (incr +
700 clib_net_to_host_u64 (dst.ip6.as_u64
701 [bucket]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702
Dave Barachd7cb1b52016-12-09 09:52:16 -0500703 }
704 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705 t[1] = vlib_time_now (vm);
706 if (count > 1)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500707 vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
708 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100709 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500710 {
711 error = clib_error_return (0, "Don't understand what you want...");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100712 goto done;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713 }
714 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100715
716
Dave Barachd7cb1b52016-12-09 09:52:16 -0500717done:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718 vec_free (dpos);
719 vec_free (prefixs);
720 vec_free (rpaths);
Billy McFalla9a20e72017-02-15 11:39:12 -0500721 unformat_free (line_input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 return error;
723}
724
Dave Barachd7cb1b52016-12-09 09:52:16 -0500725/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
727 .path = "ip",
728 .short_help = "Internet protocol (IP) commands",
729};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500730/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732/* *INDENT-OFF* */
Billy McFall0683c9c2016-10-13 08:27:31 -0400733VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
734 .path = "ip6",
735 .short_help = "Internet protocol version 6 (IPv6) commands",
736};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737/* *INDENT-ON* */
Billy McFall0683c9c2016-10-13 08:27:31 -0400738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
741 .path = "show ip",
742 .short_help = "Internet protocol (IP) show commands",
743};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
Dave Barachd7cb1b52016-12-09 09:52:16 -0500746/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
748 .path = "show ip6",
Billy McFall0683c9c2016-10-13 08:27:31 -0400749 .short_help = "Internet protocol version 6 (IPv6) show commands",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500751/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700753/*?
Billy McFall0683c9c2016-10-13 08:27:31 -0400754 * This command is used to add or delete IPv4 or IPv6 routes. All
755 * IP Addresses ('<em><dst-ip-addr>/<width></em>',
756 * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
757 * can be IPv4 or IPv6, but all must be of the same form in a single
758 * command. To display the current set of routes, use the commands
759 * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
760 *
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700761 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -0400762 * Example of how to add a straight forward static route:
763 * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
764 * Example of how to delete a straight forward static route:
765 * @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 -0700766 * Mainly for route add/del performance testing, one can add or delete
767 * multiple routes by adding 'count N' to the previous item:
Billy McFall0683c9c2016-10-13 08:27:31 -0400768 * @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 -0700769 * Add multiple routes for the same destination to create equal-cost multipath:
Billy McFall0683c9c2016-10-13 08:27:31 -0400770 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
771 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
772 * For unequal-cost multipath, specify the desired weights. This
773 * combination of weights results in 3/4 of the traffic following the
774 * second path, 1/4 following the first path:
775 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
776 * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
777 * To add a route to a particular FIB table (VRF), use:
778 * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -0700779 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -0400780/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781VLIB_CLI_COMMAND (ip_route_command, static) = {
782 .path = "ip route",
Billy McFall0683c9c2016-10-13 08:27:31 -0400783 .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table <table-id>] [via <next-hop-ip-addr> [<interface>] [weight <weight>]] | [via arp <interface> <adj-hop-ip-addr>] | [via drop|punt|local<id>|arp|classify <classify-idx>] [lookup in table <out-table-id>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784 .function = vnet_ip_route_cmd,
Dave Barachb2ef4dd2016-03-23 08:56:01 -0400785 .is_mp_safe = 1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786};
Billy McFall0683c9c2016-10-13 08:27:31 -0400787/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700788
Neale Ranns32e1c012016-11-22 17:07:28 +0000789clib_error_t *
790vnet_ip_mroute_cmd (vlib_main_t * vm,
791 unformat_input_t * main_input, vlib_cli_command_t * cmd)
792{
793 unformat_input_t _line_input, *line_input = &_line_input;
794 clib_error_t *error = NULL;
795 fib_route_path_t rpath;
796 u32 table_id, is_del;
797 vnet_main_t *vnm;
798 mfib_prefix_t pfx;
799 u32 fib_index;
800 mfib_itf_flags_t iflags = 0;
801 mfib_entry_flags_t eflags = 0;
Neale Ranns52456fc2017-02-15 00:38:27 -0800802 u32 gcount, scount, ss, gg, incr;
803 f64 timet[2];
Neale Ranns32e1c012016-11-22 17:07:28 +0000804
Neale Ranns52456fc2017-02-15 00:38:27 -0800805 gcount = scount = 1;
Neale Ranns32e1c012016-11-22 17:07:28 +0000806 vnm = vnet_get_main ();
807 is_del = 0;
808 table_id = 0;
809 memset (&pfx, 0, sizeof (pfx));
810 memset (&rpath, 0, sizeof (rpath));
811 rpath.frp_sw_if_index = ~0;
812
813 /* Get a line of input. */
814 if (!unformat_user (main_input, unformat_line_input, line_input))
815 return 0;
816
817 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
818 {
819 if (unformat (line_input, "table %d", &table_id))
820 ;
821 else if (unformat (line_input, "del"))
822 is_del = 1;
823 else if (unformat (line_input, "add"))
824 is_del = 0;
Neale Ranns52456fc2017-02-15 00:38:27 -0800825 else if (unformat (line_input, "scount %d", &scount))
826 ;
827 else if (unformat (line_input, "gcount %d", &gcount))
828 ;
Neale Ranns32e1c012016-11-22 17:07:28 +0000829 else if (unformat (line_input, "%U %U",
830 unformat_ip4_address,
831 &pfx.fp_src_addr.ip4,
832 unformat_ip4_address, &pfx.fp_grp_addr.ip4))
833 {
834 pfx.fp_proto = FIB_PROTOCOL_IP4;
835 pfx.fp_len = 64;
836 }
837 else if (unformat (line_input, "%U %U",
838 unformat_ip6_address,
839 &pfx.fp_src_addr.ip6,
840 unformat_ip6_address, &pfx.fp_grp_addr.ip6))
841 {
842 pfx.fp_proto = FIB_PROTOCOL_IP6;
843 pfx.fp_len = 256;
844 }
845 else if (unformat (line_input, "%U/%d",
846 unformat_ip4_address,
847 &pfx.fp_grp_addr.ip4, &pfx.fp_len))
848 {
849 pfx.fp_proto = FIB_PROTOCOL_IP4;
850 }
851 else if (unformat (line_input, "%U/%d",
852 unformat_ip6_address,
853 &pfx.fp_grp_addr.ip6, &pfx.fp_len))
854 {
855 pfx.fp_proto = FIB_PROTOCOL_IP6;
856 }
857 else if (unformat (line_input, "%U",
858 unformat_ip4_address, &pfx.fp_grp_addr.ip4))
859 {
860 memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
861 pfx.fp_proto = FIB_PROTOCOL_IP4;
862 pfx.fp_len = 32;
863 }
864 else if (unformat (line_input, "%U",
865 unformat_ip6_address, &pfx.fp_grp_addr.ip6))
866 {
867 memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
868 pfx.fp_proto = FIB_PROTOCOL_IP6;
869 pfx.fp_len = 128;
870 }
871 else if (unformat (line_input, "via %U",
872 unformat_vnet_sw_interface, vnm,
873 &rpath.frp_sw_if_index))
874 {
875 rpath.frp_weight = 1;
876 rpath.frp_proto = FIB_PROTOCOL_IP4;
877 }
878 else if (unformat (line_input, "%U", unformat_mfib_itf_flags, &iflags))
879 ;
880 else if (unformat (line_input, "%U",
881 unformat_mfib_entry_flags, &eflags))
882 ;
883 else
884 {
885 error = unformat_parse_error (line_input);
886 goto done;
887 }
888 }
889
Neale Ranns32e1c012016-11-22 17:07:28 +0000890 if (~0 == table_id)
891 {
892 /*
893 * if no table_id is passed we will manipulate the default
894 */
895 fib_index = 0;
896 }
897 else
898 {
899 fib_index = mfib_table_find (pfx.fp_proto, table_id);
900
901 if (~0 == fib_index)
902 {
903 error = clib_error_return (0, "Nonexistent table id %d", table_id);
904 goto done;
905 }
906 }
907
Neale Ranns52456fc2017-02-15 00:38:27 -0800908 timet[0] = vlib_time_now (vm);
909
910 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
Neale Ranns32e1c012016-11-22 17:07:28 +0000911 {
Neale Ranns52456fc2017-02-15 00:38:27 -0800912 incr = 1 << (32 - (pfx.fp_len % 32));
Neale Ranns32e1c012016-11-22 17:07:28 +0000913 }
914 else
915 {
Neale Ranns52456fc2017-02-15 00:38:27 -0800916 incr = 1 << (128 - (pfx.fp_len % 128));
Neale Ranns32e1c012016-11-22 17:07:28 +0000917 }
918
Neale Ranns52456fc2017-02-15 00:38:27 -0800919 for (ss = 0; ss < scount; ss++)
920 {
921 for (gg = 0; gg < gcount; gg++)
922 {
923 if (is_del && 0 == rpath.frp_weight)
924 {
925 /* no path provided => route delete */
926 mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
927 }
928 else if (eflags)
929 {
930 mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
931 eflags);
932 }
933 else
934 {
935 if (is_del)
936 mfib_table_entry_path_remove (fib_index,
937 &pfx, MFIB_SOURCE_CLI, &rpath);
938 else
939 mfib_table_entry_path_update (fib_index,
940 &pfx, MFIB_SOURCE_CLI, &rpath,
941 iflags);
942 }
943
944 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
945 {
946 pfx.fp_grp_addr.ip4.as_u32 =
947 clib_host_to_net_u32 (incr +
948 clib_net_to_host_u32 (pfx.
949 fp_grp_addr.ip4.
950 as_u32));
951 }
952 else
953 {
954 int bucket = (incr < 64 ? 0 : 1);
955 pfx.fp_grp_addr.ip6.as_u64[bucket] =
956 clib_host_to_net_u64 (incr +
957 clib_net_to_host_u64 (pfx.
958 fp_grp_addr.ip6.as_u64
959 [bucket]));
960
961 }
962 }
963 if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
964 {
965 pfx.fp_src_addr.ip4.as_u32 =
966 clib_host_to_net_u32 (1 +
967 clib_net_to_host_u32 (pfx.fp_src_addr.
968 ip4.as_u32));
969 }
970 else
971 {
972 pfx.fp_src_addr.ip6.as_u64[1] =
973 clib_host_to_net_u64 (1 +
974 clib_net_to_host_u64 (pfx.fp_src_addr.
975 ip6.as_u64[1]));
976 }
977 }
978
979 timet[1] = vlib_time_now (vm);
980
981 if (scount > 1 || gcount > 1)
982 vlib_cli_output (vm, "%.6e routes/sec",
983 (scount * gcount) / (timet[1] - timet[0]));
984
Neale Ranns32e1c012016-11-22 17:07:28 +0000985done:
Billy McFalla9a20e72017-02-15 11:39:12 -0500986 unformat_free (line_input);
987
Neale Ranns32e1c012016-11-22 17:07:28 +0000988 return error;
989}
990
991/*?
992 * This command is used to add or delete IPv4 or IPv6 multicastroutes. All
993 * IP Addresses ('<em><dst-ip-addr>/<width></em>',
994 * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
995 * can be IPv4 or IPv6, but all must be of the same form in a single
996 * command. To display the current set of routes, use the commands
997 * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
998 * The full set of support flags for interfaces and route is shown via;
999 * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
1000 * respectively.
1001 * @cliexpar
1002 * Example of how to add a forwarding interface to a route (and create the
1003 * route if it does not exist)
1004 * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
1005 * Example of how to add an accepting interface to a route (and create the
1006 * route if it does not exist)
1007 * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
1008 * Example of changing the route's flags to send signals via the API
1009 * @cliexcmd{ip mroute add 232.1.1.1 Signal}
1010
1011 ?*/
1012/* *INDENT-OFF* */
1013VLIB_CLI_COMMAND (ip_mroute_command, static) =
1014{
1015 .path = "ip mroute",
1016 .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [via <next-hop-ip-addr> [<interface>],",
1017 .function = vnet_ip_mroute_cmd,
1018 .is_mp_safe = 1,
1019};
1020/* *INDENT-ON* */
1021
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001022/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 * The next two routines address a longstanding script hemorrhoid.
1024 * Probing a v4 or v6 neighbor needs to appear to be synchronous,
1025 * or dependent route-adds will simply fail.
1026 */
1027static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028ip6_probe_neighbor_wait (vlib_main_t * vm, ip6_address_t * a, u32 sw_if_index,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001029 int retry_count)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031 vnet_main_t *vnm = vnet_get_main ();
1032 clib_error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 int i;
1034 int resolved = 0;
1035 uword event_type;
1036 uword *event_data = 0;
1037
Dave Barachd7cb1b52016-12-09 09:52:16 -05001038 ASSERT (vlib_in_process_context (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039
1040 if (retry_count > 0)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001041 vnet_register_ip6_neighbor_resolution_event
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042 (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001043 1 /* event */ , 0 /* data */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044
1045 for (i = 0; i < retry_count; i++)
1046 {
1047 /* The interface may be down, etc. */
1048 e = ip6_probe_neighbor (vm, a, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001049
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 if (e)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001051 return e;
1052
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053 vlib_process_wait_for_event_or_clock (vm, 1.0);
1054 event_type = vlib_process_get_events (vm, &event_data);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001055 switch (event_type)
1056 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001057 case 1: /* resolved... */
1058 vlib_cli_output (vm, "Resolved %U", format_ip6_address, a);
1059 resolved = 1;
1060 goto done;
1061
1062 case ~0: /* timeout */
1063 break;
1064
1065 default:
1066 clib_warning ("unknown event_type %d", event_type);
1067 }
Dave Barachb2ef4dd2016-03-23 08:56:01 -04001068 vec_reset_length (event_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001070
1071done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
1073 if (!resolved)
1074 return clib_error_return (0, "Resolution failed for %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001075 format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 return 0;
1077}
1078
1079static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001080ip4_probe_neighbor_wait (vlib_main_t * vm, ip4_address_t * a, u32 sw_if_index,
1081 int retry_count)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001083 vnet_main_t *vnm = vnet_get_main ();
1084 clib_error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 int i;
1086 int resolved = 0;
1087 uword event_type;
1088 uword *event_data = 0;
1089
Dave Barachd7cb1b52016-12-09 09:52:16 -05001090 ASSERT (vlib_in_process_context (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091
1092 if (retry_count > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001093 vnet_register_ip4_arp_resolution_event
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094 (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001095 1 /* event */ , 0 /* data */ );
1096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 for (i = 0; i < retry_count; i++)
1098 {
1099 /* The interface may be down, etc. */
1100 e = ip4_probe_neighbor (vm, a, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001101
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102 if (e)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001103 return e;
1104
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105 vlib_process_wait_for_event_or_clock (vm, 1.0);
1106 event_type = vlib_process_get_events (vm, &event_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001107 switch (event_type)
1108 {
1109 case 1: /* resolved... */
1110 vlib_cli_output (vm, "Resolved %U", format_ip4_address, a);
1111 resolved = 1;
1112 goto done;
1113
1114 case ~0: /* timeout */
1115 break;
1116
1117 default:
1118 clib_warning ("unknown event_type %d", event_type);
1119 }
Dave Barachb2ef4dd2016-03-23 08:56:01 -04001120 vec_reset_length (event_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001122
1123done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124
1125 vec_reset_length (event_data);
1126
1127 if (!resolved)
1128 return clib_error_return (0, "Resolution failed for %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001129 format_ip4_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130 return 0;
1131}
1132
1133static clib_error_t *
1134probe_neighbor_address (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001137 vnet_main_t *vnm = vnet_get_main ();
1138 unformat_input_t _line_input, *line_input = &_line_input;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139 ip4_address_t a4;
1140 ip6_address_t a6;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001141 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 u32 sw_if_index = ~0;
1143 int retry_count = 3;
1144 int is_ip4 = 1;
1145 int address_set = 0;
1146
1147 /* Get a line of input. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 if (!unformat_user (input, unformat_line_input, line_input))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 return 0;
1150
Dave Barachd7cb1b52016-12-09 09:52:16 -05001151 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001153 if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
1154 &sw_if_index))
1155 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 else if (unformat (line_input, "retry %d", &retry_count))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158
1159 else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001160 address_set++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161 else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001162 {
1163 address_set++;
1164 is_ip4 = 0;
1165 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 else
Billy McFalla9a20e72017-02-15 11:39:12 -05001167 {
1168 error = clib_error_return (0, "unknown input '%U'",
1169 format_unformat_error, line_input);
1170 goto done;
1171 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172 }
1173
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174 if (sw_if_index == ~0)
Billy McFalla9a20e72017-02-15 11:39:12 -05001175 {
1176 error = clib_error_return (0, "Interface required, not set.");
1177 goto done;
1178 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 if (address_set == 0)
Billy McFalla9a20e72017-02-15 11:39:12 -05001180 {
1181 error = clib_error_return (0, "ip address required, not set.");
1182 goto done;
1183 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184 if (address_set > 1)
Billy McFalla9a20e72017-02-15 11:39:12 -05001185 {
1186 error = clib_error_return (0, "Multiple ip addresses not supported.");
1187 goto done;
1188 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001189
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 if (is_ip4)
1191 error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001192 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
1194
Billy McFalla9a20e72017-02-15 11:39:12 -05001195done:
1196 unformat_free (line_input);
1197
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 return error;
1199}
1200
Billy McFall0683c9c2016-10-13 08:27:31 -04001201/*?
1202 * The '<em>ip probe-neighbor</em>' command ARPs for IPv4 addresses or
1203 * attempts IPv6 neighbor discovery depending on the supplied IP address
1204 * format.
1205 *
1206 * @note This command will not immediately affect the indicated FIB; it
1207 * is not suitable for use in establishing a FIB entry prior to adding
1208 * recursive FIB entries. As in: don't use it in a script to probe a
1209 * gateway prior to adding a default route. It won't work. Instead,
1210 * configure a static ARP cache entry [see '<em>set ip arp</em>'], or
1211 * a static IPv6 neighbor [see '<em>set ip6 neighbor</em>'].
1212 *
1213 * @cliexpar
1214 * Example of probe for an IPv4 address:
1215 * @cliexcmd{ip probe-neighbor GigabitEthernet2/0/0 172.16.1.2}
1216?*/
1217/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
1219 .path = "ip probe-neighbor",
1220 .function = probe_neighbor_address,
Billy McFall0683c9c2016-10-13 08:27:31 -04001221 .short_help = "ip probe-neighbor <interface> <ip4-addr> | <ip6-addr> [retry nn]",
Dave Barachb2ef4dd2016-03-23 08:56:01 -04001222 .is_mp_safe = 1,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223};
Billy McFall0683c9c2016-10-13 08:27:31 -04001224/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225
1226/*
1227 * fd.io coding-style-patch-verification: ON
1228 *
1229 * Local Variables:
1230 * eval: (c-set-style "gnu")
1231 * End:
1232 */