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/ip4_forward.c: IP v4 forwarding
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 <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43 #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
44 #include <vnet/ppp/ppp.h>
45 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46 #include <vnet/api_errno.h> /* for API error numbers */
52 /* This is really, really simple but stupid fib. */
54 ip4_fib_lookup_with_table (ip4_main_t * im, u32 fib_index,
56 u32 disable_default_route)
58 ip_lookup_main_t * lm = &im->lookup_main;
59 ip4_fib_t * fib = vec_elt_at_index (im->fibs, fib_index);
60 uword * p, * hash, key;
61 i32 i, i_min, dst_address, ai;
63 i_min = disable_default_route ? 1 : 0;
64 dst_address = clib_mem_unaligned (&dst->data_u32, u32);
65 for (i = ARRAY_LEN (fib->adj_index_by_dst_address) - 1; i >= i_min; i--)
67 hash = fib->adj_index_by_dst_address[i];
71 key = dst_address & im->fib_masks[i];
72 if ((p = hash_get (hash, key)) != 0)
79 /* Nothing matches in table. */
80 ai = lm->miss_adj_index;
87 create_fib_with_table_id (ip4_main_t * im, u32 table_id)
90 hash_set (im->fib_index_by_table_id, table_id, vec_len (im->fibs));
91 vec_add2 (im->fibs, fib, 1);
92 fib->table_id = table_id;
93 fib->index = fib - im->fibs;
94 fib->flow_hash_config = IP_FLOW_HASH_DEFAULT;
95 fib->fwd_classify_table_index = ~0;
96 fib->rev_classify_table_index = ~0;
97 ip4_mtrie_init (&fib->mtrie);
102 find_ip4_fib_by_table_index_or_id (ip4_main_t * im,
103 u32 table_index_or_id, u32 flags)
105 uword * p, fib_index;
107 fib_index = table_index_or_id;
108 if (! (flags & IP4_ROUTE_FLAG_FIB_INDEX))
110 if (table_index_or_id == ~0) {
111 table_index_or_id = 0;
112 while ((p = hash_get (im->fib_index_by_table_id, table_index_or_id))) {
115 return create_fib_with_table_id (im, table_index_or_id);
118 p = hash_get (im->fib_index_by_table_id, table_index_or_id);
120 return create_fib_with_table_id (im, table_index_or_id);
123 return vec_elt_at_index (im->fibs, fib_index);
127 ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm,
134 ASSERT (lm->fib_result_n_bytes >= sizeof (uword));
135 lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword)) / sizeof (uword);
137 fib->adj_index_by_dst_address[address_length] =
138 hash_create (32 /* elts */, lm->fib_result_n_words * sizeof (uword));
140 hash_set_flags (fib->adj_index_by_dst_address[address_length],
141 HASH_FLAG_NO_AUTO_SHRINK);
143 h = hash_header (fib->adj_index_by_dst_address[address_length]);
144 max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1;
146 /* Initialize new/old hash value vectors. */
147 vec_validate_init_empty (fib->new_hash_values, max_index, ~0);
148 vec_validate_init_empty (fib->old_hash_values, max_index, ~0);
152 ip4_fib_set_adj_index (ip4_main_t * im,
156 u32 dst_address_length,
159 ip_lookup_main_t * lm = &im->lookup_main;
162 if (vec_bytes(fib->old_hash_values))
163 memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values));
164 if (vec_bytes(fib->new_hash_values))
165 memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values));
166 fib->new_hash_values[0] = adj_index;
168 /* Make sure adj index is valid. */
170 (void) ip_get_adjacency (lm, adj_index);
172 hash = fib->adj_index_by_dst_address[dst_address_length];
174 hash = _hash_set3 (hash, dst_address_u32,
175 fib->new_hash_values,
176 fib->old_hash_values);
178 fib->adj_index_by_dst_address[dst_address_length] = hash;
180 if (vec_len (im->add_del_route_callbacks) > 0)
182 ip4_add_del_route_callback_t * cb;
186 d.data_u32 = dst_address_u32;
187 vec_foreach (cb, im->add_del_route_callbacks)
188 if ((flags & cb->required_flags) == cb->required_flags)
189 cb->function (im, cb->function_opaque,
191 &d, dst_address_length,
192 fib->old_hash_values,
193 fib->new_hash_values);
195 p = hash_get (hash, dst_address_u32);
196 clib_memcpy (p, fib->new_hash_values, vec_bytes (fib->new_hash_values));
200 void ip4_add_del_route (ip4_main_t * im, ip4_add_del_route_args_t * a)
202 ip_lookup_main_t * lm = &im->lookup_main;
204 u32 dst_address, dst_address_length, adj_index, old_adj_index;
205 uword * hash, is_del;
206 ip4_add_del_route_callback_t * cb;
208 /* Either create new adjacency or use given one depending on arguments. */
209 if (a->n_add_adj > 0)
211 ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
212 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
215 adj_index = a->adj_index;
217 dst_address = a->dst_address.data_u32;
218 dst_address_length = a->dst_address_length;
219 fib = find_ip4_fib_by_table_index_or_id (im, a->table_index_or_table_id, a->flags);
221 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
222 dst_address &= im->fib_masks[dst_address_length];
224 if (! fib->adj_index_by_dst_address[dst_address_length])
225 ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length);
227 hash = fib->adj_index_by_dst_address[dst_address_length];
229 is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0;
233 fib->old_hash_values[0] = ~0;
234 hash = _hash_unset (hash, dst_address, fib->old_hash_values);
235 fib->adj_index_by_dst_address[dst_address_length] = hash;
237 if (vec_len (im->add_del_route_callbacks) > 0
238 && fib->old_hash_values[0] != ~0) /* make sure destination was found in hash */
240 fib->new_hash_values[0] = ~0;
241 vec_foreach (cb, im->add_del_route_callbacks)
242 if ((a->flags & cb->required_flags) == cb->required_flags)
243 cb->function (im, cb->function_opaque,
245 &a->dst_address, dst_address_length,
246 fib->old_hash_values,
247 fib->new_hash_values);
251 ip4_fib_set_adj_index (im, fib, a->flags, dst_address, dst_address_length,
254 old_adj_index = fib->old_hash_values[0];
256 /* Avoid spurious reference count increments */
257 if (old_adj_index == adj_index
259 && !(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY))
261 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
262 if (adj->share_count > 0)
266 ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length,
267 is_del ? old_adj_index : adj_index,
270 /* Delete old adjacency index if present and changed. */
271 if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
272 && old_adj_index != ~0
273 && old_adj_index != adj_index)
274 ip_del_adjacency (lm, old_adj_index);
279 ip4_route_get_next_hop_adj (ip4_main_t * im,
281 ip4_address_t *next_hop,
282 u32 next_hop_sw_if_index,
283 u32 explicit_fib_index)
285 ip_lookup_main_t * lm = &im->lookup_main;
286 vnet_main_t * vnm = vnet_get_main();
287 uword * nh_hash, * nh_result;
288 int is_interface_next_hop;
292 fib = vec_elt_at_index (im->fibs, fib_index);
294 is_interface_next_hop = next_hop->data_u32 == 0;
295 if (is_interface_next_hop)
297 nh_result = hash_get (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index);
299 nh_adj_index = *nh_result;
302 ip_adjacency_t * adj;
303 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
305 ip4_adjacency_set_interface_route (vnm, adj, next_hop_sw_if_index, /* if_address_index */ ~0);
306 ip_call_add_del_adjacency_callbacks (lm, nh_adj_index, /* is_del */ 0);
307 hash_set (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index, nh_adj_index);
310 else if (next_hop_sw_if_index == ~0)
312 /* next-hop is recursive. we always need a indirect adj
313 * for recursive paths. Any LPM we perform now will give
314 * us a valid adj, but without tracking the next-hop we
315 * have no way to keep it valid.
317 ip_adjacency_t add_adj;
318 memset (&add_adj, 0, sizeof(add_adj));
320 add_adj.lookup_next_index = IP_LOOKUP_NEXT_INDIRECT;
321 add_adj.indirect.next_hop.ip4.as_u32 = next_hop->as_u32;
322 add_adj.explicit_fib_index = explicit_fib_index;
323 ip_add_adjacency (lm, &add_adj, 1, &nh_adj_index);
327 nh_hash = fib->adj_index_by_dst_address[32];
328 nh_result = hash_get (nh_hash, next_hop->data_u32);
330 /* Next hop must be known. */
333 ip_adjacency_t * adj;
335 /* no /32 exists, get the longest prefix match */
336 nh_adj_index = ip4_fib_lookup_with_table (im, fib_index,
338 adj = ip_get_adjacency (lm, nh_adj_index);
339 /* if ARP interface adjacency is present, we need to
340 install ARP adjaceny for specific next hop */
341 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
342 adj->arp.next_hop.ip4.as_u32 == 0)
344 nh_adj_index = vnet_arp_glean_add(fib_index, next_hop);
349 nh_adj_index = *nh_result;
353 return (nh_adj_index);
357 ip4_add_del_route_next_hop (ip4_main_t * im,
359 ip4_address_t * dst_address,
360 u32 dst_address_length,
361 ip4_address_t * next_hop,
362 u32 next_hop_sw_if_index,
363 u32 next_hop_weight, u32 adj_index,
364 u32 explicit_fib_index)
366 vnet_main_t * vnm = vnet_get_main();
367 ip_lookup_main_t * lm = &im->lookup_main;
370 u32 dst_address_u32, old_mp_adj_index, new_mp_adj_index;
371 u32 dst_adj_index, nh_adj_index;
372 uword * dst_hash, * dst_result;
373 ip_adjacency_t * dst_adj;
374 ip_multipath_adjacency_t * old_mp, * new_mp;
375 int is_del = (flags & IP4_ROUTE_FLAG_DEL) != 0;
376 clib_error_t * error = 0;
378 if (explicit_fib_index == (u32)~0)
379 fib_index = vec_elt (im->fib_index_by_sw_if_index, next_hop_sw_if_index);
381 fib_index = explicit_fib_index;
383 fib = vec_elt_at_index (im->fibs, fib_index);
385 /* Lookup next hop to be added or deleted. */
386 if (adj_index == (u32)~0)
388 nh_adj_index = ip4_route_get_next_hop_adj(im, fib_index,
390 next_hop_sw_if_index,
395 nh_adj_index = adj_index;
397 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
398 dst_address_u32 = dst_address->data_u32 & im->fib_masks[dst_address_length];
400 dst_hash = fib->adj_index_by_dst_address[dst_address_length];
401 dst_result = hash_get (dst_hash, dst_address_u32);
404 dst_adj_index = dst_result[0];
405 dst_adj = ip_get_adjacency (lm, dst_adj_index);
409 /* For deletes destination must be known. */
412 vnm->api_errno = VNET_API_ERROR_UNKNOWN_DESTINATION;
413 error = clib_error_return (0, "unknown destination %U/%d",
414 format_ip4_address, dst_address,
423 /* Ignore adds of X/32 with next hop of X. */
425 && dst_address_length == 32
426 && dst_address->data_u32 == next_hop->data_u32
427 && adj_index != (u32)~0)
429 vnm->api_errno = VNET_API_ERROR_PREFIX_MATCHES_NEXT_HOP;
430 error = clib_error_return (0, "prefix matches next hop %U/%d",
431 format_ip4_address, dst_address,
436 /* Destination is not known and default weight is set so add route
437 to existing non-multipath adjacency */
438 if (dst_adj_index == ~0 && next_hop_weight == 1 && next_hop_sw_if_index == ~0)
440 /* create / delete additional mapping of existing adjacency */
441 ip4_add_del_route_args_t a;
442 ip_adjacency_t * nh_adj = ip_get_adjacency (lm, nh_adj_index);
444 a.table_index_or_table_id = fib_index;
445 a.flags = ((is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
446 | IP4_ROUTE_FLAG_FIB_INDEX
447 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
448 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE
449 | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
450 a.dst_address = dst_address[0];
451 a.dst_address_length = dst_address_length;
452 a.adj_index = nh_adj_index;
456 ip4_add_del_route (im, &a);
458 /* adjust share count. This cannot be the only use of the adjacency
459 unless next hop is an indiect adj where share count is already
461 if (next_hop_sw_if_index != ~0)
462 nh_adj->share_count += is_del ? -1 : 1;
467 old_mp_adj_index = dst_adj ? dst_adj->heap_handle : ~0;
469 if (! ip_multipath_adjacency_add_del_next_hop
476 vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_FOUND_MP;
477 error = clib_error_return (0, "requested deleting next-hop %U not found in multi-path",
478 format_ip4_address, next_hop);
483 if (old_mp_adj_index != ~0)
484 old_mp = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
485 if (new_mp_adj_index != ~0)
486 new_mp = vec_elt_at_index (lm->multipath_adjacencies, new_mp_adj_index);
488 if (old_mp != new_mp)
490 ip4_add_del_route_args_t a;
491 ip_adjacency_t * adj;
493 a.table_index_or_table_id = fib_index;
494 a.flags = ((is_del && ! new_mp ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
495 | IP4_ROUTE_FLAG_FIB_INDEX
496 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
497 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
498 a.dst_address = dst_address[0];
499 a.dst_address_length = dst_address_length;
500 a.adj_index = new_mp ? new_mp->adj_index : dst_adj_index;
504 ip4_add_del_route (im, &a);
506 adj = ip_get_adjacency (lm, new_mp ? new_mp->adj_index : dst_adj_index);
508 adj->share_count += is_del ? -1 : 1;
513 clib_error_report (error);
517 ip4_get_route (ip4_main_t * im,
518 u32 table_index_or_table_id,
523 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
524 u32 dst_address = * (u32 *) address;
527 ASSERT (address_length < ARRAY_LEN (im->fib_masks));
528 dst_address &= im->fib_masks[address_length];
530 hash = fib->adj_index_by_dst_address[address_length];
531 p = hash_get (hash, dst_address);
536 ip4_foreach_matching_route (ip4_main_t * im,
537 u32 table_index_or_table_id,
539 ip4_address_t * address,
541 ip4_address_t ** results,
542 u8 ** result_lengths)
544 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
545 u32 dst_address = address->data_u32;
546 u32 this_length = address_length;
549 _vec_len (*results) = 0;
551 _vec_len (*result_lengths) = 0;
553 while (this_length <= 32 && vec_len (results) == 0)
556 hash_foreach (k, v, fib->adj_index_by_dst_address[this_length], ({
557 if (0 == ((k ^ dst_address) & im->fib_masks[address_length]))
561 vec_add1 (*results, a);
562 vec_add1 (*result_lengths, this_length);
570 void ip4_maybe_remap_adjacencies (ip4_main_t * im,
571 u32 table_index_or_table_id,
574 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
575 ip_lookup_main_t * lm = &im->lookup_main;
578 ip4_add_del_route_callback_t * cb;
579 static ip4_address_t * to_delete;
581 if (lm->n_adjacency_remaps == 0)
584 for (l = 0; l <= 32; l++)
587 uword * hash = fib->adj_index_by_dst_address[l];
589 if (hash_elts (hash) == 0)
593 _vec_len (to_delete) = 0;
595 hash_foreach_pair (p, hash, ({
596 u32 adj_index = p->value[0];
597 u32 m = vec_elt (lm->adjacency_remap_table, adj_index);
601 /* Record destination address from hash key. */
604 /* New adjacency points to nothing: so delete prefix. */
606 vec_add1 (to_delete, a);
609 /* Remap to new adjacency. */
610 clib_memcpy (fib->old_hash_values, p->value, vec_bytes (fib->old_hash_values));
612 /* Set new adjacency value. */
613 fib->new_hash_values[0] = p->value[0] = m - 1;
615 vec_foreach (cb, im->add_del_route_callbacks)
616 if ((flags & cb->required_flags) == cb->required_flags)
617 cb->function (im, cb->function_opaque,
618 fib, flags | IP4_ROUTE_FLAG_ADD,
620 fib->old_hash_values,
621 fib->new_hash_values);
626 fib->new_hash_values[0] = ~0;
627 for (i = 0; i < vec_len (to_delete); i++)
629 hash = _hash_unset (hash, to_delete[i].data_u32, fib->old_hash_values);
630 vec_foreach (cb, im->add_del_route_callbacks)
631 if ((flags & cb->required_flags) == cb->required_flags)
632 cb->function (im, cb->function_opaque,
633 fib, flags | IP4_ROUTE_FLAG_DEL,
635 fib->old_hash_values,
636 fib->new_hash_values);
640 /* Also remap adjacencies in mtrie. */
641 ip4_mtrie_maybe_remap_adjacencies (lm, &fib->mtrie);
643 /* Reset mapping table. */
644 vec_zero (lm->adjacency_remap_table);
646 /* All remaps have been performed. */
647 lm->n_adjacency_remaps = 0;
650 void ip4_delete_matching_routes (ip4_main_t * im,
651 u32 table_index_or_table_id,
653 ip4_address_t * address,
656 static ip4_address_t * matching_addresses;
657 static u8 * matching_address_lengths;
659 ip4_add_del_route_args_t a;
661 a.flags = IP4_ROUTE_FLAG_DEL | IP4_ROUTE_FLAG_NO_REDISTRIBUTE | flags;
662 a.table_index_or_table_id = table_index_or_table_id;
667 for (l = address_length + 1; l <= 32; l++)
669 ip4_foreach_matching_route (im, table_index_or_table_id, flags,
673 &matching_address_lengths);
674 for (i = 0; i < vec_len (matching_addresses); i++)
676 a.dst_address = matching_addresses[i];
677 a.dst_address_length = matching_address_lengths[i];
678 ip4_add_del_route (im, &a);
682 ip4_maybe_remap_adjacencies (im, table_index_or_table_id, flags);
686 ip4_forward_next_trace (vlib_main_t * vm,
687 vlib_node_runtime_t * node,
688 vlib_frame_t * frame,
689 vlib_rx_or_tx_t which_adj_index);
692 ip4_lookup_inline (vlib_main_t * vm,
693 vlib_node_runtime_t * node,
694 vlib_frame_t * frame,
695 int lookup_for_responses_to_locally_received_packets,
698 ip4_main_t * im = &ip4_main;
699 ip_lookup_main_t * lm = &im->lookup_main;
700 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
701 u32 n_left_from, n_left_to_next, * from, * to_next;
702 ip_lookup_next_t next;
703 u32 cpu_index = os_get_cpu_number();
705 from = vlib_frame_vector_args (frame);
706 n_left_from = frame->n_vectors;
707 next = node->cached_next_index;
709 while (n_left_from > 0)
711 vlib_get_next_frame (vm, node, next,
712 to_next, n_left_to_next);
714 while (n_left_from >= 4 && n_left_to_next >= 2)
716 vlib_buffer_t * p0, * p1;
717 ip4_header_t * ip0, * ip1;
718 __attribute__((unused)) tcp_header_t * tcp0, * tcp1;
719 ip_lookup_next_t next0, next1;
720 ip_adjacency_t * adj0, * adj1;
721 ip4_fib_mtrie_t * mtrie0, * mtrie1;
722 ip4_fib_mtrie_leaf_t leaf0, leaf1;
723 ip4_address_t * dst_addr0, *dst_addr1;
724 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
725 __attribute__((unused)) u32 pi1, fib_index1, adj_index1, is_tcp_udp1;
726 u32 flow_hash_config0, flow_hash_config1;
727 u32 hash_c0, hash_c1;
730 /* Prefetch next iteration. */
732 vlib_buffer_t * p2, * p3;
734 p2 = vlib_get_buffer (vm, from[2]);
735 p3 = vlib_get_buffer (vm, from[3]);
737 vlib_prefetch_buffer_header (p2, LOAD);
738 vlib_prefetch_buffer_header (p3, LOAD);
740 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
741 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
744 pi0 = to_next[0] = from[0];
745 pi1 = to_next[1] = from[1];
747 p0 = vlib_get_buffer (vm, pi0);
748 p1 = vlib_get_buffer (vm, pi1);
750 ip0 = vlib_buffer_get_current (p0);
751 ip1 = vlib_buffer_get_current (p1);
755 ip_adjacency_t * iadj0, * iadj1;
756 iadj0 = ip_get_adjacency (lm, vnet_buffer(p0)->ip.adj_index[VLIB_TX]);
757 iadj1 = ip_get_adjacency (lm, vnet_buffer(p1)->ip.adj_index[VLIB_TX]);
758 dst_addr0 = &iadj0->indirect.next_hop.ip4;
759 dst_addr1 = &iadj1->indirect.next_hop.ip4;
763 dst_addr0 = &ip0->dst_address;
764 dst_addr1 = &ip1->dst_address;
767 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
768 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
769 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
770 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
771 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
772 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
775 if (! lookup_for_responses_to_locally_received_packets)
777 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
778 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
780 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
782 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
783 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
786 tcp0 = (void *) (ip0 + 1);
787 tcp1 = (void *) (ip1 + 1);
789 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
790 || ip0->protocol == IP_PROTOCOL_UDP);
791 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
792 || ip1->protocol == IP_PROTOCOL_UDP);
794 if (! lookup_for_responses_to_locally_received_packets)
796 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
797 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
800 if (! lookup_for_responses_to_locally_received_packets)
802 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
803 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
806 if (! lookup_for_responses_to_locally_received_packets)
808 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
809 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
812 if (lookup_for_responses_to_locally_received_packets)
814 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
815 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
819 /* Handle default route. */
820 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
821 leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
823 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
824 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
827 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
829 /* no_default_route */ 0));
830 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
832 /* no_default_route */ 0));
833 adj0 = ip_get_adjacency (lm, adj_index0);
834 adj1 = ip_get_adjacency (lm, adj_index1);
836 next0 = adj0->lookup_next_index;
837 next1 = adj1->lookup_next_index;
839 /* Use flow hash to compute multipath adjacency. */
840 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
841 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
842 if (PREDICT_FALSE (adj0->n_adj > 1))
845 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
846 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
847 ip4_compute_flow_hash (ip0, flow_hash_config0);
849 if (PREDICT_FALSE(adj1->n_adj > 1))
852 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
853 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
854 ip4_compute_flow_hash (ip1, flow_hash_config1);
857 ASSERT (adj0->n_adj > 0);
858 ASSERT (adj1->n_adj > 0);
859 ASSERT (is_pow2 (adj0->n_adj));
860 ASSERT (is_pow2 (adj1->n_adj));
861 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
862 adj_index1 += (hash_c1 & (adj1->n_adj - 1));
864 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
865 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
867 vlib_increment_combined_counter
868 (cm, cpu_index, adj_index0, 1,
869 vlib_buffer_length_in_chain (vm, p0)
870 + sizeof(ethernet_header_t));
871 vlib_increment_combined_counter
872 (cm, cpu_index, adj_index1, 1,
873 vlib_buffer_length_in_chain (vm, p1)
874 + sizeof(ethernet_header_t));
881 wrong_next = (next0 != next) + 2*(next1 != next);
882 if (PREDICT_FALSE (wrong_next != 0))
891 vlib_set_next_frame_buffer (vm, node, next0, pi0);
898 vlib_set_next_frame_buffer (vm, node, next1, pi1);
905 vlib_set_next_frame_buffer (vm, node, next0, pi0);
906 vlib_set_next_frame_buffer (vm, node, next1, pi1);
910 vlib_put_next_frame (vm, node, next, n_left_to_next);
912 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
918 while (n_left_from > 0 && n_left_to_next > 0)
922 __attribute__((unused)) tcp_header_t * tcp0;
923 ip_lookup_next_t next0;
924 ip_adjacency_t * adj0;
925 ip4_fib_mtrie_t * mtrie0;
926 ip4_fib_mtrie_leaf_t leaf0;
927 ip4_address_t * dst_addr0;
928 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
929 u32 flow_hash_config0, hash_c0;
934 p0 = vlib_get_buffer (vm, pi0);
936 ip0 = vlib_buffer_get_current (p0);
940 ip_adjacency_t * iadj0;
941 iadj0 = ip_get_adjacency (lm, vnet_buffer(p0)->ip.adj_index[VLIB_TX]);
942 dst_addr0 = &iadj0->indirect.next_hop.ip4;
946 dst_addr0 = &ip0->dst_address;
949 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
950 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
951 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
953 if (! lookup_for_responses_to_locally_received_packets)
955 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
957 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
959 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
962 tcp0 = (void *) (ip0 + 1);
964 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
965 || ip0->protocol == IP_PROTOCOL_UDP);
967 if (! lookup_for_responses_to_locally_received_packets)
968 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
970 if (! lookup_for_responses_to_locally_received_packets)
971 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
973 if (! lookup_for_responses_to_locally_received_packets)
974 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
976 if (lookup_for_responses_to_locally_received_packets)
977 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
980 /* Handle default route. */
981 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
982 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
985 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
987 /* no_default_route */ 0));
989 adj0 = ip_get_adjacency (lm, adj_index0);
991 next0 = adj0->lookup_next_index;
993 /* Use flow hash to compute multipath adjacency. */
994 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
995 if (PREDICT_FALSE(adj0->n_adj > 1))
998 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
1000 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
1001 ip4_compute_flow_hash (ip0, flow_hash_config0);
1004 ASSERT (adj0->n_adj > 0);
1005 ASSERT (is_pow2 (adj0->n_adj));
1006 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
1008 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
1010 vlib_increment_combined_counter
1011 (cm, cpu_index, adj_index0, 1,
1012 vlib_buffer_length_in_chain (vm, p0)
1013 + sizeof(ethernet_header_t));
1017 n_left_to_next -= 1;
1020 if (PREDICT_FALSE (next0 != next))
1022 n_left_to_next += 1;
1023 vlib_put_next_frame (vm, node, next, n_left_to_next);
1025 vlib_get_next_frame (vm, node, next,
1026 to_next, n_left_to_next);
1029 n_left_to_next -= 1;
1033 vlib_put_next_frame (vm, node, next, n_left_to_next);
1036 if (node->flags & VLIB_NODE_FLAG_TRACE)
1037 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
1039 return frame->n_vectors;
1042 /** \brief IPv4 lookup node.
1045 This is the main IPv4 lookup dispatch node.
1047 @param vm vlib_main_t corresponding to the current thread
1048 @param node vlib_node_runtime_t
1049 @param frame vlib_frame_t whose contents should be dispatched
1051 @par Graph mechanics: buffer metadata, next index usage
1054 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
1055 - Indicates the @c sw_if_index value of the interface that the
1056 packet was received on.
1057 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
1058 - When the value is @c ~0 then the node performs a longest prefix
1059 match (LPM) for the packet destination address in the FIB attached
1060 to the receive interface.
1061 - Otherwise perform LPM for the packet destination address in the
1062 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
1063 value (0, 1, ...) and not a VRF id.
1066 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
1067 - The lookup result adjacency index.
1069 <em>Next Index:</em>
1070 - Dispatches the packet to the node index found in
1071 ip_adjacency_t @c adj->lookup_next_index
1072 (where @c adj is the lookup result adjacency).
1075 ip4_lookup (vlib_main_t * vm,
1076 vlib_node_runtime_t * node,
1077 vlib_frame_t * frame)
1079 return ip4_lookup_inline (vm, node, frame,
1080 /* lookup_for_responses_to_locally_received_packets */ 0,
1081 /* is_indirect */ 0);
1085 void ip4_adjacency_set_interface_route (vnet_main_t * vnm,
1086 ip_adjacency_t * adj,
1088 u32 if_address_index)
1090 vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1092 vnet_l3_packet_type_t packet_type;
1095 if (hw->hw_class_index == ethernet_hw_interface_class.index
1096 || hw->hw_class_index == srp_hw_interface_class.index)
1099 * We have a bit of a problem in this case. ip4-arp uses
1100 * the rewrite_header.next_index to hand pkts to the
1101 * indicated inteface output node. We can end up in
1102 * ip4_rewrite_local, too, which also pays attention to
1103 * rewrite_header.next index. Net result: a hack in
1104 * ip4_rewrite_local...
1106 n = IP_LOOKUP_NEXT_ARP;
1107 node_index = ip4_arp_node.index;
1108 adj->if_address_index = if_address_index;
1109 adj->arp.next_hop.ip4.as_u32 = 0;
1110 ip46_address_reset(&adj->arp.next_hop);
1111 packet_type = VNET_L3_PACKET_TYPE_ARP;
1115 n = IP_LOOKUP_NEXT_REWRITE;
1116 node_index = ip4_rewrite_node.index;
1117 packet_type = VNET_L3_PACKET_TYPE_IP4;
1120 adj->lookup_next_index = n;
1121 vnet_rewrite_for_sw_interface
1126 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST,
1127 &adj->rewrite_header,
1128 sizeof (adj->rewrite_data));
1132 ip4_add_interface_routes (u32 sw_if_index,
1133 ip4_main_t * im, u32 fib_index,
1134 ip_interface_address_t * a)
1136 vnet_main_t * vnm = vnet_get_main();
1137 ip_lookup_main_t * lm = &im->lookup_main;
1138 ip_adjacency_t * adj;
1139 ip4_address_t * address = ip_interface_address_get_address (lm, a);
1140 ip4_add_del_route_args_t x;
1141 vnet_hw_interface_t * hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
1142 u32 classify_table_index;
1144 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1145 x.table_index_or_table_id = fib_index;
1146 x.flags = (IP4_ROUTE_FLAG_ADD
1147 | IP4_ROUTE_FLAG_FIB_INDEX
1148 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1149 x.dst_address = address[0];
1150 x.dst_address_length = a->address_length;
1154 a->neighbor_probe_adj_index = ~0;
1155 if (a->address_length < 32)
1157 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1159 ip4_adjacency_set_interface_route (vnm, adj, sw_if_index, a - lm->if_address_pool);
1160 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1161 ip4_add_del_route (im, &x);
1162 a->neighbor_probe_adj_index = x.adj_index;
1165 /* Add e.g. 1.1.1.1/32 as local to this host. */
1166 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1169 classify_table_index = ~0;
1170 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
1171 classify_table_index = lm->classify_table_index_by_sw_if_index [sw_if_index];
1172 if (classify_table_index != (u32) ~0)
1174 adj->lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1175 adj->classify.table_index = classify_table_index;
1178 adj->lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
1180 adj->if_address_index = a - lm->if_address_pool;
1181 adj->rewrite_header.sw_if_index = sw_if_index;
1182 adj->rewrite_header.max_l3_packet_bytes = hw_if->max_l3_packet_bytes[VLIB_RX];
1184 * Local adjs are never to be rewritten. Spoofed pkts w/ src = dst = local
1185 * fail an RPF-ish check, but still go thru the rewrite code...
1187 adj->rewrite_header.data_bytes = 0;
1189 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1190 x.dst_address_length = 32;
1191 ip4_add_del_route (im, &x);
1195 ip4_del_interface_routes (ip4_main_t * im, u32 fib_index, ip4_address_t * address, u32 address_length)
1197 ip4_add_del_route_args_t x;
1199 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1200 x.table_index_or_table_id = fib_index;
1201 x.flags = (IP4_ROUTE_FLAG_DEL
1202 | IP4_ROUTE_FLAG_FIB_INDEX
1203 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1204 x.dst_address = address[0];
1205 x.dst_address_length = address_length;
1210 if (address_length < 32)
1211 ip4_add_del_route (im, &x);
1213 x.dst_address_length = 32;
1214 ip4_add_del_route (im, &x);
1216 ip4_delete_matching_routes (im,
1218 IP4_ROUTE_FLAG_FIB_INDEX,
1225 ip4_address_t address;
1227 } ip4_interface_address_t;
1229 static clib_error_t *
1230 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1232 ip4_address_t * new_address,
1238 static clib_error_t *
1239 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1241 ip4_address_t * address,
1247 vnet_main_t * vnm = vnet_get_main();
1248 ip4_main_t * im = &ip4_main;
1249 ip_lookup_main_t * lm = &im->lookup_main;
1250 clib_error_t * error = 0;
1251 u32 if_address_index, elts_before;
1252 ip4_address_fib_t ip4_af, * addr_fib = 0;
1254 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1255 ip4_addr_fib_init (&ip4_af, address,
1256 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
1257 vec_add1 (addr_fib, ip4_af);
1259 /* When adding an address check that it does not conflict with an existing address. */
1262 ip_interface_address_t * ia;
1263 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1264 0 /* honor unnumbered */,
1266 ip4_address_t * x = ip_interface_address_get_address (&im->lookup_main, ia);
1268 if (ip4_destination_matches_route (im, address, x, ia->address_length)
1269 || ip4_destination_matches_route (im, x, address, address_length))
1270 return clib_error_create ("failed to add %U which conflicts with %U for interface %U",
1271 format_ip4_address_and_length, address, address_length,
1272 format_ip4_address_and_length, x, ia->address_length,
1273 format_vnet_sw_if_index_name, vnm, sw_if_index);
1277 elts_before = pool_elts (lm->if_address_pool);
1279 error = ip_interface_address_add_del
1289 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index) && insert_routes)
1292 ip4_del_interface_routes (im, ip4_af.fib_index, address,
1296 ip4_add_interface_routes (sw_if_index,
1297 im, ip4_af.fib_index,
1299 (lm->if_address_pool, if_address_index));
1302 /* If pool did not grow/shrink: add duplicate address. */
1303 if (elts_before != pool_elts (lm->if_address_pool))
1305 ip4_add_del_interface_address_callback_t * cb;
1306 vec_foreach (cb, im->add_del_interface_address_callbacks)
1307 cb->function (im, cb->function_opaque, sw_if_index,
1308 address, address_length,
1314 vec_free (addr_fib);
1319 ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index,
1320 ip4_address_t * address, u32 address_length,
1323 return ip4_add_del_interface_address_internal
1324 (vm, sw_if_index, address, address_length,
1325 /* redistribute */ 1,
1326 /* insert_routes */ 1,
1330 static clib_error_t *
1331 ip4_sw_interface_admin_up_down (vnet_main_t * vnm,
1335 ip4_main_t * im = &ip4_main;
1336 ip_interface_address_t * ia;
1338 u32 is_admin_up, fib_index;
1340 /* Fill in lookup tables with default table (0). */
1341 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1343 vec_validate_init_empty (im->lookup_main.if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
1345 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1347 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
1349 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1350 0 /* honor unnumbered */,
1352 a = ip_interface_address_get_address (&im->lookup_main, ia);
1354 ip4_add_interface_routes (sw_if_index,
1358 ip4_del_interface_routes (im, fib_index,
1359 a, ia->address_length);
1365 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
1367 /* Built-in ip4 unicast rx feature path definition */
1368 VNET_IP4_UNICAST_FEATURE_INIT (ip4_inacl, static) = {
1369 .node_name = "ip4-inacl",
1370 .runs_before = {"ip4-source-check-via-rx", 0},
1371 .feature_index = &ip4_main.ip4_unicast_rx_feature_check_access,
1374 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
1375 .node_name = "ip4-source-check-via-rx",
1376 .runs_before = {"ip4-source-check-via-any", 0},
1378 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_rx,
1381 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
1382 .node_name = "ip4-source-check-via-any",
1383 .runs_before = {"ip4-policer-classify", 0},
1385 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
1388 VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
1389 .node_name = "ip4-policer-classify",
1390 .runs_before = {"ipsec-input-ip4", 0},
1392 &ip4_main.ip4_unicast_rx_feature_policer_classify,
1395 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
1396 .node_name = "ipsec-input-ip4",
1397 .runs_before = {"vpath-input-ip4", 0},
1398 .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
1401 VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
1402 .node_name = "vpath-input-ip4",
1403 .runs_before = {"ip4-lookup", 0},
1404 .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
1407 VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
1408 .node_name = "ip4-lookup",
1409 .runs_before = {0}, /* not before any other features */
1410 .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
1413 /* Built-in ip4 multicast rx feature path definition */
1414 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
1415 .node_name = "vpath-input-ip4",
1416 .runs_before = {"ip4-lookup-multicast", 0},
1417 .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
1420 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
1421 .node_name = "ip4-lookup-multicast",
1422 .runs_before = {0}, /* not before any other features */
1423 .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
1426 static char * feature_start_nodes[] =
1427 { "ip4-input", "ip4-input-no-checksum"};
1429 static clib_error_t *
1430 ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
1432 ip_lookup_main_t * lm = &im->lookup_main;
1433 clib_error_t * error;
1436 for (cast = 0; cast < VNET_N_CAST; cast++)
1438 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1439 vnet_config_main_t * vcm = &cm->config_main;
1441 if ((error = ip_feature_init_cast (vm, cm, vcm,
1442 feature_start_nodes,
1443 ARRAY_LEN(feature_start_nodes),
1451 static clib_error_t *
1452 ip4_sw_interface_add_del (vnet_main_t * vnm,
1456 vlib_main_t * vm = vnm->vlib_main;
1457 ip4_main_t * im = &ip4_main;
1458 ip_lookup_main_t * lm = &im->lookup_main;
1462 for (cast = 0; cast < VNET_N_CAST; cast++)
1464 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1465 vnet_config_main_t * vcm = &cm->config_main;
1467 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
1468 ci = cm->config_index_by_sw_if_index[sw_if_index];
1470 if (cast == VNET_UNICAST)
1471 feature_index = im->ip4_unicast_rx_feature_lookup;
1473 feature_index = im->ip4_multicast_rx_feature_lookup;
1476 ci = vnet_config_add_feature (vm, vcm,
1479 /* config data */ 0,
1480 /* # bytes of config data */ 0);
1482 ci = vnet_config_del_feature (vm, vcm,
1485 /* config data */ 0,
1486 /* # bytes of config data */ 0);
1488 cm->config_index_by_sw_if_index[sw_if_index] = ci;
1491 return /* no error */ 0;
1494 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1496 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args);
1498 VLIB_REGISTER_NODE (ip4_lookup_node) = {
1499 .function = ip4_lookup,
1500 .name = "ip4-lookup",
1501 .vector_size = sizeof (u32),
1503 .format_trace = format_ip4_lookup_trace,
1505 .n_next_nodes = IP4_LOOKUP_N_NEXT,
1506 .next_nodes = IP4_LOOKUP_NEXT_NODES,
1509 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
1512 ip4_indirect (vlib_main_t * vm,
1513 vlib_node_runtime_t * node,
1514 vlib_frame_t * frame)
1516 return ip4_lookup_inline (vm, node, frame,
1517 /* lookup_for_responses_to_locally_received_packets */ 0,
1518 /* is_indirect */ 1);
1521 VLIB_REGISTER_NODE (ip4_indirect_node) = {
1522 .function = ip4_indirect,
1523 .name = "ip4-indirect",
1524 .vector_size = sizeof (u32),
1525 .sibling_of = "ip4-lookup",
1526 .format_trace = format_ip4_lookup_trace,
1531 VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
1534 /* Global IP4 main. */
1535 ip4_main_t ip4_main;
1538 ip4_lookup_init (vlib_main_t * vm)
1540 ip4_main_t * im = &ip4_main;
1541 clib_error_t * error;
1544 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1549 m = pow2_mask (i) << (32 - i);
1552 im->fib_masks[i] = clib_host_to_net_u32 (m);
1555 /* Create FIB with index 0 and table id of 0. */
1556 find_ip4_fib_by_table_index_or_id (im, /* table id */ 0, IP4_ROUTE_FLAG_TABLE_ID);
1558 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1562 pn = pg_get_node (ip4_lookup_node.index);
1563 pn->unformat_edit = unformat_pg_ip4_header;
1567 ethernet_arp_header_t h;
1569 memset (&h, 0, sizeof (h));
1571 /* Set target ethernet address to all zeros. */
1572 memset (h.ip4_over_ethernet[1].ethernet, 0, sizeof (h.ip4_over_ethernet[1].ethernet));
1574 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1575 #define _8(f,v) h.f = v;
1576 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1577 _16 (l3_type, ETHERNET_TYPE_IP4);
1578 _8 (n_l2_address_bytes, 6);
1579 _8 (n_l3_address_bytes, 4);
1580 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1584 vlib_packet_template_init (vm,
1585 &im->ip4_arp_request_packet_template,
1588 /* alloc chunk size */ 8,
1592 error = ip4_feature_init (vm, im);
1597 VLIB_INIT_FUNCTION (ip4_lookup_init);
1600 /* Adjacency taken. */
1605 /* Packet data, possibly *after* rewrite. */
1606 u8 packet_data[64 - 1*sizeof(u32)];
1607 } ip4_forward_next_trace_t;
1609 static u8 * format_ip4_forward_next_trace (u8 * s, va_list * args)
1611 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1612 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1613 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1614 uword indent = format_get_indent (s);
1615 s = format (s, "%U%U",
1616 format_white_space, indent,
1617 format_ip4_header, t->packet_data);
1621 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args)
1623 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1624 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1625 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1626 vnet_main_t * vnm = vnet_get_main();
1627 ip4_main_t * im = &ip4_main;
1628 uword indent = format_get_indent (s);
1630 s = format (s, "fib %d adj-idx %d : %U flow hash: 0x%08x",
1631 t->fib_index, t->adj_index, format_ip_adjacency,
1632 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1633 s = format (s, "\n%U%U",
1634 format_white_space, indent,
1635 format_ip4_header, t->packet_data);
1639 static u8 * format_ip4_rewrite_trace (u8 * s, va_list * args)
1641 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1642 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1643 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1644 vnet_main_t * vnm = vnet_get_main();
1645 ip4_main_t * im = &ip4_main;
1646 uword indent = format_get_indent (s);
1648 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1649 t->fib_index, t->adj_index, format_ip_adjacency,
1650 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1651 s = format (s, "\n%U%U",
1652 format_white_space, indent,
1653 format_ip_adjacency_packet_data,
1654 vnm, &im->lookup_main, t->adj_index,
1655 t->packet_data, sizeof (t->packet_data));
1659 /* Common trace function for all ip4-forward next nodes. */
1661 ip4_forward_next_trace (vlib_main_t * vm,
1662 vlib_node_runtime_t * node,
1663 vlib_frame_t * frame,
1664 vlib_rx_or_tx_t which_adj_index)
1667 ip4_main_t * im = &ip4_main;
1669 n_left = frame->n_vectors;
1670 from = vlib_frame_vector_args (frame);
1675 vlib_buffer_t * b0, * b1;
1676 ip4_forward_next_trace_t * t0, * t1;
1678 /* Prefetch next iteration. */
1679 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1680 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1685 b0 = vlib_get_buffer (vm, bi0);
1686 b1 = vlib_get_buffer (vm, bi1);
1688 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1690 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1691 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1692 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1693 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1694 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1695 vec_elt (im->fib_index_by_sw_if_index,
1696 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1698 clib_memcpy (t0->packet_data,
1699 vlib_buffer_get_current (b0),
1700 sizeof (t0->packet_data));
1702 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1704 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1705 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1706 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1707 t1->fib_index = (vnet_buffer(b1)->sw_if_index[VLIB_TX] != (u32)~0) ?
1708 vnet_buffer(b1)->sw_if_index[VLIB_TX] :
1709 vec_elt (im->fib_index_by_sw_if_index,
1710 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
1711 clib_memcpy (t1->packet_data,
1712 vlib_buffer_get_current (b1),
1713 sizeof (t1->packet_data));
1723 ip4_forward_next_trace_t * t0;
1727 b0 = vlib_get_buffer (vm, bi0);
1729 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1731 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1732 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1733 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1734 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1735 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1736 vec_elt (im->fib_index_by_sw_if_index,
1737 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1738 clib_memcpy (t0->packet_data,
1739 vlib_buffer_get_current (b0),
1740 sizeof (t0->packet_data));
1748 ip4_drop_or_punt (vlib_main_t * vm,
1749 vlib_node_runtime_t * node,
1750 vlib_frame_t * frame,
1751 ip4_error_t error_code)
1753 u32 * buffers = vlib_frame_vector_args (frame);
1754 uword n_packets = frame->n_vectors;
1756 vlib_error_drop_buffers (vm, node,
1761 ip4_input_node.index,
1764 if (node->flags & VLIB_NODE_FLAG_TRACE)
1765 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1771 ip4_drop (vlib_main_t * vm,
1772 vlib_node_runtime_t * node,
1773 vlib_frame_t * frame)
1774 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP); }
1777 ip4_punt (vlib_main_t * vm,
1778 vlib_node_runtime_t * node,
1779 vlib_frame_t * frame)
1780 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); }
1783 ip4_miss (vlib_main_t * vm,
1784 vlib_node_runtime_t * node,
1785 vlib_frame_t * frame)
1786 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_DST_LOOKUP_MISS); }
1788 VLIB_REGISTER_NODE (ip4_drop_node,static) = {
1789 .function = ip4_drop,
1791 .vector_size = sizeof (u32),
1793 .format_trace = format_ip4_forward_next_trace,
1801 VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
1803 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
1804 .function = ip4_punt,
1806 .vector_size = sizeof (u32),
1808 .format_trace = format_ip4_forward_next_trace,
1816 VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
1818 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
1819 .function = ip4_miss,
1821 .vector_size = sizeof (u32),
1823 .format_trace = format_ip4_forward_next_trace,
1831 VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
1833 /* Compute TCP/UDP/ICMP4 checksum in software. */
1835 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1839 u32 ip_header_length, payload_length_host_byte_order;
1840 u32 n_this_buffer, n_bytes_left;
1842 void * data_this_buffer;
1844 /* Initialize checksum with ip header. */
1845 ip_header_length = ip4_header_bytes (ip0);
1846 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->length) - ip_header_length;
1847 sum0 = clib_host_to_net_u32 (payload_length_host_byte_order + (ip0->protocol << 16));
1849 if (BITS (uword) == 32)
1851 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u32));
1852 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
1855 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1857 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1858 data_this_buffer = (void *) ip0 + ip_header_length;
1859 if (n_this_buffer + ip_header_length > p0->current_length)
1860 n_this_buffer = p0->current_length > ip_header_length ? p0->current_length - ip_header_length : 0;
1863 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1864 n_bytes_left -= n_this_buffer;
1865 if (n_bytes_left == 0)
1868 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1869 p0 = vlib_get_buffer (vm, p0->next_buffer);
1870 data_this_buffer = vlib_buffer_get_current (p0);
1871 n_this_buffer = p0->current_length;
1874 sum16 = ~ ip_csum_fold (sum0);
1880 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1882 ip4_header_t * ip0 = vlib_buffer_get_current (p0);
1883 udp_header_t * udp0;
1886 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1887 || ip0->protocol == IP_PROTOCOL_UDP);
1889 udp0 = (void *) (ip0 + 1);
1890 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1892 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1893 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1897 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1899 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1900 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1906 ip4_local (vlib_main_t * vm,
1907 vlib_node_runtime_t * node,
1908 vlib_frame_t * frame)
1910 ip4_main_t * im = &ip4_main;
1911 ip_lookup_main_t * lm = &im->lookup_main;
1912 ip_local_next_t next_index;
1913 u32 * from, * to_next, n_left_from, n_left_to_next;
1914 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
1916 from = vlib_frame_vector_args (frame);
1917 n_left_from = frame->n_vectors;
1918 next_index = node->cached_next_index;
1920 if (node->flags & VLIB_NODE_FLAG_TRACE)
1921 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1923 while (n_left_from > 0)
1925 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1927 while (n_left_from >= 4 && n_left_to_next >= 2)
1929 vlib_buffer_t * p0, * p1;
1930 ip4_header_t * ip0, * ip1;
1931 udp_header_t * udp0, * udp1;
1932 ip4_fib_mtrie_t * mtrie0, * mtrie1;
1933 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1934 ip_adjacency_t * adj0, * adj1;
1935 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, adj_index0;
1936 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, adj_index1;
1937 i32 len_diff0, len_diff1;
1938 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1939 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1942 pi0 = to_next[0] = from[0];
1943 pi1 = to_next[1] = from[1];
1947 n_left_to_next -= 2;
1949 p0 = vlib_get_buffer (vm, pi0);
1950 p1 = vlib_get_buffer (vm, pi1);
1952 ip0 = vlib_buffer_get_current (p0);
1953 ip1 = vlib_buffer_get_current (p1);
1955 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1956 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
1957 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1958 vnet_buffer(p1)->sw_if_index[VLIB_RX]);
1960 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
1961 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
1963 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1965 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1966 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
1968 /* Treat IP frag packets as "experimental" protocol for now
1969 until support of IP frag reassembly is implemented */
1970 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
1971 proto1 = ip4_is_fragment(ip1) ? 0xfe : ip1->protocol;
1972 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1973 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1974 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1975 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1980 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1981 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1983 udp0 = ip4_next_header (ip0);
1984 udp1 = ip4_next_header (ip1);
1986 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1987 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1988 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1990 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1991 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
1993 /* Verify UDP length. */
1994 ip_len0 = clib_net_to_host_u16 (ip0->length);
1995 ip_len1 = clib_net_to_host_u16 (ip1->length);
1996 udp_len0 = clib_net_to_host_u16 (udp0->length);
1997 udp_len1 = clib_net_to_host_u16 (udp1->length);
1999 len_diff0 = ip_len0 - udp_len0;
2000 len_diff1 = ip_len1 - udp_len1;
2002 len_diff0 = is_udp0 ? len_diff0 : 0;
2003 len_diff1 = is_udp1 ? len_diff1 : 0;
2005 if (PREDICT_FALSE (! (is_tcp_udp0 & is_tcp_udp1
2006 & good_tcp_udp0 & good_tcp_udp1)))
2011 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2012 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2014 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2015 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2020 && ! (flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2021 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
2023 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2024 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2028 good_tcp_udp0 &= len_diff0 >= 0;
2029 good_tcp_udp1 &= len_diff1 >= 0;
2031 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2032 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
2034 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
2036 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2037 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
2039 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2040 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2041 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2043 error1 = (is_tcp_udp1 && ! good_tcp_udp1
2044 ? IP4_ERROR_TCP_CHECKSUM + is_udp1
2047 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2048 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
2050 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2051 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2053 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
2054 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
2056 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2058 /* no_default_route */ 1));
2059 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
2061 /* no_default_route */ 1));
2063 adj0 = ip_get_adjacency (lm, adj_index0);
2064 adj1 = ip_get_adjacency (lm, adj_index1);
2067 * Must have a route to source otherwise we drop the packet.
2068 * ip4 broadcasts are accepted, e.g. to make dhcp client work
2070 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2071 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2072 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2073 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2074 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2075 ? IP4_ERROR_SRC_LOOKUP_MISS
2077 error1 = (error1 == IP4_ERROR_UNKNOWN_PROTOCOL
2078 && adj1->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2079 && adj1->lookup_next_index != IP_LOOKUP_NEXT_ARP
2080 && adj1->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2081 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2082 ? IP4_ERROR_SRC_LOOKUP_MISS
2085 next0 = lm->local_next_by_ip_protocol[proto0];
2086 next1 = lm->local_next_by_ip_protocol[proto1];
2088 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2089 next1 = error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
2091 p0->error = error0 ? error_node->errors[error0] : 0;
2092 p1->error = error1 ? error_node->errors[error1] : 0;
2094 enqueue_code = (next0 != next_index) + 2*(next1 != next_index);
2096 if (PREDICT_FALSE (enqueue_code != 0))
2098 switch (enqueue_code)
2104 n_left_to_next += 1;
2105 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2111 n_left_to_next += 1;
2112 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2116 /* A B B or A B C */
2118 n_left_to_next += 2;
2119 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2120 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2123 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2125 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2132 while (n_left_from > 0 && n_left_to_next > 0)
2136 udp_header_t * udp0;
2137 ip4_fib_mtrie_t * mtrie0;
2138 ip4_fib_mtrie_leaf_t leaf0;
2139 ip_adjacency_t * adj0;
2140 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, adj_index0;
2142 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2144 pi0 = to_next[0] = from[0];
2148 n_left_to_next -= 1;
2150 p0 = vlib_get_buffer (vm, pi0);
2152 ip0 = vlib_buffer_get_current (p0);
2154 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2155 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2157 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2159 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2161 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2163 /* Treat IP frag packets as "experimental" protocol for now
2164 until support of IP frag reassembly is implemented */
2165 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
2166 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2167 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2171 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2173 udp0 = ip4_next_header (ip0);
2175 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2176 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2178 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2180 /* Verify UDP length. */
2181 ip_len0 = clib_net_to_host_u16 (ip0->length);
2182 udp_len0 = clib_net_to_host_u16 (udp0->length);
2184 len_diff0 = ip_len0 - udp_len0;
2186 len_diff0 = is_udp0 ? len_diff0 : 0;
2188 if (PREDICT_FALSE (! (is_tcp_udp0 & good_tcp_udp0)))
2193 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2194 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2196 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2197 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2201 good_tcp_udp0 &= len_diff0 >= 0;
2203 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2205 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
2207 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2209 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2210 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2211 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2214 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2216 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2217 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2219 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2221 /* no_default_route */ 1));
2223 adj0 = ip_get_adjacency (lm, adj_index0);
2225 /* Must have a route to source otherwise we drop the packet. */
2226 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2227 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2228 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2229 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2230 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2231 ? IP4_ERROR_SRC_LOOKUP_MISS
2234 next0 = lm->local_next_by_ip_protocol[proto0];
2236 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2238 p0->error = error0? error_node->errors[error0] : 0;
2240 if (PREDICT_FALSE (next0 != next_index))
2242 n_left_to_next += 1;
2243 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2246 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2249 n_left_to_next -= 1;
2253 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2256 return frame->n_vectors;
2259 VLIB_REGISTER_NODE (ip4_local_node,static) = {
2260 .function = ip4_local,
2261 .name = "ip4-local",
2262 .vector_size = sizeof (u32),
2264 .format_trace = format_ip4_forward_next_trace,
2266 .n_next_nodes = IP_LOCAL_N_NEXT,
2268 [IP_LOCAL_NEXT_DROP] = "error-drop",
2269 [IP_LOCAL_NEXT_PUNT] = "error-punt",
2270 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
2271 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
2275 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
2277 void ip4_register_protocol (u32 protocol, u32 node_index)
2279 vlib_main_t * vm = vlib_get_main();
2280 ip4_main_t * im = &ip4_main;
2281 ip_lookup_main_t * lm = &im->lookup_main;
2283 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
2284 lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index);
2287 static clib_error_t *
2288 show_ip_local_command_fn (vlib_main_t * vm,
2289 unformat_input_t * input,
2290 vlib_cli_command_t * cmd)
2292 ip4_main_t * im = &ip4_main;
2293 ip_lookup_main_t * lm = &im->lookup_main;
2296 vlib_cli_output (vm, "Protocols handled by ip4_local");
2297 for (i = 0; i < ARRAY_LEN(lm->local_next_by_ip_protocol); i++)
2299 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2300 vlib_cli_output (vm, "%d", i);
2307 VLIB_CLI_COMMAND (show_ip_local, static) = {
2308 .path = "show ip local",
2309 .function = show_ip_local_command_fn,
2310 .short_help = "Show ip local protocol table",
2314 ip4_arp (vlib_main_t * vm,
2315 vlib_node_runtime_t * node,
2316 vlib_frame_t * frame)
2318 vnet_main_t * vnm = vnet_get_main();
2319 ip4_main_t * im = &ip4_main;
2320 ip_lookup_main_t * lm = &im->lookup_main;
2321 u32 * from, * to_next_drop;
2322 uword n_left_from, n_left_to_next_drop, next_index;
2323 static f64 time_last_seed_change = -1e100;
2324 static u32 hash_seeds[3];
2325 static uword hash_bitmap[256 / BITS (uword)];
2328 if (node->flags & VLIB_NODE_FLAG_TRACE)
2329 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2331 time_now = vlib_time_now (vm);
2332 if (time_now - time_last_seed_change > 1e-3)
2335 u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
2336 sizeof (hash_seeds));
2337 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2338 hash_seeds[i] = r[i];
2340 /* Mark all hash keys as been no-seen before. */
2341 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2344 time_last_seed_change = time_now;
2347 from = vlib_frame_vector_args (frame);
2348 n_left_from = frame->n_vectors;
2349 next_index = node->cached_next_index;
2350 if (next_index == IP4_ARP_NEXT_DROP)
2351 next_index = IP4_ARP_N_NEXT; /* point to first interface */
2353 while (n_left_from > 0)
2355 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2356 to_next_drop, n_left_to_next_drop);
2358 while (n_left_from > 0 && n_left_to_next_drop > 0)
2362 ethernet_header_t * eh0;
2363 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
2365 ip_adjacency_t * adj0;
2369 p0 = vlib_get_buffer (vm, pi0);
2371 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2372 adj0 = ip_get_adjacency (lm, adj_index0);
2373 ip0 = vlib_buffer_get_current (p0);
2375 /* If packet destination is not local, send ARP to next hop */
2376 if (adj0->arp.next_hop.ip4.as_u32)
2377 ip0->dst_address.data_u32 = adj0->arp.next_hop.ip4.as_u32;
2380 * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP
2381 * rewrite to this packet, we need to skip it here.
2382 * Note, to distinguish from src IP addr *.8.6.*, we
2383 * check for a bcast eth dest instead of IPv4 version.
2385 eh0 = (ethernet_header_t*)ip0;
2386 if ((ip0->ip_version_and_header_length & 0xF0) != 0x40)
2389 u16 * etype = &eh0->type;
2390 while ((*etype == clib_host_to_net_u16 (0x8100)) //dot1q
2391 || (*etype == clib_host_to_net_u16 (0x88a8)))//dot1ad
2394 etype += 2; //vlan tag also 16 bits, same as etype
2396 if (*etype == clib_host_to_net_u16 (0x0806)) //arp
2398 vlib_buffer_advance (
2399 p0, sizeof(ethernet_header_t) + (4*vlan_num));
2400 ip0 = vlib_buffer_get_current (p0);
2408 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2409 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2411 a0 ^= ip0->dst_address.data_u32;
2414 hash_v3_finalize32 (a0, b0, c0);
2416 c0 &= BITS (hash_bitmap) - 1;
2417 c0 = c0 / BITS (uword);
2418 m0 = (uword) 1 << (c0 % BITS (uword));
2420 bm0 = hash_bitmap[c0];
2421 drop0 = (bm0 & m0) != 0;
2423 /* Mark it as seen. */
2424 hash_bitmap[c0] = bm0 | m0;
2428 to_next_drop[0] = pi0;
2430 n_left_to_next_drop -= 1;
2432 p0->error = node->errors[drop0 ? IP4_ARP_ERROR_DROP : IP4_ARP_ERROR_REQUEST_SENT];
2438 * Can happen if the control-plane is programming tables
2439 * with traffic flowing; at least that's today's lame excuse.
2441 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
2443 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2446 /* Send ARP request. */
2450 ethernet_arp_header_t * h0;
2451 vnet_hw_interface_t * hw_if0;
2453 h0 = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi0);
2455 /* Add rewrite/encap string for ARP packet. */
2456 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2458 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2460 /* Src ethernet address in ARP header. */
2461 clib_memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address,
2462 sizeof (h0->ip4_over_ethernet[0].ethernet));
2464 if (ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0)) {
2465 //No source address available
2466 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2467 vlib_buffer_free(vm, &bi0, 1);
2471 /* Copy in destination address we are requesting. */
2472 h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32;
2474 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2475 b0 = vlib_get_buffer (vm, bi0);
2476 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2478 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2480 vlib_set_next_frame_buffer (vm, node, adj0->rewrite_header.next_index, bi0);
2484 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2487 return frame->n_vectors;
2490 static char * ip4_arp_error_strings[] = {
2491 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2492 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2493 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2494 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2495 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2496 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
2499 VLIB_REGISTER_NODE (ip4_arp_node) = {
2500 .function = ip4_arp,
2502 .vector_size = sizeof (u32),
2504 .format_trace = format_ip4_forward_next_trace,
2506 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2507 .error_strings = ip4_arp_error_strings,
2509 .n_next_nodes = IP4_ARP_N_NEXT,
2511 [IP4_ARP_NEXT_DROP] = "error-drop",
2515 #define foreach_notrace_ip4_arp_error \
2521 clib_error_t * arp_notrace_init (vlib_main_t * vm)
2523 vlib_node_runtime_t *rt =
2524 vlib_node_get_runtime (vm, ip4_arp_node.index);
2526 /* don't trace ARP request packets */
2528 vnet_pcap_drop_trace_filter_add_del \
2529 (rt->errors[IP4_ARP_ERROR_##a], \
2531 foreach_notrace_ip4_arp_error;
2536 VLIB_INIT_FUNCTION(arp_notrace_init);
2539 /* Send an ARP request to see if given destination is reachable on given interface. */
2541 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2543 vnet_main_t * vnm = vnet_get_main();
2544 ip4_main_t * im = &ip4_main;
2545 ethernet_arp_header_t * h;
2546 ip4_address_t * src;
2547 ip_interface_address_t * ia;
2548 ip_adjacency_t * adj;
2549 vnet_hw_interface_t * hi;
2550 vnet_sw_interface_t * si;
2554 si = vnet_get_sw_interface (vnm, sw_if_index);
2556 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2558 return clib_error_return (0, "%U: interface %U down",
2559 format_ip4_address, dst,
2560 format_vnet_sw_if_index_name, vnm,
2564 src = ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2567 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2568 return clib_error_return
2569 (0, "no matching interface address for destination %U (interface %U)",
2570 format_ip4_address, dst,
2571 format_vnet_sw_if_index_name, vnm, sw_if_index);
2574 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2576 h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi);
2578 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2580 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
2582 h->ip4_over_ethernet[0].ip4 = src[0];
2583 h->ip4_over_ethernet[1].ip4 = dst[0];
2585 b = vlib_get_buffer (vm, bi);
2586 vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2588 /* Add encapsulation string for software interface (e.g. ethernet header). */
2589 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2590 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2593 vlib_frame_t * f = vlib_get_frame_to_node (vm, hi->output_node_index);
2594 u32 * to_next = vlib_frame_vector_args (f);
2597 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2600 return /* no error */ 0;
2604 IP4_REWRITE_NEXT_DROP,
2605 IP4_REWRITE_NEXT_ARP,
2606 IP4_REWRITE_NEXT_ICMP_ERROR,
2607 } ip4_rewrite_next_t;
2610 ip4_rewrite_inline (vlib_main_t * vm,
2611 vlib_node_runtime_t * node,
2612 vlib_frame_t * frame,
2613 int rewrite_for_locally_received_packets)
2615 ip_lookup_main_t * lm = &ip4_main.lookup_main;
2616 u32 * from = vlib_frame_vector_args (frame);
2617 u32 n_left_from, n_left_to_next, * to_next, next_index;
2618 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2619 vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
2621 n_left_from = frame->n_vectors;
2622 next_index = node->cached_next_index;
2623 u32 cpu_index = os_get_cpu_number();
2625 while (n_left_from > 0)
2627 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2629 while (n_left_from >= 4 && n_left_to_next >= 2)
2631 ip_adjacency_t * adj0, * adj1;
2632 vlib_buffer_t * p0, * p1;
2633 ip4_header_t * ip0, * ip1;
2634 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2635 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2636 u32 next0_override, next1_override;
2638 if (rewrite_for_locally_received_packets)
2639 next0_override = next1_override = 0;
2641 /* Prefetch next iteration. */
2643 vlib_buffer_t * p2, * p3;
2645 p2 = vlib_get_buffer (vm, from[2]);
2646 p3 = vlib_get_buffer (vm, from[3]);
2648 vlib_prefetch_buffer_header (p2, STORE);
2649 vlib_prefetch_buffer_header (p3, STORE);
2651 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2652 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2655 pi0 = to_next[0] = from[0];
2656 pi1 = to_next[1] = from[1];
2661 n_left_to_next -= 2;
2663 p0 = vlib_get_buffer (vm, pi0);
2664 p1 = vlib_get_buffer (vm, pi1);
2666 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2667 adj_index1 = vnet_buffer (p1)->ip.adj_index[adj_rx_tx];
2669 /* We should never rewrite a pkt using the MISS adjacency */
2670 ASSERT(adj_index0 && adj_index1);
2672 ip0 = vlib_buffer_get_current (p0);
2673 ip1 = vlib_buffer_get_current (p1);
2675 error0 = error1 = IP4_ERROR_NONE;
2676 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2678 /* Decrement TTL & update checksum.
2679 Works either endian, so no need for byte swap. */
2680 if (! rewrite_for_locally_received_packets)
2682 i32 ttl0 = ip0->ttl, ttl1 = ip1->ttl;
2684 /* Input node should have reject packets with ttl 0. */
2685 ASSERT (ip0->ttl > 0);
2686 ASSERT (ip1->ttl > 0);
2688 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2689 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2691 checksum0 += checksum0 >= 0xffff;
2692 checksum1 += checksum1 >= 0xffff;
2694 ip0->checksum = checksum0;
2695 ip1->checksum = checksum1;
2704 * If the ttl drops below 1 when forwarding, generate
2707 if (PREDICT_FALSE(ttl0 <= 0))
2709 error0 = IP4_ERROR_TIME_EXPIRED;
2710 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2711 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2712 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2713 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2715 if (PREDICT_FALSE(ttl1 <= 0))
2717 error1 = IP4_ERROR_TIME_EXPIRED;
2718 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
2719 icmp4_error_set_vnet_buffer(p1, ICMP4_time_exceeded,
2720 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2721 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2724 /* Verify checksum. */
2725 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2726 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2729 /* Rewrite packet header and updates lengths. */
2730 adj0 = ip_get_adjacency (lm, adj_index0);
2731 adj1 = ip_get_adjacency (lm, adj_index1);
2733 if (rewrite_for_locally_received_packets)
2736 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2737 * we end up here with a local adjacency in hand
2738 * The local adj rewrite data is 0xfefe on purpose.
2739 * Bad engineer, no donut for you.
2741 if (PREDICT_FALSE(adj0->lookup_next_index
2742 == IP_LOOKUP_NEXT_LOCAL))
2743 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2744 if (PREDICT_FALSE(adj0->lookup_next_index
2745 == IP_LOOKUP_NEXT_ARP))
2746 next0_override = IP4_REWRITE_NEXT_ARP;
2747 if (PREDICT_FALSE(adj1->lookup_next_index
2748 == IP_LOOKUP_NEXT_LOCAL))
2749 error1 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2750 if (PREDICT_FALSE(adj1->lookup_next_index
2751 == IP_LOOKUP_NEXT_ARP))
2752 next1_override = IP4_REWRITE_NEXT_ARP;
2755 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2756 rw_len0 = adj0[0].rewrite_header.data_bytes;
2757 rw_len1 = adj1[0].rewrite_header.data_bytes;
2759 /* Check MTU of outgoing interface. */
2760 error0 = (vlib_buffer_length_in_chain (vm, p0) > adj0[0].rewrite_header.max_l3_packet_bytes
2761 ? IP4_ERROR_MTU_EXCEEDED
2763 error1 = (vlib_buffer_length_in_chain (vm, p1) > adj1[0].rewrite_header.max_l3_packet_bytes
2764 ? IP4_ERROR_MTU_EXCEEDED
2767 next0 = (error0 == IP4_ERROR_NONE)
2768 ? adj0[0].rewrite_header.next_index : next0;
2770 if (rewrite_for_locally_received_packets)
2771 next0 = next0 && next0_override ? next0_override : next0;
2773 next1 = (error1 == IP4_ERROR_NONE)
2774 ? adj1[0].rewrite_header.next_index : next1;
2776 if (rewrite_for_locally_received_packets)
2777 next1 = next1 && next1_override ? next1_override : next1;
2780 * We've already accounted for an ethernet_header_t elsewhere
2782 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2783 vlib_increment_combined_counter
2784 (&lm->adjacency_counters,
2785 cpu_index, adj_index0,
2786 /* packet increment */ 0,
2787 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2789 if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
2790 vlib_increment_combined_counter
2791 (&lm->adjacency_counters,
2792 cpu_index, adj_index1,
2793 /* packet increment */ 0,
2794 /* byte increment */ rw_len1-sizeof(ethernet_header_t));
2796 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2797 * to see the IP headerr */
2798 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2800 p0->current_data -= rw_len0;
2801 p0->current_length += rw_len0;
2802 p0->error = error_node->errors[error0];
2803 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2804 adj0[0].rewrite_header.sw_if_index;
2806 if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
2808 p1->current_data -= rw_len1;
2809 p1->current_length += rw_len1;
2810 p1->error = error_node->errors[error1];
2811 vnet_buffer (p1)->sw_if_index[VLIB_TX] =
2812 adj1[0].rewrite_header.sw_if_index;
2815 /* Guess we are only writing on simple Ethernet header. */
2816 vnet_rewrite_two_headers (adj0[0], adj1[0],
2818 sizeof (ethernet_header_t));
2820 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2821 to_next, n_left_to_next,
2822 pi0, pi1, next0, next1);
2825 while (n_left_from > 0 && n_left_to_next > 0)
2827 ip_adjacency_t * adj0;
2830 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2833 if (rewrite_for_locally_received_packets)
2836 pi0 = to_next[0] = from[0];
2838 p0 = vlib_get_buffer (vm, pi0);
2840 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2842 /* We should never rewrite a pkt using the MISS adjacency */
2845 adj0 = ip_get_adjacency (lm, adj_index0);
2847 ip0 = vlib_buffer_get_current (p0);
2849 error0 = IP4_ERROR_NONE;
2850 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2852 /* Decrement TTL & update checksum. */
2853 if (! rewrite_for_locally_received_packets)
2855 i32 ttl0 = ip0->ttl;
2857 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2859 checksum0 += checksum0 >= 0xffff;
2861 ip0->checksum = checksum0;
2863 ASSERT (ip0->ttl > 0);
2869 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2871 if (PREDICT_FALSE(ttl0 <= 0))
2874 * If the ttl drops below 1 when forwarding, generate
2877 error0 = IP4_ERROR_TIME_EXPIRED;
2878 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2879 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2880 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2881 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2885 if (rewrite_for_locally_received_packets)
2888 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2889 * we end up here with a local adjacency in hand
2890 * The local adj rewrite data is 0xfefe on purpose.
2891 * Bad engineer, no donut for you.
2893 if (PREDICT_FALSE(adj0->lookup_next_index
2894 == IP_LOOKUP_NEXT_LOCAL))
2895 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2897 * We have to override the next_index in ARP adjacencies,
2898 * because they're set up for ip4-arp, not this node...
2900 if (PREDICT_FALSE(adj0->lookup_next_index
2901 == IP_LOOKUP_NEXT_ARP))
2902 next0_override = IP4_REWRITE_NEXT_ARP;
2905 /* Guess we are only writing on simple Ethernet header. */
2906 vnet_rewrite_one_header (adj0[0], ip0,
2907 sizeof (ethernet_header_t));
2909 /* Update packet buffer attributes/set output interface. */
2910 rw_len0 = adj0[0].rewrite_header.data_bytes;
2912 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2913 vlib_increment_combined_counter
2914 (&lm->adjacency_counters,
2915 cpu_index, adj_index0,
2916 /* packet increment */ 0,
2917 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2919 /* Check MTU of outgoing interface. */
2920 error0 = (vlib_buffer_length_in_chain (vm, p0)
2921 > adj0[0].rewrite_header.max_l3_packet_bytes
2922 ? IP4_ERROR_MTU_EXCEEDED
2925 p0->error = error_node->errors[error0];
2927 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2928 * to see the IP headerr */
2929 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2931 p0->current_data -= rw_len0;
2932 p0->current_length += rw_len0;
2934 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2935 adj0[0].rewrite_header.sw_if_index;
2936 next0 = adj0[0].rewrite_header.next_index;
2939 if (rewrite_for_locally_received_packets)
2940 next0 = next0 && next0_override ? next0_override : next0;
2945 n_left_to_next -= 1;
2947 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2948 to_next, n_left_to_next,
2952 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2955 /* Need to do trace after rewrites to pick up new packet data. */
2956 if (node->flags & VLIB_NODE_FLAG_TRACE)
2957 ip4_forward_next_trace (vm, node, frame, adj_rx_tx);
2959 return frame->n_vectors;
2963 /** \brief IPv4 transit rewrite node.
2964 @node ip4-rewrite-transit
2966 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2967 header checksum, fetch the ip adjacency, check the outbound mtu,
2968 apply the adjacency rewrite, and send pkts to the adjacency
2969 rewrite header's rewrite_next_index.
2971 @param vm vlib_main_t corresponding to the current thread
2972 @param node vlib_node_runtime_t
2973 @param frame vlib_frame_t whose contents should be dispatched
2975 @par Graph mechanics: buffer metadata, next index usage
2978 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2979 - the rewrite adjacency index
2980 - <code>adj->lookup_next_index</code>
2981 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2982 the packet will be dropped.
2983 - <code>adj->rewrite_header</code>
2984 - Rewrite string length, rewrite string, next_index
2987 - <code>b->current_data, b->current_length</code>
2988 - Updated net of applying the rewrite string
2990 <em>Next Indices:</em>
2991 - <code> adj->rewrite_header.next_index </code>
2995 ip4_rewrite_transit (vlib_main_t * vm,
2996 vlib_node_runtime_t * node,
2997 vlib_frame_t * frame)
2999 return ip4_rewrite_inline (vm, node, frame,
3000 /* rewrite_for_locally_received_packets */ 0);
3003 /** \brief IPv4 local rewrite node.
3004 @node ip4-rewrite-local
3006 This is the IPv4 local rewrite node. Fetch the ip adjacency, check
3007 the outbound interface mtu, apply the adjacency rewrite, and send
3008 pkts to the adjacency rewrite header's rewrite_next_index. Deal
3009 with hemorrhoids of the form "some clown sends an icmp4 w/ src =
3010 dst = interface addr."
3012 @param vm vlib_main_t corresponding to the current thread
3013 @param node vlib_node_runtime_t
3014 @param frame vlib_frame_t whose contents should be dispatched
3016 @par Graph mechanics: buffer metadata, next index usage
3019 - <code>vnet_buffer(b)->ip.adj_index[VLIB_RX]</code>
3020 - the rewrite adjacency index
3021 - <code>adj->lookup_next_index</code>
3022 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
3023 the packet will be dropped.
3024 - <code>adj->rewrite_header</code>
3025 - Rewrite string length, rewrite string, next_index
3028 - <code>b->current_data, b->current_length</code>
3029 - Updated net of applying the rewrite string
3031 <em>Next Indices:</em>
3032 - <code> adj->rewrite_header.next_index </code>
3037 ip4_rewrite_local (vlib_main_t * vm,
3038 vlib_node_runtime_t * node,
3039 vlib_frame_t * frame)
3041 return ip4_rewrite_inline (vm, node, frame,
3042 /* rewrite_for_locally_received_packets */ 1);
3045 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
3046 .function = ip4_rewrite_transit,
3047 .name = "ip4-rewrite-transit",
3048 .vector_size = sizeof (u32),
3050 .format_trace = format_ip4_rewrite_trace,
3054 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3055 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3056 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3060 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
3062 VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
3063 .function = ip4_rewrite_local,
3064 .name = "ip4-rewrite-local",
3065 .vector_size = sizeof (u32),
3067 .sibling_of = "ip4-rewrite-transit",
3069 .format_trace = format_ip4_rewrite_trace,
3074 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
3076 static clib_error_t *
3077 add_del_interface_table (vlib_main_t * vm,
3078 unformat_input_t * input,
3079 vlib_cli_command_t * cmd)
3081 vnet_main_t * vnm = vnet_get_main();
3082 clib_error_t * error = 0;
3083 u32 sw_if_index, table_id;
3087 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3089 error = clib_error_return (0, "unknown interface `%U'",
3090 format_unformat_error, input);
3094 if (unformat (input, "%d", &table_id))
3098 error = clib_error_return (0, "expected table id `%U'",
3099 format_unformat_error, input);
3104 ip4_main_t * im = &ip4_main;
3105 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
3109 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
3110 im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
3118 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
3119 .path = "set interface ip table",
3120 .function = add_del_interface_table,
3121 .short_help = "Add/delete FIB table id for interface",
3126 ip4_lookup_multicast (vlib_main_t * vm,
3127 vlib_node_runtime_t * node,
3128 vlib_frame_t * frame)
3130 ip4_main_t * im = &ip4_main;
3131 ip_lookup_main_t * lm = &im->lookup_main;
3132 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
3133 u32 n_left_from, n_left_to_next, * from, * to_next;
3134 ip_lookup_next_t next;
3135 u32 cpu_index = os_get_cpu_number();
3137 from = vlib_frame_vector_args (frame);
3138 n_left_from = frame->n_vectors;
3139 next = node->cached_next_index;
3141 while (n_left_from > 0)
3143 vlib_get_next_frame (vm, node, next,
3144 to_next, n_left_to_next);
3146 while (n_left_from >= 4 && n_left_to_next >= 2)
3148 vlib_buffer_t * p0, * p1;
3149 u32 pi0, pi1, adj_index0, adj_index1, wrong_next;
3150 ip_lookup_next_t next0, next1;
3151 ip4_header_t * ip0, * ip1;
3152 ip_adjacency_t * adj0, * adj1;
3153 u32 fib_index0, fib_index1;
3154 u32 flow_hash_config0, flow_hash_config1;
3156 /* Prefetch next iteration. */
3158 vlib_buffer_t * p2, * p3;
3160 p2 = vlib_get_buffer (vm, from[2]);
3161 p3 = vlib_get_buffer (vm, from[3]);
3163 vlib_prefetch_buffer_header (p2, LOAD);
3164 vlib_prefetch_buffer_header (p3, LOAD);
3166 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
3167 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
3170 pi0 = to_next[0] = from[0];
3171 pi1 = to_next[1] = from[1];
3173 p0 = vlib_get_buffer (vm, pi0);
3174 p1 = vlib_get_buffer (vm, pi1);
3176 ip0 = vlib_buffer_get_current (p0);
3177 ip1 = vlib_buffer_get_current (p1);
3179 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3180 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
3181 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3182 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3183 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
3184 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
3186 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3187 &ip0->dst_address, p0);
3188 adj_index1 = ip4_fib_lookup_buffer (im, fib_index1,
3189 &ip1->dst_address, p1);
3191 adj0 = ip_get_adjacency (lm, adj_index0);
3192 adj1 = ip_get_adjacency (lm, adj_index1);
3194 next0 = adj0->lookup_next_index;
3195 next1 = adj1->lookup_next_index;
3198 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3201 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
3203 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
3204 (ip0, flow_hash_config0);
3206 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
3207 (ip1, flow_hash_config1);
3209 ASSERT (adj0->n_adj > 0);
3210 ASSERT (adj1->n_adj > 0);
3211 ASSERT (is_pow2 (adj0->n_adj));
3212 ASSERT (is_pow2 (adj1->n_adj));
3213 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3214 adj_index1 += (vnet_buffer (p1)->ip.flow_hash & (adj1->n_adj - 1));
3216 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3217 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
3219 if (1) /* $$$$$$ HACK FIXME */
3220 vlib_increment_combined_counter
3221 (cm, cpu_index, adj_index0, 1,
3222 vlib_buffer_length_in_chain (vm, p0));
3223 if (1) /* $$$$$$ HACK FIXME */
3224 vlib_increment_combined_counter
3225 (cm, cpu_index, adj_index1, 1,
3226 vlib_buffer_length_in_chain (vm, p1));
3230 n_left_to_next -= 2;
3233 wrong_next = (next0 != next) + 2*(next1 != next);
3234 if (PREDICT_FALSE (wrong_next != 0))
3242 n_left_to_next += 1;
3243 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3249 n_left_to_next += 1;
3250 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3256 n_left_to_next += 2;
3257 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3258 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3262 vlib_put_next_frame (vm, node, next, n_left_to_next);
3264 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
3270 while (n_left_from > 0 && n_left_to_next > 0)
3274 u32 pi0, adj_index0;
3275 ip_lookup_next_t next0;
3276 ip_adjacency_t * adj0;
3278 u32 flow_hash_config0;
3283 p0 = vlib_get_buffer (vm, pi0);
3285 ip0 = vlib_buffer_get_current (p0);
3287 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
3288 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3289 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3290 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3292 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3293 &ip0->dst_address, p0);
3295 adj0 = ip_get_adjacency (lm, adj_index0);
3297 next0 = adj0->lookup_next_index;
3300 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3302 vnet_buffer (p0)->ip.flow_hash =
3303 ip4_compute_flow_hash (ip0, flow_hash_config0);
3305 ASSERT (adj0->n_adj > 0);
3306 ASSERT (is_pow2 (adj0->n_adj));
3307 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3309 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3311 if (1) /* $$$$$$ HACK FIXME */
3312 vlib_increment_combined_counter
3313 (cm, cpu_index, adj_index0, 1,
3314 vlib_buffer_length_in_chain (vm, p0));
3318 n_left_to_next -= 1;
3321 if (PREDICT_FALSE (next0 != next))
3323 n_left_to_next += 1;
3324 vlib_put_next_frame (vm, node, next, n_left_to_next);
3326 vlib_get_next_frame (vm, node, next,
3327 to_next, n_left_to_next);
3330 n_left_to_next -= 1;
3334 vlib_put_next_frame (vm, node, next, n_left_to_next);
3337 if (node->flags & VLIB_NODE_FLAG_TRACE)
3338 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
3340 return frame->n_vectors;
3343 VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
3344 .function = ip4_lookup_multicast,
3345 .name = "ip4-lookup-multicast",
3346 .vector_size = sizeof (u32),
3347 .sibling_of = "ip4-lookup",
3348 .format_trace = format_ip4_lookup_trace,
3353 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
3355 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
3356 .function = ip4_drop,
3357 .name = "ip4-multicast",
3358 .vector_size = sizeof (u32),
3360 .format_trace = format_ip4_forward_next_trace,
3368 int ip4_lookup_validate (ip4_address_t *a, u32 fib_index0)
3370 ip4_main_t * im = &ip4_main;
3371 ip4_fib_mtrie_t * mtrie0;
3372 ip4_fib_mtrie_leaf_t leaf0;
3375 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
3377 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
3378 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
3379 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
3380 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
3381 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
3383 /* Handle default route. */
3384 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
3386 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
3388 return adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
3390 /* no_default_route */ 0);
3393 static clib_error_t *
3394 test_lookup_command_fn (vlib_main_t * vm,
3395 unformat_input_t * input,
3396 vlib_cli_command_t * cmd)
3402 ip4_address_t ip4_base_address;
3405 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3406 if (unformat (input, "table %d", &table_id))
3408 else if (unformat (input, "count %f", &count))
3411 else if (unformat (input, "%U",
3412 unformat_ip4_address, &ip4_base_address))
3415 return clib_error_return (0, "unknown input `%U'",
3416 format_unformat_error, input);
3421 for (i = 0; i < n; i++)
3423 if (!ip4_lookup_validate (&ip4_base_address, table_id))
3426 ip4_base_address.as_u32 =
3427 clib_host_to_net_u32 (1 +
3428 clib_net_to_host_u32 (ip4_base_address.as_u32));
3432 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3434 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3439 VLIB_CLI_COMMAND (lookup_test_command, static) = {
3440 .path = "test lookup",
3441 .short_help = "test lookup",
3442 .function = test_lookup_command_fn,
3445 int vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3447 ip4_main_t * im4 = &ip4_main;
3449 uword * p = hash_get (im4->fib_index_by_table_id, table_id);
3452 return VNET_API_ERROR_NO_SUCH_FIB;
3454 fib = vec_elt_at_index (im4->fibs, p[0]);
3456 fib->flow_hash_config = flow_hash_config;
3460 static clib_error_t *
3461 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3462 unformat_input_t * input,
3463 vlib_cli_command_t * cmd)
3467 u32 flow_hash_config = 0;
3470 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3471 if (unformat (input, "table %d", &table_id))
3474 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3475 foreach_flow_hash_bit
3481 return clib_error_return (0, "unknown input `%U'",
3482 format_unformat_error, input);
3484 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3490 case VNET_API_ERROR_NO_SUCH_FIB:
3491 return clib_error_return (0, "no such FIB table %d", table_id);
3494 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3501 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
3502 .path = "set ip flow-hash",
3504 "set ip table flow-hash table <fib-id> src dst sport dport proto reverse",
3505 .function = set_ip_flow_hash_command_fn,
3508 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3511 vnet_main_t * vnm = vnet_get_main();
3512 vnet_interface_main_t * im = &vnm->interface_main;
3513 ip4_main_t * ipm = &ip4_main;
3514 ip_lookup_main_t * lm = &ipm->lookup_main;
3515 vnet_classify_main_t * cm = &vnet_classify_main;
3517 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3518 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3520 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3521 return VNET_API_ERROR_NO_SUCH_ENTRY;
3523 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3524 lm->classify_table_index_by_sw_if_index [sw_if_index] = table_index;
3529 static clib_error_t *
3530 set_ip_classify_command_fn (vlib_main_t * vm,
3531 unformat_input_t * input,
3532 vlib_cli_command_t * cmd)
3534 u32 table_index = ~0;
3535 int table_index_set = 0;
3536 u32 sw_if_index = ~0;
3539 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3540 if (unformat (input, "table-index %d", &table_index))
3541 table_index_set = 1;
3542 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3543 vnet_get_main(), &sw_if_index))
3549 if (table_index_set == 0)
3550 return clib_error_return (0, "classify table-index must be specified");
3552 if (sw_if_index == ~0)
3553 return clib_error_return (0, "interface / subif must be specified");
3555 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3562 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3563 return clib_error_return (0, "No such interface");
3565 case VNET_API_ERROR_NO_SUCH_ENTRY:
3566 return clib_error_return (0, "No such classifier table");
3571 VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
3572 .path = "set ip classify",
3574 "set ip classify intfc <int> table-index <index>",
3575 .function = set_ip_classify_command_fn,