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 /* hash_get should never return NULL here */
198 clib_memcpy (p, fib->new_hash_values,
199 vec_bytes (fib->new_hash_values));
205 void ip4_add_del_route (ip4_main_t * im, ip4_add_del_route_args_t * a)
207 ip_lookup_main_t * lm = &im->lookup_main;
209 u32 dst_address, dst_address_length, adj_index, old_adj_index;
210 uword * hash, is_del;
211 ip4_add_del_route_callback_t * cb;
213 /* Either create new adjacency or use given one depending on arguments. */
214 if (a->n_add_adj > 0)
216 ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
217 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
220 adj_index = a->adj_index;
222 dst_address = a->dst_address.data_u32;
223 dst_address_length = a->dst_address_length;
224 fib = find_ip4_fib_by_table_index_or_id (im, a->table_index_or_table_id, a->flags);
226 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
227 dst_address &= im->fib_masks[dst_address_length];
229 if (! fib->adj_index_by_dst_address[dst_address_length])
230 ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length);
232 hash = fib->adj_index_by_dst_address[dst_address_length];
234 is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0;
238 fib->old_hash_values[0] = ~0;
239 hash = _hash_unset (hash, dst_address, fib->old_hash_values);
240 fib->adj_index_by_dst_address[dst_address_length] = hash;
242 if (vec_len (im->add_del_route_callbacks) > 0
243 && fib->old_hash_values[0] != ~0) /* make sure destination was found in hash */
245 fib->new_hash_values[0] = ~0;
246 vec_foreach (cb, im->add_del_route_callbacks)
247 if ((a->flags & cb->required_flags) == cb->required_flags)
248 cb->function (im, cb->function_opaque,
250 &a->dst_address, dst_address_length,
251 fib->old_hash_values,
252 fib->new_hash_values);
256 ip4_fib_set_adj_index (im, fib, a->flags, dst_address, dst_address_length,
259 old_adj_index = fib->old_hash_values[0];
261 /* Avoid spurious reference count increments */
262 if (old_adj_index == adj_index
264 && !(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY))
266 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
267 if (adj->share_count > 0)
271 ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length,
272 is_del ? old_adj_index : adj_index,
275 /* Delete old adjacency index if present and changed. */
276 if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
277 && old_adj_index != ~0
278 && old_adj_index != adj_index)
279 ip_del_adjacency (lm, old_adj_index);
284 ip4_route_get_next_hop_adj (ip4_main_t * im,
286 ip4_address_t *next_hop,
287 u32 next_hop_sw_if_index,
288 u32 explicit_fib_index)
290 ip_lookup_main_t * lm = &im->lookup_main;
291 vnet_main_t * vnm = vnet_get_main();
292 uword * nh_hash, * nh_result;
293 int is_interface_next_hop;
297 fib = vec_elt_at_index (im->fibs, fib_index);
299 is_interface_next_hop = next_hop->data_u32 == 0;
300 if (is_interface_next_hop)
302 nh_result = hash_get (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index);
304 nh_adj_index = *nh_result;
307 ip_adjacency_t * adj;
308 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
310 ip4_adjacency_set_interface_route (vnm, adj, next_hop_sw_if_index, /* if_address_index */ ~0);
311 ip_call_add_del_adjacency_callbacks (lm, nh_adj_index, /* is_del */ 0);
312 hash_set (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index, nh_adj_index);
315 else if (next_hop_sw_if_index == ~0)
317 /* next-hop is recursive. we always need a indirect adj
318 * for recursive paths. Any LPM we perform now will give
319 * us a valid adj, but without tracking the next-hop we
320 * have no way to keep it valid.
322 ip_adjacency_t add_adj;
323 memset (&add_adj, 0, sizeof(add_adj));
325 add_adj.lookup_next_index = IP_LOOKUP_NEXT_INDIRECT;
326 add_adj.indirect.next_hop.ip4.as_u32 = next_hop->as_u32;
327 add_adj.explicit_fib_index = explicit_fib_index;
328 ip_add_adjacency (lm, &add_adj, 1, &nh_adj_index);
332 nh_hash = fib->adj_index_by_dst_address[32];
333 nh_result = hash_get (nh_hash, next_hop->data_u32);
335 /* Next hop must be known. */
338 ip_adjacency_t * adj;
340 /* no /32 exists, get the longest prefix match */
341 nh_adj_index = ip4_fib_lookup_with_table (im, fib_index,
343 adj = ip_get_adjacency (lm, nh_adj_index);
344 /* if ARP interface adjacency is present, we need to
345 install ARP adjaceny for specific next hop */
346 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
347 adj->arp.next_hop.ip4.as_u32 == 0)
349 nh_adj_index = vnet_arp_glean_add(fib_index, next_hop);
354 nh_adj_index = *nh_result;
358 return (nh_adj_index);
362 ip4_add_del_route_next_hop (ip4_main_t * im,
364 ip4_address_t * dst_address,
365 u32 dst_address_length,
366 ip4_address_t * next_hop,
367 u32 next_hop_sw_if_index,
368 u32 next_hop_weight, u32 adj_index,
369 u32 explicit_fib_index)
371 vnet_main_t * vnm = vnet_get_main();
372 ip_lookup_main_t * lm = &im->lookup_main;
375 u32 dst_address_u32, old_mp_adj_index, new_mp_adj_index;
376 u32 dst_adj_index, nh_adj_index;
377 uword * dst_hash, * dst_result;
378 ip_adjacency_t * dst_adj;
379 ip_multipath_adjacency_t * old_mp, * new_mp;
380 int is_del = (flags & IP4_ROUTE_FLAG_DEL) != 0;
381 clib_error_t * error = 0;
383 if (explicit_fib_index == (u32)~0)
384 fib_index = vec_elt (im->fib_index_by_sw_if_index, next_hop_sw_if_index);
386 fib_index = explicit_fib_index;
388 fib = vec_elt_at_index (im->fibs, fib_index);
390 /* Lookup next hop to be added or deleted. */
391 if (adj_index == (u32)~0)
393 nh_adj_index = ip4_route_get_next_hop_adj(im, fib_index,
395 next_hop_sw_if_index,
400 nh_adj_index = adj_index;
402 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
403 dst_address_u32 = dst_address->data_u32 & im->fib_masks[dst_address_length];
405 dst_hash = fib->adj_index_by_dst_address[dst_address_length];
406 dst_result = hash_get (dst_hash, dst_address_u32);
409 dst_adj_index = dst_result[0];
410 dst_adj = ip_get_adjacency (lm, dst_adj_index);
414 /* For deletes destination must be known. */
417 vnm->api_errno = VNET_API_ERROR_UNKNOWN_DESTINATION;
418 error = clib_error_return (0, "unknown destination %U/%d",
419 format_ip4_address, dst_address,
428 /* Ignore adds of X/32 with next hop of X. */
430 && dst_address_length == 32
431 && dst_address->data_u32 == next_hop->data_u32
432 && adj_index != (u32)~0)
434 vnm->api_errno = VNET_API_ERROR_PREFIX_MATCHES_NEXT_HOP;
435 error = clib_error_return (0, "prefix matches next hop %U/%d",
436 format_ip4_address, dst_address,
441 /* Destination is not known and default weight is set so add route
442 to existing non-multipath adjacency */
443 if (dst_adj_index == ~0 && next_hop_weight == 1 && next_hop_sw_if_index == ~0)
445 /* create / delete additional mapping of existing adjacency */
446 ip4_add_del_route_args_t a;
448 a.table_index_or_table_id = fib_index;
449 a.flags = ((is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
450 | IP4_ROUTE_FLAG_FIB_INDEX
451 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
452 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE
453 | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
454 a.dst_address = dst_address[0];
455 a.dst_address_length = dst_address_length;
456 a.adj_index = nh_adj_index;
460 ip4_add_del_route (im, &a);
464 old_mp_adj_index = dst_adj ? dst_adj->heap_handle : ~0;
466 if (! ip_multipath_adjacency_add_del_next_hop
473 vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_FOUND_MP;
474 error = clib_error_return (0, "requested deleting next-hop %U not found in multi-path",
475 format_ip4_address, next_hop);
480 if (old_mp_adj_index != ~0)
481 old_mp = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
482 if (new_mp_adj_index != ~0)
483 new_mp = vec_elt_at_index (lm->multipath_adjacencies, new_mp_adj_index);
485 if (old_mp != new_mp)
487 ip4_add_del_route_args_t a;
488 ip_adjacency_t * adj;
490 a.table_index_or_table_id = fib_index;
491 a.flags = ((is_del && ! new_mp ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
492 | IP4_ROUTE_FLAG_FIB_INDEX
493 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
494 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
495 a.dst_address = dst_address[0];
496 a.dst_address_length = dst_address_length;
497 a.adj_index = new_mp ? new_mp->adj_index : dst_adj_index;
501 ip4_add_del_route (im, &a);
503 adj = ip_get_adjacency (lm, new_mp ? new_mp->adj_index : dst_adj_index);
505 adj->share_count += is_del ? -1 : 1;
510 clib_error_report (error);
514 ip4_get_route (ip4_main_t * im,
515 u32 table_index_or_table_id,
520 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
521 u32 dst_address = * (u32 *) address;
524 ASSERT (address_length < ARRAY_LEN (im->fib_masks));
525 dst_address &= im->fib_masks[address_length];
527 hash = fib->adj_index_by_dst_address[address_length];
528 p = hash_get (hash, dst_address);
533 ip4_foreach_matching_route (ip4_main_t * im,
534 u32 table_index_or_table_id,
536 ip4_address_t * address,
538 ip4_address_t ** results,
539 u8 ** result_lengths)
541 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
542 u32 dst_address = address->data_u32;
543 u32 this_length = address_length;
546 _vec_len (*results) = 0;
548 _vec_len (*result_lengths) = 0;
550 while (this_length <= 32 && vec_len (results) == 0)
553 hash_foreach (k, v, fib->adj_index_by_dst_address[this_length], ({
554 if (0 == ((k ^ dst_address) & im->fib_masks[address_length]))
558 vec_add1 (*results, a);
559 vec_add1 (*result_lengths, this_length);
567 void ip4_maybe_remap_adjacencies (ip4_main_t * im,
568 u32 table_index_or_table_id,
571 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
572 ip_lookup_main_t * lm = &im->lookup_main;
575 ip4_add_del_route_callback_t * cb;
576 static ip4_address_t * to_delete;
578 if (lm->n_adjacency_remaps == 0)
581 for (l = 0; l <= 32; l++)
584 uword * hash = fib->adj_index_by_dst_address[l];
586 if (hash_elts (hash) == 0)
590 _vec_len (to_delete) = 0;
592 hash_foreach_pair (p, hash, ({
593 u32 adj_index = p->value[0];
594 u32 m = vec_elt (lm->adjacency_remap_table, adj_index);
598 /* Record destination address from hash key. */
601 /* New adjacency points to nothing: so delete prefix. */
603 vec_add1 (to_delete, a);
606 /* Remap to new adjacency. */
607 clib_memcpy (fib->old_hash_values, p->value, vec_bytes (fib->old_hash_values));
609 /* Set new adjacency value. */
610 fib->new_hash_values[0] = p->value[0] = m - 1;
612 vec_foreach (cb, im->add_del_route_callbacks)
613 if ((flags & cb->required_flags) == cb->required_flags)
614 cb->function (im, cb->function_opaque,
615 fib, flags | IP4_ROUTE_FLAG_ADD,
617 fib->old_hash_values,
618 fib->new_hash_values);
623 fib->new_hash_values[0] = ~0;
624 for (i = 0; i < vec_len (to_delete); i++)
626 hash = _hash_unset (hash, to_delete[i].data_u32, fib->old_hash_values);
627 vec_foreach (cb, im->add_del_route_callbacks)
628 if ((flags & cb->required_flags) == cb->required_flags)
629 cb->function (im, cb->function_opaque,
630 fib, flags | IP4_ROUTE_FLAG_DEL,
632 fib->old_hash_values,
633 fib->new_hash_values);
637 /* Also remap adjacencies in mtrie. */
638 ip4_mtrie_maybe_remap_adjacencies (lm, &fib->mtrie);
640 /* Reset mapping table. */
641 vec_zero (lm->adjacency_remap_table);
643 /* All remaps have been performed. */
644 lm->n_adjacency_remaps = 0;
647 void ip4_delete_matching_routes (ip4_main_t * im,
648 u32 table_index_or_table_id,
650 ip4_address_t * address,
653 static ip4_address_t * matching_addresses;
654 static u8 * matching_address_lengths;
656 ip4_add_del_route_args_t a;
658 a.flags = IP4_ROUTE_FLAG_DEL | IP4_ROUTE_FLAG_NO_REDISTRIBUTE | flags;
659 a.table_index_or_table_id = table_index_or_table_id;
664 for (l = address_length + 1; l <= 32; l++)
666 ip4_foreach_matching_route (im, table_index_or_table_id, flags,
670 &matching_address_lengths);
671 for (i = 0; i < vec_len (matching_addresses); i++)
673 a.dst_address = matching_addresses[i];
674 a.dst_address_length = matching_address_lengths[i];
675 ip4_add_del_route (im, &a);
679 ip4_maybe_remap_adjacencies (im, table_index_or_table_id, flags);
683 ip4_forward_next_trace (vlib_main_t * vm,
684 vlib_node_runtime_t * node,
685 vlib_frame_t * frame,
686 vlib_rx_or_tx_t which_adj_index);
689 ip4_lookup_inline (vlib_main_t * vm,
690 vlib_node_runtime_t * node,
691 vlib_frame_t * frame,
692 int lookup_for_responses_to_locally_received_packets,
695 ip4_main_t * im = &ip4_main;
696 ip_lookup_main_t * lm = &im->lookup_main;
697 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
698 u32 n_left_from, n_left_to_next, * from, * to_next;
699 ip_lookup_next_t next;
700 u32 cpu_index = os_get_cpu_number();
702 from = vlib_frame_vector_args (frame);
703 n_left_from = frame->n_vectors;
704 next = node->cached_next_index;
706 while (n_left_from > 0)
708 vlib_get_next_frame (vm, node, next,
709 to_next, n_left_to_next);
711 while (n_left_from >= 4 && n_left_to_next >= 2)
713 vlib_buffer_t * p0, * p1;
714 ip4_header_t * ip0, * ip1;
715 __attribute__((unused)) tcp_header_t * tcp0, * tcp1;
716 ip_lookup_next_t next0, next1;
717 ip_adjacency_t * adj0, * adj1;
718 ip4_fib_mtrie_t * mtrie0, * mtrie1;
719 ip4_fib_mtrie_leaf_t leaf0, leaf1;
720 ip4_address_t * dst_addr0, *dst_addr1;
721 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
722 __attribute__((unused)) u32 pi1, fib_index1, adj_index1, is_tcp_udp1;
723 u32 flow_hash_config0, flow_hash_config1;
724 u32 hash_c0, hash_c1;
727 /* Prefetch next iteration. */
729 vlib_buffer_t * p2, * p3;
731 p2 = vlib_get_buffer (vm, from[2]);
732 p3 = vlib_get_buffer (vm, from[3]);
734 vlib_prefetch_buffer_header (p2, LOAD);
735 vlib_prefetch_buffer_header (p3, LOAD);
737 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
738 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
741 pi0 = to_next[0] = from[0];
742 pi1 = to_next[1] = from[1];
744 p0 = vlib_get_buffer (vm, pi0);
745 p1 = vlib_get_buffer (vm, pi1);
747 ip0 = vlib_buffer_get_current (p0);
748 ip1 = vlib_buffer_get_current (p1);
752 ip_adjacency_t * iadj0, * iadj1;
753 iadj0 = ip_get_adjacency (lm, vnet_buffer(p0)->ip.adj_index[VLIB_TX]);
754 iadj1 = ip_get_adjacency (lm, vnet_buffer(p1)->ip.adj_index[VLIB_TX]);
755 dst_addr0 = &iadj0->indirect.next_hop.ip4;
756 dst_addr1 = &iadj1->indirect.next_hop.ip4;
760 dst_addr0 = &ip0->dst_address;
761 dst_addr1 = &ip1->dst_address;
764 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
765 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
766 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
767 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
768 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
769 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
772 if (! lookup_for_responses_to_locally_received_packets)
774 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
775 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
777 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
779 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
780 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
783 tcp0 = (void *) (ip0 + 1);
784 tcp1 = (void *) (ip1 + 1);
786 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
787 || ip0->protocol == IP_PROTOCOL_UDP);
788 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
789 || ip1->protocol == IP_PROTOCOL_UDP);
791 if (! lookup_for_responses_to_locally_received_packets)
793 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
794 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
797 if (! lookup_for_responses_to_locally_received_packets)
799 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
800 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
803 if (! lookup_for_responses_to_locally_received_packets)
805 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
806 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
809 if (lookup_for_responses_to_locally_received_packets)
811 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
812 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
816 /* Handle default route. */
817 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
818 leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
820 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
821 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
824 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
826 /* no_default_route */ 0));
827 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
829 /* no_default_route */ 0));
830 adj0 = ip_get_adjacency (lm, adj_index0);
831 adj1 = ip_get_adjacency (lm, adj_index1);
833 next0 = adj0->lookup_next_index;
834 next1 = adj1->lookup_next_index;
836 /* Use flow hash to compute multipath adjacency. */
837 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
838 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
839 if (PREDICT_FALSE (adj0->n_adj > 1))
842 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
843 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
844 ip4_compute_flow_hash (ip0, flow_hash_config0);
846 if (PREDICT_FALSE(adj1->n_adj > 1))
849 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
850 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
851 ip4_compute_flow_hash (ip1, flow_hash_config1);
854 ASSERT (adj0->n_adj > 0);
855 ASSERT (adj1->n_adj > 0);
856 ASSERT (is_pow2 (adj0->n_adj));
857 ASSERT (is_pow2 (adj1->n_adj));
858 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
859 adj_index1 += (hash_c1 & (adj1->n_adj - 1));
861 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
862 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
864 vlib_increment_combined_counter
865 (cm, cpu_index, adj_index0, 1,
866 vlib_buffer_length_in_chain (vm, p0)
867 + sizeof(ethernet_header_t));
868 vlib_increment_combined_counter
869 (cm, cpu_index, adj_index1, 1,
870 vlib_buffer_length_in_chain (vm, p1)
871 + sizeof(ethernet_header_t));
878 wrong_next = (next0 != next) + 2*(next1 != next);
879 if (PREDICT_FALSE (wrong_next != 0))
888 vlib_set_next_frame_buffer (vm, node, next0, pi0);
895 vlib_set_next_frame_buffer (vm, node, next1, pi1);
902 vlib_set_next_frame_buffer (vm, node, next0, pi0);
903 vlib_set_next_frame_buffer (vm, node, next1, pi1);
907 vlib_put_next_frame (vm, node, next, n_left_to_next);
909 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
915 while (n_left_from > 0 && n_left_to_next > 0)
919 __attribute__((unused)) tcp_header_t * tcp0;
920 ip_lookup_next_t next0;
921 ip_adjacency_t * adj0;
922 ip4_fib_mtrie_t * mtrie0;
923 ip4_fib_mtrie_leaf_t leaf0;
924 ip4_address_t * dst_addr0;
925 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
926 u32 flow_hash_config0, hash_c0;
931 p0 = vlib_get_buffer (vm, pi0);
933 ip0 = vlib_buffer_get_current (p0);
937 ip_adjacency_t * iadj0;
938 iadj0 = ip_get_adjacency (lm, vnet_buffer(p0)->ip.adj_index[VLIB_TX]);
939 dst_addr0 = &iadj0->indirect.next_hop.ip4;
943 dst_addr0 = &ip0->dst_address;
946 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
947 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
948 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
950 if (! lookup_for_responses_to_locally_received_packets)
952 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
954 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
956 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
959 tcp0 = (void *) (ip0 + 1);
961 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
962 || ip0->protocol == IP_PROTOCOL_UDP);
964 if (! lookup_for_responses_to_locally_received_packets)
965 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
967 if (! lookup_for_responses_to_locally_received_packets)
968 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
970 if (! lookup_for_responses_to_locally_received_packets)
971 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
973 if (lookup_for_responses_to_locally_received_packets)
974 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
977 /* Handle default route. */
978 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
979 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
982 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
984 /* no_default_route */ 0));
986 adj0 = ip_get_adjacency (lm, adj_index0);
988 next0 = adj0->lookup_next_index;
990 /* Use flow hash to compute multipath adjacency. */
991 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
992 if (PREDICT_FALSE(adj0->n_adj > 1))
995 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
997 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
998 ip4_compute_flow_hash (ip0, flow_hash_config0);
1001 ASSERT (adj0->n_adj > 0);
1002 ASSERT (is_pow2 (adj0->n_adj));
1003 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
1005 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
1007 vlib_increment_combined_counter
1008 (cm, cpu_index, adj_index0, 1,
1009 vlib_buffer_length_in_chain (vm, p0)
1010 + sizeof(ethernet_header_t));
1014 n_left_to_next -= 1;
1017 if (PREDICT_FALSE (next0 != next))
1019 n_left_to_next += 1;
1020 vlib_put_next_frame (vm, node, next, n_left_to_next);
1022 vlib_get_next_frame (vm, node, next,
1023 to_next, n_left_to_next);
1026 n_left_to_next -= 1;
1030 vlib_put_next_frame (vm, node, next, n_left_to_next);
1033 if (node->flags & VLIB_NODE_FLAG_TRACE)
1034 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
1036 return frame->n_vectors;
1039 /** @brief IPv4 lookup node.
1042 This is the main IPv4 lookup dispatch node.
1044 @param vm vlib_main_t corresponding to the current thread
1045 @param node vlib_node_runtime_t
1046 @param frame vlib_frame_t whose contents should be dispatched
1048 @par Graph mechanics: buffer metadata, next index usage
1051 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
1052 - Indicates the @c sw_if_index value of the interface that the
1053 packet was received on.
1054 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
1055 - When the value is @c ~0 then the node performs a longest prefix
1056 match (LPM) for the packet destination address in the FIB attached
1057 to the receive interface.
1058 - Otherwise perform LPM for the packet destination address in the
1059 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
1060 value (0, 1, ...) and not a VRF id.
1063 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
1064 - The lookup result adjacency index.
1066 <em>Next Index:</em>
1067 - Dispatches the packet to the node index found in
1068 ip_adjacency_t @c adj->lookup_next_index
1069 (where @c adj is the lookup result adjacency).
1072 ip4_lookup (vlib_main_t * vm,
1073 vlib_node_runtime_t * node,
1074 vlib_frame_t * frame)
1076 return ip4_lookup_inline (vm, node, frame,
1077 /* lookup_for_responses_to_locally_received_packets */ 0,
1078 /* is_indirect */ 0);
1082 void ip4_adjacency_set_interface_route (vnet_main_t * vnm,
1083 ip_adjacency_t * adj,
1085 u32 if_address_index)
1087 vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1089 vnet_l3_packet_type_t packet_type;
1092 if (hw->hw_class_index == ethernet_hw_interface_class.index
1093 || hw->hw_class_index == srp_hw_interface_class.index)
1096 * We have a bit of a problem in this case. ip4-arp uses
1097 * the rewrite_header.next_index to hand pkts to the
1098 * indicated inteface output node. We can end up in
1099 * ip4_rewrite_local, too, which also pays attention to
1100 * rewrite_header.next index. Net result: a hack in
1101 * ip4_rewrite_local...
1103 n = IP_LOOKUP_NEXT_ARP;
1104 node_index = ip4_arp_node.index;
1105 adj->if_address_index = if_address_index;
1106 adj->arp.next_hop.ip4.as_u32 = 0;
1107 ip46_address_reset(&adj->arp.next_hop);
1108 packet_type = VNET_L3_PACKET_TYPE_ARP;
1112 n = IP_LOOKUP_NEXT_REWRITE;
1113 node_index = ip4_rewrite_node.index;
1114 packet_type = VNET_L3_PACKET_TYPE_IP4;
1117 adj->lookup_next_index = n;
1118 vnet_rewrite_for_sw_interface
1123 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST,
1124 &adj->rewrite_header,
1125 sizeof (adj->rewrite_data));
1129 ip4_add_interface_routes (u32 sw_if_index,
1130 ip4_main_t * im, u32 fib_index,
1131 ip_interface_address_t * a)
1133 vnet_main_t * vnm = vnet_get_main();
1134 ip_lookup_main_t * lm = &im->lookup_main;
1135 ip_adjacency_t * adj;
1136 ip4_address_t * address = ip_interface_address_get_address (lm, a);
1137 ip4_add_del_route_args_t x;
1138 vnet_hw_interface_t * hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
1139 u32 classify_table_index;
1141 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1142 x.table_index_or_table_id = fib_index;
1143 x.flags = (IP4_ROUTE_FLAG_ADD
1144 | IP4_ROUTE_FLAG_FIB_INDEX
1145 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1146 x.dst_address = address[0];
1147 x.dst_address_length = a->address_length;
1151 a->neighbor_probe_adj_index = ~0;
1152 if (a->address_length < 32)
1154 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1156 ip4_adjacency_set_interface_route (vnm, adj, sw_if_index, a - lm->if_address_pool);
1157 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1158 ip4_add_del_route (im, &x);
1159 a->neighbor_probe_adj_index = x.adj_index;
1162 /* Add e.g. 1.1.1.1/32 as local to this host. */
1163 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1166 classify_table_index = ~0;
1167 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
1168 classify_table_index = lm->classify_table_index_by_sw_if_index [sw_if_index];
1169 if (classify_table_index != (u32) ~0)
1171 adj->lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1172 adj->classify.table_index = classify_table_index;
1175 adj->lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
1177 adj->if_address_index = a - lm->if_address_pool;
1178 adj->rewrite_header.sw_if_index = sw_if_index;
1179 adj->rewrite_header.max_l3_packet_bytes = hw_if->max_l3_packet_bytes[VLIB_RX];
1181 * Local adjs are never to be rewritten. Spoofed pkts w/ src = dst = local
1182 * fail an RPF-ish check, but still go thru the rewrite code...
1184 adj->rewrite_header.data_bytes = 0;
1186 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1187 x.dst_address_length = 32;
1188 ip4_add_del_route (im, &x);
1192 ip4_del_interface_routes (ip4_main_t * im, u32 fib_index, ip4_address_t * address, u32 address_length)
1194 ip4_add_del_route_args_t x;
1196 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1197 x.table_index_or_table_id = fib_index;
1198 x.flags = (IP4_ROUTE_FLAG_DEL
1199 | IP4_ROUTE_FLAG_FIB_INDEX
1200 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1201 x.dst_address = address[0];
1202 x.dst_address_length = address_length;
1207 if (address_length < 32)
1208 ip4_add_del_route (im, &x);
1210 x.dst_address_length = 32;
1211 ip4_add_del_route (im, &x);
1213 ip4_delete_matching_routes (im,
1215 IP4_ROUTE_FLAG_FIB_INDEX,
1222 ip4_address_t address;
1224 } ip4_interface_address_t;
1226 static clib_error_t *
1227 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1229 ip4_address_t * new_address,
1235 static clib_error_t *
1236 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1238 ip4_address_t * address,
1244 vnet_main_t * vnm = vnet_get_main();
1245 ip4_main_t * im = &ip4_main;
1246 ip_lookup_main_t * lm = &im->lookup_main;
1247 clib_error_t * error = 0;
1248 u32 if_address_index, elts_before;
1249 ip4_address_fib_t ip4_af, * addr_fib = 0;
1251 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1252 ip4_addr_fib_init (&ip4_af, address,
1253 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
1254 vec_add1 (addr_fib, ip4_af);
1256 /* When adding an address check that it does not conflict with an existing address. */
1259 ip_interface_address_t * ia;
1260 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1261 0 /* honor unnumbered */,
1263 ip4_address_t * x = ip_interface_address_get_address (&im->lookup_main, ia);
1265 if (ip4_destination_matches_route (im, address, x, ia->address_length)
1266 || ip4_destination_matches_route (im, x, address, address_length))
1267 return clib_error_create ("failed to add %U which conflicts with %U for interface %U",
1268 format_ip4_address_and_length, address, address_length,
1269 format_ip4_address_and_length, x, ia->address_length,
1270 format_vnet_sw_if_index_name, vnm, sw_if_index);
1274 elts_before = pool_elts (lm->if_address_pool);
1276 error = ip_interface_address_add_del
1286 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index) && insert_routes)
1289 ip4_del_interface_routes (im, ip4_af.fib_index, address,
1293 ip4_add_interface_routes (sw_if_index,
1294 im, ip4_af.fib_index,
1296 (lm->if_address_pool, if_address_index));
1299 /* If pool did not grow/shrink: add duplicate address. */
1300 if (elts_before != pool_elts (lm->if_address_pool))
1302 ip4_add_del_interface_address_callback_t * cb;
1303 vec_foreach (cb, im->add_del_interface_address_callbacks)
1304 cb->function (im, cb->function_opaque, sw_if_index,
1305 address, address_length,
1311 vec_free (addr_fib);
1316 ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index,
1317 ip4_address_t * address, u32 address_length,
1320 return ip4_add_del_interface_address_internal
1321 (vm, sw_if_index, address, address_length,
1322 /* redistribute */ 1,
1323 /* insert_routes */ 1,
1327 static clib_error_t *
1328 ip4_sw_interface_admin_up_down (vnet_main_t * vnm,
1332 ip4_main_t * im = &ip4_main;
1333 ip_interface_address_t * ia;
1335 u32 is_admin_up, fib_index;
1337 /* Fill in lookup tables with default table (0). */
1338 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1340 vec_validate_init_empty (im->lookup_main.if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
1342 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1344 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
1346 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1347 0 /* honor unnumbered */,
1349 a = ip_interface_address_get_address (&im->lookup_main, ia);
1351 ip4_add_interface_routes (sw_if_index,
1355 ip4_del_interface_routes (im, fib_index,
1356 a, ia->address_length);
1362 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
1364 /* Built-in ip4 unicast rx feature path definition */
1365 VNET_IP4_UNICAST_FEATURE_INIT (ip4_inacl, static) = {
1366 .node_name = "ip4-inacl",
1367 .runs_before = {"ip4-source-check-via-rx", 0},
1368 .feature_index = &ip4_main.ip4_unicast_rx_feature_check_access,
1371 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
1372 .node_name = "ip4-source-check-via-rx",
1373 .runs_before = {"ip4-source-check-via-any", 0},
1375 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_rx,
1378 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
1379 .node_name = "ip4-source-check-via-any",
1380 .runs_before = {"ip4-policer-classify", 0},
1382 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
1385 VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
1386 .node_name = "ip4-policer-classify",
1387 .runs_before = {"ipsec-input-ip4", 0},
1389 &ip4_main.ip4_unicast_rx_feature_policer_classify,
1392 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
1393 .node_name = "ipsec-input-ip4",
1394 .runs_before = {"vpath-input-ip4", 0},
1395 .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
1398 VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
1399 .node_name = "vpath-input-ip4",
1400 .runs_before = {"ip4-lookup", 0},
1401 .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
1404 VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
1405 .node_name = "ip4-lookup",
1406 .runs_before = {0}, /* not before any other features */
1407 .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
1410 /* Built-in ip4 multicast rx feature path definition */
1411 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
1412 .node_name = "vpath-input-ip4",
1413 .runs_before = {"ip4-lookup-multicast", 0},
1414 .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
1417 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
1418 .node_name = "ip4-lookup-multicast",
1419 .runs_before = {0}, /* not before any other features */
1420 .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
1423 static char * feature_start_nodes[] =
1424 { "ip4-input", "ip4-input-no-checksum"};
1426 static clib_error_t *
1427 ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
1429 ip_lookup_main_t * lm = &im->lookup_main;
1430 clib_error_t * error;
1433 for (cast = 0; cast < VNET_N_CAST; cast++)
1435 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1436 vnet_config_main_t * vcm = &cm->config_main;
1438 if ((error = ip_feature_init_cast (vm, cm, vcm,
1439 feature_start_nodes,
1440 ARRAY_LEN(feature_start_nodes),
1448 static clib_error_t *
1449 ip4_sw_interface_add_del (vnet_main_t * vnm,
1453 vlib_main_t * vm = vnm->vlib_main;
1454 ip4_main_t * im = &ip4_main;
1455 ip_lookup_main_t * lm = &im->lookup_main;
1459 for (cast = 0; cast < VNET_N_CAST; cast++)
1461 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1462 vnet_config_main_t * vcm = &cm->config_main;
1464 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
1465 ci = cm->config_index_by_sw_if_index[sw_if_index];
1467 if (cast == VNET_UNICAST)
1468 feature_index = im->ip4_unicast_rx_feature_lookup;
1470 feature_index = im->ip4_multicast_rx_feature_lookup;
1473 ci = vnet_config_add_feature (vm, vcm,
1476 /* config data */ 0,
1477 /* # bytes of config data */ 0);
1479 ci = vnet_config_del_feature (vm, vcm,
1482 /* config data */ 0,
1483 /* # bytes of config data */ 0);
1485 cm->config_index_by_sw_if_index[sw_if_index] = ci;
1488 return /* no error */ 0;
1491 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1493 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args);
1495 VLIB_REGISTER_NODE (ip4_lookup_node) = {
1496 .function = ip4_lookup,
1497 .name = "ip4-lookup",
1498 .vector_size = sizeof (u32),
1500 .format_trace = format_ip4_lookup_trace,
1502 .n_next_nodes = IP4_LOOKUP_N_NEXT,
1503 .next_nodes = IP4_LOOKUP_NEXT_NODES,
1506 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
1509 ip4_indirect (vlib_main_t * vm,
1510 vlib_node_runtime_t * node,
1511 vlib_frame_t * frame)
1513 return ip4_lookup_inline (vm, node, frame,
1514 /* lookup_for_responses_to_locally_received_packets */ 0,
1515 /* is_indirect */ 1);
1518 VLIB_REGISTER_NODE (ip4_indirect_node) = {
1519 .function = ip4_indirect,
1520 .name = "ip4-indirect",
1521 .vector_size = sizeof (u32),
1522 .sibling_of = "ip4-lookup",
1523 .format_trace = format_ip4_lookup_trace,
1528 VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
1531 /* Global IP4 main. */
1532 ip4_main_t ip4_main;
1535 ip4_lookup_init (vlib_main_t * vm)
1537 ip4_main_t * im = &ip4_main;
1538 clib_error_t * error;
1541 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1546 m = pow2_mask (i) << (32 - i);
1549 im->fib_masks[i] = clib_host_to_net_u32 (m);
1552 /* Create FIB with index 0 and table id of 0. */
1553 find_ip4_fib_by_table_index_or_id (im, /* table id */ 0, IP4_ROUTE_FLAG_TABLE_ID);
1555 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1559 pn = pg_get_node (ip4_lookup_node.index);
1560 pn->unformat_edit = unformat_pg_ip4_header;
1564 ethernet_arp_header_t h;
1566 memset (&h, 0, sizeof (h));
1568 /* Set target ethernet address to all zeros. */
1569 memset (h.ip4_over_ethernet[1].ethernet, 0, sizeof (h.ip4_over_ethernet[1].ethernet));
1571 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1572 #define _8(f,v) h.f = v;
1573 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1574 _16 (l3_type, ETHERNET_TYPE_IP4);
1575 _8 (n_l2_address_bytes, 6);
1576 _8 (n_l3_address_bytes, 4);
1577 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1581 vlib_packet_template_init (vm,
1582 &im->ip4_arp_request_packet_template,
1585 /* alloc chunk size */ 8,
1589 error = ip4_feature_init (vm, im);
1594 VLIB_INIT_FUNCTION (ip4_lookup_init);
1597 /* Adjacency taken. */
1602 /* Packet data, possibly *after* rewrite. */
1603 u8 packet_data[64 - 1*sizeof(u32)];
1604 } ip4_forward_next_trace_t;
1606 static u8 * format_ip4_forward_next_trace (u8 * s, va_list * args)
1608 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1609 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1610 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1611 uword indent = format_get_indent (s);
1612 s = format (s, "%U%U",
1613 format_white_space, indent,
1614 format_ip4_header, t->packet_data);
1618 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args)
1620 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1621 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1622 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1623 vnet_main_t * vnm = vnet_get_main();
1624 ip4_main_t * im = &ip4_main;
1625 uword indent = format_get_indent (s);
1627 s = format (s, "fib %d adj-idx %d : %U flow hash: 0x%08x",
1628 t->fib_index, t->adj_index, format_ip_adjacency,
1629 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1630 s = format (s, "\n%U%U",
1631 format_white_space, indent,
1632 format_ip4_header, t->packet_data);
1636 static u8 * format_ip4_rewrite_trace (u8 * s, va_list * args)
1638 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1639 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1640 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1641 vnet_main_t * vnm = vnet_get_main();
1642 ip4_main_t * im = &ip4_main;
1643 uword indent = format_get_indent (s);
1645 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1646 t->fib_index, t->adj_index, format_ip_adjacency,
1647 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1648 s = format (s, "\n%U%U",
1649 format_white_space, indent,
1650 format_ip_adjacency_packet_data,
1651 vnm, &im->lookup_main, t->adj_index,
1652 t->packet_data, sizeof (t->packet_data));
1656 /* Common trace function for all ip4-forward next nodes. */
1658 ip4_forward_next_trace (vlib_main_t * vm,
1659 vlib_node_runtime_t * node,
1660 vlib_frame_t * frame,
1661 vlib_rx_or_tx_t which_adj_index)
1664 ip4_main_t * im = &ip4_main;
1666 n_left = frame->n_vectors;
1667 from = vlib_frame_vector_args (frame);
1672 vlib_buffer_t * b0, * b1;
1673 ip4_forward_next_trace_t * t0, * t1;
1675 /* Prefetch next iteration. */
1676 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1677 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1682 b0 = vlib_get_buffer (vm, bi0);
1683 b1 = vlib_get_buffer (vm, bi1);
1685 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1687 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1688 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1689 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1690 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1691 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1692 vec_elt (im->fib_index_by_sw_if_index,
1693 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1695 clib_memcpy (t0->packet_data,
1696 vlib_buffer_get_current (b0),
1697 sizeof (t0->packet_data));
1699 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1701 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1702 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1703 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1704 t1->fib_index = (vnet_buffer(b1)->sw_if_index[VLIB_TX] != (u32)~0) ?
1705 vnet_buffer(b1)->sw_if_index[VLIB_TX] :
1706 vec_elt (im->fib_index_by_sw_if_index,
1707 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
1708 clib_memcpy (t1->packet_data,
1709 vlib_buffer_get_current (b1),
1710 sizeof (t1->packet_data));
1720 ip4_forward_next_trace_t * t0;
1724 b0 = vlib_get_buffer (vm, bi0);
1726 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1728 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1729 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1730 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1731 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1732 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1733 vec_elt (im->fib_index_by_sw_if_index,
1734 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1735 clib_memcpy (t0->packet_data,
1736 vlib_buffer_get_current (b0),
1737 sizeof (t0->packet_data));
1745 ip4_drop_or_punt (vlib_main_t * vm,
1746 vlib_node_runtime_t * node,
1747 vlib_frame_t * frame,
1748 ip4_error_t error_code)
1750 u32 * buffers = vlib_frame_vector_args (frame);
1751 uword n_packets = frame->n_vectors;
1753 vlib_error_drop_buffers (vm, node,
1758 ip4_input_node.index,
1761 if (node->flags & VLIB_NODE_FLAG_TRACE)
1762 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1768 ip4_drop (vlib_main_t * vm,
1769 vlib_node_runtime_t * node,
1770 vlib_frame_t * frame)
1771 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP); }
1774 ip4_punt (vlib_main_t * vm,
1775 vlib_node_runtime_t * node,
1776 vlib_frame_t * frame)
1777 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); }
1780 ip4_miss (vlib_main_t * vm,
1781 vlib_node_runtime_t * node,
1782 vlib_frame_t * frame)
1783 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_DST_LOOKUP_MISS); }
1785 VLIB_REGISTER_NODE (ip4_drop_node,static) = {
1786 .function = ip4_drop,
1788 .vector_size = sizeof (u32),
1790 .format_trace = format_ip4_forward_next_trace,
1798 VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
1800 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
1801 .function = ip4_punt,
1803 .vector_size = sizeof (u32),
1805 .format_trace = format_ip4_forward_next_trace,
1813 VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
1815 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
1816 .function = ip4_miss,
1818 .vector_size = sizeof (u32),
1820 .format_trace = format_ip4_forward_next_trace,
1828 VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
1830 /* Compute TCP/UDP/ICMP4 checksum in software. */
1832 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1836 u32 ip_header_length, payload_length_host_byte_order;
1837 u32 n_this_buffer, n_bytes_left;
1839 void * data_this_buffer;
1841 /* Initialize checksum with ip header. */
1842 ip_header_length = ip4_header_bytes (ip0);
1843 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->length) - ip_header_length;
1844 sum0 = clib_host_to_net_u32 (payload_length_host_byte_order + (ip0->protocol << 16));
1846 if (BITS (uword) == 32)
1848 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u32));
1849 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
1852 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1854 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1855 data_this_buffer = (void *) ip0 + ip_header_length;
1856 if (n_this_buffer + ip_header_length > p0->current_length)
1857 n_this_buffer = p0->current_length > ip_header_length ? p0->current_length - ip_header_length : 0;
1860 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1861 n_bytes_left -= n_this_buffer;
1862 if (n_bytes_left == 0)
1865 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1866 p0 = vlib_get_buffer (vm, p0->next_buffer);
1867 data_this_buffer = vlib_buffer_get_current (p0);
1868 n_this_buffer = p0->current_length;
1871 sum16 = ~ ip_csum_fold (sum0);
1877 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1879 ip4_header_t * ip0 = vlib_buffer_get_current (p0);
1880 udp_header_t * udp0;
1883 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1884 || ip0->protocol == IP_PROTOCOL_UDP);
1886 udp0 = (void *) (ip0 + 1);
1887 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1889 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1890 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1894 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1896 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1897 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1903 ip4_local (vlib_main_t * vm,
1904 vlib_node_runtime_t * node,
1905 vlib_frame_t * frame)
1907 ip4_main_t * im = &ip4_main;
1908 ip_lookup_main_t * lm = &im->lookup_main;
1909 ip_local_next_t next_index;
1910 u32 * from, * to_next, n_left_from, n_left_to_next;
1911 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
1913 from = vlib_frame_vector_args (frame);
1914 n_left_from = frame->n_vectors;
1915 next_index = node->cached_next_index;
1917 if (node->flags & VLIB_NODE_FLAG_TRACE)
1918 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1920 while (n_left_from > 0)
1922 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1924 while (n_left_from >= 4 && n_left_to_next >= 2)
1926 vlib_buffer_t * p0, * p1;
1927 ip4_header_t * ip0, * ip1;
1928 udp_header_t * udp0, * udp1;
1929 ip4_fib_mtrie_t * mtrie0, * mtrie1;
1930 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1931 ip_adjacency_t * adj0, * adj1;
1932 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, adj_index0;
1933 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, adj_index1;
1934 i32 len_diff0, len_diff1;
1935 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1936 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1939 pi0 = to_next[0] = from[0];
1940 pi1 = to_next[1] = from[1];
1944 n_left_to_next -= 2;
1946 p0 = vlib_get_buffer (vm, pi0);
1947 p1 = vlib_get_buffer (vm, pi1);
1949 ip0 = vlib_buffer_get_current (p0);
1950 ip1 = vlib_buffer_get_current (p1);
1952 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1953 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
1954 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1955 vnet_buffer(p1)->sw_if_index[VLIB_RX]);
1957 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
1958 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
1960 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1962 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1963 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
1965 /* Treat IP frag packets as "experimental" protocol for now
1966 until support of IP frag reassembly is implemented */
1967 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
1968 proto1 = ip4_is_fragment(ip1) ? 0xfe : ip1->protocol;
1969 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1970 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1971 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1972 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1977 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1978 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1980 udp0 = ip4_next_header (ip0);
1981 udp1 = ip4_next_header (ip1);
1983 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1984 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1985 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1987 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1988 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
1990 /* Verify UDP length. */
1991 ip_len0 = clib_net_to_host_u16 (ip0->length);
1992 ip_len1 = clib_net_to_host_u16 (ip1->length);
1993 udp_len0 = clib_net_to_host_u16 (udp0->length);
1994 udp_len1 = clib_net_to_host_u16 (udp1->length);
1996 len_diff0 = ip_len0 - udp_len0;
1997 len_diff1 = ip_len1 - udp_len1;
1999 len_diff0 = is_udp0 ? len_diff0 : 0;
2000 len_diff1 = is_udp1 ? len_diff1 : 0;
2002 if (PREDICT_FALSE (! (is_tcp_udp0 & is_tcp_udp1
2003 & good_tcp_udp0 & good_tcp_udp1)))
2008 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2009 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2011 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2012 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2017 && ! (flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2018 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
2020 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2021 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2025 good_tcp_udp0 &= len_diff0 >= 0;
2026 good_tcp_udp1 &= len_diff1 >= 0;
2028 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2029 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
2031 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
2033 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2034 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
2036 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2037 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2038 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2040 error1 = (is_tcp_udp1 && ! good_tcp_udp1
2041 ? IP4_ERROR_TCP_CHECKSUM + is_udp1
2044 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2045 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
2047 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2048 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2050 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
2051 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
2053 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2055 /* no_default_route */ 1));
2056 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
2058 /* no_default_route */ 1));
2060 adj0 = ip_get_adjacency (lm, adj_index0);
2061 adj1 = ip_get_adjacency (lm, adj_index1);
2064 * Must have a route to source otherwise we drop the packet.
2065 * ip4 broadcasts are accepted, e.g. to make dhcp client work
2067 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2068 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2069 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2070 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2071 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2072 ? IP4_ERROR_SRC_LOOKUP_MISS
2074 error1 = (error1 == IP4_ERROR_UNKNOWN_PROTOCOL
2075 && adj1->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2076 && adj1->lookup_next_index != IP_LOOKUP_NEXT_ARP
2077 && adj1->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2078 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2079 ? IP4_ERROR_SRC_LOOKUP_MISS
2082 next0 = lm->local_next_by_ip_protocol[proto0];
2083 next1 = lm->local_next_by_ip_protocol[proto1];
2085 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2086 next1 = error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
2088 p0->error = error0 ? error_node->errors[error0] : 0;
2089 p1->error = error1 ? error_node->errors[error1] : 0;
2091 enqueue_code = (next0 != next_index) + 2*(next1 != next_index);
2093 if (PREDICT_FALSE (enqueue_code != 0))
2095 switch (enqueue_code)
2101 n_left_to_next += 1;
2102 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2108 n_left_to_next += 1;
2109 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2113 /* A B B or A B C */
2115 n_left_to_next += 2;
2116 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2117 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2120 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2122 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2129 while (n_left_from > 0 && n_left_to_next > 0)
2133 udp_header_t * udp0;
2134 ip4_fib_mtrie_t * mtrie0;
2135 ip4_fib_mtrie_leaf_t leaf0;
2136 ip_adjacency_t * adj0;
2137 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, adj_index0;
2139 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2141 pi0 = to_next[0] = from[0];
2145 n_left_to_next -= 1;
2147 p0 = vlib_get_buffer (vm, pi0);
2149 ip0 = vlib_buffer_get_current (p0);
2151 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2152 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2154 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2156 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2158 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2160 /* Treat IP frag packets as "experimental" protocol for now
2161 until support of IP frag reassembly is implemented */
2162 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
2163 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2164 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2168 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2170 udp0 = ip4_next_header (ip0);
2172 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2173 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2175 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2177 /* Verify UDP length. */
2178 ip_len0 = clib_net_to_host_u16 (ip0->length);
2179 udp_len0 = clib_net_to_host_u16 (udp0->length);
2181 len_diff0 = ip_len0 - udp_len0;
2183 len_diff0 = is_udp0 ? len_diff0 : 0;
2185 if (PREDICT_FALSE (! (is_tcp_udp0 & good_tcp_udp0)))
2190 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2191 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2193 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2194 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2198 good_tcp_udp0 &= len_diff0 >= 0;
2200 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2202 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
2204 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2206 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2207 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2208 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2211 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2213 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2214 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2216 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2218 /* no_default_route */ 1));
2220 adj0 = ip_get_adjacency (lm, adj_index0);
2222 /* Must have a route to source otherwise we drop the packet. */
2223 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2224 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2225 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2226 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2227 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2228 ? IP4_ERROR_SRC_LOOKUP_MISS
2231 next0 = lm->local_next_by_ip_protocol[proto0];
2233 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2235 p0->error = error0? error_node->errors[error0] : 0;
2237 if (PREDICT_FALSE (next0 != next_index))
2239 n_left_to_next += 1;
2240 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2243 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2246 n_left_to_next -= 1;
2250 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2253 return frame->n_vectors;
2256 VLIB_REGISTER_NODE (ip4_local_node,static) = {
2257 .function = ip4_local,
2258 .name = "ip4-local",
2259 .vector_size = sizeof (u32),
2261 .format_trace = format_ip4_forward_next_trace,
2263 .n_next_nodes = IP_LOCAL_N_NEXT,
2265 [IP_LOCAL_NEXT_DROP] = "error-drop",
2266 [IP_LOCAL_NEXT_PUNT] = "error-punt",
2267 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
2268 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
2272 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
2274 void ip4_register_protocol (u32 protocol, u32 node_index)
2276 vlib_main_t * vm = vlib_get_main();
2277 ip4_main_t * im = &ip4_main;
2278 ip_lookup_main_t * lm = &im->lookup_main;
2280 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
2281 lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index);
2284 static clib_error_t *
2285 show_ip_local_command_fn (vlib_main_t * vm,
2286 unformat_input_t * input,
2287 vlib_cli_command_t * cmd)
2289 ip4_main_t * im = &ip4_main;
2290 ip_lookup_main_t * lm = &im->lookup_main;
2293 vlib_cli_output (vm, "Protocols handled by ip4_local");
2294 for (i = 0; i < ARRAY_LEN(lm->local_next_by_ip_protocol); i++)
2296 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2297 vlib_cli_output (vm, "%d", i);
2304 VLIB_CLI_COMMAND (show_ip_local, static) = {
2305 .path = "show ip local",
2306 .function = show_ip_local_command_fn,
2307 .short_help = "Show ip local protocol table",
2311 ip4_arp (vlib_main_t * vm,
2312 vlib_node_runtime_t * node,
2313 vlib_frame_t * frame)
2315 vnet_main_t * vnm = vnet_get_main();
2316 ip4_main_t * im = &ip4_main;
2317 ip_lookup_main_t * lm = &im->lookup_main;
2318 u32 * from, * to_next_drop;
2319 uword n_left_from, n_left_to_next_drop, next_index;
2320 static f64 time_last_seed_change = -1e100;
2321 static u32 hash_seeds[3];
2322 static uword hash_bitmap[256 / BITS (uword)];
2325 if (node->flags & VLIB_NODE_FLAG_TRACE)
2326 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2328 time_now = vlib_time_now (vm);
2329 if (time_now - time_last_seed_change > 1e-3)
2332 u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
2333 sizeof (hash_seeds));
2334 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2335 hash_seeds[i] = r[i];
2337 /* Mark all hash keys as been no-seen before. */
2338 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2341 time_last_seed_change = time_now;
2344 from = vlib_frame_vector_args (frame);
2345 n_left_from = frame->n_vectors;
2346 next_index = node->cached_next_index;
2347 if (next_index == IP4_ARP_NEXT_DROP)
2348 next_index = IP4_ARP_N_NEXT; /* point to first interface */
2350 while (n_left_from > 0)
2352 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2353 to_next_drop, n_left_to_next_drop);
2355 while (n_left_from > 0 && n_left_to_next_drop > 0)
2359 ethernet_header_t * eh0;
2360 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
2362 ip_adjacency_t * adj0;
2366 p0 = vlib_get_buffer (vm, pi0);
2368 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2369 adj0 = ip_get_adjacency (lm, adj_index0);
2370 ip0 = vlib_buffer_get_current (p0);
2372 /* If packet destination is not local, send ARP to next hop */
2373 if (adj0->arp.next_hop.ip4.as_u32)
2374 ip0->dst_address.data_u32 = adj0->arp.next_hop.ip4.as_u32;
2377 * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP
2378 * rewrite to this packet, we need to skip it here.
2379 * Note, to distinguish from src IP addr *.8.6.*, we
2380 * check for a bcast eth dest instead of IPv4 version.
2382 eh0 = (ethernet_header_t*)ip0;
2383 if ((ip0->ip_version_and_header_length & 0xF0) != 0x40)
2386 u16 * etype = &eh0->type;
2387 while ((*etype == clib_host_to_net_u16 (0x8100)) //dot1q
2388 || (*etype == clib_host_to_net_u16 (0x88a8)))//dot1ad
2391 etype += 2; //vlan tag also 16 bits, same as etype
2393 if (*etype == clib_host_to_net_u16 (0x0806)) //arp
2395 vlib_buffer_advance (
2396 p0, sizeof(ethernet_header_t) + (4*vlan_num));
2397 ip0 = vlib_buffer_get_current (p0);
2405 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2406 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2408 a0 ^= ip0->dst_address.data_u32;
2411 hash_v3_finalize32 (a0, b0, c0);
2413 c0 &= BITS (hash_bitmap) - 1;
2414 c0 = c0 / BITS (uword);
2415 m0 = (uword) 1 << (c0 % BITS (uword));
2417 bm0 = hash_bitmap[c0];
2418 drop0 = (bm0 & m0) != 0;
2420 /* Mark it as seen. */
2421 hash_bitmap[c0] = bm0 | m0;
2425 to_next_drop[0] = pi0;
2427 n_left_to_next_drop -= 1;
2429 p0->error = node->errors[drop0 ? IP4_ARP_ERROR_DROP : IP4_ARP_ERROR_REQUEST_SENT];
2435 * Can happen if the control-plane is programming tables
2436 * with traffic flowing; at least that's today's lame excuse.
2438 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
2440 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2443 /* Send ARP request. */
2447 ethernet_arp_header_t * h0;
2448 vnet_hw_interface_t * hw_if0;
2450 h0 = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi0);
2452 /* Add rewrite/encap string for ARP packet. */
2453 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2455 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2457 /* Src ethernet address in ARP header. */
2458 clib_memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address,
2459 sizeof (h0->ip4_over_ethernet[0].ethernet));
2461 if (ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0)) {
2462 //No source address available
2463 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2464 vlib_buffer_free(vm, &bi0, 1);
2468 /* Copy in destination address we are requesting. */
2469 h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32;
2471 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2472 b0 = vlib_get_buffer (vm, bi0);
2473 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2475 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2477 vlib_set_next_frame_buffer (vm, node, adj0->rewrite_header.next_index, bi0);
2481 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2484 return frame->n_vectors;
2487 static char * ip4_arp_error_strings[] = {
2488 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2489 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2490 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2491 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2492 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2493 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
2496 VLIB_REGISTER_NODE (ip4_arp_node) = {
2497 .function = ip4_arp,
2499 .vector_size = sizeof (u32),
2501 .format_trace = format_ip4_forward_next_trace,
2503 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2504 .error_strings = ip4_arp_error_strings,
2506 .n_next_nodes = IP4_ARP_N_NEXT,
2508 [IP4_ARP_NEXT_DROP] = "error-drop",
2512 #define foreach_notrace_ip4_arp_error \
2518 clib_error_t * arp_notrace_init (vlib_main_t * vm)
2520 vlib_node_runtime_t *rt =
2521 vlib_node_get_runtime (vm, ip4_arp_node.index);
2523 /* don't trace ARP request packets */
2525 vnet_pcap_drop_trace_filter_add_del \
2526 (rt->errors[IP4_ARP_ERROR_##a], \
2528 foreach_notrace_ip4_arp_error;
2533 VLIB_INIT_FUNCTION(arp_notrace_init);
2536 /* Send an ARP request to see if given destination is reachable on given interface. */
2538 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2540 vnet_main_t * vnm = vnet_get_main();
2541 ip4_main_t * im = &ip4_main;
2542 ethernet_arp_header_t * h;
2543 ip4_address_t * src;
2544 ip_interface_address_t * ia;
2545 ip_adjacency_t * adj;
2546 vnet_hw_interface_t * hi;
2547 vnet_sw_interface_t * si;
2551 si = vnet_get_sw_interface (vnm, sw_if_index);
2553 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2555 return clib_error_return (0, "%U: interface %U down",
2556 format_ip4_address, dst,
2557 format_vnet_sw_if_index_name, vnm,
2561 src = ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2564 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2565 return clib_error_return
2566 (0, "no matching interface address for destination %U (interface %U)",
2567 format_ip4_address, dst,
2568 format_vnet_sw_if_index_name, vnm, sw_if_index);
2571 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2573 h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi);
2575 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2577 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
2579 h->ip4_over_ethernet[0].ip4 = src[0];
2580 h->ip4_over_ethernet[1].ip4 = dst[0];
2582 b = vlib_get_buffer (vm, bi);
2583 vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2585 /* Add encapsulation string for software interface (e.g. ethernet header). */
2586 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2587 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2590 vlib_frame_t * f = vlib_get_frame_to_node (vm, hi->output_node_index);
2591 u32 * to_next = vlib_frame_vector_args (f);
2594 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2597 return /* no error */ 0;
2601 IP4_REWRITE_NEXT_DROP,
2602 IP4_REWRITE_NEXT_ARP,
2603 IP4_REWRITE_NEXT_ICMP_ERROR,
2604 } ip4_rewrite_next_t;
2607 ip4_rewrite_inline (vlib_main_t * vm,
2608 vlib_node_runtime_t * node,
2609 vlib_frame_t * frame,
2610 int rewrite_for_locally_received_packets)
2612 ip_lookup_main_t * lm = &ip4_main.lookup_main;
2613 u32 * from = vlib_frame_vector_args (frame);
2614 u32 n_left_from, n_left_to_next, * to_next, next_index;
2615 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2616 vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
2618 n_left_from = frame->n_vectors;
2619 next_index = node->cached_next_index;
2620 u32 cpu_index = os_get_cpu_number();
2622 while (n_left_from > 0)
2624 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2626 while (n_left_from >= 4 && n_left_to_next >= 2)
2628 ip_adjacency_t * adj0, * adj1;
2629 vlib_buffer_t * p0, * p1;
2630 ip4_header_t * ip0, * ip1;
2631 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2632 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2633 u32 next0_override, next1_override;
2635 if (rewrite_for_locally_received_packets)
2636 next0_override = next1_override = 0;
2638 /* Prefetch next iteration. */
2640 vlib_buffer_t * p2, * p3;
2642 p2 = vlib_get_buffer (vm, from[2]);
2643 p3 = vlib_get_buffer (vm, from[3]);
2645 vlib_prefetch_buffer_header (p2, STORE);
2646 vlib_prefetch_buffer_header (p3, STORE);
2648 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2649 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2652 pi0 = to_next[0] = from[0];
2653 pi1 = to_next[1] = from[1];
2658 n_left_to_next -= 2;
2660 p0 = vlib_get_buffer (vm, pi0);
2661 p1 = vlib_get_buffer (vm, pi1);
2663 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2664 adj_index1 = vnet_buffer (p1)->ip.adj_index[adj_rx_tx];
2666 /* We should never rewrite a pkt using the MISS adjacency */
2667 ASSERT(adj_index0 && adj_index1);
2669 ip0 = vlib_buffer_get_current (p0);
2670 ip1 = vlib_buffer_get_current (p1);
2672 error0 = error1 = IP4_ERROR_NONE;
2673 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2675 /* Decrement TTL & update checksum.
2676 Works either endian, so no need for byte swap. */
2677 if (! rewrite_for_locally_received_packets)
2679 i32 ttl0 = ip0->ttl, ttl1 = ip1->ttl;
2681 /* Input node should have reject packets with ttl 0. */
2682 ASSERT (ip0->ttl > 0);
2683 ASSERT (ip1->ttl > 0);
2685 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2686 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2688 checksum0 += checksum0 >= 0xffff;
2689 checksum1 += checksum1 >= 0xffff;
2691 ip0->checksum = checksum0;
2692 ip1->checksum = checksum1;
2701 * If the ttl drops below 1 when forwarding, generate
2704 if (PREDICT_FALSE(ttl0 <= 0))
2706 error0 = IP4_ERROR_TIME_EXPIRED;
2707 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2708 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2709 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2710 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2712 if (PREDICT_FALSE(ttl1 <= 0))
2714 error1 = IP4_ERROR_TIME_EXPIRED;
2715 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
2716 icmp4_error_set_vnet_buffer(p1, ICMP4_time_exceeded,
2717 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2718 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2721 /* Verify checksum. */
2722 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2723 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2726 /* Rewrite packet header and updates lengths. */
2727 adj0 = ip_get_adjacency (lm, adj_index0);
2728 adj1 = ip_get_adjacency (lm, adj_index1);
2730 if (rewrite_for_locally_received_packets)
2733 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2734 * we end up here with a local adjacency in hand
2735 * The local adj rewrite data is 0xfefe on purpose.
2736 * Bad engineer, no donut for you.
2738 if (PREDICT_FALSE(adj0->lookup_next_index
2739 == IP_LOOKUP_NEXT_LOCAL))
2740 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2741 if (PREDICT_FALSE(adj0->lookup_next_index
2742 == IP_LOOKUP_NEXT_ARP))
2743 next0_override = IP4_REWRITE_NEXT_ARP;
2744 if (PREDICT_FALSE(adj1->lookup_next_index
2745 == IP_LOOKUP_NEXT_LOCAL))
2746 error1 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2747 if (PREDICT_FALSE(adj1->lookup_next_index
2748 == IP_LOOKUP_NEXT_ARP))
2749 next1_override = IP4_REWRITE_NEXT_ARP;
2752 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2753 rw_len0 = adj0[0].rewrite_header.data_bytes;
2754 rw_len1 = adj1[0].rewrite_header.data_bytes;
2756 /* Check MTU of outgoing interface. */
2757 error0 = (vlib_buffer_length_in_chain (vm, p0) > adj0[0].rewrite_header.max_l3_packet_bytes
2758 ? IP4_ERROR_MTU_EXCEEDED
2760 error1 = (vlib_buffer_length_in_chain (vm, p1) > adj1[0].rewrite_header.max_l3_packet_bytes
2761 ? IP4_ERROR_MTU_EXCEEDED
2764 next0 = (error0 == IP4_ERROR_NONE)
2765 ? adj0[0].rewrite_header.next_index : next0;
2767 if (rewrite_for_locally_received_packets)
2768 next0 = next0 && next0_override ? next0_override : next0;
2770 next1 = (error1 == IP4_ERROR_NONE)
2771 ? adj1[0].rewrite_header.next_index : next1;
2773 if (rewrite_for_locally_received_packets)
2774 next1 = next1 && next1_override ? next1_override : next1;
2777 * We've already accounted for an ethernet_header_t elsewhere
2779 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2780 vlib_increment_combined_counter
2781 (&lm->adjacency_counters,
2782 cpu_index, adj_index0,
2783 /* packet increment */ 0,
2784 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2786 if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
2787 vlib_increment_combined_counter
2788 (&lm->adjacency_counters,
2789 cpu_index, adj_index1,
2790 /* packet increment */ 0,
2791 /* byte increment */ rw_len1-sizeof(ethernet_header_t));
2793 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2794 * to see the IP headerr */
2795 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2797 p0->current_data -= rw_len0;
2798 p0->current_length += rw_len0;
2799 p0->error = error_node->errors[error0];
2800 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2801 adj0[0].rewrite_header.sw_if_index;
2803 if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
2805 p1->current_data -= rw_len1;
2806 p1->current_length += rw_len1;
2807 p1->error = error_node->errors[error1];
2808 vnet_buffer (p1)->sw_if_index[VLIB_TX] =
2809 adj1[0].rewrite_header.sw_if_index;
2812 /* Guess we are only writing on simple Ethernet header. */
2813 vnet_rewrite_two_headers (adj0[0], adj1[0],
2815 sizeof (ethernet_header_t));
2817 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2818 to_next, n_left_to_next,
2819 pi0, pi1, next0, next1);
2822 while (n_left_from > 0 && n_left_to_next > 0)
2824 ip_adjacency_t * adj0;
2827 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2830 if (rewrite_for_locally_received_packets)
2833 pi0 = to_next[0] = from[0];
2835 p0 = vlib_get_buffer (vm, pi0);
2837 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2839 /* We should never rewrite a pkt using the MISS adjacency */
2842 adj0 = ip_get_adjacency (lm, adj_index0);
2844 ip0 = vlib_buffer_get_current (p0);
2846 error0 = IP4_ERROR_NONE;
2847 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2849 /* Decrement TTL & update checksum. */
2850 if (! rewrite_for_locally_received_packets)
2852 i32 ttl0 = ip0->ttl;
2854 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2856 checksum0 += checksum0 >= 0xffff;
2858 ip0->checksum = checksum0;
2860 ASSERT (ip0->ttl > 0);
2866 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2868 if (PREDICT_FALSE(ttl0 <= 0))
2871 * If the ttl drops below 1 when forwarding, generate
2874 error0 = IP4_ERROR_TIME_EXPIRED;
2875 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2876 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2877 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2878 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2882 if (rewrite_for_locally_received_packets)
2885 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2886 * we end up here with a local adjacency in hand
2887 * The local adj rewrite data is 0xfefe on purpose.
2888 * Bad engineer, no donut for you.
2890 if (PREDICT_FALSE(adj0->lookup_next_index
2891 == IP_LOOKUP_NEXT_LOCAL))
2892 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2894 * We have to override the next_index in ARP adjacencies,
2895 * because they're set up for ip4-arp, not this node...
2897 if (PREDICT_FALSE(adj0->lookup_next_index
2898 == IP_LOOKUP_NEXT_ARP))
2899 next0_override = IP4_REWRITE_NEXT_ARP;
2902 /* Guess we are only writing on simple Ethernet header. */
2903 vnet_rewrite_one_header (adj0[0], ip0,
2904 sizeof (ethernet_header_t));
2906 /* Update packet buffer attributes/set output interface. */
2907 rw_len0 = adj0[0].rewrite_header.data_bytes;
2909 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2910 vlib_increment_combined_counter
2911 (&lm->adjacency_counters,
2912 cpu_index, adj_index0,
2913 /* packet increment */ 0,
2914 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2916 /* Check MTU of outgoing interface. */
2917 error0 = (vlib_buffer_length_in_chain (vm, p0)
2918 > adj0[0].rewrite_header.max_l3_packet_bytes
2919 ? IP4_ERROR_MTU_EXCEEDED
2922 p0->error = error_node->errors[error0];
2924 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2925 * to see the IP headerr */
2926 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2928 p0->current_data -= rw_len0;
2929 p0->current_length += rw_len0;
2931 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2932 adj0[0].rewrite_header.sw_if_index;
2933 next0 = adj0[0].rewrite_header.next_index;
2936 if (rewrite_for_locally_received_packets)
2937 next0 = next0 && next0_override ? next0_override : next0;
2942 n_left_to_next -= 1;
2944 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2945 to_next, n_left_to_next,
2949 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2952 /* Need to do trace after rewrites to pick up new packet data. */
2953 if (node->flags & VLIB_NODE_FLAG_TRACE)
2954 ip4_forward_next_trace (vm, node, frame, adj_rx_tx);
2956 return frame->n_vectors;
2960 /** @brief IPv4 transit rewrite node.
2961 @node ip4-rewrite-transit
2963 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2964 header checksum, fetch the ip adjacency, check the outbound mtu,
2965 apply the adjacency rewrite, and send pkts to the adjacency
2966 rewrite header's rewrite_next_index.
2968 @param vm vlib_main_t corresponding to the current thread
2969 @param node vlib_node_runtime_t
2970 @param frame vlib_frame_t whose contents should be dispatched
2972 @par Graph mechanics: buffer metadata, next index usage
2975 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2976 - the rewrite adjacency index
2977 - <code>adj->lookup_next_index</code>
2978 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2979 the packet will be dropped.
2980 - <code>adj->rewrite_header</code>
2981 - Rewrite string length, rewrite string, next_index
2984 - <code>b->current_data, b->current_length</code>
2985 - Updated net of applying the rewrite string
2987 <em>Next Indices:</em>
2988 - <code> adj->rewrite_header.next_index </code>
2992 ip4_rewrite_transit (vlib_main_t * vm,
2993 vlib_node_runtime_t * node,
2994 vlib_frame_t * frame)
2996 return ip4_rewrite_inline (vm, node, frame,
2997 /* rewrite_for_locally_received_packets */ 0);
3000 /** @brief IPv4 local rewrite node.
3001 @node ip4-rewrite-local
3003 This is the IPv4 local rewrite node. Fetch the ip adjacency, check
3004 the outbound interface mtu, apply the adjacency rewrite, and send
3005 pkts to the adjacency rewrite header's rewrite_next_index. Deal
3006 with hemorrhoids of the form "some clown sends an icmp4 w/ src =
3007 dst = interface addr."
3009 @param vm vlib_main_t corresponding to the current thread
3010 @param node vlib_node_runtime_t
3011 @param frame vlib_frame_t whose contents should be dispatched
3013 @par Graph mechanics: buffer metadata, next index usage
3016 - <code>vnet_buffer(b)->ip.adj_index[VLIB_RX]</code>
3017 - the rewrite adjacency index
3018 - <code>adj->lookup_next_index</code>
3019 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
3020 the packet will be dropped.
3021 - <code>adj->rewrite_header</code>
3022 - Rewrite string length, rewrite string, next_index
3025 - <code>b->current_data, b->current_length</code>
3026 - Updated net of applying the rewrite string
3028 <em>Next Indices:</em>
3029 - <code> adj->rewrite_header.next_index </code>
3034 ip4_rewrite_local (vlib_main_t * vm,
3035 vlib_node_runtime_t * node,
3036 vlib_frame_t * frame)
3038 return ip4_rewrite_inline (vm, node, frame,
3039 /* rewrite_for_locally_received_packets */ 1);
3042 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
3043 .function = ip4_rewrite_transit,
3044 .name = "ip4-rewrite-transit",
3045 .vector_size = sizeof (u32),
3047 .format_trace = format_ip4_rewrite_trace,
3051 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3052 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3053 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3057 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
3059 VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
3060 .function = ip4_rewrite_local,
3061 .name = "ip4-rewrite-local",
3062 .vector_size = sizeof (u32),
3064 .sibling_of = "ip4-rewrite-transit",
3066 .format_trace = format_ip4_rewrite_trace,
3071 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
3073 static clib_error_t *
3074 add_del_interface_table (vlib_main_t * vm,
3075 unformat_input_t * input,
3076 vlib_cli_command_t * cmd)
3078 vnet_main_t * vnm = vnet_get_main();
3079 clib_error_t * error = 0;
3080 u32 sw_if_index, table_id;
3084 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3086 error = clib_error_return (0, "unknown interface `%U'",
3087 format_unformat_error, input);
3091 if (unformat (input, "%d", &table_id))
3095 error = clib_error_return (0, "expected table id `%U'",
3096 format_unformat_error, input);
3101 ip4_main_t * im = &ip4_main;
3102 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
3106 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
3107 im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
3115 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
3116 .path = "set interface ip table",
3117 .function = add_del_interface_table,
3118 .short_help = "Add/delete FIB table id for interface",
3123 ip4_lookup_multicast (vlib_main_t * vm,
3124 vlib_node_runtime_t * node,
3125 vlib_frame_t * frame)
3127 ip4_main_t * im = &ip4_main;
3128 ip_lookup_main_t * lm = &im->lookup_main;
3129 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
3130 u32 n_left_from, n_left_to_next, * from, * to_next;
3131 ip_lookup_next_t next;
3132 u32 cpu_index = os_get_cpu_number();
3134 from = vlib_frame_vector_args (frame);
3135 n_left_from = frame->n_vectors;
3136 next = node->cached_next_index;
3138 while (n_left_from > 0)
3140 vlib_get_next_frame (vm, node, next,
3141 to_next, n_left_to_next);
3143 while (n_left_from >= 4 && n_left_to_next >= 2)
3145 vlib_buffer_t * p0, * p1;
3146 u32 pi0, pi1, adj_index0, adj_index1, wrong_next;
3147 ip_lookup_next_t next0, next1;
3148 ip4_header_t * ip0, * ip1;
3149 ip_adjacency_t * adj0, * adj1;
3150 u32 fib_index0, fib_index1;
3151 u32 flow_hash_config0, flow_hash_config1;
3153 /* Prefetch next iteration. */
3155 vlib_buffer_t * p2, * p3;
3157 p2 = vlib_get_buffer (vm, from[2]);
3158 p3 = vlib_get_buffer (vm, from[3]);
3160 vlib_prefetch_buffer_header (p2, LOAD);
3161 vlib_prefetch_buffer_header (p3, LOAD);
3163 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
3164 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
3167 pi0 = to_next[0] = from[0];
3168 pi1 = to_next[1] = from[1];
3170 p0 = vlib_get_buffer (vm, pi0);
3171 p1 = vlib_get_buffer (vm, pi1);
3173 ip0 = vlib_buffer_get_current (p0);
3174 ip1 = vlib_buffer_get_current (p1);
3176 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3177 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
3178 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3179 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3180 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
3181 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
3183 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3184 &ip0->dst_address, p0);
3185 adj_index1 = ip4_fib_lookup_buffer (im, fib_index1,
3186 &ip1->dst_address, p1);
3188 adj0 = ip_get_adjacency (lm, adj_index0);
3189 adj1 = ip_get_adjacency (lm, adj_index1);
3191 next0 = adj0->lookup_next_index;
3192 next1 = adj1->lookup_next_index;
3195 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3198 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
3200 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
3201 (ip0, flow_hash_config0);
3203 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
3204 (ip1, flow_hash_config1);
3206 ASSERT (adj0->n_adj > 0);
3207 ASSERT (adj1->n_adj > 0);
3208 ASSERT (is_pow2 (adj0->n_adj));
3209 ASSERT (is_pow2 (adj1->n_adj));
3210 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3211 adj_index1 += (vnet_buffer (p1)->ip.flow_hash & (adj1->n_adj - 1));
3213 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3214 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
3216 if (1) /* $$$$$$ HACK FIXME */
3217 vlib_increment_combined_counter
3218 (cm, cpu_index, adj_index0, 1,
3219 vlib_buffer_length_in_chain (vm, p0));
3220 if (1) /* $$$$$$ HACK FIXME */
3221 vlib_increment_combined_counter
3222 (cm, cpu_index, adj_index1, 1,
3223 vlib_buffer_length_in_chain (vm, p1));
3227 n_left_to_next -= 2;
3230 wrong_next = (next0 != next) + 2*(next1 != next);
3231 if (PREDICT_FALSE (wrong_next != 0))
3239 n_left_to_next += 1;
3240 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3246 n_left_to_next += 1;
3247 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3253 n_left_to_next += 2;
3254 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3255 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3259 vlib_put_next_frame (vm, node, next, n_left_to_next);
3261 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
3267 while (n_left_from > 0 && n_left_to_next > 0)
3271 u32 pi0, adj_index0;
3272 ip_lookup_next_t next0;
3273 ip_adjacency_t * adj0;
3275 u32 flow_hash_config0;
3280 p0 = vlib_get_buffer (vm, pi0);
3282 ip0 = vlib_buffer_get_current (p0);
3284 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
3285 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3286 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3287 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3289 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3290 &ip0->dst_address, p0);
3292 adj0 = ip_get_adjacency (lm, adj_index0);
3294 next0 = adj0->lookup_next_index;
3297 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3299 vnet_buffer (p0)->ip.flow_hash =
3300 ip4_compute_flow_hash (ip0, flow_hash_config0);
3302 ASSERT (adj0->n_adj > 0);
3303 ASSERT (is_pow2 (adj0->n_adj));
3304 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3306 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3308 if (1) /* $$$$$$ HACK FIXME */
3309 vlib_increment_combined_counter
3310 (cm, cpu_index, adj_index0, 1,
3311 vlib_buffer_length_in_chain (vm, p0));
3315 n_left_to_next -= 1;
3318 if (PREDICT_FALSE (next0 != next))
3320 n_left_to_next += 1;
3321 vlib_put_next_frame (vm, node, next, n_left_to_next);
3323 vlib_get_next_frame (vm, node, next,
3324 to_next, n_left_to_next);
3327 n_left_to_next -= 1;
3331 vlib_put_next_frame (vm, node, next, n_left_to_next);
3334 if (node->flags & VLIB_NODE_FLAG_TRACE)
3335 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
3337 return frame->n_vectors;
3340 VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
3341 .function = ip4_lookup_multicast,
3342 .name = "ip4-lookup-multicast",
3343 .vector_size = sizeof (u32),
3344 .sibling_of = "ip4-lookup",
3345 .format_trace = format_ip4_lookup_trace,
3350 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
3352 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
3353 .function = ip4_drop,
3354 .name = "ip4-multicast",
3355 .vector_size = sizeof (u32),
3357 .format_trace = format_ip4_forward_next_trace,
3365 int ip4_lookup_validate (ip4_address_t *a, u32 fib_index0)
3367 ip4_main_t * im = &ip4_main;
3368 ip4_fib_mtrie_t * mtrie0;
3369 ip4_fib_mtrie_leaf_t leaf0;
3372 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
3374 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
3375 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
3376 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
3377 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
3378 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
3380 /* Handle default route. */
3381 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
3383 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
3385 return adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
3387 /* no_default_route */ 0);
3390 static clib_error_t *
3391 test_lookup_command_fn (vlib_main_t * vm,
3392 unformat_input_t * input,
3393 vlib_cli_command_t * cmd)
3399 ip4_address_t ip4_base_address;
3402 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3403 if (unformat (input, "table %d", &table_id))
3405 else if (unformat (input, "count %f", &count))
3408 else if (unformat (input, "%U",
3409 unformat_ip4_address, &ip4_base_address))
3412 return clib_error_return (0, "unknown input `%U'",
3413 format_unformat_error, input);
3418 for (i = 0; i < n; i++)
3420 if (!ip4_lookup_validate (&ip4_base_address, table_id))
3423 ip4_base_address.as_u32 =
3424 clib_host_to_net_u32 (1 +
3425 clib_net_to_host_u32 (ip4_base_address.as_u32));
3429 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3431 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3436 VLIB_CLI_COMMAND (lookup_test_command, static) = {
3437 .path = "test lookup",
3438 .short_help = "test lookup",
3439 .function = test_lookup_command_fn,
3442 int vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3444 ip4_main_t * im4 = &ip4_main;
3446 uword * p = hash_get (im4->fib_index_by_table_id, table_id);
3449 return VNET_API_ERROR_NO_SUCH_FIB;
3451 fib = vec_elt_at_index (im4->fibs, p[0]);
3453 fib->flow_hash_config = flow_hash_config;
3457 static clib_error_t *
3458 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3459 unformat_input_t * input,
3460 vlib_cli_command_t * cmd)
3464 u32 flow_hash_config = 0;
3467 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3468 if (unformat (input, "table %d", &table_id))
3471 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3472 foreach_flow_hash_bit
3478 return clib_error_return (0, "unknown input `%U'",
3479 format_unformat_error, input);
3481 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3487 case VNET_API_ERROR_NO_SUCH_FIB:
3488 return clib_error_return (0, "no such FIB table %d", table_id);
3491 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3498 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
3499 .path = "set ip flow-hash",
3501 "set ip table flow-hash table <fib-id> src dst sport dport proto reverse",
3502 .function = set_ip_flow_hash_command_fn,
3505 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3508 vnet_main_t * vnm = vnet_get_main();
3509 vnet_interface_main_t * im = &vnm->interface_main;
3510 ip4_main_t * ipm = &ip4_main;
3511 ip_lookup_main_t * lm = &ipm->lookup_main;
3512 vnet_classify_main_t * cm = &vnet_classify_main;
3514 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3515 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3517 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3518 return VNET_API_ERROR_NO_SUCH_ENTRY;
3520 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3521 lm->classify_table_index_by_sw_if_index [sw_if_index] = table_index;
3526 static clib_error_t *
3527 set_ip_classify_command_fn (vlib_main_t * vm,
3528 unformat_input_t * input,
3529 vlib_cli_command_t * cmd)
3531 u32 table_index = ~0;
3532 int table_index_set = 0;
3533 u32 sw_if_index = ~0;
3536 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3537 if (unformat (input, "table-index %d", &table_index))
3538 table_index_set = 1;
3539 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3540 vnet_get_main(), &sw_if_index))
3546 if (table_index_set == 0)
3547 return clib_error_return (0, "classify table-index must be specified");
3549 if (sw_if_index == ~0)
3550 return clib_error_return (0, "interface / subif must be specified");
3552 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3559 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3560 return clib_error_return (0, "No such interface");
3562 case VNET_API_ERROR_NO_SUCH_ENTRY:
3563 return clib_error_return (0, "No such classifier table");
3568 VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
3569 .path = "set ip classify",
3571 "set ip classify intfc <int> table-index <index>",
3572 .function = set_ip_classify_command_fn,