Initial commit of vpp code.
[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 <vppinfra/math.h>              /* for fabs */
41 #include <vnet/ip/ip.h>
42
43 static void
44 ip_multipath_del_adjacency (ip_lookup_main_t * lm, u32 del_adj_index);
45
46 always_inline void
47 ip_poison_adjacencies (ip_adjacency_t * adj, uword n_adj)
48 {
49   if (CLIB_DEBUG > 0)
50     memset (adj, 0xfe, n_adj * sizeof (adj[0]));
51 }
52
53 /* Create new block of given number of contiguous adjacencies. */
54 ip_adjacency_t *
55 ip_add_adjacency (ip_lookup_main_t * lm,
56                   ip_adjacency_t * copy_adj,
57                   u32 n_adj,
58                   u32 * adj_index_return)
59 {
60   ip_adjacency_t * adj;
61   u32 ai, i, handle;
62
63   ai = heap_alloc (lm->adjacency_heap, n_adj, handle);
64   adj = heap_elt_at_index (lm->adjacency_heap, ai);
65
66   ip_poison_adjacencies (adj, n_adj);
67
68   /* Validate adjacency counters. */
69   vlib_validate_combined_counter (&lm->adjacency_counters, ai + n_adj - 1);
70
71   for (i = 0; i < n_adj; i++)
72     {
73       /* Make sure certain fields are always initialized. */
74       adj[i].rewrite_header.sw_if_index = ~0;
75       adj[i].explicit_fib_index = ~0;
76       adj[i].mcast_group_index = ~0;
77       adj[i].classify_table_index = ~0;
78       adj[i].saved_lookup_next_index = 0;
79
80       if (copy_adj)
81         adj[i] = copy_adj[i];
82
83       adj[i].heap_handle = handle;
84       adj[i].n_adj = n_adj;
85
86       /* Zero possibly stale counters for re-used adjacencies. */
87       vlib_zero_combined_counter (&lm->adjacency_counters, ai + i);
88     }
89
90   *adj_index_return = ai;
91   return adj;
92 }
93
94 static void ip_del_adjacency2 (ip_lookup_main_t * lm, u32 adj_index, u32 delete_multipath_adjacency)
95 {
96   ip_adjacency_t * adj;
97   uword handle;
98
99   ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 1);
100
101   adj = ip_get_adjacency (lm, adj_index);
102   handle = adj->heap_handle;
103
104   if (delete_multipath_adjacency)
105     ip_multipath_del_adjacency (lm, adj_index);
106
107   ip_poison_adjacencies (adj, adj->n_adj);
108
109   heap_dealloc (lm->adjacency_heap, handle);
110 }
111
112 void ip_del_adjacency (ip_lookup_main_t * lm, u32 adj_index)
113 { ip_del_adjacency2 (lm, adj_index, /* delete_multipath_adjacency */ 1); }
114
115 static int
116 next_hop_sort_by_weight (ip_multipath_next_hop_t * n1,
117                          ip_multipath_next_hop_t * n2)
118 {
119   int cmp = (int) n1->weight - (int) n2->weight;
120   return (cmp == 0
121           ? (int) n1->next_hop_adj_index - (int) n2->next_hop_adj_index
122           : (cmp > 0 ? +1 : -1));
123 }
124
125 /* Given next hop vector is over-written with normalized one with sorted weights and
126    with weights corresponding to the number of adjacencies for each next hop.
127    Returns number of adjacencies in block. */
128 static u32 ip_multipath_normalize_next_hops (ip_lookup_main_t * lm,
129                                              ip_multipath_next_hop_t * raw_next_hops,
130                                              ip_multipath_next_hop_t ** normalized_next_hops)
131 {
132   ip_multipath_next_hop_t * nhs;
133   uword n_nhs, n_adj, n_adj_left, i;
134   f64 sum_weight, norm, error;
135
136   n_nhs = vec_len (raw_next_hops);
137   ASSERT (n_nhs > 0);
138   if (n_nhs == 0)
139     return 0;
140
141   /* Allocate enough space for 2 copies; we'll use second copy to save original weights. */
142   nhs = *normalized_next_hops;
143   vec_validate (nhs, 2*n_nhs - 1);
144
145   /* Fast path: 1 next hop in block. */
146   n_adj = n_nhs;
147   if (n_nhs == 1)
148     {
149       nhs[0] = raw_next_hops[0];
150       nhs[0].weight = 1;
151       _vec_len (nhs) = 1;
152       goto done;
153     }
154
155   else if (n_nhs == 2)
156     {
157       int cmp = next_hop_sort_by_weight (&raw_next_hops[0], &raw_next_hops[1]) < 0;
158
159       /* Fast sort. */
160       nhs[0] = raw_next_hops[cmp];
161       nhs[1] = raw_next_hops[cmp ^ 1];
162
163       /* Fast path: equal cost multipath with 2 next hops. */
164       if (nhs[0].weight == nhs[1].weight)
165         {
166           nhs[0].weight = nhs[1].weight = 1;
167           _vec_len (nhs) = 2;
168           goto done;
169         }
170     }
171   else
172     {
173       memcpy (nhs, raw_next_hops, n_nhs * sizeof (raw_next_hops[0]));
174       qsort (nhs, n_nhs, sizeof (nhs[0]), (void *) next_hop_sort_by_weight);
175     }
176
177   /* Find total weight to normalize weights. */
178   sum_weight = 0;
179   for (i = 0; i < n_nhs; i++)
180     sum_weight += nhs[i].weight;
181
182   /* In the unlikely case that all weights are given as 0, set them all to 1. */
183   if (sum_weight == 0)
184     {
185       for (i = 0; i < n_nhs; i++)
186         nhs[i].weight = 1;
187       sum_weight = n_nhs;
188     }
189
190   /* Save copies of all next hop weights to avoid being overwritten in loop below. */
191   for (i = 0; i < n_nhs; i++)
192     nhs[n_nhs + i].weight = nhs[i].weight;
193
194   /* Try larger and larger power of 2 sized adjacency blocks until we
195      find one where traffic flows to within 1% of specified weights. */
196   for (n_adj = max_pow2 (n_nhs); ; n_adj *= 2)
197     {
198       error = 0;
199
200       norm = n_adj / sum_weight;
201       n_adj_left = n_adj;
202       for (i = 0; i < n_nhs; i++)
203         {
204           f64 nf = nhs[n_nhs + i].weight * norm; /* use saved weights */
205           word n = flt_round_nearest (nf);
206
207           n = n > n_adj_left ? n_adj_left : n;
208           n_adj_left -= n;
209           error += fabs (nf - n);
210           nhs[i].weight = n;
211         }
212         
213       nhs[0].weight += n_adj_left;
214
215       /* Less than 5% average error per adjacency with this size adjacency block? */
216       if (error <= lm->multipath_next_hop_error_tolerance*n_adj)
217         {
218           /* Truncate any next hops with zero weight. */
219           _vec_len (nhs) = i;
220           break;
221         }
222     }
223
224  done:
225   /* Save vector for next call. */
226   *normalized_next_hops = nhs;
227   return n_adj;
228 }
229
230 always_inline uword
231 ip_next_hop_hash_key_from_handle (uword handle)
232 { return 1 + 2*handle; }
233
234 always_inline uword
235 ip_next_hop_hash_key_is_heap_handle (uword k)
236 { return k & 1; }
237
238 always_inline uword
239 ip_next_hop_hash_key_get_heap_handle (uword k)
240 {
241   ASSERT (ip_next_hop_hash_key_is_heap_handle (k));
242   return k / 2;
243 }
244
245 static u32
246 ip_multipath_adjacency_get (ip_lookup_main_t * lm,
247                             ip_multipath_next_hop_t * raw_next_hops,
248                             uword create_if_non_existent)
249 {
250   uword * p;
251   u32 i, j, n_adj, adj_index, adj_heap_handle;
252   ip_adjacency_t * adj, * copy_adj;
253   ip_multipath_next_hop_t * nh, * nhs;
254   ip_multipath_adjacency_t * madj;
255
256   n_adj = ip_multipath_normalize_next_hops (lm, raw_next_hops, &lm->next_hop_hash_lookup_key_normalized);
257   nhs = lm->next_hop_hash_lookup_key_normalized;
258
259   /* Basic sanity. */
260   ASSERT (n_adj >= vec_len (raw_next_hops));
261
262   /* Use normalized next hops to see if we've seen a block equivalent to this one before. */
263   p = hash_get_mem (lm->multipath_adjacency_by_next_hops, nhs);
264   if (p)
265     return p[0];
266
267   if (! create_if_non_existent)
268     return 0;
269
270   adj = ip_add_adjacency (lm, /* copy_adj */ 0, n_adj, &adj_index);
271   adj_heap_handle = adj[0].heap_handle;
272
273   /* Fill in adjacencies in block based on corresponding next hop adjacencies. */
274   i = 0;
275   vec_foreach (nh, nhs)
276     {
277       copy_adj = ip_get_adjacency (lm, nh->next_hop_adj_index);
278       for (j = 0; j < nh->weight; j++)
279         {
280           adj[i] = copy_adj[0];
281           adj[i].heap_handle = adj_heap_handle;
282           adj[i].n_adj = n_adj;
283           i++;
284         }
285     }
286
287   /* All adjacencies should have been initialized. */
288   ASSERT (i == n_adj);
289
290   vec_validate (lm->multipath_adjacencies, adj_heap_handle);
291   madj = vec_elt_at_index (lm->multipath_adjacencies, adj_heap_handle);
292
293   madj->adj_index = adj_index;
294   madj->n_adj_in_block = n_adj;
295   madj->reference_count = 0;    /* caller will set to one. */
296
297   madj->normalized_next_hops.count = vec_len (nhs);
298   madj->normalized_next_hops.heap_offset
299     = heap_alloc (lm->next_hop_heap, vec_len (nhs),
300                   madj->normalized_next_hops.heap_handle);
301   memcpy (lm->next_hop_heap + madj->normalized_next_hops.heap_offset,
302           nhs, vec_bytes (nhs));
303
304   hash_set (lm->multipath_adjacency_by_next_hops,
305             ip_next_hop_hash_key_from_handle (madj->normalized_next_hops.heap_handle),
306             madj - lm->multipath_adjacencies);
307
308   madj->unnormalized_next_hops.count = vec_len (raw_next_hops);
309   madj->unnormalized_next_hops.heap_offset
310     = heap_alloc (lm->next_hop_heap, vec_len (raw_next_hops),
311                   madj->unnormalized_next_hops.heap_handle);
312   memcpy (lm->next_hop_heap + madj->unnormalized_next_hops.heap_offset,
313           raw_next_hops, vec_bytes (raw_next_hops));
314
315   ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
316
317   return adj_heap_handle;
318 }
319
320 /* Returns 0 for next hop not found. */
321 u32
322 ip_multipath_adjacency_add_del_next_hop (ip_lookup_main_t * lm,
323                                          u32 is_del,
324                                          u32 old_mp_adj_index,
325                                          u32 next_hop_adj_index,
326                                          u32 next_hop_weight,
327                                          u32 * new_mp_adj_index)
328 {
329   ip_multipath_adjacency_t * mp_old, * mp_new;
330   ip_multipath_next_hop_t * nh, * nhs, * hash_nhs;
331   u32 n_nhs, i_nh;
332
333   mp_new = mp_old = 0;
334   n_nhs = 0;
335   i_nh = 0;
336   nhs = 0;
337
338   /* If old multipath adjacency is valid, find requested next hop. */
339   if (old_mp_adj_index < vec_len (lm->multipath_adjacencies)
340       && lm->multipath_adjacencies[old_mp_adj_index].normalized_next_hops.count > 0)
341     {
342       mp_old = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
343         
344       nhs = vec_elt_at_index (lm->next_hop_heap, mp_old->unnormalized_next_hops.heap_offset);
345       n_nhs = mp_old->unnormalized_next_hops.count;
346
347       /* Linear search: ok since n_next_hops is small. */
348       for (i_nh = 0; i_nh < n_nhs; i_nh++)
349         if (nhs[i_nh].next_hop_adj_index == next_hop_adj_index)
350           break;
351
352       /* Given next hop not found. */
353       if (i_nh >= n_nhs && is_del)
354         return 0;
355     }
356
357   hash_nhs = lm->next_hop_hash_lookup_key;
358   if (hash_nhs)
359     _vec_len (hash_nhs) = 0;
360
361   if (is_del)
362     {
363       if (n_nhs > 1)
364         {
365           /* Prepare lookup key for multipath with target next hop deleted. */
366           if (i_nh > 0)
367             vec_add (hash_nhs, nhs + 0, i_nh);
368           if (i_nh + 1 < n_nhs)
369             vec_add (hash_nhs, nhs + i_nh + 1, n_nhs - (i_nh + 1));
370         }
371     }
372   else /* it's an add. */
373     {
374       /* If next hop is already there with the same weight, we have nothing to do. */
375       if (i_nh < n_nhs && nhs[i_nh].weight == next_hop_weight)
376         {
377           new_mp_adj_index[0] = ~0;
378           goto done;
379         }
380
381       /* Copy old next hops to lookup key vector. */
382       if (n_nhs > 0)
383         vec_add (hash_nhs, nhs, n_nhs);
384
385       if (i_nh < n_nhs)
386         {
387           /* Change weight of existing next hop. */
388           nh = vec_elt_at_index (hash_nhs, i_nh);
389         }
390       else
391         {
392           /* Add a new next hop. */
393           vec_add2 (hash_nhs, nh, 1);
394           nh->next_hop_adj_index = next_hop_adj_index;
395         }
396
397       /* Set weight for added or old next hop. */
398       nh->weight = next_hop_weight;
399     }
400
401   if (vec_len (hash_nhs) > 0)
402     {
403       u32 tmp = ip_multipath_adjacency_get (lm, hash_nhs,
404                                             /* create_if_non_existent */ 1);
405       if (tmp != ~0)
406         mp_new = vec_elt_at_index (lm->multipath_adjacencies, tmp);
407
408       /* Fetch again since pool may have moved. */
409       if (mp_old)
410         mp_old = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
411     }
412
413   new_mp_adj_index[0] = mp_new ? mp_new - lm->multipath_adjacencies : ~0;
414
415   if (mp_new != mp_old)
416     {
417       if (mp_old)
418         {
419           ASSERT (mp_old->reference_count > 0);
420           mp_old->reference_count -= 1;
421         }
422       if (mp_new)
423         mp_new->reference_count += 1;
424     }
425
426   if (mp_old && mp_old->reference_count == 0)
427     ip_multipath_adjacency_free (lm, mp_old);
428
429  done:
430   /* Save key vector next call. */
431   lm->next_hop_hash_lookup_key = hash_nhs;
432
433   return 1;
434 }
435
436 static void
437 ip_multipath_del_adjacency (ip_lookup_main_t * lm, u32 del_adj_index)
438 {
439   ip_adjacency_t * adj = ip_get_adjacency (lm, del_adj_index);
440   ip_multipath_adjacency_t * madj, * new_madj;
441   ip_multipath_next_hop_t * nhs, * hash_nhs;
442   u32 i, n_nhs, madj_index, new_madj_index;
443
444   if (adj->heap_handle >= vec_len (lm->multipath_adjacencies))
445     return;
446
447   vec_validate (lm->adjacency_remap_table, vec_len (lm->adjacency_heap) - 1);
448
449   for (madj_index = 0; madj_index < vec_len (lm->multipath_adjacencies); madj_index++)
450     {
451       madj = vec_elt_at_index (lm->multipath_adjacencies, madj_index);
452       if (madj->n_adj_in_block == 0)
453         continue;
454
455       nhs = heap_elt_at_index (lm->next_hop_heap, madj->unnormalized_next_hops.heap_offset);
456       n_nhs = madj->unnormalized_next_hops.count;
457       for (i = 0; i < n_nhs; i++)
458         if (nhs[i].next_hop_adj_index == del_adj_index)
459           break;
460
461       /* del_adj_index not found in unnormalized_next_hops?  We're done. */
462       if (i >= n_nhs)
463         continue;
464
465       new_madj = 0;
466       if (n_nhs > 1)
467         {
468           hash_nhs = lm->next_hop_hash_lookup_key;
469           if (hash_nhs)
470             _vec_len (hash_nhs) = 0;
471           if (i > 0)
472             vec_add (hash_nhs, nhs + 0, i);
473           if (i + 1 < n_nhs)
474             vec_add (hash_nhs, nhs + i + 1, n_nhs - (i + 1));
475
476           new_madj_index = ip_multipath_adjacency_get (lm, hash_nhs, /* create_if_non_existent */ 1);
477
478           lm->next_hop_hash_lookup_key = hash_nhs;
479
480           if (new_madj_index == madj_index)
481             continue;
482
483           new_madj = vec_elt_at_index (lm->multipath_adjacencies, new_madj_index);
484         }
485
486       lm->adjacency_remap_table[madj->adj_index] = new_madj ? 1 + new_madj->adj_index : ~0;
487       lm->n_adjacency_remaps += 1;
488       ip_multipath_adjacency_free (lm, madj);
489     }
490 }
491
492 void
493 ip_multipath_adjacency_free (ip_lookup_main_t * lm,
494                              ip_multipath_adjacency_t * a)
495 {
496   hash_unset (lm->multipath_adjacency_by_next_hops,
497               ip_next_hop_hash_key_from_handle (a->normalized_next_hops.heap_handle));
498   heap_dealloc (lm->next_hop_heap, a->normalized_next_hops.heap_handle);
499   heap_dealloc (lm->next_hop_heap, a->unnormalized_next_hops.heap_handle);
500
501   ip_del_adjacency2 (lm, a->adj_index, a->reference_count == 0);
502   memset (a, 0, sizeof (a[0]));
503 }
504
505 always_inline ip_multipath_next_hop_t *
506 ip_next_hop_hash_key_get_next_hops (ip_lookup_main_t * lm, uword k,
507                                     uword * n_next_hops)
508 {
509   ip_multipath_next_hop_t * nhs;
510   uword n_nhs;
511   if (ip_next_hop_hash_key_is_heap_handle (k))
512     {
513       uword handle = ip_next_hop_hash_key_get_heap_handle (k);
514       nhs = heap_elt_with_handle (lm->next_hop_heap, handle);
515       n_nhs = heap_len (lm->next_hop_heap, handle);
516     }
517   else
518     {
519       nhs = uword_to_pointer (k, ip_multipath_next_hop_t *);
520       n_nhs = vec_len (nhs);
521     }
522   *n_next_hops = n_nhs;
523   return nhs;
524 }
525
526 static uword
527 ip_next_hop_hash_key_sum (hash_t * h, uword key0)
528 {
529   ip_lookup_main_t * lm = uword_to_pointer (h->user, ip_lookup_main_t *);  
530   ip_multipath_next_hop_t * k0;
531   uword n0;
532
533   k0 = ip_next_hop_hash_key_get_next_hops (lm, key0, &n0);
534   return hash_memory (k0, n0 * sizeof (k0[0]), /* seed */ n0);
535 }
536
537 static uword
538 ip_next_hop_hash_key_equal (hash_t * h, uword key0, uword key1)
539 {
540   ip_lookup_main_t * lm = uword_to_pointer (h->user, ip_lookup_main_t *);  
541   ip_multipath_next_hop_t * k0, * k1;
542   uword n0, n1;
543
544   k0 = ip_next_hop_hash_key_get_next_hops (lm, key0, &n0);
545   k1 = ip_next_hop_hash_key_get_next_hops (lm, key1, &n1);
546
547   return n0 == n1 && ! memcmp (k0, k1, n0 * sizeof (k0[0]));
548 }
549
550 clib_error_t *
551 ip_interface_address_add_del (ip_lookup_main_t * lm,
552                               u32 sw_if_index,
553                               void * addr_fib,
554                               u32 address_length,
555                               u32 is_del,
556                               u32 * result_if_address_index)
557 {
558   vnet_main_t * vnm = vnet_get_main();
559   ip_interface_address_t * a, * prev, * next;
560   uword * p = mhash_get (&lm->address_to_if_address_index, addr_fib);
561
562   vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
563   a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0;
564
565   /* Verify given length. */
566   if ((a && (address_length != a->address_length)) || (address_length == 0))
567     {
568       vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
569       return clib_error_create 
570         ( "%U wrong length (expected %d) for interface %U",
571           lm->format_address_and_length, addr_fib,
572           address_length, a? a->address_length : -1,
573           format_vnet_sw_if_index_name, vnm, sw_if_index);
574     }
575
576   if (is_del)
577     {
578       if (!a) 
579         {
580           vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, sw_if_index);
581           vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
582           return clib_error_create ("%U not found for interface %U",
583                                     lm->format_address_and_length, 
584                                     addr_fib, address_length,
585                                     format_vnet_sw_interface_name, vnm, si);
586         }
587
588       if (a->prev_this_sw_interface != ~0)
589         {
590           prev = pool_elt_at_index (lm->if_address_pool, a->prev_this_sw_interface);
591           prev->next_this_sw_interface = a->next_this_sw_interface;
592         }
593       if (a->next_this_sw_interface != ~0)
594         {
595           next = pool_elt_at_index (lm->if_address_pool, a->next_this_sw_interface);
596           next->prev_this_sw_interface = a->prev_this_sw_interface;
597
598           if(a->prev_this_sw_interface == ~0)
599                  lm->if_address_pool_index_by_sw_if_index[sw_if_index]  = a->next_this_sw_interface;
600         }
601
602       if ((a->next_this_sw_interface  == ~0) &&  (a->prev_this_sw_interface == ~0))
603         lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0;
604
605       mhash_unset (&lm->address_to_if_address_index, addr_fib,
606                    /* old_value */ 0);
607       pool_put (lm->if_address_pool, a);
608
609       if (result_if_address_index)
610         *result_if_address_index = ~0;
611     }
612
613   else if (! a)
614     {
615       u32 pi; /* previous index */
616       u32 ai; 
617       u32 hi; /* head index */
618
619       pool_get (lm->if_address_pool, a);
620       memset (a, ~0, sizeof (a[0]));
621       ai = a - lm->if_address_pool;
622
623       hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
624       prev = 0;
625       while (pi != (u32)~0)
626         {
627           prev = pool_elt_at_index(lm->if_address_pool, pi);
628           pi = prev->next_this_sw_interface;
629         }
630       pi = prev ? prev - lm->if_address_pool : (u32)~0;
631
632       a->address_key = mhash_set (&lm->address_to_if_address_index,
633                                   addr_fib, ai, /* old_value */ 0);
634       a->address_length = address_length;
635       a->sw_if_index = sw_if_index;
636       a->flags = 0;
637       a->prev_this_sw_interface = pi;
638       a->next_this_sw_interface = ~0;
639       if (prev)
640           prev->next_this_sw_interface = ai;
641
642       lm->if_address_pool_index_by_sw_if_index[sw_if_index] = 
643         (hi != ~0) ? hi : ai;
644       if (result_if_address_index)
645         *result_if_address_index = ai;
646     }
647   else
648     {
649       if (result_if_address_index)
650         *result_if_address_index = a - lm->if_address_pool;
651     }
652     
653
654   return /* no error */ 0;
655 }
656
657 void serialize_vec_ip_adjacency (serialize_main_t * m, va_list * va)
658 {
659   ip_adjacency_t * a = va_arg (*va, ip_adjacency_t *);
660   u32 n = va_arg (*va, u32);
661   u32 i;
662   for (i = 0; i < n; i++)
663     {
664       serialize_integer (m, a[i].heap_handle, sizeof (a[i].heap_handle));
665       serialize_integer (m, a[i].n_adj, sizeof (a[i].n_adj));
666       serialize_integer (m, a[i].lookup_next_index, sizeof (a[i].lookup_next_index_as_int));
667       switch (a[i].lookup_next_index)
668         {
669         case IP_LOOKUP_NEXT_LOCAL:
670           serialize_integer (m, a[i].if_address_index, sizeof (a[i].if_address_index));
671           break;
672
673         case IP_LOOKUP_NEXT_ARP:
674           serialize_integer (m, a[i].if_address_index, sizeof (a[i].if_address_index));
675           serialize_integer (m, a[i].rewrite_header.sw_if_index, sizeof (a[i].rewrite_header.sw_if_index));
676           break;
677
678         case IP_LOOKUP_NEXT_REWRITE:
679           serialize (m, serialize_vnet_rewrite, &a[i].rewrite_header, sizeof (a[i].rewrite_data));
680           break;
681
682         default:
683           /* nothing else to serialize. */
684           break;
685         }
686     }
687 }
688
689 void unserialize_vec_ip_adjacency (serialize_main_t * m, va_list * va)
690 {
691   ip_adjacency_t * a = va_arg (*va, ip_adjacency_t *);
692   u32 n = va_arg (*va, u32);
693   u32 i;
694   ip_poison_adjacencies (a, n);
695   for (i = 0; i < n; i++)
696     {
697       unserialize_integer (m, &a[i].heap_handle, sizeof (a[i].heap_handle));
698       unserialize_integer (m, &a[i].n_adj, sizeof (a[i].n_adj));
699       unserialize_integer (m, &a[i].lookup_next_index_as_int, sizeof (a[i].lookup_next_index_as_int));
700       switch (a[i].lookup_next_index)
701         {
702         case IP_LOOKUP_NEXT_LOCAL:
703           unserialize_integer (m, &a[i].if_address_index, sizeof (a[i].if_address_index));
704           break;
705
706         case IP_LOOKUP_NEXT_ARP:
707           unserialize_integer (m, &a[i].if_address_index, sizeof (a[i].if_address_index));
708           unserialize_integer (m, &a[i].rewrite_header.sw_if_index, sizeof (a[i].rewrite_header.sw_if_index));
709           break;
710
711         case IP_LOOKUP_NEXT_REWRITE:
712           unserialize (m, unserialize_vnet_rewrite, &a[i].rewrite_header, sizeof (a[i].rewrite_data));
713           break;
714
715         default:
716           /* nothing else to unserialize. */
717           break;
718         }
719     }
720 }
721
722 static void serialize_vec_ip_multipath_next_hop (serialize_main_t * m, va_list * va)
723 {
724   ip_multipath_next_hop_t * nh = va_arg (*va, ip_multipath_next_hop_t *);
725   u32 n = va_arg (*va, u32);
726   u32 i;
727   for (i = 0; i < n; i++)
728     {
729       serialize_integer (m, nh[i].next_hop_adj_index, sizeof (nh[i].next_hop_adj_index));
730       serialize_integer (m, nh[i].weight, sizeof (nh[i].weight));
731     }
732 }
733
734 static void unserialize_vec_ip_multipath_next_hop (serialize_main_t * m, va_list * va)
735 {
736   ip_multipath_next_hop_t * nh = va_arg (*va, ip_multipath_next_hop_t *);
737   u32 n = va_arg (*va, u32);
738   u32 i;
739   for (i = 0; i < n; i++)
740     {
741       unserialize_integer (m, &nh[i].next_hop_adj_index, sizeof (nh[i].next_hop_adj_index));
742       unserialize_integer (m, &nh[i].weight, sizeof (nh[i].weight));
743     }
744 }
745
746 static void serialize_vec_ip_multipath_adjacency (serialize_main_t * m, va_list * va)
747 {
748   ip_multipath_adjacency_t * a = va_arg (*va, ip_multipath_adjacency_t *);
749   u32 n = va_arg (*va, u32);
750   u32 i;
751   for (i = 0; i < n; i++)
752     {
753 #define foreach_ip_multipath_adjacency_field            \
754   _ (adj_index) _ (n_adj_in_block) _ (reference_count)  \
755   _ (normalized_next_hops.count)                        \
756   _ (normalized_next_hops.heap_offset)                  \
757   _ (normalized_next_hops.heap_handle)                  \
758   _ (unnormalized_next_hops.count)                      \
759   _ (unnormalized_next_hops.heap_offset)                \
760   _ (unnormalized_next_hops.heap_handle)
761
762 #define _(f) serialize_integer (m, a[i].f, sizeof (a[i].f));
763       foreach_ip_multipath_adjacency_field;
764 #undef _
765     }
766 }
767
768 static void unserialize_vec_ip_multipath_adjacency (serialize_main_t * m, va_list * va)
769 {
770   ip_multipath_adjacency_t * a = va_arg (*va, ip_multipath_adjacency_t *);
771   u32 n = va_arg (*va, u32);
772   u32 i;
773   for (i = 0; i < n; i++)
774     {
775 #define _(f) unserialize_integer (m, &a[i].f, sizeof (a[i].f));
776       foreach_ip_multipath_adjacency_field;
777 #undef _
778     }
779 }
780
781 void serialize_ip_lookup_main (serialize_main_t * m, va_list * va)
782 {
783   ip_lookup_main_t * lm = va_arg (*va, ip_lookup_main_t *);
784
785   /* If this isn't true you need to call e.g. ip4_maybe_remap_adjacencies
786      to make it true. */
787   ASSERT (lm->n_adjacency_remaps == 0);
788
789   serialize (m, serialize_heap, lm->adjacency_heap, serialize_vec_ip_adjacency);
790
791   serialize (m, serialize_heap, lm->next_hop_heap, serialize_vec_ip_multipath_next_hop);
792   vec_serialize (m, lm->multipath_adjacencies, serialize_vec_ip_multipath_adjacency);
793
794   /* Adjacency counters (FIXME disabled for now). */
795   if (0)
796     serialize (m, serialize_vlib_combined_counter_main, &lm->adjacency_counters, /* incremental */ 0);
797 }
798
799 void unserialize_ip_lookup_main (serialize_main_t * m, va_list * va)
800 {
801   ip_lookup_main_t * lm = va_arg (*va, ip_lookup_main_t *);
802
803   unserialize (m, unserialize_heap, &lm->adjacency_heap, unserialize_vec_ip_adjacency);
804   unserialize (m, unserialize_heap, &lm->next_hop_heap, unserialize_vec_ip_multipath_next_hop);
805   vec_unserialize (m, &lm->multipath_adjacencies, unserialize_vec_ip_multipath_adjacency);
806
807   /* Build hash table from unserialized data. */
808   {
809     ip_multipath_adjacency_t * a;
810
811     vec_foreach (a, lm->multipath_adjacencies)
812       {
813         if (a->n_adj_in_block > 0 && a->reference_count > 0)
814           hash_set (lm->multipath_adjacency_by_next_hops,
815                     ip_next_hop_hash_key_from_handle (a->normalized_next_hops.heap_handle),
816                     a - lm->multipath_adjacencies);
817       }
818   }
819
820   /* Validate adjacency counters. */
821   vlib_validate_combined_counter (&lm->adjacency_counters, 
822                                   vec_len (lm->adjacency_heap) - 1);
823
824   /* Adjacency counters (FIXME disabled for now). */
825   if (0)
826     unserialize (m, unserialize_vlib_combined_counter_main, &lm->adjacency_counters, /* incremental */ 0);
827 }
828
829 void ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
830 {
831   ip_adjacency_t * adj;
832
833   /* Hand-craft special miss adjacency to use when nothing matches in the
834      routing table.  Same for drop adjacency. */
835   adj = ip_add_adjacency (lm, /* template */ 0, /* n-adj */ 1, &lm->miss_adj_index);
836   adj->lookup_next_index = IP_LOOKUP_NEXT_MISS;
837   ASSERT (lm->miss_adj_index == IP_LOOKUP_MISS_ADJ_INDEX);
838
839   adj = ip_add_adjacency (lm, /* template */ 0, /* n-adj */ 1, &lm->drop_adj_index);
840   adj->lookup_next_index = IP_LOOKUP_NEXT_DROP;
841
842   adj = ip_add_adjacency (lm, /* template */ 0, /* n-adj */ 1, &lm->local_adj_index);
843   adj->lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
844   adj->if_address_index = ~0;
845
846   if (! lm->fib_result_n_bytes)
847     lm->fib_result_n_bytes = sizeof (uword);
848
849   lm->multipath_adjacency_by_next_hops
850     = hash_create2 (/* elts */ 0,
851                     /* user */ pointer_to_uword (lm),
852                     /* value_bytes */ sizeof (uword),
853                     ip_next_hop_hash_key_sum,
854                     ip_next_hop_hash_key_equal,
855                     /* format pair/arg */
856                     0, 0);
857
858   /* 1% max error tolerance for multipath. */
859   lm->multipath_next_hop_error_tolerance = .01;
860
861   lm->is_ip6 = is_ip6;
862   if (is_ip6)
863     {
864       lm->format_address_and_length = format_ip6_address_and_length;
865       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
866                   sizeof (ip6_address_fib_t));
867     }
868   else
869     {
870       lm->format_address_and_length = format_ip4_address_and_length;
871       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
872                   sizeof (ip4_address_fib_t));
873     }
874
875   {
876     int i;
877
878     /* Setup all IP protocols to be punted and builtin-unknown. */
879     for (i = 0; i < 256; i++)
880       {
881         lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
882         lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
883       }
884 #if 0
885     /* Eliot's TCP doesn't actually work */
886     lm->local_next_by_ip_protocol[IP_PROTOCOL_TCP] = IP_LOCAL_NEXT_TCP_LOOKUP;
887     lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_TCP] = 
888         IP_BUILTIN_PROTOCOL_TCP;
889 #endif
890
891     lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
892     lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
893     lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] = IP_BUILTIN_PROTOCOL_UDP;
894     lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_BUILTIN_PROTOCOL_ICMP;
895   }
896 }
897
898 u8 * format_ip_flow_hash_config (u8 * s, va_list * args)
899 {
900   u32 flow_hash_config = va_arg (*args, u32);
901     
902 #define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
903   foreach_flow_hash_bit;
904 #undef _
905
906   return s;
907 }
908
909 u8 * format_ip_lookup_next (u8 * s, va_list * args)
910 {
911   ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
912   char * t = 0;
913
914   switch (n)
915     {
916     default:
917       s = format (s, "unknown %d", n);
918       return s;
919
920     case IP_LOOKUP_NEXT_MISS: t = "miss"; break;
921     case IP_LOOKUP_NEXT_DROP: t = "drop"; break;
922     case IP_LOOKUP_NEXT_PUNT: t = "punt"; break;
923     case IP_LOOKUP_NEXT_LOCAL: t = "local"; break;
924     case IP_LOOKUP_NEXT_ARP: t = "arp"; break;
925     case IP_LOOKUP_NEXT_CLASSIFY: t = "classify"; break;
926     case IP_LOOKUP_NEXT_MAP: t = "map"; break;
927     case IP_LOOKUP_NEXT_MAP_T: t = "map-t"; break;
928     case IP_LOOKUP_NEXT_SIXRD: t = "sixrd"; break;
929     case IP_LOOKUP_NEXT_REWRITE:
930       break;
931     }
932
933   if (t)
934     vec_add (s, t, strlen (t));
935
936   return s;
937 }
938
939 static u8 * format_ip_interface_address (u8 * s, va_list * args)
940 {
941   ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
942   u32 if_address_index = va_arg (*args, u32);
943   ip_interface_address_t * ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
944   void * a = ip_interface_address_get_address (lm, ia);
945
946   if (lm->is_ip6)
947     return format (s, "%U", format_ip6_address_and_length, a, ia->address_length);
948   else
949     return format (s, "%U", format_ip4_address_and_length, a, ia->address_length);
950 }
951
952 u8 * format_ip_adjacency (u8 * s, va_list * args)
953 {
954   vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
955   ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
956   u32 adj_index = va_arg (*args, u32);
957   ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
958
959   switch (adj->lookup_next_index)
960     {
961     case IP_LOOKUP_NEXT_REWRITE:
962       s = format (s, "%U",
963                   format_vnet_rewrite,
964                   vnm->vlib_main, &adj->rewrite_header, sizeof (adj->rewrite_data));
965       break;
966
967     default:
968       s = format (s, "%U", format_ip_lookup_next, adj->lookup_next_index);
969       if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
970         s = format (s, " %U",
971                     format_vnet_sw_interface_name,
972                     vnm,
973                     vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index));
974       switch (adj->lookup_next_index)
975         {
976         case IP_LOOKUP_NEXT_ARP:
977         case IP_LOOKUP_NEXT_LOCAL:
978           if (adj->if_address_index != ~0)
979             s = format (s, " %U", format_ip_interface_address, lm, adj->if_address_index);
980           break;
981
982         case IP_LOOKUP_NEXT_CLASSIFY:
983             s = format (s, " table %d", adj->classify_table_index);
984
985         default:
986           break;
987         }
988       break;
989     }
990   if (adj->explicit_fib_index != ~0 && adj->explicit_fib_index != 0)
991     s = format (s, " lookup fib index %d", adj->explicit_fib_index);
992
993   return s;
994 }
995
996 u8 * format_ip_adjacency_packet_data (u8 * s, va_list * args)
997 {
998   vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
999   ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
1000   u32 adj_index = va_arg (*args, u32);
1001   u8 * packet_data = va_arg (*args, u8 *);
1002   u32 n_packet_data_bytes = va_arg (*args, u32);
1003   ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
1004
1005   switch (adj->lookup_next_index)
1006     {
1007     case IP_LOOKUP_NEXT_REWRITE:
1008       s = format (s, "%U",
1009                   format_vnet_rewrite_header,
1010                   vnm->vlib_main, &adj->rewrite_header, packet_data, n_packet_data_bytes);
1011       break;
1012
1013     default:
1014       break;
1015     }
1016
1017   return s;
1018 }
1019
1020 static uword unformat_ip_lookup_next (unformat_input_t * input, va_list * args)
1021 {
1022   ip_lookup_next_t * result = va_arg (*args, ip_lookup_next_t *);
1023   ip_lookup_next_t n;
1024
1025   if (unformat (input, "drop"))
1026     n = IP_LOOKUP_NEXT_DROP;
1027
1028   else if (unformat (input, "punt"))
1029     n = IP_LOOKUP_NEXT_PUNT;
1030
1031   else if (unformat (input, "local"))
1032     n = IP_LOOKUP_NEXT_LOCAL;
1033
1034   else if (unformat (input, "arp"))
1035     n = IP_LOOKUP_NEXT_ARP;
1036
1037   else if (unformat (input, "classify"))
1038     n = IP_LOOKUP_NEXT_CLASSIFY;
1039
1040   else
1041     return 0;
1042     
1043   *result = n;
1044   return 1;
1045 }
1046
1047 static uword unformat_ip_adjacency (unformat_input_t * input, va_list * args)
1048 {
1049   vlib_main_t * vm = va_arg (*args, vlib_main_t *);
1050   ip_adjacency_t * adj = va_arg (*args, ip_adjacency_t *);
1051   u32 node_index = va_arg (*args, u32);
1052   vnet_main_t * vnm = vnet_get_main();
1053   u32 sw_if_index, is_ip6;
1054   ip46_address_t a46;
1055   ip_lookup_next_t next;
1056
1057   is_ip6 = node_index == ip6_rewrite_node.index;
1058   adj->rewrite_header.node_index = node_index;
1059   adj->explicit_fib_index = ~0;
1060
1061   if (unformat (input, "arp %U %U",
1062                 unformat_vnet_sw_interface, vnm, &sw_if_index,
1063                 unformat_ip46_address, &a46, is_ip6))
1064     {
1065       ip_lookup_main_t * lm = is_ip6 ? &ip6_main.lookup_main : &ip4_main.lookup_main;
1066       ip_adjacency_t * a_adj;
1067       u32 adj_index;
1068
1069       if (is_ip6)
1070         adj_index = ip6_fib_lookup (&ip6_main, sw_if_index, &a46.ip6);
1071       else
1072         adj_index = ip4_fib_lookup (&ip4_main, sw_if_index, &a46.ip4);
1073
1074       a_adj = ip_get_adjacency (lm, adj_index);
1075
1076       if (a_adj->rewrite_header.sw_if_index != sw_if_index)
1077         return 0;
1078
1079       if (is_ip6)
1080         ip6_adjacency_set_interface_route (vnm, adj, sw_if_index, a_adj->if_address_index);
1081       else
1082         ip4_adjacency_set_interface_route (vnm, adj, sw_if_index, a_adj->if_address_index);
1083     }
1084
1085   else if (unformat_user (input, unformat_ip_lookup_next, &next))
1086     {
1087       adj->lookup_next_index = next;
1088       adj->if_address_index = ~0;
1089       if (next == IP_LOOKUP_NEXT_LOCAL)
1090         (void) unformat (input, "%d", &adj->if_address_index);
1091       else if (next == IP_LOOKUP_NEXT_CLASSIFY)
1092         if (!unformat (input, "%d", &adj->classify_table_index))
1093           {
1094             clib_warning ("classify adj must specify table index");
1095             return 0;
1096           }
1097     }
1098
1099   else if (unformat_user (input,
1100                           unformat_vnet_rewrite,
1101                           vm, &adj->rewrite_header, sizeof (adj->rewrite_data)))
1102     adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1103
1104   else
1105     return 0;
1106
1107   return 1;
1108 }
1109
1110 clib_error_t *
1111 vnet_ip_route_cmd (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
1112 {
1113   vnet_main_t * vnm = vnet_get_main();
1114   clib_error_t * error = 0;
1115   u32 table_id, is_del;
1116   u32 weight, * weights = 0;
1117   u32 * table_ids = 0;
1118   u32 sw_if_index, * sw_if_indices = 0;
1119   ip4_address_t ip4_addr, * ip4_dst_addresses = 0, * ip4_via_next_hops = 0;
1120   ip6_address_t ip6_addr, * ip6_dst_addresses = 0, * ip6_via_next_hops = 0;
1121   u32 dst_address_length, * dst_address_lengths = 0;
1122   ip_adjacency_t parse_adj, * add_adj = 0;
1123   unformat_input_t _line_input, * line_input = &_line_input;
1124   f64 count;
1125   u32 outer_table_id;
1126
1127   is_del = 0;
1128   table_id = 0;
1129   count = 1;
1130
1131   /* Get a line of input. */
1132   if (! unformat_user (main_input, unformat_line_input, line_input))
1133     return 0;
1134
1135   memset(&parse_adj, 0, sizeof (parse_adj));
1136
1137   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1138     {
1139       if (unformat (line_input, "table %d", &table_id))
1140         ;
1141       else if (unformat (line_input, "del"))
1142         is_del = 1;
1143       else if (unformat (line_input, "add"))
1144         is_del = 0;
1145       else if (unformat (line_input, "count %f", &count))
1146         ;
1147
1148       else if (unformat (line_input, "%U/%d",
1149                          unformat_ip4_address, &ip4_addr,
1150                          &dst_address_length))
1151         {
1152           vec_add1 (ip4_dst_addresses, ip4_addr);
1153           vec_add1 (dst_address_lengths, dst_address_length);
1154         }
1155
1156       else if (unformat (line_input, "%U/%d",
1157                          unformat_ip6_address, &ip6_addr,
1158                          &dst_address_length))
1159         {
1160           vec_add1 (ip6_dst_addresses, ip6_addr);
1161           vec_add1 (dst_address_lengths, dst_address_length);
1162         }
1163
1164       else if (unformat (line_input, "via %U %U weight %u",
1165                          unformat_ip4_address, &ip4_addr,
1166                          unformat_vnet_sw_interface, vnm, &sw_if_index,
1167                          &weight))
1168         {
1169           vec_add1 (ip4_via_next_hops, ip4_addr);
1170           vec_add1 (sw_if_indices, sw_if_index);
1171           vec_add1 (weights, weight);
1172           vec_add1 (table_ids, (u32)~0);
1173         }
1174
1175       else if (unformat (line_input, "via %U %U weight %u",
1176                          unformat_ip6_address, &ip6_addr,
1177                          unformat_vnet_sw_interface, vnm, &sw_if_index,
1178                          &weight))
1179         {
1180           vec_add1 (ip6_via_next_hops, ip6_addr);
1181           vec_add1 (sw_if_indices, sw_if_index);
1182           vec_add1 (weights, weight);
1183           vec_add1 (table_ids, (u32)~0);
1184         }
1185
1186       else if (unformat (line_input, "via %U %U",
1187                          unformat_ip4_address, &ip4_addr,
1188                          unformat_vnet_sw_interface, vnm, &sw_if_index))
1189         {
1190           vec_add1 (ip4_via_next_hops, ip4_addr);
1191           vec_add1 (sw_if_indices, sw_if_index);
1192           vec_add1 (weights, 1);
1193           vec_add1 (table_ids, (u32)~0);
1194         }
1195                          
1196       else if (unformat (line_input, "via %U %U",
1197                          unformat_ip6_address, &ip6_addr,
1198                          unformat_vnet_sw_interface, vnm, &sw_if_index))
1199         {
1200           vec_add1 (ip6_via_next_hops, ip6_addr);
1201           vec_add1 (sw_if_indices, sw_if_index);
1202           vec_add1 (weights, 1);
1203           vec_add1 (table_ids, (u32)~0);
1204         }
1205       else if (unformat (line_input, "via %U",
1206                          unformat_ip4_address, &ip4_addr))
1207         {
1208           vec_add1 (ip4_via_next_hops, ip4_addr);
1209           vec_add1 (sw_if_indices, (u32)~0);
1210           vec_add1 (weights, 1);
1211           vec_add1 (table_ids, table_id);
1212         }
1213       else if (unformat (line_input, "via %U",
1214                          unformat_ip6_address, &ip6_addr))
1215         {
1216           vec_add1 (ip6_via_next_hops, ip6_addr);
1217           vec_add1 (sw_if_indices, (u32)~0);
1218           vec_add1 (weights, 1);
1219           vec_add1 (table_ids, (u32)table_id);
1220         }
1221                          
1222       else if (vec_len (ip4_dst_addresses) > 0
1223                && unformat (line_input, "via %U",
1224                             unformat_ip_adjacency, vm, &parse_adj, ip4_rewrite_node.index))
1225           vec_add1 (add_adj, parse_adj);
1226
1227       else if (vec_len (ip6_dst_addresses) > 0
1228                && unformat (line_input, "via %U",
1229                             unformat_ip_adjacency, vm, &parse_adj, ip6_rewrite_node.index))
1230         vec_add1 (add_adj, parse_adj);
1231       else if (unformat (line_input, "lookup in table %d", &outer_table_id))
1232         {
1233           uword * p;
1234
1235           if (vec_len (ip4_dst_addresses) > 0)
1236             p = hash_get (ip4_main.fib_index_by_table_id, outer_table_id);
1237           else
1238             p = hash_get (ip6_main.fib_index_by_table_id, outer_table_id);
1239
1240           if (p == 0)
1241             {
1242               error = clib_error_return (0, "Nonexistent outer table id %d", 
1243                                          outer_table_id);
1244               goto done;
1245             }
1246
1247           parse_adj.lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
1248           parse_adj.explicit_fib_index = p[0];
1249           vec_add1 (add_adj, parse_adj);
1250         }
1251       else
1252         {
1253           error = unformat_parse_error (line_input);
1254           goto done;
1255         }
1256     }
1257     
1258   unformat_free (line_input);
1259
1260   if (vec_len (ip4_dst_addresses) + vec_len (ip6_dst_addresses) == 0)
1261     {
1262       error = clib_error_return (0, "expected ip4/ip6 destination address/length.");
1263       goto done;
1264     }
1265
1266   if (vec_len (ip4_dst_addresses) > 0 && vec_len (ip6_dst_addresses) > 0)
1267     {
1268       error = clib_error_return (0, "mixed ip4/ip6 address/length.");
1269       goto done;
1270     }
1271
1272   if (vec_len (ip4_dst_addresses) > 0 && vec_len (ip6_via_next_hops) > 0)
1273     {
1274       error = clib_error_return (0, "ip4 destinations with ip6 next hops.");
1275       goto done;
1276     }
1277
1278   if (vec_len (ip6_dst_addresses) > 0 && vec_len (ip4_via_next_hops) > 0)
1279     {
1280       error = clib_error_return (0, "ip6 destinations with ip4 next hops.");
1281       goto done;
1282     }
1283
1284   if (! is_del && vec_len (add_adj) + vec_len (weights) == 0)
1285     {
1286       error = clib_error_return (0, "no next hops or adjacencies to add.");
1287       goto done;
1288     }
1289
1290   if (vec_len(ip4_via_next_hops))
1291     {
1292       if (sw_if_indices[0] == (u32)~0)
1293         {
1294           u32 ai;
1295           uword * p;
1296           u32 fib_index;
1297           ip_adjacency_t *nh_adj;
1298
1299           p = hash_get (ip4_main.fib_index_by_table_id, table_ids[0]);
1300           if (p == 0)
1301             {
1302               error = clib_error_return (0, "Nonexistent FIB id %d",
1303                                          table_ids[0]);
1304               goto done;
1305             }
1306
1307           fib_index = p[0];
1308
1309           ai = ip4_fib_lookup_with_table (&ip4_main,
1310                                           fib_index,
1311                                           ip4_via_next_hops,
1312                                           1 /* disable default route */);
1313           if (ai == 0)
1314             {
1315               error = clib_error_return (0, "next hop %U not in FIB",
1316                                          format_ip4_address,
1317                                          ip4_via_next_hops);
1318               goto done;
1319             }
1320           nh_adj = ip_get_adjacency (&ip4_main.lookup_main, ai);
1321           vec_add1 (add_adj, nh_adj[0]);
1322         }
1323     }
1324   if (vec_len(ip6_via_next_hops))
1325     {
1326       if (sw_if_indices[0] == (u32)~0)
1327         {
1328           u32 ai;
1329           uword * p;
1330           u32 fib_index;
1331           ip_adjacency_t *nh_adj;
1332
1333           p = hash_get (ip6_main.fib_index_by_table_id, table_ids[0]);
1334           if (p == 0)
1335             {
1336               error = clib_error_return (0, "Nonexistent FIB id %d",
1337                                          table_ids[0]);
1338               goto done;
1339             }
1340
1341           fib_index = p[0];
1342           ai = ip6_fib_lookup_with_table (&ip6_main,
1343                                           fib_index,
1344                                           ip6_via_next_hops);
1345           if (ai == 0)
1346             {
1347               error = clib_error_return (0, "next hop %U not in FIB",
1348                                          format_ip6_address,
1349                                          ip6_via_next_hops);
1350               goto done;
1351             }
1352           nh_adj = ip_get_adjacency (&ip6_main.lookup_main, ai);
1353           vec_add1 (add_adj, nh_adj[0]);
1354         }
1355     }
1356
1357   {
1358     int i;
1359     ip4_main_t * im4 = &ip4_main;
1360     ip6_main_t * im6 = &ip6_main;
1361
1362     for (i = 0; i < vec_len (ip4_dst_addresses); i++)
1363       {
1364         ip4_add_del_route_args_t a;
1365
1366         memset (&a, 0, sizeof (a));
1367         a.flags = IP4_ROUTE_FLAG_TABLE_ID;
1368         a.table_index_or_table_id = table_id;
1369         a.dst_address = ip4_dst_addresses[i];
1370         a.dst_address_length = dst_address_lengths[i];
1371         a.adj_index = ~0;
1372
1373         if (is_del)
1374           {
1375             if (vec_len (ip4_via_next_hops) == 0)
1376               {
1377                 uword * dst_hash, * dst_result;
1378                 u32 dst_address_u32;
1379                 ip4_fib_t * fib;
1380
1381                 fib = find_ip4_fib_by_table_index_or_id (im4, table_id, 
1382                                                          0 /* by table id */);
1383
1384                 a.flags |= IP4_ROUTE_FLAG_DEL;
1385                 dst_address_u32 = a.dst_address.as_u32 
1386                   & im4->fib_masks[a.dst_address_length];
1387
1388                 dst_hash = 
1389                   fib->adj_index_by_dst_address[a.dst_address_length];
1390                 dst_result = hash_get (dst_hash, dst_address_u32);
1391                 if (dst_result)
1392                   a.adj_index = dst_result[0];
1393                 else
1394                   {
1395                     clib_warning ("%U/%d not in FIB",
1396                                   format_ip4_address, &a.dst_address,
1397                                   a.dst_address_length);
1398                     continue;
1399                   }
1400
1401                 ip4_add_del_route (im4, &a);
1402                 ip4_maybe_remap_adjacencies (im4, table_id, 
1403                                              IP4_ROUTE_FLAG_TABLE_ID);
1404               }
1405             else
1406               {
1407                 u32 i, j, n, f, incr;
1408                 ip4_address_t dst = a.dst_address;
1409                 f64 t[2];
1410                 n = count;
1411                 t[0] = vlib_time_now (vm);
1412                 incr = 1<<(32 - a.dst_address_length);
1413                 for (i = 0; i < n; i++)
1414                   {
1415                     f = i + 1 < n ? IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP : 0;
1416                     a.dst_address = dst;
1417                     for (j = 0; j < vec_len (ip4_via_next_hops); j++)
1418                       {
1419                         if (table_ids[j] != (u32)~0)
1420                           {
1421                             uword * p = hash_get (im4->fib_index_by_table_id, 
1422                                                   table_ids[j]);
1423                             if (p == 0) 
1424                               {
1425                                 clib_warning ("no such FIB table %d",
1426                                               table_ids[j]);
1427                                 continue;
1428                               }
1429                             table_ids[j] = p[0];
1430                           }
1431                         
1432                         ip4_add_del_route_next_hop (im4,
1433                                                     IP4_ROUTE_FLAG_DEL | f,
1434                                                     &a.dst_address,
1435                                                     a.dst_address_length,
1436                                                     &ip4_via_next_hops[j],
1437                                                     sw_if_indices[j],
1438                                                     weights[j], (u32)~0, 
1439                                                     table_ids[j] /* fib index */);
1440                       }
1441                     dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
1442                   }
1443                 t[1] = vlib_time_now (vm);
1444                 if (count > 1)
1445                   vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
1446               }
1447           }
1448         else
1449           {
1450             if (vec_len (add_adj) > 0)
1451               {
1452                 a.flags |= IP4_ROUTE_FLAG_ADD;
1453                 a.add_adj = add_adj;
1454                 a.n_add_adj = vec_len (add_adj);
1455               
1456                 ip4_add_del_route (im4, &a);
1457               }
1458             else if (vec_len (ip4_via_next_hops) > 0)
1459               {
1460                 u32 i, j, n, f, incr;
1461                 ip4_address_t dst = a.dst_address;
1462                 f64 t[2];
1463                 n = count;
1464                 t[0] = vlib_time_now (vm);
1465                 incr = 1<<(32 - a.dst_address_length);
1466                 for (i = 0; i < n; i++)
1467                   {
1468                     f = i + 1 < n ? IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP : 0;
1469                     a.dst_address = dst;
1470                     for (j = 0; j < vec_len (ip4_via_next_hops); j++)
1471                       {
1472                         if (table_ids[j] != (u32)~0)
1473                           {
1474                             uword * p = hash_get (im4->fib_index_by_table_id, 
1475                                                   table_ids[j]);
1476                             if (p == 0) 
1477                               {
1478                                 clib_warning ("no such FIB table %d",
1479                                               table_ids[j]);
1480                                 continue;
1481                               }
1482                             table_ids[j] = p[0];
1483                           }
1484                       ip4_add_del_route_next_hop (im4,
1485                                                   IP4_ROUTE_FLAG_ADD | f,
1486                                                   &a.dst_address,
1487                                                   a.dst_address_length,
1488                                                   &ip4_via_next_hops[j],
1489                                                   sw_if_indices[j],
1490                                                   weights[j], (u32)~0, 
1491                                                   table_ids[j] /* fib index */);
1492                       }
1493                     dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
1494                   }
1495                 t[1] = vlib_time_now (vm);
1496                 if (count > 1)
1497                   vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
1498               }
1499           }
1500       }
1501
1502     for (i = 0; i < vec_len (ip6_dst_addresses); i++)
1503       {
1504         ip6_add_del_route_args_t a;
1505         
1506
1507         memset (&a, 0, sizeof (a));
1508         a.flags = IP6_ROUTE_FLAG_TABLE_ID;
1509         a.table_index_or_table_id = table_id;
1510         a.dst_address = ip6_dst_addresses[i];
1511         a.dst_address_length = dst_address_lengths[i];
1512         a.adj_index = ~0;
1513
1514         if (is_del)
1515           {
1516             if (vec_len (ip6_via_next_hops) == 0)
1517               {
1518                 BVT(clib_bihash_kv) kv, value;
1519                 ip6_address_t dst_address;
1520                 ip6_fib_t * fib;
1521
1522                 fib = find_ip6_fib_by_table_index_or_id (im6, table_id, 
1523                                                          0 /* by table id */);
1524
1525                 a.flags |= IP4_ROUTE_FLAG_DEL;
1526
1527                 dst_address = ip6_dst_addresses[i];
1528
1529                 ip6_address_mask (&dst_address, 
1530                                   &im6->fib_masks[dst_address_length]);
1531                 
1532                 kv.key[0] = dst_address.as_u64[0];
1533                 kv.key[1] = dst_address.as_u64[1];
1534                 kv.key[2] = ((u64)(fib - im6->fibs)<<32)
1535                   | a.dst_address_length;
1536                 
1537                 if (BV(clib_bihash_search)(&im6->ip6_lookup_table,
1538                                            &kv, &value) == 0)
1539                   a.adj_index = value.value;
1540                 else
1541                   {
1542                     clib_warning ("%U/%d not in FIB",
1543                                   format_ip6_address, &a.dst_address,
1544                                   a.dst_address_length);
1545                     continue;
1546                   }
1547                 
1548                 a.flags |= IP6_ROUTE_FLAG_DEL;
1549                 ip6_add_del_route (im6, &a);
1550                 ip6_maybe_remap_adjacencies (im6, table_id, 
1551                                              IP6_ROUTE_FLAG_TABLE_ID);
1552               }
1553             else
1554               {
1555                 u32 i;
1556                 for (i = 0; i < vec_len (ip6_via_next_hops); i++)
1557                   {
1558                     ip6_add_del_route_next_hop (im6,
1559                                                 IP6_ROUTE_FLAG_DEL,
1560                                                 &a.dst_address,
1561                                                 a.dst_address_length,
1562                                                 &ip6_via_next_hops[i],
1563                                                 sw_if_indices[i],
1564                                                 weights[i], (u32)~0,
1565                                                 table_ids[i] /* fib index */);
1566                   }
1567               }
1568           }
1569         else
1570           {
1571             if (vec_len (add_adj) > 0)
1572               {
1573                 a.flags |= IP6_ROUTE_FLAG_ADD;
1574                 a.add_adj = add_adj;
1575                 a.n_add_adj = vec_len (add_adj);
1576               
1577                 ip6_add_del_route (im6, &a);
1578               }
1579             else if (vec_len (ip6_via_next_hops) > 0)
1580               {
1581                 u32 i;
1582                 for (i = 0; i < vec_len (ip6_via_next_hops); i++)
1583                   {
1584                     ip6_add_del_route_next_hop (im6,
1585                                                 IP6_ROUTE_FLAG_ADD,
1586                                                 &a.dst_address,
1587                                                 a.dst_address_length,
1588                                                 &ip6_via_next_hops[i],
1589                                                 sw_if_indices[i],
1590                                                 weights[i], (u32)~0,
1591                                                 table_ids[i]);
1592                   }
1593               }
1594           }
1595       }
1596   }
1597
1598  done:
1599   vec_free (add_adj);
1600   vec_free (weights);
1601   vec_free (dst_address_lengths);
1602   vec_free (ip4_dst_addresses);
1603   vec_free (ip6_dst_addresses);
1604   vec_free (ip4_via_next_hops);
1605   vec_free (ip6_via_next_hops);
1606   return error;
1607 }
1608
1609 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
1610   .path = "ip",
1611   .short_help = "Internet protocol (IP) commands",
1612 };
1613
1614 VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
1615   .path = "show ip",
1616   .short_help = "Internet protocol (IP) show commands",
1617 };
1618
1619 VLIB_CLI_COMMAND (vlib_cli_show_ip4_command, static) = {
1620   .path = "show ip4",
1621   .short_help = "Internet protocol version 4 (IP4) show commands",
1622 };
1623
1624 VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
1625   .path = "show ip6",
1626   .short_help = "Internet protocol version 6 (IP6) show commands",
1627 };
1628
1629 VLIB_CLI_COMMAND (ip_route_command, static) = {
1630   .path = "ip route",
1631   .short_help = "Add/delete IP routes",
1632   .function = vnet_ip_route_cmd,
1633 };
1634
1635 /* 
1636  * The next two routines address a longstanding script hemorrhoid.
1637  * Probing a v4 or v6 neighbor needs to appear to be synchronous,
1638  * or dependent route-adds will simply fail.
1639  */
1640 static clib_error_t *
1641 ip6_probe_neighbor_wait (vlib_main_t *vm, ip6_address_t * a, u32 sw_if_index,
1642                          int retry_count)
1643 {
1644   vnet_main_t * vnm = vnet_get_main();
1645   clib_error_t * e;
1646   int i;
1647   int resolved = 0;
1648   uword event_type;
1649   uword *event_data = 0;
1650
1651   ASSERT (vlib_in_process_context(vm));
1652
1653   if (retry_count > 0)
1654     vnet_register_ip6_neighbor_resolution_event 
1655       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1656        1 /* event */, 0 /* data */);
1657
1658   for (i = 0; i < retry_count; i++)
1659     {
1660       /* The interface may be down, etc. */
1661       e = ip6_probe_neighbor (vm, a, sw_if_index);
1662       
1663       if (e)
1664         return e;
1665       
1666       vlib_process_wait_for_event_or_clock (vm, 1.0);
1667       event_type = vlib_process_get_events (vm, &event_data);
1668       switch (event_type) 
1669         {
1670         case 1: /* resolved... */
1671           vlib_cli_output (vm, "Resolved %U", 
1672                            format_ip6_address, a);
1673           resolved = 1;
1674           goto done;
1675           
1676         case ~0: /* timeout */
1677           break;
1678           
1679         default:
1680           clib_warning ("unknown event_type %d", event_type);
1681         }
1682     }
1683   
1684  done:
1685   vec_reset_length (event_data);
1686
1687   if (!resolved)
1688     return clib_error_return (0, "Resolution failed for %U",
1689                               format_ip6_address, a);
1690   return 0;
1691 }
1692
1693 static clib_error_t *
1694 ip4_probe_neighbor_wait (vlib_main_t *vm, ip4_address_t * a, u32 sw_if_index,
1695                          int retry_count)
1696 {
1697   vnet_main_t * vnm = vnet_get_main();
1698   clib_error_t * e;
1699   int i;
1700   int resolved = 0;
1701   uword event_type;
1702   uword *event_data = 0;
1703
1704   ASSERT (vlib_in_process_context(vm));
1705
1706   if (retry_count > 0)
1707     vnet_register_ip4_arp_resolution_event 
1708       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1709        1 /* event */, 0 /* data */);
1710   
1711   for (i = 0; i < retry_count; i++)
1712     {
1713       /* The interface may be down, etc. */
1714       e = ip4_probe_neighbor (vm, a, sw_if_index);
1715       
1716       if (e)
1717         return e;
1718       
1719       vlib_process_wait_for_event_or_clock (vm, 1.0);
1720       event_type = vlib_process_get_events (vm, &event_data);
1721       switch (event_type) 
1722         {
1723         case 1: /* resolved... */
1724           vlib_cli_output (vm, "Resolved %U", 
1725                            format_ip4_address, a);
1726           resolved = 1;
1727           goto done;
1728           
1729         case ~0: /* timeout */
1730           break;
1731           
1732         default:
1733           clib_warning ("unknown event_type %d", event_type);
1734         }
1735     }
1736   
1737  done:
1738
1739   vec_reset_length (event_data);
1740
1741   if (!resolved)
1742     return clib_error_return (0, "Resolution failed for %U",
1743                               format_ip4_address, a);
1744   return 0;
1745 }
1746
1747 static clib_error_t *
1748 probe_neighbor_address (vlib_main_t * vm,
1749                         unformat_input_t * input,
1750                         vlib_cli_command_t * cmd)
1751 {
1752   vnet_main_t * vnm = vnet_get_main();
1753   unformat_input_t _line_input, * line_input = &_line_input;
1754   ip4_address_t a4;
1755   ip6_address_t a6;
1756   clib_error_t * error = 0;
1757   u32 sw_if_index = ~0;
1758   int retry_count = 3;
1759   int is_ip4 = 1;
1760   int address_set = 0;
1761
1762   /* Get a line of input. */
1763   if (! unformat_user (input, unformat_line_input, line_input))
1764     return 0;
1765
1766   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) 
1767     {
1768       if (unformat_user (line_input, unformat_vnet_sw_interface, vnm, 
1769                          &sw_if_index))
1770         ;
1771       else if (unformat (line_input, "retry %d", &retry_count))
1772         ;
1773
1774       else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
1775         address_set++;
1776       else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
1777         {
1778           address_set++;
1779           is_ip4 = 0;
1780         }
1781       else
1782         return clib_error_return (0, "unknown input '%U'",
1783                                   format_unformat_error, line_input);
1784     }
1785
1786   unformat_free (line_input);
1787
1788   if (sw_if_index == ~0)
1789     return clib_error_return (0, "Interface required, not set.");
1790   if (address_set == 0)
1791     return clib_error_return (0, "ip address required, not set.");
1792   if (address_set > 1)
1793     return clib_error_return (0, "Multiple ip addresses not supported.");
1794     
1795   if (is_ip4)
1796     error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
1797   else 
1798     error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
1799
1800   return error;
1801 }
1802
1803 VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
1804   .path = "ip probe-neighbor",
1805   .function = probe_neighbor_address,
1806   .short_help = "ip probe-neighbor <intfc> <ip4-addr> | <ip6-addr> [retry nn]",
1807 };
1808
1809 typedef CLIB_PACKED (struct {
1810   ip4_address_t address;
1811
1812   u32 address_length : 6;
1813
1814   u32 index : 26;
1815 }) ip4_route_t;
1816
1817 static clib_error_t *
1818 ip4_show_fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1819 {
1820   vnet_main_t * vnm = vnet_get_main();
1821   ip4_main_t * im4 = &ip4_main;
1822   ip4_route_t * routes, * r;
1823   ip4_fib_t * fib;
1824   ip_lookup_main_t * lm = &im4->lookup_main;
1825   uword * results, i;
1826   int verbose, matching, mtrie, include_empty_fibs;
1827   ip4_address_t matching_address;
1828   u8 clear = 0;
1829   int table_id = -1;
1830
1831   routes = 0;
1832   results = 0;
1833   verbose = 1;
1834   include_empty_fibs = 0;
1835   matching = 0;
1836   mtrie = 0;
1837   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1838     {
1839       if (unformat (input, "brief") || unformat (input, "summary")
1840           || unformat (input, "sum"))
1841         verbose = 0;
1842
1843       else if (unformat (input, "mtrie"))
1844         mtrie = 1;
1845
1846       else if (unformat (input, "include-empty"))
1847         include_empty_fibs = 1;
1848
1849       else if (unformat (input, "%U", unformat_ip4_address, &matching_address))
1850         matching = 1;
1851
1852       else if (unformat (input, "clear"))
1853         clear = 1;
1854
1855       else if (unformat (input, "table %d", &table_id))
1856                ;
1857       else
1858         break;
1859     }
1860
1861   vec_foreach (fib, im4->fibs)
1862     {
1863       int fib_not_empty;
1864
1865       fib_not_empty = 0;
1866       for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1867         {
1868           uword * hash = fib->adj_index_by_dst_address[i];
1869           uword n_elts = hash_elts (hash);
1870           if (n_elts)
1871             {
1872               fib_not_empty = 1;
1873               break;
1874             }
1875         }
1876       
1877       if (fib_not_empty == 0 && include_empty_fibs == 0)
1878         continue;
1879
1880       if (table_id >= 0 && table_id != (int)fib->table_id)
1881         continue;
1882
1883       if (include_empty_fibs)
1884           vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U", 
1885                            fib->table_id, fib - im4->fibs,
1886                            format_ip_flow_hash_config, fib->flow_hash_config);
1887
1888       /* Show summary? */
1889       if (! verbose)
1890         {
1891         if (include_empty_fibs == 0)
1892             vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U", 
1893                              fib->table_id, fib - im4->fibs,
1894                              format_ip_flow_hash_config, fib->flow_hash_config);
1895           vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
1896           for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1897             {
1898               uword * hash = fib->adj_index_by_dst_address[i];
1899               uword n_elts = hash_elts (hash);
1900               if (n_elts > 0)
1901                 vlib_cli_output (vm, "%20d%16d", i, n_elts);
1902             }
1903           continue;
1904         }
1905
1906       if (routes)
1907         _vec_len (routes) = 0;
1908       if (results)
1909         _vec_len (results) = 0;
1910
1911       for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1912         {
1913           uword * hash = fib->adj_index_by_dst_address[i];
1914           hash_pair_t * p;
1915           ip4_route_t x;
1916
1917           x.address_length = i;
1918
1919           if (matching)
1920             {
1921               x.address.as_u32 = matching_address.as_u32 & im4->fib_masks[i];
1922               p = hash_get_pair (hash, x.address.as_u32);
1923               if (p)
1924                 {
1925                   if (lm->fib_result_n_words > 1)
1926                     {
1927                       x.index = vec_len (results);
1928                       vec_add (results, p->value, lm->fib_result_n_words);
1929                     }
1930                   else
1931                     x.index = p->value[0];
1932                   vec_add1 (routes, x);
1933                 }
1934             }
1935           else
1936             {
1937               hash_foreach_pair (p, hash, ({
1938                 x.address.data_u32 = p->key;
1939                 if (lm->fib_result_n_words > 1)
1940                   {
1941                     x.index = vec_len (results);
1942                     vec_add (results, p->value, lm->fib_result_n_words);
1943                   }
1944                 else
1945                   x.index = p->value[0];
1946
1947                 vec_add1 (routes, x);
1948               }));
1949             }
1950         }
1951
1952       vec_sort (routes, r1, r2,
1953                 ({ int cmp = ip4_address_compare (&r1->address, &r2->address);
1954                   cmp ? cmp : ((int) r1->address_length - (int) r2->address_length); }));
1955       if (vec_len(routes)) {
1956           if (include_empty_fibs == 0)
1957               vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U", 
1958                                fib->table_id, fib - im4->fibs,
1959                                format_ip_flow_hash_config, fib->flow_hash_config);
1960           if (mtrie)
1961               vlib_cli_output (vm, "%U", format_ip4_fib_mtrie, &fib->mtrie);
1962           vlib_cli_output (vm, "%=20s%=16s%=16s%=16s",
1963                            "Destination", "Packets", "Bytes", "Adjacency");
1964       }
1965       vec_foreach (r, routes)
1966         {
1967           vlib_counter_t c, sum;
1968           uword i, j, n_left, n_nhs, adj_index, * result = 0;
1969           ip_adjacency_t * adj;
1970           ip_multipath_next_hop_t * nhs, tmp_nhs[1];
1971
1972           adj_index = r->index;
1973           if (lm->fib_result_n_words > 1)
1974             {
1975               result = vec_elt_at_index (results, adj_index);
1976               adj_index = result[0];
1977             }
1978
1979           adj = ip_get_adjacency (lm, adj_index);
1980           if (adj->n_adj == 1)
1981             {
1982               nhs = &tmp_nhs[0];
1983               nhs[0].next_hop_adj_index = ~0; /* not used */
1984               nhs[0].weight = 1;
1985               n_nhs = 1;
1986             }
1987           else
1988             {
1989               ip_multipath_adjacency_t * madj;
1990               madj = vec_elt_at_index (lm->multipath_adjacencies, adj->heap_handle);
1991               nhs = heap_elt_at_index (lm->next_hop_heap, madj->normalized_next_hops.heap_offset);
1992               n_nhs = madj->normalized_next_hops.count;
1993             }
1994
1995           n_left = nhs[0].weight;
1996           vlib_counter_zero (&sum);
1997           for (i = j = 0; i < adj->n_adj; i++)
1998             {
1999               n_left -= 1;
2000               vlib_get_combined_counter (&lm->adjacency_counters, 
2001                                          adj_index + i, &c);
2002               if (clear)
2003                 vlib_zero_combined_counter (&lm->adjacency_counters,
2004                                             adj_index + i);
2005               vlib_counter_add (&sum, &c);
2006               if (n_left == 0)
2007                 {
2008                   u8 * msg = 0;
2009                   uword indent;
2010
2011                   if (j == 0)
2012                     msg = format (msg, "%-20U",
2013                                   format_ip4_address_and_length,
2014                                   r->address.data, r->address_length);
2015                   else
2016                     msg = format (msg, "%U", format_white_space, 20);
2017
2018                   msg = format (msg, "%16Ld%16Ld ", sum.packets, sum.bytes);
2019
2020                   indent = vec_len (msg);
2021                   msg = format (msg, "weight %d, index %d\n%U%U",
2022                                 nhs[j].weight, adj_index + i,
2023                                 format_white_space, indent,
2024                                 format_ip_adjacency,
2025                                 vnm, lm, adj_index + i);
2026
2027                   vlib_cli_output (vm, "%v", msg);
2028                   vec_free (msg);
2029
2030                   if (result && lm->format_fib_result)
2031                     vlib_cli_output (vm, "%20s%U", "",
2032                                      lm->format_fib_result, vm, lm, result,
2033                                      i + 1 - nhs[j].weight,
2034                                      nhs[j].weight);
2035
2036                   j++;
2037                   if (j < n_nhs)
2038                     {
2039                       n_left = nhs[j].weight;
2040                       vlib_counter_zero (&sum);
2041                     }
2042                 }
2043             }
2044         }
2045     }
2046
2047   vec_free (routes);
2048   vec_free (results);
2049
2050   return 0;
2051 }
2052
2053 VLIB_CLI_COMMAND (ip4_show_fib_command, static) = {
2054   .path = "show ip fib",
2055   .short_help = "show ip fib [mtrie] [summary] [table <n>] [<ip4-addr>] [clear] [include-empty]",
2056   .function = ip4_show_fib,
2057 };
2058
2059 typedef struct {
2060   ip6_address_t address;
2061
2062   u32 address_length;
2063
2064   u32 index;
2065 } ip6_route_t;
2066
2067 typedef struct {
2068   u32 fib_index;
2069   ip6_route_t ** routep;
2070 } add_routes_in_fib_arg_t;
2071
2072 static void add_routes_in_fib (BVT(clib_bihash_kv) * kvp, void *arg)
2073 {
2074   add_routes_in_fib_arg_t * ap = arg;
2075
2076   if (kvp->key[2]>>32 == ap->fib_index)
2077     {
2078       ip6_address_t *addr;
2079       ip6_route_t * r;
2080       addr = (ip6_address_t *) kvp;
2081       vec_add2 (*ap->routep, r, 1);
2082       r->address = addr[0];
2083       r->address_length = kvp->key[2] & 0xFF;
2084       r->index = kvp->value;
2085     }
2086 }
2087
2088 typedef struct {
2089   u32 fib_index;
2090   u64 count_by_prefix_length[129];
2091 } count_routes_in_fib_at_prefix_length_arg_t;
2092
2093 static void count_routes_in_fib_at_prefix_length 
2094 (BVT(clib_bihash_kv) * kvp, void *arg)
2095 {
2096   count_routes_in_fib_at_prefix_length_arg_t * ap = arg;
2097   int mask_width;
2098
2099   if ((kvp->key[2]>>32) != ap->fib_index)
2100     return;
2101
2102   mask_width = kvp->key[2] & 0xFF;
2103
2104   ap->count_by_prefix_length[mask_width]++;
2105 }
2106
2107
2108 static clib_error_t *
2109 ip6_show_fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
2110 {
2111   vnet_main_t * vnm = vnet_get_main();
2112   ip6_main_t * im6 = &ip6_main;
2113   ip6_route_t * routes, * r;
2114   ip6_fib_t * fib;
2115   ip_lookup_main_t * lm = &im6->lookup_main;
2116   uword * results;
2117   int verbose;
2118   BVT(clib_bihash) * h = &im6->ip6_lookup_table;
2119   __attribute__((unused)) u8 clear = 0;
2120   add_routes_in_fib_arg_t _a, *a=&_a;
2121   count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
2122
2123   routes = 0;
2124   results = 0;
2125   verbose = 1;
2126   if (unformat (input, "brief") || unformat (input, "summary")
2127       || unformat (input, "sum"))
2128     verbose = 0;
2129
2130   if (unformat (input, "clear"))
2131     clear = 1;
2132
2133   vlib_cli_output (vm, "FIB lookup table: %d buckets, %lld MB heap",
2134                    im6->lookup_table_nbuckets, im6->lookup_table_size>>20);
2135   vlib_cli_output (vm, "%U", format_mheap, h->mheap, 0 /*verbose*/); 
2136   vlib_cli_output (vm, " ");
2137   
2138   vec_foreach (fib, im6->fibs)
2139     {
2140       vlib_cli_output (vm, "VRF %d, fib_index %d, flow hash: %U", 
2141                        fib->table_id, fib - im6->fibs,
2142                        format_ip_flow_hash_config, fib->flow_hash_config);
2143       
2144       /* Show summary? */
2145       if (! verbose)
2146         {
2147           int len;
2148           vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
2149
2150           memset (ca, 0, sizeof(*ca));
2151           ca->fib_index = fib - im6->fibs;
2152
2153           BV(clib_bihash_foreach_key_value_pair)
2154             (h, count_routes_in_fib_at_prefix_length, ca);
2155
2156           for (len = 128; len >= 0; len--)
2157             {
2158               if (ca->count_by_prefix_length[len])
2159                 vlib_cli_output (vm, "%=20d%=16lld", 
2160                                  len, ca->count_by_prefix_length[len]);
2161             }
2162           continue;
2163         }
2164
2165       if (routes)
2166         _vec_len (routes) = 0;
2167       if (results)
2168         _vec_len (results) = 0;
2169
2170       a->fib_index = fib - im6->fibs;
2171       a->routep = &routes;
2172
2173       BV(clib_bihash_foreach_key_value_pair)(h, add_routes_in_fib, a);
2174       
2175       vec_sort (routes, r1, r2,
2176                 ({ int cmp = ip6_address_compare (&r1->address, &r2->address);
2177                   cmp ? cmp : ((int) r1->address_length - (int) r2->address_length); }));
2178
2179       vlib_cli_output (vm, "%=45s%=16s%=16s%=16s",
2180                        "Destination", "Packets", "Bytes", "Adjacency");
2181       vec_foreach (r, routes)
2182         {
2183           vlib_counter_t c, sum;
2184           uword i, j, n_left, n_nhs, adj_index, * result = 0;
2185           ip_adjacency_t * adj;
2186           ip_multipath_next_hop_t * nhs, tmp_nhs[1];
2187
2188           adj_index = r->index;
2189           if (lm->fib_result_n_words > 1)
2190             {
2191               result = vec_elt_at_index (results, adj_index);
2192               adj_index = result[0];
2193             }
2194
2195           adj = ip_get_adjacency (lm, adj_index);
2196           if (adj->n_adj == 1)
2197             {
2198               nhs = &tmp_nhs[0];
2199               nhs[0].next_hop_adj_index = ~0; /* not used */
2200               nhs[0].weight = 1;
2201               n_nhs = 1;
2202             }
2203           else
2204             {
2205               ip_multipath_adjacency_t * madj;
2206               madj = vec_elt_at_index (lm->multipath_adjacencies, adj->heap_handle);
2207               nhs = heap_elt_at_index (lm->next_hop_heap, madj->normalized_next_hops.heap_offset);
2208               n_nhs = madj->normalized_next_hops.count;
2209             }
2210
2211           n_left = nhs[0].weight;
2212           vlib_counter_zero (&sum);
2213           for (i = j = 0; i < adj->n_adj; i++)
2214             {
2215               n_left -= 1;
2216               vlib_get_combined_counter (&lm->adjacency_counters, 
2217                                          adj_index + i, &c);
2218               if (clear)
2219                 vlib_zero_combined_counter (&lm->adjacency_counters, 
2220                                             adj_index + i);
2221               vlib_counter_add (&sum, &c);
2222               if (n_left == 0)
2223                 {
2224                   u8 * msg = 0;
2225                   uword indent;
2226
2227                   if (j == 0)
2228                     msg = format (msg, "%-45U",
2229                                   format_ip6_address_and_length,
2230                                   r->address.as_u8, r->address_length);
2231                   else
2232                     msg = format (msg, "%U", format_white_space, 20);
2233
2234                   msg = format (msg, "%16Ld%16Ld ", sum.packets, sum.bytes);
2235
2236                   indent = vec_len (msg);
2237                   msg = format (msg, "weight %d, index %d\n%U%U",
2238                                 nhs[j].weight, adj_index + i,
2239                                 format_white_space, indent,
2240                                 format_ip_adjacency,
2241                                 vnm, lm, adj_index + i);
2242
2243                   vlib_cli_output (vm, "%v", msg);
2244                   vec_free (msg);
2245
2246                   j++;
2247                   if (j < n_nhs)
2248                     {
2249                       n_left = nhs[j].weight;
2250                       vlib_counter_zero (&sum);
2251                     }
2252                 }
2253             }
2254
2255           if (result && lm->format_fib_result)
2256             vlib_cli_output (vm, "%20s%U", "", lm->format_fib_result, vm, lm, result, 0);
2257         }
2258       vlib_cli_output (vm, " ");
2259     }
2260
2261   vec_free (routes);
2262   vec_free (results);
2263
2264   return 0;
2265 }
2266
2267 VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
2268   .path = "show ip6 fib",
2269   .short_help = "show ip6 fib [summary] [clear]",
2270   .function = ip6_show_fib,
2271 };