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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 * ip/ip_lookup.c: ip4/6 adjacency and lookup table managment
18 * Copyright (c) 2008 Eliot Dresselhaus
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:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
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.
40 #include <vppinfra/math.h> /* for fabs */
41 #include <vnet/ip/ip.h>
42 #include <vnet/ip/adj_alloc.h>
45 ip_multipath_del_adjacency (ip_lookup_main_t * lm, u32 del_adj_index);
48 ip_poison_adjacencies (ip_adjacency_t * adj, uword n_adj)
52 u32 save_handle = adj->heap_handle;;
53 u32 save_n_adj = adj->n_adj;
55 memset (adj, 0xfe, n_adj * sizeof (adj[0]));
57 adj->heap_handle = save_handle;
58 adj->n_adj = save_n_adj;
62 /* Create new block of given number of contiguous adjacencies. */
64 ip_add_adjacency (ip_lookup_main_t * lm,
65 ip_adjacency_t * copy_adj,
67 u32 * adj_index_return)
72 /* See if we know enough to attempt to share an existing adjacency */
73 if (copy_adj && n_adj == 1)
78 switch (copy_adj->lookup_next_index)
80 case IP_LOOKUP_NEXT_DROP:
81 if (lm->drop_adj_index)
83 adj = ip_get_adjacency (lm, lm->drop_adj_index);
84 *adj_index_return = lm->drop_adj_index;
89 case IP_LOOKUP_NEXT_LOCAL:
90 if (lm->local_adj_index)
92 adj = ip_get_adjacency (lm, lm->local_adj_index);
93 *adj_index_return = lm->local_adj_index;
100 signature = vnet_ip_adjacency_signature (copy_adj);
101 p = hash_get (lm->adj_index_by_signature, signature);
104 adj = vec_elt_at_index (lm->adjacency_heap, p[0]);
107 if (vnet_ip_adjacency_share_compare (adj, copy_adj))
110 *adj_index_return = p[0];
113 if (adj->next_adj_with_signature == 0)
115 adj = vec_elt_at_index (lm->adjacency_heap,
116 adj->next_adj_with_signature);
121 lm->adjacency_heap = aa_alloc (lm->adjacency_heap, &adj, n_adj);
122 handle = ai = adj->heap_handle;
124 ip_poison_adjacencies (adj, n_adj);
126 /* Validate adjacency counters. */
127 vlib_validate_combined_counter (&lm->adjacency_counters, ai + n_adj - 1);
129 for (i = 0; i < n_adj; i++)
131 /* Make sure certain fields are always initialized. */
132 adj[i].rewrite_header.sw_if_index = ~0;
133 adj[i].explicit_fib_index = ~0;
134 adj[i].mcast_group_index = ~0;
135 adj[i].classify_table_index = ~0;
136 adj[i].saved_lookup_next_index = 0;
139 adj[i] = copy_adj[i];
141 adj[i].heap_handle = handle;
142 adj[i].n_adj = n_adj;
143 adj[i].share_count = 0;
144 adj[i].next_adj_with_signature = 0;
146 /* Zero possibly stale counters for re-used adjacencies. */
147 vlib_zero_combined_counter (&lm->adjacency_counters, ai + i);
150 /* Set up to share the adj later */
151 if (copy_adj && n_adj == 1)
155 uword signature = vnet_ip_adjacency_signature (adj);
157 p = hash_get (lm->adj_index_by_signature, signature);
158 /* Hash collision? */
161 /* Save the adj index, p[0] will be toast after the unset! */
163 hash_unset (lm->adj_index_by_signature, signature);
164 hash_set (lm->adj_index_by_signature, signature, ai);
165 adj->next_adj_with_signature = old_ai;
169 adj->next_adj_with_signature = 0;
170 hash_set (lm->adj_index_by_signature, signature, ai);
174 *adj_index_return = ai;
178 static void ip_del_adjacency2 (ip_lookup_main_t * lm, u32 adj_index, u32 delete_multipath_adjacency)
180 ip_adjacency_t * adj;
182 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 1);
184 adj = ip_get_adjacency (lm, adj_index);
186 /* Special-case miss, local, drop adjs */
195 ip_adjacency_t * this_adj, * prev_adj = 0;
196 if (adj->share_count > 0)
202 signature = vnet_ip_adjacency_signature (adj);
203 p = hash_get (lm->adj_index_by_signature, signature);
208 /* At the top of the signature chain (likely)? */
209 if (this_ai == adj_index)
211 if (adj->next_adj_with_signature == 0)
213 hash_unset (lm->adj_index_by_signature, signature);
218 this_adj = ip_get_adjacency (lm, adj->next_adj_with_signature);
219 hash_unset (lm->adj_index_by_signature, signature);
220 hash_set (lm->adj_index_by_signature, signature,
221 this_adj->heap_handle);
224 else /* walk signature chain */
226 this_adj = ip_get_adjacency (lm, this_ai);
227 while (this_adj != adj)
230 this_adj = ip_get_adjacency
231 (lm, this_adj->next_adj_with_signature);
233 * This can happen when creating the first multipath adj of a set
234 * We end up looking at the miss adjacency (handle==0).
236 if (this_adj->heap_handle == 0)
239 prev_adj->next_adj_with_signature = this_adj->next_adj_with_signature;
244 if (delete_multipath_adjacency)
245 ip_multipath_del_adjacency (lm, adj_index);
247 ip_poison_adjacencies (adj, adj->n_adj);
249 aa_free (lm->adjacency_heap, adj);
252 void ip_del_adjacency (ip_lookup_main_t * lm, u32 adj_index)
253 { ip_del_adjacency2 (lm, adj_index, /* delete_multipath_adjacency */ 1); }
256 next_hop_sort_by_weight (ip_multipath_next_hop_t * n1,
257 ip_multipath_next_hop_t * n2)
259 int cmp = (int) n1->weight - (int) n2->weight;
261 ? (int) n1->next_hop_adj_index - (int) n2->next_hop_adj_index
262 : (cmp > 0 ? +1 : -1));
265 /* Given next hop vector is over-written with normalized one with sorted weights and
266 with weights corresponding to the number of adjacencies for each next hop.
267 Returns number of adjacencies in block. */
268 static u32 ip_multipath_normalize_next_hops (ip_lookup_main_t * lm,
269 ip_multipath_next_hop_t * raw_next_hops,
270 ip_multipath_next_hop_t ** normalized_next_hops)
272 ip_multipath_next_hop_t * nhs;
273 uword n_nhs, n_adj, n_adj_left, i;
274 f64 sum_weight, norm, error;
276 n_nhs = vec_len (raw_next_hops);
281 /* Allocate enough space for 2 copies; we'll use second copy to save original weights. */
282 nhs = *normalized_next_hops;
283 vec_validate (nhs, 2*n_nhs - 1);
285 /* Fast path: 1 next hop in block. */
289 nhs[0] = raw_next_hops[0];
297 int cmp = next_hop_sort_by_weight (&raw_next_hops[0], &raw_next_hops[1]) < 0;
300 nhs[0] = raw_next_hops[cmp];
301 nhs[1] = raw_next_hops[cmp ^ 1];
303 /* Fast path: equal cost multipath with 2 next hops. */
304 if (nhs[0].weight == nhs[1].weight)
306 nhs[0].weight = nhs[1].weight = 1;
313 memcpy (nhs, raw_next_hops, n_nhs * sizeof (raw_next_hops[0]));
314 qsort (nhs, n_nhs, sizeof (nhs[0]), (void *) next_hop_sort_by_weight);
317 /* Find total weight to normalize weights. */
319 for (i = 0; i < n_nhs; i++)
320 sum_weight += nhs[i].weight;
322 /* In the unlikely case that all weights are given as 0, set them all to 1. */
325 for (i = 0; i < n_nhs; i++)
330 /* Save copies of all next hop weights to avoid being overwritten in loop below. */
331 for (i = 0; i < n_nhs; i++)
332 nhs[n_nhs + i].weight = nhs[i].weight;
334 /* Try larger and larger power of 2 sized adjacency blocks until we
335 find one where traffic flows to within 1% of specified weights. */
336 for (n_adj = max_pow2 (n_nhs); ; n_adj *= 2)
340 norm = n_adj / sum_weight;
342 for (i = 0; i < n_nhs; i++)
344 f64 nf = nhs[n_nhs + i].weight * norm; /* use saved weights */
345 word n = flt_round_nearest (nf);
347 n = n > n_adj_left ? n_adj_left : n;
349 error += fabs (nf - n);
353 nhs[0].weight += n_adj_left;
355 /* Less than 5% average error per adjacency with this size adjacency block? */
356 if (error <= lm->multipath_next_hop_error_tolerance*n_adj)
358 /* Truncate any next hops with zero weight. */
365 /* Save vector for next call. */
366 *normalized_next_hops = nhs;
371 ip_next_hop_hash_key_from_handle (uword handle)
372 { return 1 + 2*handle; }
375 ip_next_hop_hash_key_is_heap_handle (uword k)
379 ip_next_hop_hash_key_get_heap_handle (uword k)
381 ASSERT (ip_next_hop_hash_key_is_heap_handle (k));
386 ip_multipath_adjacency_get (ip_lookup_main_t * lm,
387 ip_multipath_next_hop_t * raw_next_hops,
388 uword create_if_non_existent)
391 u32 i, j, n_adj, adj_index, adj_heap_handle;
392 ip_adjacency_t * adj, * copy_adj;
393 ip_multipath_next_hop_t * nh, * nhs;
394 ip_multipath_adjacency_t * madj;
396 n_adj = ip_multipath_normalize_next_hops (lm, raw_next_hops, &lm->next_hop_hash_lookup_key_normalized);
397 nhs = lm->next_hop_hash_lookup_key_normalized;
400 ASSERT (n_adj >= vec_len (raw_next_hops));
402 /* Use normalized next hops to see if we've seen a block equivalent to this one before. */
403 p = hash_get_mem (lm->multipath_adjacency_by_next_hops, nhs);
407 if (! create_if_non_existent)
410 adj = ip_add_adjacency (lm, /* copy_adj */ 0, n_adj, &adj_index);
411 adj_heap_handle = adj[0].heap_handle;
413 /* Fill in adjacencies in block based on corresponding next hop adjacencies. */
415 vec_foreach (nh, nhs)
417 copy_adj = ip_get_adjacency (lm, nh->next_hop_adj_index);
418 for (j = 0; j < nh->weight; j++)
420 adj[i] = copy_adj[0];
421 adj[i].heap_handle = adj_heap_handle;
422 adj[i].n_adj = n_adj;
427 /* All adjacencies should have been initialized. */
430 vec_validate (lm->multipath_adjacencies, adj_heap_handle);
431 madj = vec_elt_at_index (lm->multipath_adjacencies, adj_heap_handle);
433 madj->adj_index = adj_index;
434 madj->n_adj_in_block = n_adj;
435 madj->reference_count = 0; /* caller will set to one. */
437 madj->normalized_next_hops.count = vec_len (nhs);
438 madj->normalized_next_hops.heap_offset
439 = heap_alloc (lm->next_hop_heap, vec_len (nhs),
440 madj->normalized_next_hops.heap_handle);
441 memcpy (lm->next_hop_heap + madj->normalized_next_hops.heap_offset,
442 nhs, vec_bytes (nhs));
444 hash_set (lm->multipath_adjacency_by_next_hops,
445 ip_next_hop_hash_key_from_handle (madj->normalized_next_hops.heap_handle),
446 madj - lm->multipath_adjacencies);
448 madj->unnormalized_next_hops.count = vec_len (raw_next_hops);
449 madj->unnormalized_next_hops.heap_offset
450 = heap_alloc (lm->next_hop_heap, vec_len (raw_next_hops),
451 madj->unnormalized_next_hops.heap_handle);
452 memcpy (lm->next_hop_heap + madj->unnormalized_next_hops.heap_offset,
453 raw_next_hops, vec_bytes (raw_next_hops));
455 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
457 return adj_heap_handle;
460 /* Returns 0 for next hop not found. */
462 ip_multipath_adjacency_add_del_next_hop (ip_lookup_main_t * lm,
464 u32 old_mp_adj_index,
465 u32 next_hop_adj_index,
467 u32 * new_mp_adj_index)
469 ip_multipath_adjacency_t * mp_old, * mp_new;
470 ip_multipath_next_hop_t * nh, * nhs, * hash_nhs;
478 /* If old multipath adjacency is valid, find requested next hop. */
479 if (old_mp_adj_index < vec_len (lm->multipath_adjacencies)
480 && lm->multipath_adjacencies[old_mp_adj_index].normalized_next_hops.count > 0)
482 mp_old = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
484 nhs = vec_elt_at_index (lm->next_hop_heap, mp_old->unnormalized_next_hops.heap_offset);
485 n_nhs = mp_old->unnormalized_next_hops.count;
487 /* Linear search: ok since n_next_hops is small. */
488 for (i_nh = 0; i_nh < n_nhs; i_nh++)
489 if (nhs[i_nh].next_hop_adj_index == next_hop_adj_index)
492 /* Given next hop not found. */
493 if (i_nh >= n_nhs && is_del)
497 hash_nhs = lm->next_hop_hash_lookup_key;
499 _vec_len (hash_nhs) = 0;
505 /* Prepare lookup key for multipath with target next hop deleted. */
507 vec_add (hash_nhs, nhs + 0, i_nh);
508 if (i_nh + 1 < n_nhs)
509 vec_add (hash_nhs, nhs + i_nh + 1, n_nhs - (i_nh + 1));
512 else /* it's an add. */
514 /* If next hop is already there with the same weight, we have nothing to do. */
515 if (i_nh < n_nhs && nhs[i_nh].weight == next_hop_weight)
517 new_mp_adj_index[0] = ~0;
521 /* Copy old next hops to lookup key vector. */
523 vec_add (hash_nhs, nhs, n_nhs);
527 /* Change weight of existing next hop. */
528 nh = vec_elt_at_index (hash_nhs, i_nh);
532 /* Add a new next hop. */
533 vec_add2 (hash_nhs, nh, 1);
534 nh->next_hop_adj_index = next_hop_adj_index;
537 /* Set weight for added or old next hop. */
538 nh->weight = next_hop_weight;
541 if (vec_len (hash_nhs) > 0)
543 u32 tmp = ip_multipath_adjacency_get (lm, hash_nhs,
544 /* create_if_non_existent */ 1);
546 mp_new = vec_elt_at_index (lm->multipath_adjacencies, tmp);
548 /* Fetch again since pool may have moved. */
550 mp_old = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
553 new_mp_adj_index[0] = mp_new ? mp_new - lm->multipath_adjacencies : ~0;
555 if (mp_new != mp_old)
559 ASSERT (mp_old->reference_count > 0);
560 mp_old->reference_count -= 1;
563 mp_new->reference_count += 1;
566 if (mp_old && mp_old->reference_count == 0)
567 ip_multipath_adjacency_free (lm, mp_old);
570 /* Save key vector next call. */
571 lm->next_hop_hash_lookup_key = hash_nhs;
577 ip_multipath_del_adjacency (ip_lookup_main_t * lm, u32 del_adj_index)
579 ip_adjacency_t * adj = ip_get_adjacency (lm, del_adj_index);
580 ip_multipath_adjacency_t * madj, * new_madj;
581 ip_multipath_next_hop_t * nhs, * hash_nhs;
582 u32 i, n_nhs, madj_index, new_madj_index;
584 if (adj->heap_handle >= vec_len (lm->multipath_adjacencies))
587 vec_validate (lm->adjacency_remap_table, vec_len (lm->adjacency_heap) - 1);
589 for (madj_index = 0; madj_index < vec_len (lm->multipath_adjacencies); madj_index++)
591 madj = vec_elt_at_index (lm->multipath_adjacencies, madj_index);
592 if (madj->n_adj_in_block == 0)
595 nhs = heap_elt_at_index (lm->next_hop_heap, madj->unnormalized_next_hops.heap_offset);
596 n_nhs = madj->unnormalized_next_hops.count;
597 for (i = 0; i < n_nhs; i++)
598 if (nhs[i].next_hop_adj_index == del_adj_index)
601 /* del_adj_index not found in unnormalized_next_hops? We're done. */
608 hash_nhs = lm->next_hop_hash_lookup_key;
610 _vec_len (hash_nhs) = 0;
612 vec_add (hash_nhs, nhs + 0, i);
614 vec_add (hash_nhs, nhs + i + 1, n_nhs - (i + 1));
616 new_madj_index = ip_multipath_adjacency_get (lm, hash_nhs, /* create_if_non_existent */ 1);
618 lm->next_hop_hash_lookup_key = hash_nhs;
620 if (new_madj_index == madj_index)
623 new_madj = vec_elt_at_index (lm->multipath_adjacencies, new_madj_index);
626 lm->adjacency_remap_table[madj->adj_index] = new_madj ? 1 + new_madj->adj_index : ~0;
627 lm->n_adjacency_remaps += 1;
628 ip_multipath_adjacency_free (lm, madj);
633 ip_multipath_adjacency_free (ip_lookup_main_t * lm,
634 ip_multipath_adjacency_t * a)
636 hash_unset (lm->multipath_adjacency_by_next_hops,
637 ip_next_hop_hash_key_from_handle (a->normalized_next_hops.heap_handle));
638 heap_dealloc (lm->next_hop_heap, a->normalized_next_hops.heap_handle);
639 heap_dealloc (lm->next_hop_heap, a->unnormalized_next_hops.heap_handle);
641 ip_del_adjacency2 (lm, a->adj_index, a->reference_count == 0);
642 memset (a, 0, sizeof (a[0]));
645 always_inline ip_multipath_next_hop_t *
646 ip_next_hop_hash_key_get_next_hops (ip_lookup_main_t * lm, uword k,
649 ip_multipath_next_hop_t * nhs;
651 if (ip_next_hop_hash_key_is_heap_handle (k))
653 uword handle = ip_next_hop_hash_key_get_heap_handle (k);
654 nhs = heap_elt_with_handle (lm->next_hop_heap, handle);
655 n_nhs = heap_len (lm->next_hop_heap, handle);
659 nhs = uword_to_pointer (k, ip_multipath_next_hop_t *);
660 n_nhs = vec_len (nhs);
662 *n_next_hops = n_nhs;
667 ip_next_hop_hash_key_sum (hash_t * h, uword key0)
669 ip_lookup_main_t * lm = uword_to_pointer (h->user, ip_lookup_main_t *);
670 ip_multipath_next_hop_t * k0;
673 k0 = ip_next_hop_hash_key_get_next_hops (lm, key0, &n0);
674 return hash_memory (k0, n0 * sizeof (k0[0]), /* seed */ n0);
678 ip_next_hop_hash_key_equal (hash_t * h, uword key0, uword key1)
680 ip_lookup_main_t * lm = uword_to_pointer (h->user, ip_lookup_main_t *);
681 ip_multipath_next_hop_t * k0, * k1;
684 k0 = ip_next_hop_hash_key_get_next_hops (lm, key0, &n0);
685 k1 = ip_next_hop_hash_key_get_next_hops (lm, key1, &n1);
687 return n0 == n1 && ! memcmp (k0, k1, n0 * sizeof (k0[0]));
691 ip_interface_address_add_del (ip_lookup_main_t * lm,
696 u32 * result_if_address_index)
698 vnet_main_t * vnm = vnet_get_main();
699 ip_interface_address_t * a, * prev, * next;
700 uword * p = mhash_get (&lm->address_to_if_address_index, addr_fib);
702 vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
703 a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0;
705 /* Verify given length. */
706 if ((a && (address_length != a->address_length)) || (address_length == 0))
708 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
709 return clib_error_create
710 ( "%U wrong length (expected %d) for interface %U",
711 lm->format_address_and_length, addr_fib,
712 address_length, a? a->address_length : -1,
713 format_vnet_sw_if_index_name, vnm, sw_if_index);
720 vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, sw_if_index);
721 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
722 return clib_error_create ("%U not found for interface %U",
723 lm->format_address_and_length,
724 addr_fib, address_length,
725 format_vnet_sw_interface_name, vnm, si);
728 if (a->prev_this_sw_interface != ~0)
730 prev = pool_elt_at_index (lm->if_address_pool, a->prev_this_sw_interface);
731 prev->next_this_sw_interface = a->next_this_sw_interface;
733 if (a->next_this_sw_interface != ~0)
735 next = pool_elt_at_index (lm->if_address_pool, a->next_this_sw_interface);
736 next->prev_this_sw_interface = a->prev_this_sw_interface;
738 if(a->prev_this_sw_interface == ~0)
739 lm->if_address_pool_index_by_sw_if_index[sw_if_index] = a->next_this_sw_interface;
742 if ((a->next_this_sw_interface == ~0) && (a->prev_this_sw_interface == ~0))
743 lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0;
745 mhash_unset (&lm->address_to_if_address_index, addr_fib,
747 pool_put (lm->if_address_pool, a);
749 if (result_if_address_index)
750 *result_if_address_index = ~0;
755 u32 pi; /* previous index */
757 u32 hi; /* head index */
759 pool_get (lm->if_address_pool, a);
760 memset (a, ~0, sizeof (a[0]));
761 ai = a - lm->if_address_pool;
763 hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
765 while (pi != (u32)~0)
767 prev = pool_elt_at_index(lm->if_address_pool, pi);
768 pi = prev->next_this_sw_interface;
770 pi = prev ? prev - lm->if_address_pool : (u32)~0;
772 a->address_key = mhash_set (&lm->address_to_if_address_index,
773 addr_fib, ai, /* old_value */ 0);
774 a->address_length = address_length;
775 a->sw_if_index = sw_if_index;
777 a->prev_this_sw_interface = pi;
778 a->next_this_sw_interface = ~0;
780 prev->next_this_sw_interface = ai;
782 lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
783 (hi != ~0) ? hi : ai;
784 if (result_if_address_index)
785 *result_if_address_index = ai;
789 if (result_if_address_index)
790 *result_if_address_index = a - lm->if_address_pool;
794 return /* no error */ 0;
797 void ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
799 ip_adjacency_t * adj;
800 ip_adjacency_t template_adj;
802 /* ensure that adjacency is cacheline aligned and sized */
803 ASSERT(STRUCT_OFFSET_OF(ip_adjacency_t, cacheline0) == 0);
804 ASSERT(STRUCT_OFFSET_OF(ip_adjacency_t, cacheline1) == CLIB_CACHE_LINE_BYTES);
806 lm->adj_index_by_signature = hash_create (0, sizeof (uword));
807 memset (&template_adj, 0, sizeof (template_adj));
809 /* Preallocate three "special" adjacencies */
810 lm->adjacency_heap = aa_bootstrap (0, 3 /* n=1 free items */);
812 /* Hand-craft special miss adjacency to use when nothing matches in the
813 routing table. Same for drop adjacency. */
814 adj = ip_add_adjacency (lm, /* template */ 0, /* n-adj */ 1,
815 &lm->miss_adj_index);
816 adj->lookup_next_index = IP_LOOKUP_NEXT_MISS;
817 ASSERT (lm->miss_adj_index == IP_LOOKUP_MISS_ADJ_INDEX);
819 /* Make the "drop" adj sharable */
820 template_adj.lookup_next_index = IP_LOOKUP_NEXT_DROP;
821 adj = ip_add_adjacency (lm, &template_adj, /* n-adj */ 1,
822 &lm->drop_adj_index);
824 /* Make the "local" adj sharable */
825 template_adj.lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
826 template_adj.if_address_index = ~0;
827 adj = ip_add_adjacency (lm, &template_adj, /* n-adj */ 1,
828 &lm->local_adj_index);
830 if (! lm->fib_result_n_bytes)
831 lm->fib_result_n_bytes = sizeof (uword);
833 lm->multipath_adjacency_by_next_hops
834 = hash_create2 (/* elts */ 0,
835 /* user */ pointer_to_uword (lm),
836 /* value_bytes */ sizeof (uword),
837 ip_next_hop_hash_key_sum,
838 ip_next_hop_hash_key_equal,
839 /* format pair/arg */
842 /* 1% max error tolerance for multipath. */
843 lm->multipath_next_hop_error_tolerance = .01;
848 lm->format_address_and_length = format_ip6_address_and_length;
849 mhash_init (&lm->address_to_if_address_index, sizeof (uword),
850 sizeof (ip6_address_fib_t));
854 lm->format_address_and_length = format_ip4_address_and_length;
855 mhash_init (&lm->address_to_if_address_index, sizeof (uword),
856 sizeof (ip4_address_fib_t));
862 /* Setup all IP protocols to be punted and builtin-unknown. */
863 for (i = 0; i < 256; i++)
865 lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
866 lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
869 lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
870 lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
871 lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] = IP_BUILTIN_PROTOCOL_UDP;
872 lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 : IP_PROTOCOL_ICMP] = IP_BUILTIN_PROTOCOL_ICMP;
876 u8 * format_ip_flow_hash_config (u8 * s, va_list * args)
878 u32 flow_hash_config = va_arg (*args, u32);
880 #define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
881 foreach_flow_hash_bit;
887 u8 * format_ip_lookup_next (u8 * s, va_list * args)
889 ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
895 s = format (s, "unknown %d", n);
898 case IP_LOOKUP_NEXT_MISS: t = "miss"; break;
899 case IP_LOOKUP_NEXT_DROP: t = "drop"; break;
900 case IP_LOOKUP_NEXT_PUNT: t = "punt"; break;
901 case IP_LOOKUP_NEXT_LOCAL: t = "local"; break;
902 case IP_LOOKUP_NEXT_ARP: t = "arp"; break;
903 case IP_LOOKUP_NEXT_CLASSIFY: t = "classify"; break;
904 case IP_LOOKUP_NEXT_MAP: t = "map"; break;
905 case IP_LOOKUP_NEXT_MAP_T: t = "map-t"; break;
906 case IP_LOOKUP_NEXT_SIXRD: t = "sixrd"; break;
907 case IP_LOOKUP_NEXT_REWRITE:
912 vec_add (s, t, strlen (t));
917 static u8 * format_ip_interface_address (u8 * s, va_list * args)
919 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
920 u32 if_address_index = va_arg (*args, u32);
921 ip_interface_address_t * ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
922 void * a = ip_interface_address_get_address (lm, ia);
925 return format (s, "%U", format_ip6_address_and_length, a, ia->address_length);
927 return format (s, "%U", format_ip4_address_and_length, a, ia->address_length);
930 u8 * format_ip_adjacency (u8 * s, va_list * args)
932 vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
933 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
934 u32 adj_index = va_arg (*args, u32);
935 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
937 switch (adj->lookup_next_index)
939 case IP_LOOKUP_NEXT_REWRITE:
942 vnm->vlib_main, &adj->rewrite_header, sizeof (adj->rewrite_data));
946 s = format (s, "%U", format_ip_lookup_next, adj->lookup_next_index);
947 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
948 s = format (s, " %U",
949 format_vnet_sw_interface_name,
951 vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index));
952 switch (adj->lookup_next_index)
954 case IP_LOOKUP_NEXT_ARP:
955 case IP_LOOKUP_NEXT_LOCAL:
956 if (adj->if_address_index != ~0)
957 s = format (s, " %U", format_ip_interface_address, lm, adj->if_address_index);
960 case IP_LOOKUP_NEXT_CLASSIFY:
961 s = format (s, " table %d", adj->classify_table_index);
968 if (adj->explicit_fib_index != ~0 && adj->explicit_fib_index != 0)
969 s = format (s, " lookup fib index %d", adj->explicit_fib_index);
970 if (adj->share_count > 0)
971 s = format (s, " shared %d", adj->share_count + 1);
972 if (adj->next_adj_with_signature)
973 s = format (s, " next_adj_with_signature %d", adj->next_adj_with_signature);
978 u8 * format_ip_adjacency_packet_data (u8 * s, va_list * args)
980 vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
981 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
982 u32 adj_index = va_arg (*args, u32);
983 u8 * packet_data = va_arg (*args, u8 *);
984 u32 n_packet_data_bytes = va_arg (*args, u32);
985 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
987 switch (adj->lookup_next_index)
989 case IP_LOOKUP_NEXT_REWRITE:
991 format_vnet_rewrite_header,
992 vnm->vlib_main, &adj->rewrite_header, packet_data, n_packet_data_bytes);
1002 static uword unformat_ip_lookup_next (unformat_input_t * input, va_list * args)
1004 ip_lookup_next_t * result = va_arg (*args, ip_lookup_next_t *);
1007 if (unformat (input, "drop"))
1008 n = IP_LOOKUP_NEXT_DROP;
1010 else if (unformat (input, "punt"))
1011 n = IP_LOOKUP_NEXT_PUNT;
1013 else if (unformat (input, "local"))
1014 n = IP_LOOKUP_NEXT_LOCAL;
1016 else if (unformat (input, "arp"))
1017 n = IP_LOOKUP_NEXT_ARP;
1019 else if (unformat (input, "classify"))
1020 n = IP_LOOKUP_NEXT_CLASSIFY;
1029 static uword unformat_ip_adjacency (unformat_input_t * input, va_list * args)
1031 vlib_main_t * vm = va_arg (*args, vlib_main_t *);
1032 ip_adjacency_t * adj = va_arg (*args, ip_adjacency_t *);
1033 u32 node_index = va_arg (*args, u32);
1034 vnet_main_t * vnm = vnet_get_main();
1035 u32 sw_if_index, is_ip6;
1037 ip_lookup_next_t next;
1039 is_ip6 = node_index == ip6_rewrite_node.index;
1040 adj->rewrite_header.node_index = node_index;
1041 adj->explicit_fib_index = ~0;
1043 if (unformat (input, "arp %U %U",
1044 unformat_vnet_sw_interface, vnm, &sw_if_index,
1045 unformat_ip46_address, &a46, is_ip6))
1047 ip_lookup_main_t * lm = is_ip6 ? &ip6_main.lookup_main : &ip4_main.lookup_main;
1048 ip_adjacency_t * a_adj;
1052 adj_index = ip6_fib_lookup (&ip6_main, sw_if_index, &a46.ip6);
1054 adj_index = ip4_fib_lookup (&ip4_main, sw_if_index, &a46.ip4);
1056 a_adj = ip_get_adjacency (lm, adj_index);
1058 if (a_adj->rewrite_header.sw_if_index != sw_if_index)
1062 ip6_adjacency_set_interface_route (vnm, adj, sw_if_index, a_adj->if_address_index);
1064 ip4_adjacency_set_interface_route (vnm, adj, sw_if_index, a_adj->if_address_index);
1067 else if (unformat_user (input, unformat_ip_lookup_next, &next))
1069 adj->lookup_next_index = next;
1070 adj->if_address_index = ~0;
1071 if (next == IP_LOOKUP_NEXT_LOCAL)
1072 (void) unformat (input, "%d", &adj->if_address_index);
1073 else if (next == IP_LOOKUP_NEXT_CLASSIFY)
1075 if (!unformat (input, "%d", &adj->classify_table_index))
1077 clib_warning ("classify adj must specify table index");
1081 else if (next == IP_LOOKUP_NEXT_DROP)
1083 adj->rewrite_header.node_index = 0;
1087 else if (unformat_user (input,
1088 unformat_vnet_rewrite,
1089 vm, &adj->rewrite_header, sizeof (adj->rewrite_data)))
1090 adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1099 vnet_ip_route_cmd (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
1101 vnet_main_t * vnm = vnet_get_main();
1102 clib_error_t * error = 0;
1103 u32 table_id, is_del;
1104 u32 weight, * weights = 0;
1105 u32 * table_ids = 0;
1106 u32 sw_if_index, * sw_if_indices = 0;
1107 ip4_address_t ip4_addr, * ip4_dst_addresses = 0, * ip4_via_next_hops = 0;
1108 ip6_address_t ip6_addr, * ip6_dst_addresses = 0, * ip6_via_next_hops = 0;
1109 u32 dst_address_length, * dst_address_lengths = 0;
1110 ip_adjacency_t parse_adj, * add_adj = 0;
1111 unformat_input_t _line_input, * line_input = &_line_input;
1119 /* Get a line of input. */
1120 if (! unformat_user (main_input, unformat_line_input, line_input))
1123 memset(&parse_adj, 0, sizeof (parse_adj));
1125 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1127 if (unformat (line_input, "table %d", &table_id))
1129 else if (unformat (line_input, "del"))
1131 else if (unformat (line_input, "add"))
1133 else if (unformat (line_input, "count %f", &count))
1136 else if (unformat (line_input, "%U/%d",
1137 unformat_ip4_address, &ip4_addr,
1138 &dst_address_length))
1140 vec_add1 (ip4_dst_addresses, ip4_addr);
1141 vec_add1 (dst_address_lengths, dst_address_length);
1144 else if (unformat (line_input, "%U/%d",
1145 unformat_ip6_address, &ip6_addr,
1146 &dst_address_length))
1148 vec_add1 (ip6_dst_addresses, ip6_addr);
1149 vec_add1 (dst_address_lengths, dst_address_length);
1152 else if (unformat (line_input, "via %U %U weight %u",
1153 unformat_ip4_address, &ip4_addr,
1154 unformat_vnet_sw_interface, vnm, &sw_if_index,
1157 vec_add1 (ip4_via_next_hops, ip4_addr);
1158 vec_add1 (sw_if_indices, sw_if_index);
1159 vec_add1 (weights, weight);
1160 vec_add1 (table_ids, (u32)~0);
1163 else if (unformat (line_input, "via %U %U weight %u",
1164 unformat_ip6_address, &ip6_addr,
1165 unformat_vnet_sw_interface, vnm, &sw_if_index,
1168 vec_add1 (ip6_via_next_hops, ip6_addr);
1169 vec_add1 (sw_if_indices, sw_if_index);
1170 vec_add1 (weights, weight);
1171 vec_add1 (table_ids, (u32)~0);
1174 else if (unformat (line_input, "via %U %U",
1175 unformat_ip4_address, &ip4_addr,
1176 unformat_vnet_sw_interface, vnm, &sw_if_index))
1178 vec_add1 (ip4_via_next_hops, ip4_addr);
1179 vec_add1 (sw_if_indices, sw_if_index);
1180 vec_add1 (weights, 1);
1181 vec_add1 (table_ids, (u32)~0);
1184 else if (unformat (line_input, "via %U %U",
1185 unformat_ip6_address, &ip6_addr,
1186 unformat_vnet_sw_interface, vnm, &sw_if_index))
1188 vec_add1 (ip6_via_next_hops, ip6_addr);
1189 vec_add1 (sw_if_indices, sw_if_index);
1190 vec_add1 (weights, 1);
1191 vec_add1 (table_ids, (u32)~0);
1193 else if (unformat (line_input, "via %U",
1194 unformat_ip4_address, &ip4_addr))
1196 vec_add1 (ip4_via_next_hops, ip4_addr);
1197 vec_add1 (sw_if_indices, (u32)~0);
1198 vec_add1 (weights, 1);
1199 vec_add1 (table_ids, table_id);
1201 else if (unformat (line_input, "via %U",
1202 unformat_ip6_address, &ip6_addr))
1204 vec_add1 (ip6_via_next_hops, ip6_addr);
1205 vec_add1 (sw_if_indices, (u32)~0);
1206 vec_add1 (weights, 1);
1207 vec_add1 (table_ids, (u32)table_id);
1210 else if (vec_len (ip4_dst_addresses) > 0
1211 && unformat (line_input, "via %U",
1212 unformat_ip_adjacency, vm, &parse_adj, ip4_rewrite_node.index))
1213 vec_add1 (add_adj, parse_adj);
1215 else if (vec_len (ip6_dst_addresses) > 0
1216 && unformat (line_input, "via %U",
1217 unformat_ip_adjacency, vm, &parse_adj, ip6_rewrite_node.index))
1218 vec_add1 (add_adj, parse_adj);
1219 else if (unformat (line_input, "lookup in table %d", &outer_table_id))
1223 if (vec_len (ip4_dst_addresses) > 0)
1224 p = hash_get (ip4_main.fib_index_by_table_id, outer_table_id);
1226 p = hash_get (ip6_main.fib_index_by_table_id, outer_table_id);
1230 error = clib_error_return (0, "Nonexistent outer table id %d",
1235 parse_adj.lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
1236 parse_adj.explicit_fib_index = p[0];
1237 vec_add1 (add_adj, parse_adj);
1241 error = unformat_parse_error (line_input);
1246 unformat_free (line_input);
1248 if (vec_len (ip4_dst_addresses) + vec_len (ip6_dst_addresses) == 0)
1250 error = clib_error_return (0, "expected ip4/ip6 destination address/length.");
1254 if (vec_len (ip4_dst_addresses) > 0 && vec_len (ip6_dst_addresses) > 0)
1256 error = clib_error_return (0, "mixed ip4/ip6 address/length.");
1260 if (vec_len (ip4_dst_addresses) > 0 && vec_len (ip6_via_next_hops) > 0)
1262 error = clib_error_return (0, "ip4 destinations with ip6 next hops.");
1266 if (vec_len (ip6_dst_addresses) > 0 && vec_len (ip4_via_next_hops) > 0)
1268 error = clib_error_return (0, "ip6 destinations with ip4 next hops.");
1272 if (! is_del && vec_len (add_adj) + vec_len (weights) == 0)
1274 error = clib_error_return (0, "no next hops or adjacencies to add.");
1278 if (vec_len(ip4_via_next_hops))
1280 if (sw_if_indices[0] == (u32)~0)
1285 ip_adjacency_t *nh_adj;
1287 p = hash_get (ip4_main.fib_index_by_table_id, table_ids[0]);
1290 error = clib_error_return (0, "Nonexistent FIB id %d",
1297 ai = ip4_fib_lookup_with_table (&ip4_main,
1300 1 /* disable default route */);
1303 error = clib_error_return (0, "next hop %U not in FIB",
1308 nh_adj = ip_get_adjacency (&ip4_main.lookup_main, ai);
1309 vec_add1 (add_adj, nh_adj[0]);
1312 if (vec_len(ip6_via_next_hops))
1314 if (sw_if_indices[0] == (u32)~0)
1319 ip_adjacency_t *nh_adj;
1321 p = hash_get (ip6_main.fib_index_by_table_id, table_ids[0]);
1324 error = clib_error_return (0, "Nonexistent FIB id %d",
1330 ai = ip6_fib_lookup_with_table (&ip6_main,
1335 error = clib_error_return (0, "next hop %U not in FIB",
1340 nh_adj = ip_get_adjacency (&ip6_main.lookup_main, ai);
1341 vec_add1 (add_adj, nh_adj[0]);
1347 ip4_main_t * im4 = &ip4_main;
1348 ip6_main_t * im6 = &ip6_main;
1350 for (i = 0; i < vec_len (ip4_dst_addresses); i++)
1352 ip4_add_del_route_args_t a;
1354 memset (&a, 0, sizeof (a));
1355 a.flags = IP4_ROUTE_FLAG_TABLE_ID;
1356 a.table_index_or_table_id = table_id;
1357 a.dst_address = ip4_dst_addresses[i];
1358 a.dst_address_length = dst_address_lengths[i];
1363 if (vec_len (ip4_via_next_hops) == 0)
1365 uword * dst_hash, * dst_result;
1366 u32 dst_address_u32;
1369 fib = find_ip4_fib_by_table_index_or_id (im4, table_id,
1370 0 /* by table id */);
1372 a.flags |= IP4_ROUTE_FLAG_DEL;
1373 dst_address_u32 = a.dst_address.as_u32
1374 & im4->fib_masks[a.dst_address_length];
1377 fib->adj_index_by_dst_address[a.dst_address_length];
1378 dst_result = hash_get (dst_hash, dst_address_u32);
1380 a.adj_index = dst_result[0];
1383 clib_warning ("%U/%d not in FIB",
1384 format_ip4_address, &a.dst_address,
1385 a.dst_address_length);
1389 ip4_add_del_route (im4, &a);
1390 ip4_maybe_remap_adjacencies (im4, table_id,
1391 IP4_ROUTE_FLAG_TABLE_ID);
1395 u32 i, j, n, f, incr;
1396 ip4_address_t dst = a.dst_address;
1399 t[0] = vlib_time_now (vm);
1400 incr = 1<<(32 - a.dst_address_length);
1401 for (i = 0; i < n; i++)
1403 f = i + 1 < n ? IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP : 0;
1404 a.dst_address = dst;
1405 for (j = 0; j < vec_len (ip4_via_next_hops); j++)
1407 if (table_ids[j] != (u32)~0)
1409 uword * p = hash_get (im4->fib_index_by_table_id,
1413 clib_warning ("no such FIB table %d",
1417 table_ids[j] = p[0];
1420 ip4_add_del_route_next_hop (im4,
1421 IP4_ROUTE_FLAG_DEL | f,
1423 a.dst_address_length,
1424 &ip4_via_next_hops[j],
1426 weights[j], (u32)~0,
1427 table_ids[j] /* fib index */);
1429 dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
1431 t[1] = vlib_time_now (vm);
1433 vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
1438 if (vec_len (add_adj) > 0)
1440 a.flags |= IP4_ROUTE_FLAG_ADD;
1441 a.add_adj = add_adj;
1442 a.n_add_adj = vec_len (add_adj);
1444 ip4_add_del_route (im4, &a);
1446 else if (vec_len (ip4_via_next_hops) > 0)
1448 u32 i, j, n, f, incr;
1449 ip4_address_t dst = a.dst_address;
1452 t[0] = vlib_time_now (vm);
1453 incr = 1<<(32 - a.dst_address_length);
1454 for (i = 0; i < n; i++)
1456 f = i + 1 < n ? IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP : 0;
1457 a.dst_address = dst;
1458 for (j = 0; j < vec_len (ip4_via_next_hops); j++)
1460 if (table_ids[j] != (u32)~0)
1462 uword * p = hash_get (im4->fib_index_by_table_id,
1466 clib_warning ("no such FIB table %d",
1470 table_ids[j] = p[0];
1472 ip4_add_del_route_next_hop (im4,
1473 IP4_ROUTE_FLAG_ADD | f,
1475 a.dst_address_length,
1476 &ip4_via_next_hops[j],
1478 weights[j], (u32)~0,
1479 table_ids[j] /* fib index */);
1481 dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
1483 t[1] = vlib_time_now (vm);
1485 vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
1490 for (i = 0; i < vec_len (ip6_dst_addresses); i++)
1492 ip6_add_del_route_args_t a;
1495 memset (&a, 0, sizeof (a));
1496 a.flags = IP6_ROUTE_FLAG_TABLE_ID;
1497 a.table_index_or_table_id = table_id;
1498 a.dst_address = ip6_dst_addresses[i];
1499 a.dst_address_length = dst_address_lengths[i];
1504 if (vec_len (ip6_via_next_hops) == 0)
1506 BVT(clib_bihash_kv) kv, value;
1507 ip6_address_t dst_address;
1510 fib = find_ip6_fib_by_table_index_or_id (im6, table_id,
1511 0 /* by table id */);
1513 a.flags |= IP4_ROUTE_FLAG_DEL;
1515 dst_address = ip6_dst_addresses[i];
1517 ip6_address_mask (&dst_address,
1518 &im6->fib_masks[dst_address_length]);
1520 kv.key[0] = dst_address.as_u64[0];
1521 kv.key[1] = dst_address.as_u64[1];
1522 kv.key[2] = ((u64)(fib - im6->fibs)<<32)
1523 | a.dst_address_length;
1525 if (BV(clib_bihash_search)(&im6->ip6_lookup_table,
1527 a.adj_index = value.value;
1530 clib_warning ("%U/%d not in FIB",
1531 format_ip6_address, &a.dst_address,
1532 a.dst_address_length);
1536 a.flags |= IP6_ROUTE_FLAG_DEL;
1537 ip6_add_del_route (im6, &a);
1538 ip6_maybe_remap_adjacencies (im6, table_id,
1539 IP6_ROUTE_FLAG_TABLE_ID);
1544 for (i = 0; i < vec_len (ip6_via_next_hops); i++)
1546 ip6_add_del_route_next_hop (im6,
1549 a.dst_address_length,
1550 &ip6_via_next_hops[i],
1552 weights[i], (u32)~0,
1553 table_ids[i] /* fib index */);
1559 if (vec_len (add_adj) > 0)
1561 a.flags |= IP6_ROUTE_FLAG_ADD;
1562 a.add_adj = add_adj;
1563 a.n_add_adj = vec_len (add_adj);
1565 ip6_add_del_route (im6, &a);
1567 else if (vec_len (ip6_via_next_hops) > 0)
1570 for (i = 0; i < vec_len (ip6_via_next_hops); i++)
1572 ip6_add_del_route_next_hop (im6,
1575 a.dst_address_length,
1576 &ip6_via_next_hops[i],
1578 weights[i], (u32)~0,
1589 vec_free (dst_address_lengths);
1590 vec_free (ip4_dst_addresses);
1591 vec_free (ip6_dst_addresses);
1592 vec_free (ip4_via_next_hops);
1593 vec_free (ip6_via_next_hops);
1597 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
1599 .short_help = "Internet protocol (IP) commands",
1602 VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
1604 .short_help = "Internet protocol (IP) show commands",
1607 VLIB_CLI_COMMAND (vlib_cli_show_ip4_command, static) = {
1609 .short_help = "Internet protocol version 4 (IP4) show commands",
1612 VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
1614 .short_help = "Internet protocol version 6 (IP6) show commands",
1617 VLIB_CLI_COMMAND (ip_route_command, static) = {
1619 .short_help = "Add/delete IP routes",
1620 .function = vnet_ip_route_cmd,
1625 * The next two routines address a longstanding script hemorrhoid.
1626 * Probing a v4 or v6 neighbor needs to appear to be synchronous,
1627 * or dependent route-adds will simply fail.
1629 static clib_error_t *
1630 ip6_probe_neighbor_wait (vlib_main_t *vm, ip6_address_t * a, u32 sw_if_index,
1633 vnet_main_t * vnm = vnet_get_main();
1638 uword *event_data = 0;
1640 ASSERT (vlib_in_process_context(vm));
1642 if (retry_count > 0)
1643 vnet_register_ip6_neighbor_resolution_event
1644 (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1645 1 /* event */, 0 /* data */);
1647 for (i = 0; i < retry_count; i++)
1649 /* The interface may be down, etc. */
1650 e = ip6_probe_neighbor (vm, a, sw_if_index);
1655 vlib_process_wait_for_event_or_clock (vm, 1.0);
1656 event_type = vlib_process_get_events (vm, &event_data);
1659 case 1: /* resolved... */
1660 vlib_cli_output (vm, "Resolved %U",
1661 format_ip6_address, a);
1665 case ~0: /* timeout */
1669 clib_warning ("unknown event_type %d", event_type);
1671 vec_reset_length (event_data);
1677 return clib_error_return (0, "Resolution failed for %U",
1678 format_ip6_address, a);
1682 static clib_error_t *
1683 ip4_probe_neighbor_wait (vlib_main_t *vm, ip4_address_t * a, u32 sw_if_index,
1686 vnet_main_t * vnm = vnet_get_main();
1691 uword *event_data = 0;
1693 ASSERT (vlib_in_process_context(vm));
1695 if (retry_count > 0)
1696 vnet_register_ip4_arp_resolution_event
1697 (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1698 1 /* event */, 0 /* data */);
1700 for (i = 0; i < retry_count; i++)
1702 /* The interface may be down, etc. */
1703 e = ip4_probe_neighbor (vm, a, sw_if_index);
1708 vlib_process_wait_for_event_or_clock (vm, 1.0);
1709 event_type = vlib_process_get_events (vm, &event_data);
1712 case 1: /* resolved... */
1713 vlib_cli_output (vm, "Resolved %U",
1714 format_ip4_address, a);
1718 case ~0: /* timeout */
1722 clib_warning ("unknown event_type %d", event_type);
1724 vec_reset_length (event_data);
1729 vec_reset_length (event_data);
1732 return clib_error_return (0, "Resolution failed for %U",
1733 format_ip4_address, a);
1737 static clib_error_t *
1738 probe_neighbor_address (vlib_main_t * vm,
1739 unformat_input_t * input,
1740 vlib_cli_command_t * cmd)
1742 vnet_main_t * vnm = vnet_get_main();
1743 unformat_input_t _line_input, * line_input = &_line_input;
1746 clib_error_t * error = 0;
1747 u32 sw_if_index = ~0;
1748 int retry_count = 3;
1750 int address_set = 0;
1752 /* Get a line of input. */
1753 if (! unformat_user (input, unformat_line_input, line_input))
1756 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1758 if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
1761 else if (unformat (line_input, "retry %d", &retry_count))
1764 else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
1766 else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
1772 return clib_error_return (0, "unknown input '%U'",
1773 format_unformat_error, line_input);
1776 unformat_free (line_input);
1778 if (sw_if_index == ~0)
1779 return clib_error_return (0, "Interface required, not set.");
1780 if (address_set == 0)
1781 return clib_error_return (0, "ip address required, not set.");
1782 if (address_set > 1)
1783 return clib_error_return (0, "Multiple ip addresses not supported.");
1786 error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
1788 error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
1793 VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
1794 .path = "ip probe-neighbor",
1795 .function = probe_neighbor_address,
1796 .short_help = "ip probe-neighbor <intfc> <ip4-addr> | <ip6-addr> [retry nn]",
1800 typedef CLIB_PACKED (struct {
1801 ip4_address_t address;
1803 u32 address_length : 6;
1809 ip4_route_cmp (void * a1, void * a2)
1811 ip4_route_t * r1 = a1;
1812 ip4_route_t * r2 = a2;
1814 int cmp = ip4_address_compare (&r1->address, &r2->address);
1815 return cmp ? cmp : ((int) r1->address_length - (int) r2->address_length);
1818 static clib_error_t *
1819 ip4_show_fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1821 vnet_main_t * vnm = vnet_get_main();
1822 ip4_main_t * im4 = &ip4_main;
1823 ip4_route_t * routes, * r;
1825 ip_lookup_main_t * lm = &im4->lookup_main;
1827 int verbose, matching, mtrie, include_empty_fibs;
1828 ip4_address_t matching_address;
1835 include_empty_fibs = 0;
1838 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1840 if (unformat (input, "brief") || unformat (input, "summary")
1841 || unformat (input, "sum"))
1844 else if (unformat (input, "mtrie"))
1847 else if (unformat (input, "include-empty"))
1848 include_empty_fibs = 1;
1850 else if (unformat (input, "%U", unformat_ip4_address, &matching_address))
1853 else if (unformat (input, "clear"))
1856 else if (unformat (input, "table %d", &table_id))
1862 vec_foreach (fib, im4->fibs)
1867 for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1869 uword * hash = fib->adj_index_by_dst_address[i];
1870 uword n_elts = hash_elts (hash);
1878 if (fib_not_empty == 0 && include_empty_fibs == 0)
1881 if (table_id >= 0 && table_id != (int)fib->table_id)
1884 if (include_empty_fibs)
1885 vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U",
1886 fib->table_id, fib - im4->fibs,
1887 format_ip_flow_hash_config, fib->flow_hash_config);
1892 if (include_empty_fibs == 0)
1893 vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U",
1894 fib->table_id, fib - im4->fibs,
1895 format_ip_flow_hash_config, fib->flow_hash_config);
1896 vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
1897 for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1899 uword * hash = fib->adj_index_by_dst_address[i];
1900 uword n_elts = hash_elts (hash);
1902 vlib_cli_output (vm, "%20d%16d", i, n_elts);
1908 _vec_len (routes) = 0;
1910 _vec_len (results) = 0;
1912 for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
1914 uword * hash = fib->adj_index_by_dst_address[i];
1918 x.address_length = i;
1922 x.address.as_u32 = matching_address.as_u32 & im4->fib_masks[i];
1923 p = hash_get_pair (hash, x.address.as_u32);
1926 if (lm->fib_result_n_words > 1)
1928 x.index = vec_len (results);
1929 vec_add (results, p->value, lm->fib_result_n_words);
1932 x.index = p->value[0];
1933 vec_add1 (routes, x);
1938 hash_foreach_pair (p, hash, ({
1939 x.address.data_u32 = p->key;
1940 if (lm->fib_result_n_words > 1)
1942 x.index = vec_len (results);
1943 vec_add (results, p->value, lm->fib_result_n_words);
1946 x.index = p->value[0];
1948 vec_add1 (routes, x);
1953 vec_sort_with_function (routes, ip4_route_cmp);
1954 if (vec_len(routes)) {
1955 if (include_empty_fibs == 0)
1956 vlib_cli_output (vm, "Table %d, fib_index %d, flow hash: %U",
1957 fib->table_id, fib - im4->fibs,
1958 format_ip_flow_hash_config, fib->flow_hash_config);
1960 vlib_cli_output (vm, "%U", format_ip4_fib_mtrie, &fib->mtrie);
1961 vlib_cli_output (vm, "%=20s%=16s%=16s%=16s",
1962 "Destination", "Packets", "Bytes", "Adjacency");
1964 vec_foreach (r, routes)
1966 vlib_counter_t c, sum;
1967 uword i, j, n_left, n_nhs, adj_index, * result = 0;
1968 ip_adjacency_t * adj;
1969 ip_multipath_next_hop_t * nhs, tmp_nhs[1];
1971 adj_index = r->index;
1972 if (lm->fib_result_n_words > 1)
1974 result = vec_elt_at_index (results, adj_index);
1975 adj_index = result[0];
1978 adj = ip_get_adjacency (lm, adj_index);
1979 if (adj->n_adj == 1)
1982 nhs[0].next_hop_adj_index = ~0; /* not used */
1988 ip_multipath_adjacency_t * madj;
1989 madj = vec_elt_at_index (lm->multipath_adjacencies, adj->heap_handle);
1990 nhs = heap_elt_at_index (lm->next_hop_heap, madj->normalized_next_hops.heap_offset);
1991 n_nhs = madj->normalized_next_hops.count;
1994 n_left = nhs[0].weight;
1995 vlib_counter_zero (&sum);
1996 for (i = j = 0; i < adj->n_adj; i++)
1999 vlib_get_combined_counter (&lm->adjacency_counters,
2002 vlib_zero_combined_counter (&lm->adjacency_counters,
2004 vlib_counter_add (&sum, &c);
2011 msg = format (msg, "%-20U",
2012 format_ip4_address_and_length,
2013 r->address.data, r->address_length);
2015 msg = format (msg, "%U", format_white_space, 20);
2017 msg = format (msg, "%16Ld%16Ld ", sum.packets, sum.bytes);
2019 indent = vec_len (msg);
2020 msg = format (msg, "weight %d, index %d\n%U%U",
2021 nhs[j].weight, adj_index + i,
2022 format_white_space, indent,
2023 format_ip_adjacency,
2024 vnm, lm, adj_index + i);
2026 vlib_cli_output (vm, "%v", msg);
2029 if (result && lm->format_fib_result)
2030 vlib_cli_output (vm, "%20s%U", "",
2031 lm->format_fib_result, vm, lm, result,
2032 i + 1 - nhs[j].weight,
2038 n_left = nhs[j].weight;
2039 vlib_counter_zero (&sum);
2052 VLIB_CLI_COMMAND (ip4_show_fib_command, static) = {
2053 .path = "show ip fib",
2054 .short_help = "show ip fib [mtrie] [summary] [table <n>] [<ip4-addr>] [clear] [include-empty]",
2055 .function = ip4_show_fib,
2059 ip6_address_t address;
2068 ip6_route_t ** routep;
2069 } add_routes_in_fib_arg_t;
2071 static void add_routes_in_fib (BVT(clib_bihash_kv) * kvp, void *arg)
2073 add_routes_in_fib_arg_t * ap = arg;
2075 if (kvp->key[2]>>32 == ap->fib_index)
2077 ip6_address_t *addr;
2079 addr = (ip6_address_t *) kvp;
2080 vec_add2 (*ap->routep, r, 1);
2081 r->address = addr[0];
2082 r->address_length = kvp->key[2] & 0xFF;
2083 r->index = kvp->value;
2089 u64 count_by_prefix_length[129];
2090 } count_routes_in_fib_at_prefix_length_arg_t;
2092 static void count_routes_in_fib_at_prefix_length
2093 (BVT(clib_bihash_kv) * kvp, void *arg)
2095 count_routes_in_fib_at_prefix_length_arg_t * ap = arg;
2098 if ((kvp->key[2]>>32) != ap->fib_index)
2101 mask_width = kvp->key[2] & 0xFF;
2103 ap->count_by_prefix_length[mask_width]++;
2107 ip6_route_cmp (void * a1, void * a2)
2109 ip6_route_t * r1 = a1;
2110 ip6_route_t * r2 = a2;
2112 int cmp = ip6_address_compare (&r1->address, &r2->address);
2113 return cmp ? cmp : ((int) r1->address_length - (int) r2->address_length);
2116 static clib_error_t *
2117 ip6_show_fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
2119 vnet_main_t * vnm = vnet_get_main();
2120 ip6_main_t * im6 = &ip6_main;
2121 ip6_route_t * routes, * r;
2123 ip_lookup_main_t * lm = &im6->lookup_main;
2126 BVT(clib_bihash) * h = &im6->ip6_lookup_table;
2127 __attribute__((unused)) u8 clear = 0;
2128 add_routes_in_fib_arg_t _a, *a=&_a;
2129 count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
2134 if (unformat (input, "brief") || unformat (input, "summary")
2135 || unformat (input, "sum"))
2138 if (unformat (input, "clear"))
2141 vlib_cli_output (vm, "FIB lookup table: %d buckets, %lld MB heap",
2142 im6->lookup_table_nbuckets, im6->lookup_table_size>>20);
2143 vlib_cli_output (vm, "%U", format_mheap, h->mheap, 0 /*verbose*/);
2144 vlib_cli_output (vm, " ");
2146 vec_foreach (fib, im6->fibs)
2148 vlib_cli_output (vm, "VRF %d, fib_index %d, flow hash: %U",
2149 fib->table_id, fib - im6->fibs,
2150 format_ip_flow_hash_config, fib->flow_hash_config);
2156 vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
2158 memset (ca, 0, sizeof(*ca));
2159 ca->fib_index = fib - im6->fibs;
2161 BV(clib_bihash_foreach_key_value_pair)
2162 (h, count_routes_in_fib_at_prefix_length, ca);
2164 for (len = 128; len >= 0; len--)
2166 if (ca->count_by_prefix_length[len])
2167 vlib_cli_output (vm, "%=20d%=16lld",
2168 len, ca->count_by_prefix_length[len]);
2174 _vec_len (routes) = 0;
2176 _vec_len (results) = 0;
2178 a->fib_index = fib - im6->fibs;
2179 a->routep = &routes;
2181 BV(clib_bihash_foreach_key_value_pair)(h, add_routes_in_fib, a);
2183 vec_sort_with_function (routes, ip6_route_cmp);
2185 vlib_cli_output (vm, "%=45s%=16s%=16s%=16s",
2186 "Destination", "Packets", "Bytes", "Adjacency");
2187 vec_foreach (r, routes)
2189 vlib_counter_t c, sum;
2190 uword i, j, n_left, n_nhs, adj_index, * result = 0;
2191 ip_adjacency_t * adj;
2192 ip_multipath_next_hop_t * nhs, tmp_nhs[1];
2194 adj_index = r->index;
2195 if (lm->fib_result_n_words > 1)
2197 result = vec_elt_at_index (results, adj_index);
2198 adj_index = result[0];
2201 adj = ip_get_adjacency (lm, adj_index);
2202 if (adj->n_adj == 1)
2205 nhs[0].next_hop_adj_index = ~0; /* not used */
2211 ip_multipath_adjacency_t * madj;
2212 madj = vec_elt_at_index (lm->multipath_adjacencies, adj->heap_handle);
2213 nhs = heap_elt_at_index (lm->next_hop_heap, madj->normalized_next_hops.heap_offset);
2214 n_nhs = madj->normalized_next_hops.count;
2217 n_left = nhs[0].weight;
2218 vlib_counter_zero (&sum);
2219 for (i = j = 0; i < adj->n_adj; i++)
2222 vlib_get_combined_counter (&lm->adjacency_counters,
2225 vlib_zero_combined_counter (&lm->adjacency_counters,
2227 vlib_counter_add (&sum, &c);
2234 msg = format (msg, "%-45U",
2235 format_ip6_address_and_length,
2236 r->address.as_u8, r->address_length);
2238 msg = format (msg, "%U", format_white_space, 20);
2240 msg = format (msg, "%16Ld%16Ld ", sum.packets, sum.bytes);
2242 indent = vec_len (msg);
2243 msg = format (msg, "weight %d, index %d\n%U%U",
2244 nhs[j].weight, adj_index + i,
2245 format_white_space, indent,
2246 format_ip_adjacency,
2247 vnm, lm, adj_index + i);
2249 vlib_cli_output (vm, "%v", msg);
2255 n_left = nhs[j].weight;
2256 vlib_counter_zero (&sum);
2261 if (result && lm->format_fib_result)
2262 vlib_cli_output (vm, "%20s%U", "", lm->format_fib_result, vm, lm, result, 0);
2264 vlib_cli_output (vm, " ");
2273 VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
2274 .path = "show ip6 fib",
2275 .short_help = "show ip6 fib [summary] [clear]",
2276 .function = ip6_show_fib,