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 = {"ipsec-input-ip4", 0},
1385 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
1388 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
1389 .node_name = "ipsec-input-ip4",
1390 .runs_before = {"vpath-input-ip4", 0},
1391 .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
1394 VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
1395 .node_name = "vpath-input-ip4",
1396 .runs_before = {"ip4-lookup", 0},
1397 .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
1400 VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
1401 .node_name = "ip4-lookup",
1402 .runs_before = {0}, /* not before any other features */
1403 .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
1406 /* Built-in ip4 multicast rx feature path definition */
1407 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
1408 .node_name = "vpath-input-ip4",
1409 .runs_before = {"ip4-lookup-multicast", 0},
1410 .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
1413 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
1414 .node_name = "ip4-lookup-multicast",
1415 .runs_before = {0}, /* not before any other features */
1416 .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
1419 static char * feature_start_nodes[] =
1420 { "ip4-input", "ip4-input-no-checksum"};
1422 static clib_error_t *
1423 ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
1425 ip_lookup_main_t * lm = &im->lookup_main;
1426 clib_error_t * error;
1429 for (cast = 0; cast < VNET_N_CAST; cast++)
1431 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1432 vnet_config_main_t * vcm = &cm->config_main;
1434 if ((error = ip_feature_init_cast (vm, cm, vcm,
1435 feature_start_nodes,
1436 ARRAY_LEN(feature_start_nodes),
1444 static clib_error_t *
1445 ip4_sw_interface_add_del (vnet_main_t * vnm,
1449 vlib_main_t * vm = vnm->vlib_main;
1450 ip4_main_t * im = &ip4_main;
1451 ip_lookup_main_t * lm = &im->lookup_main;
1455 for (cast = 0; cast < VNET_N_CAST; cast++)
1457 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1458 vnet_config_main_t * vcm = &cm->config_main;
1460 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
1461 ci = cm->config_index_by_sw_if_index[sw_if_index];
1463 if (cast == VNET_UNICAST)
1464 feature_index = im->ip4_unicast_rx_feature_lookup;
1466 feature_index = im->ip4_multicast_rx_feature_lookup;
1469 ci = vnet_config_add_feature (vm, vcm,
1472 /* config data */ 0,
1473 /* # bytes of config data */ 0);
1475 ci = vnet_config_del_feature (vm, vcm,
1478 /* config data */ 0,
1479 /* # bytes of config data */ 0);
1481 cm->config_index_by_sw_if_index[sw_if_index] = ci;
1484 return /* no error */ 0;
1487 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1489 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args);
1491 VLIB_REGISTER_NODE (ip4_lookup_node) = {
1492 .function = ip4_lookup,
1493 .name = "ip4-lookup",
1494 .vector_size = sizeof (u32),
1496 .format_trace = format_ip4_lookup_trace,
1498 .n_next_nodes = IP4_LOOKUP_N_NEXT,
1499 .next_nodes = IP4_LOOKUP_NEXT_NODES,
1502 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
1505 ip4_indirect (vlib_main_t * vm,
1506 vlib_node_runtime_t * node,
1507 vlib_frame_t * frame)
1509 return ip4_lookup_inline (vm, node, frame,
1510 /* lookup_for_responses_to_locally_received_packets */ 0,
1511 /* is_indirect */ 1);
1514 VLIB_REGISTER_NODE (ip4_indirect_node) = {
1515 .function = ip4_indirect,
1516 .name = "ip4-indirect",
1517 .vector_size = sizeof (u32),
1518 .sibling_of = "ip4-lookup",
1519 .format_trace = format_ip4_lookup_trace,
1524 VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
1527 /* Global IP4 main. */
1528 ip4_main_t ip4_main;
1531 ip4_lookup_init (vlib_main_t * vm)
1533 ip4_main_t * im = &ip4_main;
1534 clib_error_t * error;
1537 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1542 m = pow2_mask (i) << (32 - i);
1545 im->fib_masks[i] = clib_host_to_net_u32 (m);
1548 /* Create FIB with index 0 and table id of 0. */
1549 find_ip4_fib_by_table_index_or_id (im, /* table id */ 0, IP4_ROUTE_FLAG_TABLE_ID);
1551 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1555 pn = pg_get_node (ip4_lookup_node.index);
1556 pn->unformat_edit = unformat_pg_ip4_header;
1560 ethernet_arp_header_t h;
1562 memset (&h, 0, sizeof (h));
1564 /* Set target ethernet address to all zeros. */
1565 memset (h.ip4_over_ethernet[1].ethernet, 0, sizeof (h.ip4_over_ethernet[1].ethernet));
1567 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1568 #define _8(f,v) h.f = v;
1569 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1570 _16 (l3_type, ETHERNET_TYPE_IP4);
1571 _8 (n_l2_address_bytes, 6);
1572 _8 (n_l3_address_bytes, 4);
1573 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1577 vlib_packet_template_init (vm,
1578 &im->ip4_arp_request_packet_template,
1581 /* alloc chunk size */ 8,
1585 error = ip4_feature_init (vm, im);
1590 VLIB_INIT_FUNCTION (ip4_lookup_init);
1593 /* Adjacency taken. */
1598 /* Packet data, possibly *after* rewrite. */
1599 u8 packet_data[64 - 1*sizeof(u32)];
1600 } ip4_forward_next_trace_t;
1602 static u8 * format_ip4_forward_next_trace (u8 * s, va_list * args)
1604 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1605 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1606 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1607 uword indent = format_get_indent (s);
1608 s = format (s, "%U%U",
1609 format_white_space, indent,
1610 format_ip4_header, t->packet_data);
1614 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args)
1616 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1617 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1618 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1619 vnet_main_t * vnm = vnet_get_main();
1620 ip4_main_t * im = &ip4_main;
1621 uword indent = format_get_indent (s);
1623 s = format (s, "fib %d adj-idx %d : %U flow hash: 0x%08x",
1624 t->fib_index, t->adj_index, format_ip_adjacency,
1625 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1626 s = format (s, "\n%U%U",
1627 format_white_space, indent,
1628 format_ip4_header, t->packet_data);
1632 static u8 * format_ip4_rewrite_trace (u8 * s, va_list * args)
1634 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1635 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1636 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1637 vnet_main_t * vnm = vnet_get_main();
1638 ip4_main_t * im = &ip4_main;
1639 uword indent = format_get_indent (s);
1641 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1642 t->fib_index, t->adj_index, format_ip_adjacency,
1643 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1644 s = format (s, "\n%U%U",
1645 format_white_space, indent,
1646 format_ip_adjacency_packet_data,
1647 vnm, &im->lookup_main, t->adj_index,
1648 t->packet_data, sizeof (t->packet_data));
1652 /* Common trace function for all ip4-forward next nodes. */
1654 ip4_forward_next_trace (vlib_main_t * vm,
1655 vlib_node_runtime_t * node,
1656 vlib_frame_t * frame,
1657 vlib_rx_or_tx_t which_adj_index)
1660 ip4_main_t * im = &ip4_main;
1662 n_left = frame->n_vectors;
1663 from = vlib_frame_vector_args (frame);
1668 vlib_buffer_t * b0, * b1;
1669 ip4_forward_next_trace_t * t0, * t1;
1671 /* Prefetch next iteration. */
1672 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1673 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1678 b0 = vlib_get_buffer (vm, bi0);
1679 b1 = vlib_get_buffer (vm, bi1);
1681 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1683 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1684 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1685 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1686 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1687 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1688 vec_elt (im->fib_index_by_sw_if_index,
1689 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1691 clib_memcpy (t0->packet_data,
1692 vlib_buffer_get_current (b0),
1693 sizeof (t0->packet_data));
1695 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1697 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1698 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1699 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1700 t1->fib_index = (vnet_buffer(b1)->sw_if_index[VLIB_TX] != (u32)~0) ?
1701 vnet_buffer(b1)->sw_if_index[VLIB_TX] :
1702 vec_elt (im->fib_index_by_sw_if_index,
1703 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
1704 clib_memcpy (t1->packet_data,
1705 vlib_buffer_get_current (b1),
1706 sizeof (t1->packet_data));
1716 ip4_forward_next_trace_t * t0;
1720 b0 = vlib_get_buffer (vm, bi0);
1722 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1724 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1725 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1726 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1727 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1728 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1729 vec_elt (im->fib_index_by_sw_if_index,
1730 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1731 clib_memcpy (t0->packet_data,
1732 vlib_buffer_get_current (b0),
1733 sizeof (t0->packet_data));
1741 ip4_drop_or_punt (vlib_main_t * vm,
1742 vlib_node_runtime_t * node,
1743 vlib_frame_t * frame,
1744 ip4_error_t error_code)
1746 u32 * buffers = vlib_frame_vector_args (frame);
1747 uword n_packets = frame->n_vectors;
1749 vlib_error_drop_buffers (vm, node,
1754 ip4_input_node.index,
1757 if (node->flags & VLIB_NODE_FLAG_TRACE)
1758 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1764 ip4_drop (vlib_main_t * vm,
1765 vlib_node_runtime_t * node,
1766 vlib_frame_t * frame)
1767 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP); }
1770 ip4_punt (vlib_main_t * vm,
1771 vlib_node_runtime_t * node,
1772 vlib_frame_t * frame)
1773 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); }
1776 ip4_miss (vlib_main_t * vm,
1777 vlib_node_runtime_t * node,
1778 vlib_frame_t * frame)
1779 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_DST_LOOKUP_MISS); }
1781 VLIB_REGISTER_NODE (ip4_drop_node,static) = {
1782 .function = ip4_drop,
1784 .vector_size = sizeof (u32),
1786 .format_trace = format_ip4_forward_next_trace,
1794 VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
1796 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
1797 .function = ip4_punt,
1799 .vector_size = sizeof (u32),
1801 .format_trace = format_ip4_forward_next_trace,
1809 VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
1811 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
1812 .function = ip4_miss,
1814 .vector_size = sizeof (u32),
1816 .format_trace = format_ip4_forward_next_trace,
1824 VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
1826 /* Compute TCP/UDP/ICMP4 checksum in software. */
1828 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1832 u32 ip_header_length, payload_length_host_byte_order;
1833 u32 n_this_buffer, n_bytes_left;
1835 void * data_this_buffer;
1837 /* Initialize checksum with ip header. */
1838 ip_header_length = ip4_header_bytes (ip0);
1839 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->length) - ip_header_length;
1840 sum0 = clib_host_to_net_u32 (payload_length_host_byte_order + (ip0->protocol << 16));
1842 if (BITS (uword) == 32)
1844 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u32));
1845 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
1848 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1850 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1851 data_this_buffer = (void *) ip0 + ip_header_length;
1852 if (n_this_buffer + ip_header_length > p0->current_length)
1853 n_this_buffer = p0->current_length > ip_header_length ? p0->current_length - ip_header_length : 0;
1856 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1857 n_bytes_left -= n_this_buffer;
1858 if (n_bytes_left == 0)
1861 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1862 p0 = vlib_get_buffer (vm, p0->next_buffer);
1863 data_this_buffer = vlib_buffer_get_current (p0);
1864 n_this_buffer = p0->current_length;
1867 sum16 = ~ ip_csum_fold (sum0);
1873 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1875 ip4_header_t * ip0 = vlib_buffer_get_current (p0);
1876 udp_header_t * udp0;
1879 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1880 || ip0->protocol == IP_PROTOCOL_UDP);
1882 udp0 = (void *) (ip0 + 1);
1883 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1885 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1886 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1890 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1892 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1893 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1899 ip4_local (vlib_main_t * vm,
1900 vlib_node_runtime_t * node,
1901 vlib_frame_t * frame)
1903 ip4_main_t * im = &ip4_main;
1904 ip_lookup_main_t * lm = &im->lookup_main;
1905 ip_local_next_t next_index;
1906 u32 * from, * to_next, n_left_from, n_left_to_next;
1907 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
1909 from = vlib_frame_vector_args (frame);
1910 n_left_from = frame->n_vectors;
1911 next_index = node->cached_next_index;
1913 if (node->flags & VLIB_NODE_FLAG_TRACE)
1914 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1916 while (n_left_from > 0)
1918 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1920 while (n_left_from >= 4 && n_left_to_next >= 2)
1922 vlib_buffer_t * p0, * p1;
1923 ip4_header_t * ip0, * ip1;
1924 udp_header_t * udp0, * udp1;
1925 ip4_fib_mtrie_t * mtrie0, * mtrie1;
1926 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1927 ip_adjacency_t * adj0, * adj1;
1928 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, adj_index0;
1929 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, adj_index1;
1930 i32 len_diff0, len_diff1;
1931 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1932 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1935 pi0 = to_next[0] = from[0];
1936 pi1 = to_next[1] = from[1];
1940 n_left_to_next -= 2;
1942 p0 = vlib_get_buffer (vm, pi0);
1943 p1 = vlib_get_buffer (vm, pi1);
1945 ip0 = vlib_buffer_get_current (p0);
1946 ip1 = vlib_buffer_get_current (p1);
1948 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1949 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
1950 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1951 vnet_buffer(p1)->sw_if_index[VLIB_RX]);
1953 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
1954 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
1956 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1958 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1959 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
1961 /* Treat IP frag packets as "experimental" protocol for now
1962 until support of IP frag reassembly is implemented */
1963 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
1964 proto1 = ip4_is_fragment(ip1) ? 0xfe : ip1->protocol;
1965 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1966 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1967 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1968 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1973 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1974 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1976 udp0 = ip4_next_header (ip0);
1977 udp1 = ip4_next_header (ip1);
1979 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1980 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1981 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1983 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1984 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
1986 /* Verify UDP length. */
1987 ip_len0 = clib_net_to_host_u16 (ip0->length);
1988 ip_len1 = clib_net_to_host_u16 (ip1->length);
1989 udp_len0 = clib_net_to_host_u16 (udp0->length);
1990 udp_len1 = clib_net_to_host_u16 (udp1->length);
1992 len_diff0 = ip_len0 - udp_len0;
1993 len_diff1 = ip_len1 - udp_len1;
1995 len_diff0 = is_udp0 ? len_diff0 : 0;
1996 len_diff1 = is_udp1 ? len_diff1 : 0;
1998 if (PREDICT_FALSE (! (is_tcp_udp0 & is_tcp_udp1
1999 & good_tcp_udp0 & good_tcp_udp1)))
2004 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2005 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2007 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2008 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2013 && ! (flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2014 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
2016 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2017 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2021 good_tcp_udp0 &= len_diff0 >= 0;
2022 good_tcp_udp1 &= len_diff1 >= 0;
2024 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2025 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
2027 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
2029 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2030 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
2032 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2033 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2034 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2036 error1 = (is_tcp_udp1 && ! good_tcp_udp1
2037 ? IP4_ERROR_TCP_CHECKSUM + is_udp1
2040 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2041 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
2043 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2044 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2046 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
2047 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
2049 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2051 /* no_default_route */ 1));
2052 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
2054 /* no_default_route */ 1));
2056 adj0 = ip_get_adjacency (lm, adj_index0);
2057 adj1 = ip_get_adjacency (lm, adj_index1);
2060 * Must have a route to source otherwise we drop the packet.
2061 * ip4 broadcasts are accepted, e.g. to make dhcp client work
2063 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2064 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2065 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2066 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2067 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2068 ? IP4_ERROR_SRC_LOOKUP_MISS
2070 error1 = (error1 == IP4_ERROR_UNKNOWN_PROTOCOL
2071 && adj1->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2072 && adj1->lookup_next_index != IP_LOOKUP_NEXT_ARP
2073 && adj1->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2074 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2075 ? IP4_ERROR_SRC_LOOKUP_MISS
2078 next0 = lm->local_next_by_ip_protocol[proto0];
2079 next1 = lm->local_next_by_ip_protocol[proto1];
2081 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2082 next1 = error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
2084 p0->error = error0 ? error_node->errors[error0] : 0;
2085 p1->error = error1 ? error_node->errors[error1] : 0;
2087 enqueue_code = (next0 != next_index) + 2*(next1 != next_index);
2089 if (PREDICT_FALSE (enqueue_code != 0))
2091 switch (enqueue_code)
2097 n_left_to_next += 1;
2098 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2104 n_left_to_next += 1;
2105 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2109 /* A B B or A B C */
2111 n_left_to_next += 2;
2112 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2113 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2116 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2118 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2125 while (n_left_from > 0 && n_left_to_next > 0)
2129 udp_header_t * udp0;
2130 ip4_fib_mtrie_t * mtrie0;
2131 ip4_fib_mtrie_leaf_t leaf0;
2132 ip_adjacency_t * adj0;
2133 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, adj_index0;
2135 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2137 pi0 = to_next[0] = from[0];
2141 n_left_to_next -= 1;
2143 p0 = vlib_get_buffer (vm, pi0);
2145 ip0 = vlib_buffer_get_current (p0);
2147 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2148 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2150 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2152 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2154 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2156 /* Treat IP frag packets as "experimental" protocol for now
2157 until support of IP frag reassembly is implemented */
2158 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
2159 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2160 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2164 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2166 udp0 = ip4_next_header (ip0);
2168 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2169 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2171 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2173 /* Verify UDP length. */
2174 ip_len0 = clib_net_to_host_u16 (ip0->length);
2175 udp_len0 = clib_net_to_host_u16 (udp0->length);
2177 len_diff0 = ip_len0 - udp_len0;
2179 len_diff0 = is_udp0 ? len_diff0 : 0;
2181 if (PREDICT_FALSE (! (is_tcp_udp0 & good_tcp_udp0)))
2186 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2187 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2189 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2190 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2194 good_tcp_udp0 &= len_diff0 >= 0;
2196 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2198 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
2200 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2202 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2203 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2204 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2207 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2209 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2210 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2212 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2214 /* no_default_route */ 1));
2216 adj0 = ip_get_adjacency (lm, adj_index0);
2218 /* Must have a route to source otherwise we drop the packet. */
2219 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2220 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2221 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2222 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2223 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2224 ? IP4_ERROR_SRC_LOOKUP_MISS
2227 next0 = lm->local_next_by_ip_protocol[proto0];
2229 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2231 p0->error = error0? error_node->errors[error0] : 0;
2233 if (PREDICT_FALSE (next0 != next_index))
2235 n_left_to_next += 1;
2236 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2239 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2242 n_left_to_next -= 1;
2246 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2249 return frame->n_vectors;
2252 VLIB_REGISTER_NODE (ip4_local_node,static) = {
2253 .function = ip4_local,
2254 .name = "ip4-local",
2255 .vector_size = sizeof (u32),
2257 .format_trace = format_ip4_forward_next_trace,
2259 .n_next_nodes = IP_LOCAL_N_NEXT,
2261 [IP_LOCAL_NEXT_DROP] = "error-drop",
2262 [IP_LOCAL_NEXT_PUNT] = "error-punt",
2263 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
2264 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
2268 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
2270 void ip4_register_protocol (u32 protocol, u32 node_index)
2272 vlib_main_t * vm = vlib_get_main();
2273 ip4_main_t * im = &ip4_main;
2274 ip_lookup_main_t * lm = &im->lookup_main;
2276 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
2277 lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index);
2280 static clib_error_t *
2281 show_ip_local_command_fn (vlib_main_t * vm,
2282 unformat_input_t * input,
2283 vlib_cli_command_t * cmd)
2285 ip4_main_t * im = &ip4_main;
2286 ip_lookup_main_t * lm = &im->lookup_main;
2289 vlib_cli_output (vm, "Protocols handled by ip4_local");
2290 for (i = 0; i < ARRAY_LEN(lm->local_next_by_ip_protocol); i++)
2292 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2293 vlib_cli_output (vm, "%d", i);
2300 VLIB_CLI_COMMAND (show_ip_local, static) = {
2301 .path = "show ip local",
2302 .function = show_ip_local_command_fn,
2303 .short_help = "Show ip local protocol table",
2307 ip4_arp (vlib_main_t * vm,
2308 vlib_node_runtime_t * node,
2309 vlib_frame_t * frame)
2311 vnet_main_t * vnm = vnet_get_main();
2312 ip4_main_t * im = &ip4_main;
2313 ip_lookup_main_t * lm = &im->lookup_main;
2314 u32 * from, * to_next_drop;
2315 uword n_left_from, n_left_to_next_drop, next_index;
2316 static f64 time_last_seed_change = -1e100;
2317 static u32 hash_seeds[3];
2318 static uword hash_bitmap[256 / BITS (uword)];
2321 if (node->flags & VLIB_NODE_FLAG_TRACE)
2322 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2324 time_now = vlib_time_now (vm);
2325 if (time_now - time_last_seed_change > 1e-3)
2328 u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
2329 sizeof (hash_seeds));
2330 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2331 hash_seeds[i] = r[i];
2333 /* Mark all hash keys as been no-seen before. */
2334 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2337 time_last_seed_change = time_now;
2340 from = vlib_frame_vector_args (frame);
2341 n_left_from = frame->n_vectors;
2342 next_index = node->cached_next_index;
2343 if (next_index == IP4_ARP_NEXT_DROP)
2344 next_index = IP4_ARP_N_NEXT; /* point to first interface */
2346 while (n_left_from > 0)
2348 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2349 to_next_drop, n_left_to_next_drop);
2351 while (n_left_from > 0 && n_left_to_next_drop > 0)
2355 ethernet_header_t * eh0;
2356 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
2358 ip_adjacency_t * adj0;
2362 p0 = vlib_get_buffer (vm, pi0);
2364 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2365 adj0 = ip_get_adjacency (lm, adj_index0);
2366 ip0 = vlib_buffer_get_current (p0);
2368 /* If packet destination is not local, send ARP to next hop */
2369 if (adj0->arp.next_hop.ip4.as_u32)
2370 ip0->dst_address.data_u32 = adj0->arp.next_hop.ip4.as_u32;
2373 * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP
2374 * rewrite to this packet, we need to skip it here.
2375 * Note, to distinguish from src IP addr *.8.6.*, we
2376 * check for a bcast eth dest instead of IPv4 version.
2378 eh0 = (ethernet_header_t*)ip0;
2379 if ((ip0->ip_version_and_header_length & 0xF0) != 0x40)
2382 u16 * etype = &eh0->type;
2383 while ((*etype == clib_host_to_net_u16 (0x8100)) //dot1q
2384 || (*etype == clib_host_to_net_u16 (0x88a8)))//dot1ad
2387 etype += 2; //vlan tag also 16 bits, same as etype
2389 if (*etype == clib_host_to_net_u16 (0x0806)) //arp
2391 vlib_buffer_advance (
2392 p0, sizeof(ethernet_header_t) + (4*vlan_num));
2393 ip0 = vlib_buffer_get_current (p0);
2401 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2402 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2404 a0 ^= ip0->dst_address.data_u32;
2407 hash_v3_finalize32 (a0, b0, c0);
2409 c0 &= BITS (hash_bitmap) - 1;
2410 c0 = c0 / BITS (uword);
2411 m0 = (uword) 1 << (c0 % BITS (uword));
2413 bm0 = hash_bitmap[c0];
2414 drop0 = (bm0 & m0) != 0;
2416 /* Mark it as seen. */
2417 hash_bitmap[c0] = bm0 | m0;
2421 to_next_drop[0] = pi0;
2423 n_left_to_next_drop -= 1;
2425 p0->error = node->errors[drop0 ? IP4_ARP_ERROR_DROP : IP4_ARP_ERROR_REQUEST_SENT];
2431 * Can happen if the control-plane is programming tables
2432 * with traffic flowing; at least that's today's lame excuse.
2434 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
2436 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2439 /* Send ARP request. */
2443 ethernet_arp_header_t * h0;
2444 vnet_hw_interface_t * hw_if0;
2446 h0 = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi0);
2448 /* Add rewrite/encap string for ARP packet. */
2449 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2451 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2453 /* Src ethernet address in ARP header. */
2454 clib_memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address,
2455 sizeof (h0->ip4_over_ethernet[0].ethernet));
2457 if (ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0)) {
2458 //No source address available
2459 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2460 vlib_buffer_free(vm, &bi0, 1);
2464 /* Copy in destination address we are requesting. */
2465 h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32;
2467 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2468 b0 = vlib_get_buffer (vm, bi0);
2469 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2471 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2473 vlib_set_next_frame_buffer (vm, node, adj0->rewrite_header.next_index, bi0);
2477 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2480 return frame->n_vectors;
2483 static char * ip4_arp_error_strings[] = {
2484 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2485 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2486 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2487 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2488 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2489 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
2492 VLIB_REGISTER_NODE (ip4_arp_node) = {
2493 .function = ip4_arp,
2495 .vector_size = sizeof (u32),
2497 .format_trace = format_ip4_forward_next_trace,
2499 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2500 .error_strings = ip4_arp_error_strings,
2502 .n_next_nodes = IP4_ARP_N_NEXT,
2504 [IP4_ARP_NEXT_DROP] = "error-drop",
2508 #define foreach_notrace_ip4_arp_error \
2514 clib_error_t * arp_notrace_init (vlib_main_t * vm)
2516 vlib_node_runtime_t *rt =
2517 vlib_node_get_runtime (vm, ip4_arp_node.index);
2519 /* don't trace ARP request packets */
2521 vnet_pcap_drop_trace_filter_add_del \
2522 (rt->errors[IP4_ARP_ERROR_##a], \
2524 foreach_notrace_ip4_arp_error;
2529 VLIB_INIT_FUNCTION(arp_notrace_init);
2532 /* Send an ARP request to see if given destination is reachable on given interface. */
2534 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2536 vnet_main_t * vnm = vnet_get_main();
2537 ip4_main_t * im = &ip4_main;
2538 ethernet_arp_header_t * h;
2539 ip4_address_t * src;
2540 ip_interface_address_t * ia;
2541 ip_adjacency_t * adj;
2542 vnet_hw_interface_t * hi;
2543 vnet_sw_interface_t * si;
2547 si = vnet_get_sw_interface (vnm, sw_if_index);
2549 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2551 return clib_error_return (0, "%U: interface %U down",
2552 format_ip4_address, dst,
2553 format_vnet_sw_if_index_name, vnm,
2557 src = ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2560 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2561 return clib_error_return
2562 (0, "no matching interface address for destination %U (interface %U)",
2563 format_ip4_address, dst,
2564 format_vnet_sw_if_index_name, vnm, sw_if_index);
2567 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2569 h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi);
2571 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2573 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
2575 h->ip4_over_ethernet[0].ip4 = src[0];
2576 h->ip4_over_ethernet[1].ip4 = dst[0];
2578 b = vlib_get_buffer (vm, bi);
2579 vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2581 /* Add encapsulation string for software interface (e.g. ethernet header). */
2582 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2583 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2586 vlib_frame_t * f = vlib_get_frame_to_node (vm, hi->output_node_index);
2587 u32 * to_next = vlib_frame_vector_args (f);
2590 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2593 return /* no error */ 0;
2597 IP4_REWRITE_NEXT_DROP,
2598 IP4_REWRITE_NEXT_ARP,
2599 IP4_REWRITE_NEXT_ICMP_ERROR,
2600 } ip4_rewrite_next_t;
2603 ip4_rewrite_inline (vlib_main_t * vm,
2604 vlib_node_runtime_t * node,
2605 vlib_frame_t * frame,
2606 int rewrite_for_locally_received_packets)
2608 ip_lookup_main_t * lm = &ip4_main.lookup_main;
2609 u32 * from = vlib_frame_vector_args (frame);
2610 u32 n_left_from, n_left_to_next, * to_next, next_index;
2611 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2612 vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
2614 n_left_from = frame->n_vectors;
2615 next_index = node->cached_next_index;
2616 u32 cpu_index = os_get_cpu_number();
2618 while (n_left_from > 0)
2620 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2622 while (n_left_from >= 4 && n_left_to_next >= 2)
2624 ip_adjacency_t * adj0, * adj1;
2625 vlib_buffer_t * p0, * p1;
2626 ip4_header_t * ip0, * ip1;
2627 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2628 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2629 u32 next0_override, next1_override;
2631 if (rewrite_for_locally_received_packets)
2632 next0_override = next1_override = 0;
2634 /* Prefetch next iteration. */
2636 vlib_buffer_t * p2, * p3;
2638 p2 = vlib_get_buffer (vm, from[2]);
2639 p3 = vlib_get_buffer (vm, from[3]);
2641 vlib_prefetch_buffer_header (p2, STORE);
2642 vlib_prefetch_buffer_header (p3, STORE);
2644 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2645 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2648 pi0 = to_next[0] = from[0];
2649 pi1 = to_next[1] = from[1];
2654 n_left_to_next -= 2;
2656 p0 = vlib_get_buffer (vm, pi0);
2657 p1 = vlib_get_buffer (vm, pi1);
2659 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2660 adj_index1 = vnet_buffer (p1)->ip.adj_index[adj_rx_tx];
2662 /* We should never rewrite a pkt using the MISS adjacency */
2663 ASSERT(adj_index0 && adj_index1);
2665 ip0 = vlib_buffer_get_current (p0);
2666 ip1 = vlib_buffer_get_current (p1);
2668 error0 = error1 = IP4_ERROR_NONE;
2669 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2671 /* Decrement TTL & update checksum.
2672 Works either endian, so no need for byte swap. */
2673 if (! rewrite_for_locally_received_packets)
2675 i32 ttl0 = ip0->ttl, ttl1 = ip1->ttl;
2677 /* Input node should have reject packets with ttl 0. */
2678 ASSERT (ip0->ttl > 0);
2679 ASSERT (ip1->ttl > 0);
2681 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2682 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2684 checksum0 += checksum0 >= 0xffff;
2685 checksum1 += checksum1 >= 0xffff;
2687 ip0->checksum = checksum0;
2688 ip1->checksum = checksum1;
2697 * If the ttl drops below 1 when forwarding, generate
2700 if (PREDICT_FALSE(ttl0 <= 0))
2702 error0 = IP4_ERROR_TIME_EXPIRED;
2703 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2704 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2705 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2706 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2708 if (PREDICT_FALSE(ttl1 <= 0))
2710 error1 = IP4_ERROR_TIME_EXPIRED;
2711 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
2712 icmp4_error_set_vnet_buffer(p1, ICMP4_time_exceeded,
2713 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2714 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2717 /* Verify checksum. */
2718 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2719 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2722 /* Rewrite packet header and updates lengths. */
2723 adj0 = ip_get_adjacency (lm, adj_index0);
2724 adj1 = ip_get_adjacency (lm, adj_index1);
2726 if (rewrite_for_locally_received_packets)
2729 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2730 * we end up here with a local adjacency in hand
2731 * The local adj rewrite data is 0xfefe on purpose.
2732 * Bad engineer, no donut for you.
2734 if (PREDICT_FALSE(adj0->lookup_next_index
2735 == IP_LOOKUP_NEXT_LOCAL))
2736 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2737 if (PREDICT_FALSE(adj0->lookup_next_index
2738 == IP_LOOKUP_NEXT_ARP))
2739 next0_override = IP4_REWRITE_NEXT_ARP;
2740 if (PREDICT_FALSE(adj1->lookup_next_index
2741 == IP_LOOKUP_NEXT_LOCAL))
2742 error1 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2743 if (PREDICT_FALSE(adj1->lookup_next_index
2744 == IP_LOOKUP_NEXT_ARP))
2745 next1_override = IP4_REWRITE_NEXT_ARP;
2748 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2749 rw_len0 = adj0[0].rewrite_header.data_bytes;
2750 rw_len1 = adj1[0].rewrite_header.data_bytes;
2752 /* Check MTU of outgoing interface. */
2753 error0 = (vlib_buffer_length_in_chain (vm, p0) > adj0[0].rewrite_header.max_l3_packet_bytes
2754 ? IP4_ERROR_MTU_EXCEEDED
2756 error1 = (vlib_buffer_length_in_chain (vm, p1) > adj1[0].rewrite_header.max_l3_packet_bytes
2757 ? IP4_ERROR_MTU_EXCEEDED
2760 next0 = (error0 == IP4_ERROR_NONE)
2761 ? adj0[0].rewrite_header.next_index : next0;
2763 if (rewrite_for_locally_received_packets)
2764 next0 = next0 && next0_override ? next0_override : next0;
2766 next1 = (error1 == IP4_ERROR_NONE)
2767 ? adj1[0].rewrite_header.next_index : next1;
2769 if (rewrite_for_locally_received_packets)
2770 next1 = next1 && next1_override ? next1_override : next1;
2773 * We've already accounted for an ethernet_header_t elsewhere
2775 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2776 vlib_increment_combined_counter
2777 (&lm->adjacency_counters,
2778 cpu_index, adj_index0,
2779 /* packet increment */ 0,
2780 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2782 if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
2783 vlib_increment_combined_counter
2784 (&lm->adjacency_counters,
2785 cpu_index, adj_index1,
2786 /* packet increment */ 0,
2787 /* byte increment */ rw_len1-sizeof(ethernet_header_t));
2789 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2790 * to see the IP headerr */
2791 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2793 p0->current_data -= rw_len0;
2794 p0->current_length += rw_len0;
2795 p0->error = error_node->errors[error0];
2796 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2797 adj0[0].rewrite_header.sw_if_index;
2799 if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
2801 p1->current_data -= rw_len1;
2802 p1->current_length += rw_len1;
2803 p1->error = error_node->errors[error1];
2804 vnet_buffer (p1)->sw_if_index[VLIB_TX] =
2805 adj1[0].rewrite_header.sw_if_index;
2808 /* Guess we are only writing on simple Ethernet header. */
2809 vnet_rewrite_two_headers (adj0[0], adj1[0],
2811 sizeof (ethernet_header_t));
2813 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2814 to_next, n_left_to_next,
2815 pi0, pi1, next0, next1);
2818 while (n_left_from > 0 && n_left_to_next > 0)
2820 ip_adjacency_t * adj0;
2823 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2826 if (rewrite_for_locally_received_packets)
2829 pi0 = to_next[0] = from[0];
2831 p0 = vlib_get_buffer (vm, pi0);
2833 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2835 /* We should never rewrite a pkt using the MISS adjacency */
2838 adj0 = ip_get_adjacency (lm, adj_index0);
2840 ip0 = vlib_buffer_get_current (p0);
2842 error0 = IP4_ERROR_NONE;
2843 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2845 /* Decrement TTL & update checksum. */
2846 if (! rewrite_for_locally_received_packets)
2848 i32 ttl0 = ip0->ttl;
2850 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2852 checksum0 += checksum0 >= 0xffff;
2854 ip0->checksum = checksum0;
2856 ASSERT (ip0->ttl > 0);
2862 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2864 if (PREDICT_FALSE(ttl0 <= 0))
2867 * If the ttl drops below 1 when forwarding, generate
2870 error0 = IP4_ERROR_TIME_EXPIRED;
2871 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2872 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2873 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2874 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2878 if (rewrite_for_locally_received_packets)
2881 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2882 * we end up here with a local adjacency in hand
2883 * The local adj rewrite data is 0xfefe on purpose.
2884 * Bad engineer, no donut for you.
2886 if (PREDICT_FALSE(adj0->lookup_next_index
2887 == IP_LOOKUP_NEXT_LOCAL))
2888 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2890 * We have to override the next_index in ARP adjacencies,
2891 * because they're set up for ip4-arp, not this node...
2893 if (PREDICT_FALSE(adj0->lookup_next_index
2894 == IP_LOOKUP_NEXT_ARP))
2895 next0_override = IP4_REWRITE_NEXT_ARP;
2898 /* Guess we are only writing on simple Ethernet header. */
2899 vnet_rewrite_one_header (adj0[0], ip0,
2900 sizeof (ethernet_header_t));
2902 /* Update packet buffer attributes/set output interface. */
2903 rw_len0 = adj0[0].rewrite_header.data_bytes;
2905 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2906 vlib_increment_combined_counter
2907 (&lm->adjacency_counters,
2908 cpu_index, adj_index0,
2909 /* packet increment */ 0,
2910 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2912 /* Check MTU of outgoing interface. */
2913 error0 = (vlib_buffer_length_in_chain (vm, p0)
2914 > adj0[0].rewrite_header.max_l3_packet_bytes
2915 ? IP4_ERROR_MTU_EXCEEDED
2918 p0->error = error_node->errors[error0];
2920 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2921 * to see the IP headerr */
2922 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2924 p0->current_data -= rw_len0;
2925 p0->current_length += rw_len0;
2927 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2928 adj0[0].rewrite_header.sw_if_index;
2929 next0 = adj0[0].rewrite_header.next_index;
2932 if (rewrite_for_locally_received_packets)
2933 next0 = next0 && next0_override ? next0_override : next0;
2938 n_left_to_next -= 1;
2940 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2941 to_next, n_left_to_next,
2945 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2948 /* Need to do trace after rewrites to pick up new packet data. */
2949 if (node->flags & VLIB_NODE_FLAG_TRACE)
2950 ip4_forward_next_trace (vm, node, frame, adj_rx_tx);
2952 return frame->n_vectors;
2956 /** \brief IPv4 transit rewrite node.
2957 @node ip4-rewrite-transit
2959 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2960 header checksum, fetch the ip adjacency, check the outbound mtu,
2961 apply the adjacency rewrite, and send pkts to the adjacency
2962 rewrite header's rewrite_next_index.
2964 @param vm vlib_main_t corresponding to the current thread
2965 @param node vlib_node_runtime_t
2966 @param frame vlib_frame_t whose contents should be dispatched
2968 @par Graph mechanics: buffer metadata, next index usage
2971 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2972 - the rewrite adjacency index
2973 - <code>adj->lookup_next_index</code>
2974 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2975 the packet will be dropped.
2976 - <code>adj->rewrite_header</code>
2977 - Rewrite string length, rewrite string, next_index
2980 - <code>b->current_data, b->current_length</code>
2981 - Updated net of applying the rewrite string
2983 <em>Next Indices:</em>
2984 - <code> adj->rewrite_header.next_index </code>
2988 ip4_rewrite_transit (vlib_main_t * vm,
2989 vlib_node_runtime_t * node,
2990 vlib_frame_t * frame)
2992 return ip4_rewrite_inline (vm, node, frame,
2993 /* rewrite_for_locally_received_packets */ 0);
2996 /** \brief IPv4 local rewrite node.
2997 @node ip4-rewrite-local
2999 This is the IPv4 local rewrite node. Fetch the ip adjacency, check
3000 the outbound interface mtu, apply the adjacency rewrite, and send
3001 pkts to the adjacency rewrite header's rewrite_next_index. Deal
3002 with hemorrhoids of the form "some clown sends an icmp4 w/ src =
3003 dst = interface addr."
3005 @param vm vlib_main_t corresponding to the current thread
3006 @param node vlib_node_runtime_t
3007 @param frame vlib_frame_t whose contents should be dispatched
3009 @par Graph mechanics: buffer metadata, next index usage
3012 - <code>vnet_buffer(b)->ip.adj_index[VLIB_RX]</code>
3013 - the rewrite adjacency index
3014 - <code>adj->lookup_next_index</code>
3015 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
3016 the packet will be dropped.
3017 - <code>adj->rewrite_header</code>
3018 - Rewrite string length, rewrite string, next_index
3021 - <code>b->current_data, b->current_length</code>
3022 - Updated net of applying the rewrite string
3024 <em>Next Indices:</em>
3025 - <code> adj->rewrite_header.next_index </code>
3030 ip4_rewrite_local (vlib_main_t * vm,
3031 vlib_node_runtime_t * node,
3032 vlib_frame_t * frame)
3034 return ip4_rewrite_inline (vm, node, frame,
3035 /* rewrite_for_locally_received_packets */ 1);
3038 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
3039 .function = ip4_rewrite_transit,
3040 .name = "ip4-rewrite-transit",
3041 .vector_size = sizeof (u32),
3043 .format_trace = format_ip4_rewrite_trace,
3047 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3048 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3049 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3053 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
3055 VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
3056 .function = ip4_rewrite_local,
3057 .name = "ip4-rewrite-local",
3058 .vector_size = sizeof (u32),
3060 .sibling_of = "ip4-rewrite-transit",
3062 .format_trace = format_ip4_rewrite_trace,
3067 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
3069 static clib_error_t *
3070 add_del_interface_table (vlib_main_t * vm,
3071 unformat_input_t * input,
3072 vlib_cli_command_t * cmd)
3074 vnet_main_t * vnm = vnet_get_main();
3075 clib_error_t * error = 0;
3076 u32 sw_if_index, table_id;
3080 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3082 error = clib_error_return (0, "unknown interface `%U'",
3083 format_unformat_error, input);
3087 if (unformat (input, "%d", &table_id))
3091 error = clib_error_return (0, "expected table id `%U'",
3092 format_unformat_error, input);
3097 ip4_main_t * im = &ip4_main;
3098 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
3102 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
3103 im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
3111 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
3112 .path = "set interface ip table",
3113 .function = add_del_interface_table,
3114 .short_help = "Add/delete FIB table id for interface",
3119 ip4_lookup_multicast (vlib_main_t * vm,
3120 vlib_node_runtime_t * node,
3121 vlib_frame_t * frame)
3123 ip4_main_t * im = &ip4_main;
3124 ip_lookup_main_t * lm = &im->lookup_main;
3125 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
3126 u32 n_left_from, n_left_to_next, * from, * to_next;
3127 ip_lookup_next_t next;
3128 u32 cpu_index = os_get_cpu_number();
3130 from = vlib_frame_vector_args (frame);
3131 n_left_from = frame->n_vectors;
3132 next = node->cached_next_index;
3134 while (n_left_from > 0)
3136 vlib_get_next_frame (vm, node, next,
3137 to_next, n_left_to_next);
3139 while (n_left_from >= 4 && n_left_to_next >= 2)
3141 vlib_buffer_t * p0, * p1;
3142 u32 pi0, pi1, adj_index0, adj_index1, wrong_next;
3143 ip_lookup_next_t next0, next1;
3144 ip4_header_t * ip0, * ip1;
3145 ip_adjacency_t * adj0, * adj1;
3146 u32 fib_index0, fib_index1;
3147 u32 flow_hash_config0, flow_hash_config1;
3149 /* Prefetch next iteration. */
3151 vlib_buffer_t * p2, * p3;
3153 p2 = vlib_get_buffer (vm, from[2]);
3154 p3 = vlib_get_buffer (vm, from[3]);
3156 vlib_prefetch_buffer_header (p2, LOAD);
3157 vlib_prefetch_buffer_header (p3, LOAD);
3159 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
3160 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
3163 pi0 = to_next[0] = from[0];
3164 pi1 = to_next[1] = from[1];
3166 p0 = vlib_get_buffer (vm, pi0);
3167 p1 = vlib_get_buffer (vm, pi1);
3169 ip0 = vlib_buffer_get_current (p0);
3170 ip1 = vlib_buffer_get_current (p1);
3172 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3173 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
3174 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3175 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3176 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
3177 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
3179 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3180 &ip0->dst_address, p0);
3181 adj_index1 = ip4_fib_lookup_buffer (im, fib_index1,
3182 &ip1->dst_address, p1);
3184 adj0 = ip_get_adjacency (lm, adj_index0);
3185 adj1 = ip_get_adjacency (lm, adj_index1);
3187 next0 = adj0->lookup_next_index;
3188 next1 = adj1->lookup_next_index;
3191 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3194 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
3196 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
3197 (ip0, flow_hash_config0);
3199 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
3200 (ip1, flow_hash_config1);
3202 ASSERT (adj0->n_adj > 0);
3203 ASSERT (adj1->n_adj > 0);
3204 ASSERT (is_pow2 (adj0->n_adj));
3205 ASSERT (is_pow2 (adj1->n_adj));
3206 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3207 adj_index1 += (vnet_buffer (p1)->ip.flow_hash & (adj1->n_adj - 1));
3209 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3210 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
3212 if (1) /* $$$$$$ HACK FIXME */
3213 vlib_increment_combined_counter
3214 (cm, cpu_index, adj_index0, 1,
3215 vlib_buffer_length_in_chain (vm, p0));
3216 if (1) /* $$$$$$ HACK FIXME */
3217 vlib_increment_combined_counter
3218 (cm, cpu_index, adj_index1, 1,
3219 vlib_buffer_length_in_chain (vm, p1));
3223 n_left_to_next -= 2;
3226 wrong_next = (next0 != next) + 2*(next1 != next);
3227 if (PREDICT_FALSE (wrong_next != 0))
3235 n_left_to_next += 1;
3236 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3242 n_left_to_next += 1;
3243 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3249 n_left_to_next += 2;
3250 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3251 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3255 vlib_put_next_frame (vm, node, next, n_left_to_next);
3257 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
3263 while (n_left_from > 0 && n_left_to_next > 0)
3267 u32 pi0, adj_index0;
3268 ip_lookup_next_t next0;
3269 ip_adjacency_t * adj0;
3271 u32 flow_hash_config0;
3276 p0 = vlib_get_buffer (vm, pi0);
3278 ip0 = vlib_buffer_get_current (p0);
3280 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
3281 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3282 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3283 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3285 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3286 &ip0->dst_address, p0);
3288 adj0 = ip_get_adjacency (lm, adj_index0);
3290 next0 = adj0->lookup_next_index;
3293 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3295 vnet_buffer (p0)->ip.flow_hash =
3296 ip4_compute_flow_hash (ip0, flow_hash_config0);
3298 ASSERT (adj0->n_adj > 0);
3299 ASSERT (is_pow2 (adj0->n_adj));
3300 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3302 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3304 if (1) /* $$$$$$ HACK FIXME */
3305 vlib_increment_combined_counter
3306 (cm, cpu_index, adj_index0, 1,
3307 vlib_buffer_length_in_chain (vm, p0));
3311 n_left_to_next -= 1;
3314 if (PREDICT_FALSE (next0 != next))
3316 n_left_to_next += 1;
3317 vlib_put_next_frame (vm, node, next, n_left_to_next);
3319 vlib_get_next_frame (vm, node, next,
3320 to_next, n_left_to_next);
3323 n_left_to_next -= 1;
3327 vlib_put_next_frame (vm, node, next, n_left_to_next);
3330 if (node->flags & VLIB_NODE_FLAG_TRACE)
3331 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
3333 return frame->n_vectors;
3336 VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
3337 .function = ip4_lookup_multicast,
3338 .name = "ip4-lookup-multicast",
3339 .vector_size = sizeof (u32),
3340 .sibling_of = "ip4-lookup",
3341 .format_trace = format_ip4_lookup_trace,
3346 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
3348 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
3349 .function = ip4_drop,
3350 .name = "ip4-multicast",
3351 .vector_size = sizeof (u32),
3353 .format_trace = format_ip4_forward_next_trace,
3361 int ip4_lookup_validate (ip4_address_t *a, u32 fib_index0)
3363 ip4_main_t * im = &ip4_main;
3364 ip4_fib_mtrie_t * mtrie0;
3365 ip4_fib_mtrie_leaf_t leaf0;
3368 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
3370 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
3371 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
3372 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
3373 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
3374 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
3376 /* Handle default route. */
3377 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
3379 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
3381 return adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
3383 /* no_default_route */ 0);
3386 static clib_error_t *
3387 test_lookup_command_fn (vlib_main_t * vm,
3388 unformat_input_t * input,
3389 vlib_cli_command_t * cmd)
3395 ip4_address_t ip4_base_address;
3398 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3399 if (unformat (input, "table %d", &table_id))
3401 else if (unformat (input, "count %f", &count))
3404 else if (unformat (input, "%U",
3405 unformat_ip4_address, &ip4_base_address))
3408 return clib_error_return (0, "unknown input `%U'",
3409 format_unformat_error, input);
3414 for (i = 0; i < n; i++)
3416 if (!ip4_lookup_validate (&ip4_base_address, table_id))
3419 ip4_base_address.as_u32 =
3420 clib_host_to_net_u32 (1 +
3421 clib_net_to_host_u32 (ip4_base_address.as_u32));
3425 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3427 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3432 VLIB_CLI_COMMAND (lookup_test_command, static) = {
3433 .path = "test lookup",
3434 .short_help = "test lookup",
3435 .function = test_lookup_command_fn,
3438 int vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3440 ip4_main_t * im4 = &ip4_main;
3442 uword * p = hash_get (im4->fib_index_by_table_id, table_id);
3445 return VNET_API_ERROR_NO_SUCH_FIB;
3447 fib = vec_elt_at_index (im4->fibs, p[0]);
3449 fib->flow_hash_config = flow_hash_config;
3453 static clib_error_t *
3454 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3455 unformat_input_t * input,
3456 vlib_cli_command_t * cmd)
3460 u32 flow_hash_config = 0;
3463 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3464 if (unformat (input, "table %d", &table_id))
3467 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3468 foreach_flow_hash_bit
3474 return clib_error_return (0, "unknown input `%U'",
3475 format_unformat_error, input);
3477 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3483 case VNET_API_ERROR_NO_SUCH_FIB:
3484 return clib_error_return (0, "no such FIB table %d", table_id);
3487 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3494 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
3495 .path = "set ip flow-hash",
3497 "set ip table flow-hash table <fib-id> src dst sport dport proto reverse",
3498 .function = set_ip_flow_hash_command_fn,
3501 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3504 vnet_main_t * vnm = vnet_get_main();
3505 vnet_interface_main_t * im = &vnm->interface_main;
3506 ip4_main_t * ipm = &ip4_main;
3507 ip_lookup_main_t * lm = &ipm->lookup_main;
3508 vnet_classify_main_t * cm = &vnet_classify_main;
3510 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3511 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3513 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3514 return VNET_API_ERROR_NO_SUCH_ENTRY;
3516 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3517 lm->classify_table_index_by_sw_if_index [sw_if_index] = table_index;
3522 static clib_error_t *
3523 set_ip_classify_command_fn (vlib_main_t * vm,
3524 unformat_input_t * input,
3525 vlib_cli_command_t * cmd)
3527 u32 table_index = ~0;
3528 int table_index_set = 0;
3529 u32 sw_if_index = ~0;
3532 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3533 if (unformat (input, "table-index %d", &table_index))
3534 table_index_set = 1;
3535 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3536 vnet_get_main(), &sw_if_index))
3542 if (table_index_set == 0)
3543 return clib_error_return (0, "classify table-index must be specified");
3545 if (sw_if_index == ~0)
3546 return clib_error_return (0, "interface / subif must be specified");
3548 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3555 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3556 return clib_error_return (0, "No such interface");
3558 case VNET_API_ERROR_NO_SUCH_ENTRY:
3559 return clib_error_return (0, "No such classifier table");
3564 VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
3565 .path = "set ip classify",
3567 "set ip classify intfc <int> table-index <index>",
3568 .function = set_ip_classify_command_fn,