78152f01c0483d9498856cf62742c44318a07ade
[vpp.git] / vnet / 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/dpo/drop_dpo.h>
47 #include <vnet/dpo/classify_dpo.h>
48 #include <vnet/dpo/punt_dpo.h>
49 #include <vnet/dpo/receive_dpo.h>
50 #include <vnet/dpo/ip_null_dpo.h>
51
52 /**
53  * @file
54  * @brief IPv4 and IPv6 adjacency and lookup table managment.
55  *
56  */
57
58 clib_error_t *
59 ip_interface_address_add_del (ip_lookup_main_t * lm,
60                               u32 sw_if_index,
61                               void * addr_fib,
62                               u32 address_length,
63                               u32 is_del,
64                               u32 * result_if_address_index)
65 {
66   vnet_main_t * vnm = vnet_get_main();
67   ip_interface_address_t * a, * prev, * next;
68   uword * p = mhash_get (&lm->address_to_if_address_index, addr_fib);
69
70   vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
71   a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0;
72
73   /* Verify given length. */
74   if ((a && (address_length != a->address_length)) || (address_length == 0))
75     {
76       vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
77       return clib_error_create 
78         ( "%U wrong length (expected %d) for interface %U",
79           lm->format_address_and_length, addr_fib,
80           address_length, a? a->address_length : -1,
81           format_vnet_sw_if_index_name, vnm, sw_if_index);
82     }
83
84   if (is_del)
85     {
86       if (!a) 
87         {
88           vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, sw_if_index);
89           vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
90           return clib_error_create ("%U not found for interface %U",
91                                     lm->format_address_and_length, 
92                                     addr_fib, address_length,
93                                     format_vnet_sw_interface_name, vnm, si);
94         }
95
96       if (a->prev_this_sw_interface != ~0)
97         {
98           prev = pool_elt_at_index (lm->if_address_pool, a->prev_this_sw_interface);
99           prev->next_this_sw_interface = a->next_this_sw_interface;
100         }
101       if (a->next_this_sw_interface != ~0)
102         {
103           next = pool_elt_at_index (lm->if_address_pool, a->next_this_sw_interface);
104           next->prev_this_sw_interface = a->prev_this_sw_interface;
105
106           if(a->prev_this_sw_interface == ~0)
107                  lm->if_address_pool_index_by_sw_if_index[sw_if_index]  = a->next_this_sw_interface;
108         }
109
110       if ((a->next_this_sw_interface  == ~0) &&  (a->prev_this_sw_interface == ~0))
111         lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0;
112
113       mhash_unset (&lm->address_to_if_address_index, addr_fib,
114                    /* old_value */ 0);
115       pool_put (lm->if_address_pool, a);
116
117       if (result_if_address_index)
118         *result_if_address_index = ~0;
119     }
120
121   else if (! a)
122     {
123       u32 pi; /* previous index */
124       u32 ai; 
125       u32 hi; /* head index */
126
127       pool_get (lm->if_address_pool, a);
128       memset (a, ~0, sizeof (a[0]));
129       ai = a - lm->if_address_pool;
130
131       hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
132       prev = 0;
133       while (pi != (u32)~0)
134         {
135           prev = pool_elt_at_index(lm->if_address_pool, pi);
136           pi = prev->next_this_sw_interface;
137         }
138       pi = prev ? prev - lm->if_address_pool : (u32)~0;
139
140       a->address_key = mhash_set (&lm->address_to_if_address_index,
141                                   addr_fib, ai, /* old_value */ 0);
142       a->address_length = address_length;
143       a->sw_if_index = sw_if_index;
144       a->flags = 0;
145       a->prev_this_sw_interface = pi;
146       a->next_this_sw_interface = ~0;
147       if (prev)
148           prev->next_this_sw_interface = ai;
149
150       lm->if_address_pool_index_by_sw_if_index[sw_if_index] = 
151         (hi != ~0) ? hi : ai;
152       if (result_if_address_index)
153         *result_if_address_index = ai;
154     }
155   else
156     {
157       if (result_if_address_index)
158         *result_if_address_index = a - lm->if_address_pool;
159     }
160     
161
162   return /* no error */ 0;
163 }
164
165 void ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
166 {
167   /* ensure that adjacency is cacheline aligned and sized */
168   ASSERT(STRUCT_OFFSET_OF(ip_adjacency_t, cacheline0) == 0);
169   ASSERT(STRUCT_OFFSET_OF(ip_adjacency_t, cacheline1) == CLIB_CACHE_LINE_BYTES);
170
171   /* Preallocate three "special" adjacencies */
172   lm->adjacency_heap = adj_pool;
173
174   if (! lm->fib_result_n_bytes)
175     lm->fib_result_n_bytes = sizeof (uword);
176
177   lm->is_ip6 = is_ip6;
178   if (is_ip6)
179     {
180       lm->format_address_and_length = format_ip6_address_and_length;
181       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
182                   sizeof (ip6_address_fib_t));
183     }
184   else
185     {
186       lm->format_address_and_length = format_ip4_address_and_length;
187       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
188                   sizeof (ip4_address_fib_t));
189     }
190
191   {
192     int i;
193
194     /* Setup all IP protocols to be punted and builtin-unknown. */
195     for (i = 0; i < 256; i++)
196       {
197         lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
198         lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
199       }
200
201     lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
202     lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
203     lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] = IP_BUILTIN_PROTOCOL_UDP;
204     lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_BUILTIN_PROTOCOL_ICMP;
205   }
206 }
207
208 u8 * format_ip_flow_hash_config (u8 * s, va_list * args)
209 {
210   flow_hash_config_t flow_hash_config = va_arg (*args, u32);
211     
212 #define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
213   foreach_flow_hash_bit;
214 #undef _
215
216   return s;
217 }
218
219 u8 * format_ip_lookup_next (u8 * s, va_list * args)
220 {
221   ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
222   char * t = 0;
223
224   switch (n)
225     {
226     default:
227       s = format (s, "unknown %d", n);
228       return s;
229
230     case IP_LOOKUP_NEXT_DROP: t = "drop"; break;
231     case IP_LOOKUP_NEXT_PUNT: t = "punt"; break;
232     case IP_LOOKUP_NEXT_ARP: t = "arp"; break;
233     case IP_LOOKUP_NEXT_MIDCHAIN: t="midchain"; break;
234     case IP_LOOKUP_NEXT_GLEAN: t="glean"; break;
235     case IP_LOOKUP_NEXT_REWRITE:
236       break;
237     }
238
239   if (t)
240     vec_add (s, t, strlen (t));
241
242   return s;
243 }
244
245 u8 * format_ip_adjacency_packet_data (u8 * s, va_list * args)
246 {
247   vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
248   u32 adj_index = va_arg (*args, u32);
249   u8 * packet_data = va_arg (*args, u8 *);
250   u32 n_packet_data_bytes = va_arg (*args, u32);
251   ip_adjacency_t * adj = adj_get(adj_index);
252
253   switch (adj->lookup_next_index)
254     {
255     case IP_LOOKUP_NEXT_REWRITE:
256       s = format (s, "%U",
257                   format_vnet_rewrite_header,
258                   vnm->vlib_main, &adj->rewrite_header, packet_data, n_packet_data_bytes);
259       break;
260
261     default:
262       break;
263     }
264
265   return s;
266 }
267
268 static uword unformat_dpo (unformat_input_t * input, va_list * args)
269 {
270   dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
271   fib_protocol_t fp = va_arg (*args, int);
272   dpo_proto_t proto;
273
274   proto = fib_proto_to_dpo(fp);
275
276   if (unformat (input, "drop"))
277     dpo_copy(dpo, drop_dpo_get(proto));
278   else if (unformat (input, "punt"))
279     dpo_copy(dpo, punt_dpo_get(proto));
280   else if (unformat (input, "local"))
281     receive_dpo_add_or_lock(proto, ~0, NULL, dpo);
282   else if (unformat (input, "null-send-unreach"))
283       ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
284   else if (unformat (input, "null-send-prohibit"))
285       ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
286   else if (unformat (input, "null"))
287       ip_null_dpo_add_and_lock(proto, IP_NULL_ACTION_NONE, dpo);
288   else if (unformat (input, "classify"))
289     {
290       u32 classify_table_index;
291
292       if (!unformat (input, "%d", &classify_table_index))
293         {
294           clib_warning ("classify adj must specify table index");
295           return 0;
296         }
297
298       dpo_set(dpo, DPO_CLASSIFY, proto,
299               classify_dpo_create(fp, classify_table_index));
300     }
301   else
302     return 0;
303
304   return 1;
305 }
306
307 const ip46_address_t zero_addr = {
308     .as_u64 = {
309         0, 0
310     },
311 };
312
313 u32
314 fib_table_id_find_fib_index (fib_protocol_t proto,
315                              u32 table_id)
316 {
317     ip4_main_t *im4 = &ip4_main;
318     ip6_main_t *im6 = &ip6_main;
319     uword * p;
320
321     switch (proto)
322     {
323     case FIB_PROTOCOL_IP4:
324         p = hash_get(im4->fib_index_by_table_id, table_id);
325         break;
326     case FIB_PROTOCOL_IP6:
327         p = hash_get(im6->fib_index_by_table_id, table_id);
328         break;
329     default:
330         p = NULL;
331         break;
332     }
333     if (NULL != p)
334     {
335         return (p[0]);
336     }
337     return (~0);
338 }
339
340 clib_error_t *
341 vnet_ip_route_cmd (vlib_main_t * vm,
342                    unformat_input_t * main_input,
343                    vlib_cli_command_t * cmd)
344 {
345   unformat_input_t _line_input, * line_input = &_line_input;
346   fib_route_path_t *rpaths = NULL, rpath;
347   dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
348   fib_prefix_t *prefixs = NULL, pfx;
349   clib_error_t * error = NULL;
350   mpls_label_t out_label;
351   u32 table_id, is_del;
352   vnet_main_t * vnm;
353   u32 fib_index;
354   f64 count;
355   int i;
356
357   vnm = vnet_get_main();
358   is_del = 0;
359   table_id = 0;
360   count = 1;
361   memset(&pfx, 0, sizeof(pfx));
362
363   /* Get a line of input. */
364   if (! unformat_user (main_input, unformat_line_input, line_input))
365     return 0;
366
367   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
368     {
369       memset(&rpath, 0, sizeof(rpath));
370
371       if (unformat (line_input, "table %d", &table_id))
372         ;
373       else if (unformat (line_input, "del"))
374         is_del = 1;
375       else if (unformat (line_input, "add"))
376         is_del = 0;
377       else if (unformat (line_input, "resolve-via-host"))
378       {
379           if (vec_len(rpaths) == 0)
380           {
381               error = clib_error_return(0 , "Paths then flags");
382               goto done;
383           }
384           rpaths[vec_len(rpaths)-1].frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
385       }
386       else if (unformat (line_input, "resolve-via-attached"))
387       {
388           if (vec_len(rpaths) == 0)
389           {
390               error = clib_error_return(0 , "Paths then flags");
391               goto done;
392           }
393           rpaths[vec_len(rpaths)-1].frp_flags |=
394               FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
395       }
396       else if (unformat (line_input, "out-label %U",
397                          unformat_mpls_unicast_label, &out_label))
398       {
399           if (vec_len(rpaths) == 0)
400           {
401               error = clib_error_return(0 , "Paths then labels");
402               goto done;
403           }
404           rpaths[vec_len(rpaths)-1].frp_label = out_label;
405       }
406       else if (unformat (line_input, "count %f", &count))
407         ;
408
409       else if (unformat (line_input, "%U/%d",
410                          unformat_ip4_address,
411                          &pfx.fp_addr.ip4,
412                          &pfx.fp_len))
413       {
414           pfx.fp_proto = FIB_PROTOCOL_IP4;
415           vec_add1(prefixs, pfx);
416       }
417       else if (unformat (line_input, "%U/%d",
418                          unformat_ip6_address,
419                          &pfx.fp_addr.ip6,
420                          &pfx.fp_len))
421       {
422           pfx.fp_proto = FIB_PROTOCOL_IP6;
423           vec_add1(prefixs, pfx);
424       }
425       else if (unformat (line_input, "via %U %U weight %u",
426                          unformat_ip4_address,
427                          &rpath.frp_addr.ip4,
428                          unformat_vnet_sw_interface, vnm,
429                          &rpath.frp_sw_if_index,
430                          &rpath.frp_weight))
431       {
432           rpath.frp_label = MPLS_LABEL_INVALID;
433           rpath.frp_proto = FIB_PROTOCOL_IP4;
434           vec_add1(rpaths, rpath);
435       }
436
437       else if (unformat (line_input, "via %U %U weight %u",
438                          unformat_ip6_address,
439                          &rpath.frp_addr.ip6,
440                          unformat_vnet_sw_interface, vnm,
441                          &rpath.frp_sw_if_index,
442                          &rpath.frp_weight))
443       {
444           rpath.frp_label = MPLS_LABEL_INVALID;
445           rpath.frp_proto = FIB_PROTOCOL_IP6;
446           vec_add1(rpaths, rpath);
447       }
448
449       else if (unformat (line_input, "via %U %U",
450                          unformat_ip4_address,
451                          &rpath.frp_addr.ip4,
452                          unformat_vnet_sw_interface, vnm,
453                          &rpath.frp_sw_if_index))
454       {
455           rpath.frp_label = MPLS_LABEL_INVALID;
456           rpath.frp_weight = 1;
457           rpath.frp_proto = FIB_PROTOCOL_IP4;
458           vec_add1(rpaths, rpath);
459       }
460                          
461       else if (unformat (line_input, "via %U %U",
462                          unformat_ip6_address,
463                          &rpath.frp_addr.ip6,
464                          unformat_vnet_sw_interface, vnm,
465                          &rpath.frp_sw_if_index))
466       {
467           rpath.frp_label = MPLS_LABEL_INVALID;
468           rpath.frp_weight = 1;
469           rpath.frp_proto = FIB_PROTOCOL_IP6;
470           vec_add1(rpaths, rpath);
471       }
472       else if (unformat (line_input, "via %U next-hop-table %d",
473                          unformat_ip4_address,
474                          &rpath.frp_addr.ip4,
475                          &rpath.frp_fib_index))
476       {
477           rpath.frp_weight = 1;
478           rpath.frp_sw_if_index = ~0;
479           rpath.frp_label = MPLS_LABEL_INVALID;
480           rpath.frp_proto = FIB_PROTOCOL_IP4;
481           vec_add1(rpaths, rpath);
482       }
483       else if (unformat (line_input, "via %U next-hop-table %d",
484                          unformat_ip6_address,
485                          &rpath.frp_addr.ip6,
486                          &rpath.frp_fib_index))
487       {
488           rpath.frp_weight = 1;
489           rpath.frp_sw_if_index = ~0;
490           rpath.frp_label = MPLS_LABEL_INVALID;
491           rpath.frp_proto = FIB_PROTOCOL_IP6;
492           vec_add1(rpaths, rpath);
493       }
494       else if (unformat (line_input, "via %U",
495                          unformat_ip4_address,
496                          &rpath.frp_addr.ip4))
497       {
498           /*
499            * the recursive next-hops are by default in the same table
500            * as the prefix
501            */
502           rpath.frp_fib_index = table_id;
503           rpath.frp_weight = 1;
504           rpath.frp_sw_if_index = ~0;
505           rpath.frp_label = MPLS_LABEL_INVALID;
506           rpath.frp_proto = FIB_PROTOCOL_IP4;
507           vec_add1(rpaths, rpath);
508       }
509       else if (unformat (line_input, "via %U",
510                          unformat_ip6_address,
511                          &rpath.frp_addr.ip6))
512       {
513           rpath.frp_fib_index = table_id;
514           rpath.frp_weight = 1;
515           rpath.frp_sw_if_index = ~0;
516           rpath.frp_label = MPLS_LABEL_INVALID;
517           rpath.frp_proto = FIB_PROTOCOL_IP6;
518           vec_add1(rpaths, rpath);
519       }
520       else if (unformat (line_input,
521                          "lookup in table %d",
522                          &rpath.frp_fib_index))
523       {
524           rpath.frp_label = MPLS_LABEL_INVALID;
525           rpath.frp_proto = pfx.fp_proto;
526           rpath.frp_sw_if_index = ~0;
527           vec_add1(rpaths, rpath);
528       }
529       else if (vec_len (prefixs) > 0 &&
530                unformat (line_input, "via %U",
531                          unformat_dpo, &dpo, prefixs[0].fp_proto))
532       {
533           rpath.frp_label = MPLS_LABEL_INVALID;
534           vec_add1 (dpos, dpo);
535       }
536       else
537       {
538           error = unformat_parse_error (line_input);
539           goto done;
540       }
541     }
542     
543   unformat_free (line_input);
544
545   if (vec_len (prefixs) == 0)
546   {
547       error = clib_error_return (0, "expected ip4/ip6 destination address/length.");
548       goto done;
549     }
550
551   if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
552     {
553       error = clib_error_return (0, "expected paths.");
554       goto done;
555     }
556
557   if (~0 == table_id)
558   {
559       /*
560        * if no table_id is passed we will manipulate the default
561        */
562       fib_index = 0;
563   }
564   else
565   {
566       fib_index = fib_table_id_find_fib_index(prefixs[0].fp_proto,
567                                               table_id);
568
569       if (~0 == fib_index)
570       {
571           error = clib_error_return (0,
572                                      "Nonexistent table id %d", 
573                                      table_id);
574           goto done;
575       }
576   }
577
578   for (i = 0; i < vec_len (prefixs); i++)
579   {
580       if (is_del && 0 == vec_len (rpaths))
581       {
582           fib_table_entry_delete(fib_index,
583                                  &prefixs[i],
584                                  FIB_SOURCE_CLI);
585       }
586       else if (!is_del && 1 == vec_len (dpos))
587       {
588           fib_table_entry_special_dpo_add(fib_index,
589                                           &prefixs[i],
590                                           FIB_SOURCE_CLI,
591                                           FIB_ENTRY_FLAG_EXCLUSIVE,
592                                           &dpos[0]);
593           dpo_reset(&dpos[0]);
594       }
595       else if (vec_len (dpos) > 0)
596       {
597           error = clib_error_return(0 , "Load-balancing over multiple special adjacencies is unsupported");
598           goto done;
599       }
600       else if (0 < vec_len (rpaths))
601       {
602           u32 k, j, n, incr;
603           ip46_address_t dst = prefixs[i].fp_addr;
604           f64 t[2];
605           n = count;
606           t[0] = vlib_time_now (vm);
607           incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
608                        prefixs[i].fp_len);
609
610           for (k = 0; k < n; k++)
611           {
612               for (j = 0; j < vec_len (rpaths); j++)
613               {
614                   u32 fi;
615                   /*
616                    * the CLI parsing stored table Ids, swap to FIB indicies
617                    */
618                   fi = fib_table_id_find_fib_index(prefixs[i].fp_proto,
619                                                    rpaths[i].frp_fib_index);
620
621                   if (~0 == fi)
622                   {
623                       error = clib_error_return(0 , "Via table %d does not exist",
624                                                 rpaths[i].frp_fib_index);
625                       goto done;
626                   }
627                   rpaths[i].frp_fib_index = fi;
628
629                   fib_prefix_t rpfx = {
630                       .fp_len = prefixs[i].fp_len,
631                       .fp_proto = prefixs[i].fp_proto,
632                       .fp_addr = dst,
633                   };
634
635                   if (is_del)
636                       fib_table_entry_path_remove2(fib_index,
637                                                    &rpfx,
638                                                    FIB_SOURCE_CLI,
639                                                    &rpaths[j]);
640                   else
641                       fib_table_entry_path_add2(fib_index,
642                                                 &rpfx,
643                                                 FIB_SOURCE_CLI,
644                                                 FIB_ENTRY_FLAG_NONE,
645                                                 &rpaths[j]);
646               }
647
648               if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
649               {
650                   dst.ip4.as_u32 =
651                       clib_host_to_net_u32(incr +
652                                            clib_net_to_host_u32 (dst.ip4.as_u32));
653               }
654               else
655               {
656                   int bucket = (incr < 64 ? 0 : 1);
657                   dst.ip6.as_u64[bucket] =
658                       clib_host_to_net_u64(incr +
659                                            clib_net_to_host_u64 (
660                                                dst.ip6.as_u64[bucket]));
661
662               }
663           }
664           t[1] = vlib_time_now (vm);
665           if (count > 1)
666               vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
667       }
668       else
669       {
670           error = clib_error_return(0 , "Don't understand what you want...");
671           goto done;
672       }
673   }
674
675
676  done:
677   vec_free (dpos);
678   vec_free (prefixs);
679   vec_free (rpaths);
680   return error;
681 }
682
683 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
684   .path = "ip",
685   .short_help = "Internet protocol (IP) commands",
686 };
687
688 VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
689   .path = "ip6",
690   .short_help = "Internet protocol version 6 (IPv6) commands",
691 };
692
693 VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
694   .path = "show ip",
695   .short_help = "Internet protocol (IP) show commands",
696 };
697
698 VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
699   .path = "show ip6",
700   .short_help = "Internet protocol version 6 (IPv6) show commands",
701 };
702
703 /*?
704  * This command is used to add or delete IPv4 or IPv6 routes. All
705  * IP Addresses ('<em><dst-ip-addr>/<width></em>',
706  * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
707  * can be IPv4 or IPv6, but all must be of the same form in a single
708  * command. To display the current set of routes, use the commands
709  * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
710  *
711  * @cliexpar
712  * Example of how to add a straight forward static route:
713  * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
714  * Example of how to delete a straight forward static route:
715  * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
716  * Mainly for route add/del performance testing, one can add or delete
717  * multiple routes by adding 'count N' to the previous item:
718  * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
719  * Add multiple routes for the same destination to create equal-cost multipath:
720  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
721  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
722  * For unequal-cost multipath, specify the desired weights. This
723  * combination of weights results in 3/4 of the traffic following the
724  * second path, 1/4 following the first path:
725  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
726  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
727  * To add a route to a particular FIB table (VRF), use:
728  * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
729  ?*/
730 /* *INDENT-OFF* */
731 VLIB_CLI_COMMAND (ip_route_command, static) = {
732   .path = "ip route",
733   .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>]",
734   .function = vnet_ip_route_cmd,
735   .is_mp_safe = 1,
736 };
737 /* *INDENT-ON* */
738
739 /*
740  * The next two routines address a longstanding script hemorrhoid.
741  * Probing a v4 or v6 neighbor needs to appear to be synchronous,
742  * or dependent route-adds will simply fail.
743  */
744 static clib_error_t *
745 ip6_probe_neighbor_wait (vlib_main_t *vm, ip6_address_t * a, u32 sw_if_index,
746                          int retry_count)
747 {
748   vnet_main_t * vnm = vnet_get_main();
749   clib_error_t * e;
750   int i;
751   int resolved = 0;
752   uword event_type;
753   uword *event_data = 0;
754
755   ASSERT (vlib_in_process_context(vm));
756
757   if (retry_count > 0)
758     vnet_register_ip6_neighbor_resolution_event
759       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
760        1 /* event */, 0 /* data */);
761
762   for (i = 0; i < retry_count; i++)
763     {
764       /* The interface may be down, etc. */
765       e = ip6_probe_neighbor (vm, a, sw_if_index);
766
767       if (e)
768         return e;
769
770       vlib_process_wait_for_event_or_clock (vm, 1.0);
771       event_type = vlib_process_get_events (vm, &event_data);
772       switch (event_type)
773         {
774         case 1: /* resolved... */
775           vlib_cli_output (vm, "Resolved %U",
776                            format_ip6_address, a);
777           resolved = 1;
778           goto done;
779           
780         case ~0: /* timeout */
781           break;
782           
783         default:
784           clib_warning ("unknown event_type %d", event_type);
785         }
786       vec_reset_length (event_data);
787     }
788   
789  done:
790
791   if (!resolved)
792     return clib_error_return (0, "Resolution failed for %U",
793                               format_ip6_address, a);
794   return 0;
795 }
796
797 static clib_error_t *
798 ip4_probe_neighbor_wait (vlib_main_t *vm, ip4_address_t * a, u32 sw_if_index,
799                          int retry_count)
800 {
801   vnet_main_t * vnm = vnet_get_main();
802   clib_error_t * e;
803   int i;
804   int resolved = 0;
805   uword event_type;
806   uword *event_data = 0;
807
808   ASSERT (vlib_in_process_context(vm));
809
810   if (retry_count > 0)
811     vnet_register_ip4_arp_resolution_event 
812       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
813        1 /* event */, 0 /* data */);
814   
815   for (i = 0; i < retry_count; i++)
816     {
817       /* The interface may be down, etc. */
818       e = ip4_probe_neighbor (vm, a, sw_if_index);
819       
820       if (e)
821         return e;
822       
823       vlib_process_wait_for_event_or_clock (vm, 1.0);
824       event_type = vlib_process_get_events (vm, &event_data);
825       switch (event_type) 
826         {
827         case 1: /* resolved... */
828           vlib_cli_output (vm, "Resolved %U", 
829                            format_ip4_address, a);
830           resolved = 1;
831           goto done;
832           
833         case ~0: /* timeout */
834           break;
835           
836         default:
837           clib_warning ("unknown event_type %d", event_type);
838         }
839       vec_reset_length (event_data);
840     }
841   
842  done:
843
844   vec_reset_length (event_data);
845
846   if (!resolved)
847     return clib_error_return (0, "Resolution failed for %U",
848                               format_ip4_address, a);
849   return 0;
850 }
851
852 static clib_error_t *
853 probe_neighbor_address (vlib_main_t * vm,
854                         unformat_input_t * input,
855                         vlib_cli_command_t * cmd)
856 {
857   vnet_main_t * vnm = vnet_get_main();
858   unformat_input_t _line_input, * line_input = &_line_input;
859   ip4_address_t a4;
860   ip6_address_t a6;
861   clib_error_t * error = 0;
862   u32 sw_if_index = ~0;
863   int retry_count = 3;
864   int is_ip4 = 1;
865   int address_set = 0;
866
867   /* Get a line of input. */
868   if (! unformat_user (input, unformat_line_input, line_input))
869     return 0;
870
871   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) 
872     {
873       if (unformat_user (line_input, unformat_vnet_sw_interface, vnm, 
874                          &sw_if_index))
875         ;
876       else if (unformat (line_input, "retry %d", &retry_count))
877         ;
878
879       else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
880         address_set++;
881       else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
882         {
883           address_set++;
884           is_ip4 = 0;
885         }
886       else
887         return clib_error_return (0, "unknown input '%U'",
888                                   format_unformat_error, line_input);
889     }
890
891   unformat_free (line_input);
892
893   if (sw_if_index == ~0)
894     return clib_error_return (0, "Interface required, not set.");
895   if (address_set == 0)
896     return clib_error_return (0, "ip address required, not set.");
897   if (address_set > 1)
898     return clib_error_return (0, "Multiple ip addresses not supported.");
899     
900   if (is_ip4)
901     error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
902   else 
903     error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
904
905   return error;
906 }
907
908 /*?
909  * The '<em>ip probe-neighbor</em>' command ARPs for IPv4 addresses or
910  * attempts IPv6 neighbor discovery depending on the supplied IP address
911  * format.
912  *
913  * @note This command will not immediately affect the indicated FIB; it
914  * is not suitable for use in establishing a FIB entry prior to adding
915  * recursive FIB entries. As in: don't use it in a script to probe a
916  * gateway prior to adding a default route. It won't work. Instead,
917  * configure a static ARP cache entry [see '<em>set ip arp</em>'], or
918  * a static IPv6 neighbor [see '<em>set ip6 neighbor</em>'].
919  *
920  * @cliexpar
921  * Example of probe for an IPv4 address:
922  * @cliexcmd{ip probe-neighbor GigabitEthernet2/0/0 172.16.1.2}
923 ?*/
924 /* *INDENT-OFF* */
925 VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
926   .path = "ip probe-neighbor",
927   .function = probe_neighbor_address,
928   .short_help = "ip probe-neighbor <interface> <ip4-addr> | <ip6-addr> [retry nn]",
929   .is_mp_safe = 1,
930 };
931 /* *INDENT-ON* */