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