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