ARP resilience in the absence of IP config on input and output interfaces
[vpp.git] / src / vnet / ip / lookup.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * ip/ip_lookup.c: ip4/6 adjacency and lookup table 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
40 #include <vnet/ip/ip.h>
41 #include <vnet/adj/adj.h>
42 #include <vnet/fib/fib_table.h>
43 #include <vnet/fib/ip4_fib.h>
44 #include <vnet/fib/ip6_fib.h>
45 #include <vnet/mpls/mpls.h>
46 #include <vnet/mfib/mfib_table.h>
47 #include <vnet/dpo/drop_dpo.h>
48 #include <vnet/dpo/classify_dpo.h>
49 #include <vnet/dpo/punt_dpo.h>
50 #include <vnet/dpo/receive_dpo.h>
51 #include <vnet/dpo/ip_null_dpo.h>
52 #include <vnet/ip/ip6_neighbor.h>
53
54 /**
55  * @file
56  * @brief IPv4 and IPv6 adjacency and lookup table managment.
57  *
58  */
59
60 clib_error_t *
61 ip_interface_address_add_del (ip_lookup_main_t * lm,
62                               u32 sw_if_index,
63                               void *addr_fib,
64                               u32 address_length,
65                               u32 is_del, u32 * result_if_address_index)
66 {
67   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);
70
71   vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
72                            sw_if_index, ~0);
73   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;
79       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);
84     }
85
86   if (is_del)
87     {
88       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         }
97
98       if (a->prev_this_sw_interface != ~0)
99         {
100           prev =
101             pool_elt_at_index (lm->if_address_pool,
102                                a->prev_this_sw_interface);
103           prev->next_this_sw_interface = a->next_this_sw_interface;
104         }
105       if (a->next_this_sw_interface != ~0)
106         {
107           next =
108             pool_elt_at_index (lm->if_address_pool,
109                                a->next_this_sw_interface);
110           next->prev_this_sw_interface = a->prev_this_sw_interface;
111
112           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;
115         }
116
117       if ((a->next_this_sw_interface == ~0)
118           && (a->prev_this_sw_interface == ~0))
119         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
129   else if (!a)
130     {
131       u32 pi;                   /* previous index */
132       u32 ai;
133       u32 hi;                   /* head index */
134
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;
141       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;
147
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)
156         prev->next_this_sw_interface = ai;
157
158       lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
159         (hi != ~0) ? hi : ai;
160       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     }
168
169
170   return /* no error */ 0;
171 }
172
173 static clib_error_t *
174 ip_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
186 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
187
188 void
189 ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
190 {
191   /* ensure that adjacency is cacheline aligned and sized */
192   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");
197
198   /* Preallocate three "special" adjacencies */
199   lm->adjacency_heap = adj_pool;
200
201   if (!lm->fib_result_n_bytes)
202     lm->fib_result_n_bytes = sizeof (uword);
203
204   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       }
227
228     lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
229     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;
236   }
237 }
238
239 u8 *
240 format_ip_flow_hash_config (u8 * s, va_list * args)
241 {
242   flow_hash_config_t flow_hash_config = va_arg (*args, u32);
243
244 #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
251 u8 *
252 format_ip_lookup_next (u8 * s, va_list * args)
253 {
254   ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
255   char *t = 0;
256
257   switch (n)
258     {
259     default:
260       s = format (s, "unknown %d", n);
261       return s;
262
263     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;
278     case IP_LOOKUP_NEXT_MCAST:
279       t = "mcast";
280       break;
281     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
291 u8 *
292 format_ip_adjacency_packet_data (u8 * s, va_list * args)
293 {
294   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
295   u32 adj_index = va_arg (*args, u32);
296   u8 *packet_data = va_arg (*args, u8 *);
297   u32 n_packet_data_bytes = va_arg (*args, u32);
298   ip_adjacency_t *adj = adj_get (adj_index);
299
300   switch (adj->lookup_next_index)
301     {
302     case IP_LOOKUP_NEXT_REWRITE:
303       s = format (s, "%U",
304                   format_vnet_rewrite_header,
305                   vnm->vlib_main, &adj->rewrite_header, packet_data,
306                   n_packet_data_bytes);
307       break;
308
309     default:
310       break;
311     }
312
313   return s;
314 }
315
316 static uword
317 unformat_dpo (unformat_input_t * input, va_list * args)
318 {
319   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
323   proto = fib_proto_to_dpo (fp);
324
325   if (unformat (input, "drop"))
326     dpo_copy (dpo, drop_dpo_get (proto));
327   else if (unformat (input, "punt"))
328     dpo_copy (dpo, punt_dpo_get (proto));
329   else if (unformat (input, "local"))
330     receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
331   else if (unformat (input, "null-send-unreach"))
332     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
333   else if (unformat (input, "null-send-prohibit"))
334     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
335   else if (unformat (input, "null"))
336     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
337   else if (unformat (input, "classify"))
338     {
339       u32 classify_table_index;
340
341       if (!unformat (input, "%d", &classify_table_index))
342         {
343           clib_warning ("classify adj must specify table index");
344           return 0;
345         }
346
347       dpo_set (dpo, DPO_CLASSIFY, proto,
348                classify_dpo_create (proto, classify_table_index));
349     }
350   else
351     return 0;
352
353   return 1;
354 }
355
356 const ip46_address_t zero_addr = {
357   .as_u64 = {
358              0, 0},
359 };
360
361 u32
362 fib_table_id_find_fib_index (fib_protocol_t proto, u32 table_id)
363 {
364   ip4_main_t *im4 = &ip4_main;
365   ip6_main_t *im6 = &ip6_main;
366   uword *p;
367
368   switch (proto)
369     {
370     case FIB_PROTOCOL_IP4:
371       p = hash_get (im4->fib_index_by_table_id, table_id);
372       break;
373     case FIB_PROTOCOL_IP6:
374       p = hash_get (im6->fib_index_by_table_id, table_id);
375       break;
376     default:
377       p = NULL;
378       break;
379     }
380   if (NULL != p)
381     {
382       return (p[0]);
383     }
384   return (~0);
385 }
386
387 clib_error_t *
388 vnet_ip_route_cmd (vlib_main_t * vm,
389                    unformat_input_t * main_input, vlib_cli_command_t * cmd)
390 {
391   unformat_input_t _line_input, *line_input = &_line_input;
392   fib_route_path_t *rpaths = NULL, rpath;
393   dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
394   fib_prefix_t *prefixs = NULL, pfx;
395   mpls_label_t out_label, via_label;
396   clib_error_t *error = NULL;
397   u32 table_id, is_del;
398   vnet_main_t *vnm;
399   u32 fib_index;
400   f64 count;
401   int i;
402
403   vnm = vnet_get_main ();
404   is_del = 0;
405   table_id = 0;
406   count = 1;
407   memset (&pfx, 0, sizeof (pfx));
408   out_label = via_label = MPLS_LABEL_INVALID;
409
410   /* Get a line of input. */
411   if (!unformat_user (main_input, unformat_line_input, line_input))
412     return 0;
413
414   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
415     {
416       memset (&rpath, 0, sizeof (rpath));
417
418       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;
424       else if (unformat (line_input, "resolve-via-host"))
425         {
426           if (vec_len (rpaths) == 0)
427             {
428               error = clib_error_return (0, "Paths then flags");
429               goto done;
430             }
431           rpaths[vec_len (rpaths) - 1].frp_flags |=
432             FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
433         }
434       else if (unformat (line_input, "resolve-via-attached"))
435         {
436           if (vec_len (rpaths) == 0)
437             {
438               error = clib_error_return (0, "Paths then flags");
439               goto done;
440             }
441           rpaths[vec_len (rpaths) - 1].frp_flags |=
442             FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
443         }
444       else if (unformat (line_input, "out-label %U",
445                          unformat_mpls_unicast_label, &out_label))
446         {
447           if (vec_len (rpaths) == 0)
448             {
449               error = clib_error_return (0, "Paths then labels");
450               goto done;
451             }
452           vec_add1 (rpaths[vec_len (rpaths) - 1].frp_label_stack, out_label);
453         }
454       else if (unformat (line_input, "via-label %U",
455                          unformat_mpls_unicast_label, &rpath.frp_local_label))
456         {
457           rpath.frp_weight = 1;
458           rpath.frp_proto = FIB_PROTOCOL_MPLS;
459           rpath.frp_sw_if_index = ~0;
460           vec_add1 (rpaths, rpath);
461         }
462       else if (unformat (line_input, "count %f", &count))
463         ;
464
465       else if (unformat (line_input, "%U/%d",
466                          unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
467         {
468           pfx.fp_proto = FIB_PROTOCOL_IP4;
469           vec_add1 (prefixs, pfx);
470         }
471       else if (unformat (line_input, "%U/%d",
472                          unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
473         {
474           pfx.fp_proto = FIB_PROTOCOL_IP6;
475           vec_add1 (prefixs, pfx);
476         }
477       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,
481                          &rpath.frp_sw_if_index, &rpath.frp_weight))
482         {
483           rpath.frp_proto = FIB_PROTOCOL_IP4;
484           vec_add1 (rpaths, rpath);
485         }
486
487       else if (unformat (line_input, "via %U %U weight %u",
488                          unformat_ip6_address,
489                          &rpath.frp_addr.ip6,
490                          unformat_vnet_sw_interface, vnm,
491                          &rpath.frp_sw_if_index, &rpath.frp_weight))
492         {
493           rpath.frp_proto = FIB_PROTOCOL_IP6;
494           vec_add1 (rpaths, rpath);
495         }
496
497       else if (unformat (line_input, "via %U %U",
498                          unformat_ip4_address,
499                          &rpath.frp_addr.ip4,
500                          unformat_vnet_sw_interface, vnm,
501                          &rpath.frp_sw_if_index))
502         {
503           rpath.frp_weight = 1;
504           rpath.frp_proto = FIB_PROTOCOL_IP4;
505           vec_add1 (rpaths, rpath);
506         }
507
508       else if (unformat (line_input, "via %U %U",
509                          unformat_ip6_address,
510                          &rpath.frp_addr.ip6,
511                          unformat_vnet_sw_interface, vnm,
512                          &rpath.frp_sw_if_index))
513         {
514           rpath.frp_weight = 1;
515           rpath.frp_proto = FIB_PROTOCOL_IP6;
516           vec_add1 (rpaths, rpath);
517         }
518       else if (unformat (line_input, "via %U next-hop-table %d",
519                          unformat_ip4_address,
520                          &rpath.frp_addr.ip4, &rpath.frp_fib_index))
521         {
522           rpath.frp_weight = 1;
523           rpath.frp_sw_if_index = ~0;
524           rpath.frp_proto = FIB_PROTOCOL_IP4;
525           vec_add1 (rpaths, rpath);
526         }
527       else if (unformat (line_input, "via %U next-hop-table %d",
528                          unformat_ip6_address,
529                          &rpath.frp_addr.ip6, &rpath.frp_fib_index))
530         {
531           rpath.frp_weight = 1;
532           rpath.frp_sw_if_index = ~0;
533           rpath.frp_proto = FIB_PROTOCOL_IP6;
534           vec_add1 (rpaths, rpath);
535         }
536       else if (unformat (line_input, "via %U",
537                          unformat_ip4_address, &rpath.frp_addr.ip4))
538         {
539           /*
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;
546           rpath.frp_proto = FIB_PROTOCOL_IP4;
547           vec_add1 (rpaths, rpath);
548         }
549       else if (unformat (line_input, "via %U",
550                          unformat_ip6_address, &rpath.frp_addr.ip6))
551         {
552           rpath.frp_fib_index = table_id;
553           rpath.frp_weight = 1;
554           rpath.frp_sw_if_index = ~0;
555           rpath.frp_proto = FIB_PROTOCOL_IP6;
556           vec_add1 (rpaths, rpath);
557         }
558       else if (unformat (line_input,
559                          "lookup in table %d", &rpath.frp_fib_index))
560         {
561           rpath.frp_proto = pfx.fp_proto;
562           rpath.frp_sw_if_index = ~0;
563           vec_add1 (rpaths, rpath);
564         }
565       else if (vec_len (prefixs) > 0 &&
566                unformat (line_input, "via %U",
567                          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",
576                          unformat_dpo, &dpo, prefixs[0].fp_proto))
577         {
578           vec_add1 (dpos, dpo);
579         }
580       else
581         {
582           error = unformat_parse_error (line_input);
583           goto done;
584         }
585     }
586
587   if (vec_len (prefixs) == 0)
588     {
589       error =
590         clib_error_return (0, "expected ip4/ip6 destination address/length.");
591       goto done;
592     }
593
594   if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
595     {
596       error = clib_error_return (0, "expected paths.");
597       goto done;
598     }
599
600   if (~0 == table_id)
601     {
602       /*
603        * if no table_id is passed we will manipulate the default
604        */
605       fib_index = 0;
606     }
607   else
608     {
609       fib_index = fib_table_id_find_fib_index (prefixs[0].fp_proto, table_id);
610
611       if (~0 == fib_index)
612         {
613           error = clib_error_return (0, "Nonexistent table id %d", table_id);
614           goto done;
615         }
616     }
617
618   for (i = 0; i < vec_len (prefixs); i++)
619     {
620       if (is_del && 0 == vec_len (rpaths))
621         {
622           fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
623         }
624       else if (!is_del && 1 == vec_len (dpos))
625         {
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         }
633       else if (vec_len (dpos) > 0)
634         {
635           error =
636             clib_error_return (0,
637                                "Load-balancing over multiple special adjacencies is unsupported");
638           goto done;
639         }
640       else if (0 < vec_len (rpaths))
641         {
642           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++)
651             {
652               for (j = 0; j < vec_len (rpaths); j++)
653                 {
654                   u32 fi;
655                   /*
656                    * the CLI parsing stored table Ids, swap to FIB indicies
657                    */
658                   fi = fib_table_id_find_fib_index (prefixs[i].fp_proto,
659                                                     rpaths[i].frp_fib_index);
660
661                   if (~0 == fi)
662                     {
663                       error =
664                         clib_error_return (0, "Via table %d does not exist",
665                                            rpaths[i].frp_fib_index);
666                       goto done;
667                     }
668                   rpaths[i].frp_fib_index = fi;
669
670                   fib_prefix_t rpfx = {
671                     .fp_len = prefixs[i].fp_len,
672                     .fp_proto = prefixs[i].fp_proto,
673                     .fp_addr = dst,
674                   };
675
676                   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                 }
687
688               if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
689                 {
690                   dst.ip4.as_u32 =
691                     clib_host_to_net_u32 (incr +
692                                           clib_net_to_host_u32 (dst.
693                                                                 ip4.as_u32));
694                 }
695               else
696                 {
697                   int bucket = (incr < 64 ? 0 : 1);
698                   dst.ip6.as_u64[bucket] =
699                     clib_host_to_net_u64 (incr +
700                                           clib_net_to_host_u64 (dst.ip6.as_u64
701                                                                 [bucket]));
702
703                 }
704             }
705           t[1] = vlib_time_now (vm);
706           if (count > 1)
707             vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
708         }
709       else
710         {
711           error = clib_error_return (0, "Don't understand what you want...");
712           goto done;
713         }
714     }
715
716
717 done:
718   vec_free (dpos);
719   vec_free (prefixs);
720   vec_free (rpaths);
721   unformat_free (line_input);
722   return error;
723 }
724
725 /* *INDENT-OFF* */
726 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
727   .path = "ip",
728   .short_help = "Internet protocol (IP) commands",
729 };
730 /* *INDENT-ON* */
731
732 /* *INDENT-OFF* */
733 VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
734   .path = "ip6",
735   .short_help = "Internet protocol version 6 (IPv6) commands",
736 };
737 /* *INDENT-ON* */
738
739 /* *INDENT-OFF* */
740 VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
741   .path = "show ip",
742   .short_help = "Internet protocol (IP) show commands",
743 };
744 /* *INDENT-ON* */
745
746 /* *INDENT-OFF* */
747 VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
748   .path = "show ip6",
749   .short_help = "Internet protocol version 6 (IPv6) show commands",
750 };
751 /* *INDENT-ON* */
752
753 /*?
754  * 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  *
761  * @cliexpar
762  * 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}
766  * Mainly for route add/del performance testing, one can add or delete
767  * multiple routes by adding 'count N' to the previous item:
768  * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
769  * Add multiple routes for the same destination to create equal-cost multipath:
770  * @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}
779  ?*/
780 /* *INDENT-OFF* */
781 VLIB_CLI_COMMAND (ip_route_command, static) = {
782   .path = "ip route",
783   .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>]",
784   .function = vnet_ip_route_cmd,
785   .is_mp_safe = 1,
786 };
787 /* *INDENT-ON* */
788
789 clib_error_t *
790 vnet_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;
802   u32 gcount, scount, ss, gg, incr;
803   f64 timet[2];
804
805   gcount = scount = 1;
806   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;
825       else if (unformat (line_input, "scount %d", &scount))
826         ;
827       else if (unformat (line_input, "gcount %d", &gcount))
828         ;
829       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
890   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
908   timet[0] = vlib_time_now (vm);
909
910   if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
911     {
912       incr = 1 << (32 - (pfx.fp_len % 32));
913     }
914   else
915     {
916       incr = 1 << (128 - (pfx.fp_len % 128));
917     }
918
919   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
985 done:
986   unformat_free (line_input);
987
988   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* */
1013 VLIB_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
1022 /*
1023  * 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  */
1027 static clib_error_t *
1028 ip6_probe_neighbor_wait (vlib_main_t * vm, ip6_address_t * a, u32 sw_if_index,
1029                          int retry_count)
1030 {
1031   vnet_main_t *vnm = vnet_get_main ();
1032   clib_error_t *e;
1033   int i;
1034   int resolved = 0;
1035   uword event_type;
1036   uword *event_data = 0;
1037
1038   ASSERT (vlib_in_process_context (vm));
1039
1040   if (retry_count > 0)
1041     vnet_register_ip6_neighbor_resolution_event
1042       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1043        1 /* event */ , 0 /* data */ );
1044
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);
1049
1050       if (e)
1051         return e;
1052
1053       vlib_process_wait_for_event_or_clock (vm, 1.0);
1054       event_type = vlib_process_get_events (vm, &event_data);
1055       switch (event_type)
1056         {
1057         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         }
1068       vec_reset_length (event_data);
1069     }
1070
1071 done:
1072
1073   if (!resolved)
1074     return clib_error_return (0, "Resolution failed for %U",
1075                               format_ip6_address, a);
1076   return 0;
1077 }
1078
1079 static clib_error_t *
1080 ip4_probe_neighbor_wait (vlib_main_t * vm, ip4_address_t * a, u32 sw_if_index,
1081                          int retry_count)
1082 {
1083   vnet_main_t *vnm = vnet_get_main ();
1084   clib_error_t *e;
1085   int i;
1086   int resolved = 0;
1087   uword event_type;
1088   uword *event_data = 0;
1089
1090   ASSERT (vlib_in_process_context (vm));
1091
1092   if (retry_count > 0)
1093     vnet_register_ip4_arp_resolution_event
1094       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1095        1 /* event */ , 0 /* data */ );
1096
1097   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);
1101
1102       if (e)
1103         return e;
1104
1105       vlib_process_wait_for_event_or_clock (vm, 1.0);
1106       event_type = vlib_process_get_events (vm, &event_data);
1107       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         }
1120       vec_reset_length (event_data);
1121     }
1122
1123 done:
1124
1125   vec_reset_length (event_data);
1126
1127   if (!resolved)
1128     return clib_error_return (0, "Resolution failed for %U",
1129                               format_ip4_address, a);
1130   return 0;
1131 }
1132
1133 static clib_error_t *
1134 probe_neighbor_address (vlib_main_t * vm,
1135                         unformat_input_t * input, vlib_cli_command_t * cmd)
1136 {
1137   vnet_main_t *vnm = vnet_get_main ();
1138   unformat_input_t _line_input, *line_input = &_line_input;
1139   ip4_address_t a4;
1140   ip6_address_t a6;
1141   clib_error_t *error = 0;
1142   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. */
1148   if (!unformat_user (input, unformat_line_input, line_input))
1149     return 0;
1150
1151   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1152     {
1153       if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
1154                          &sw_if_index))
1155         ;
1156       else if (unformat (line_input, "retry %d", &retry_count))
1157         ;
1158
1159       else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
1160         address_set++;
1161       else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
1162         {
1163           address_set++;
1164           is_ip4 = 0;
1165         }
1166       else
1167         {
1168           error = clib_error_return (0, "unknown input '%U'",
1169                                      format_unformat_error, line_input);
1170           goto done;
1171         }
1172     }
1173
1174   if (sw_if_index == ~0)
1175     {
1176       error = clib_error_return (0, "Interface required, not set.");
1177       goto done;
1178     }
1179   if (address_set == 0)
1180     {
1181       error = clib_error_return (0, "ip address required, not set.");
1182       goto done;
1183     }
1184   if (address_set > 1)
1185     {
1186       error = clib_error_return (0, "Multiple ip addresses not supported.");
1187       goto done;
1188     }
1189
1190   if (is_ip4)
1191     error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
1192   else
1193     error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
1194
1195 done:
1196   unformat_free (line_input);
1197
1198   return error;
1199 }
1200
1201 /*?
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* */
1218 VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
1219   .path = "ip probe-neighbor",
1220   .function = probe_neighbor_address,
1221   .short_help = "ip probe-neighbor <interface> <ip4-addr> | <ip6-addr> [retry nn]",
1222   .is_mp_safe = 1,
1223 };
1224 /* *INDENT-ON* */
1225
1226 /*
1227  * fd.io coding-style-patch-verification: ON
1228  *
1229  * Local Variables:
1230  * eval: (c-set-style "gnu")
1231  * End:
1232  */