2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 * ip/ip4_forward.c: IP v4 forwarding
18 * Copyright (c) 2008 Eliot Dresselhaus
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #include <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43 #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
44 #include <vnet/ppp/ppp.h>
45 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46 #include <vnet/api_errno.h> /* for API error numbers */
52 /* This is really, really simple but stupid fib. */
54 ip4_fib_lookup_with_table (ip4_main_t * im, u32 fib_index,
56 u32 disable_default_route)
58 ip_lookup_main_t * lm = &im->lookup_main;
59 ip4_fib_t * fib = vec_elt_at_index (im->fibs, fib_index);
60 uword * p, * hash, key;
61 i32 i, i_min, dst_address, ai;
63 i_min = disable_default_route ? 1 : 0;
64 dst_address = clib_mem_unaligned (&dst->data_u32, u32);
65 for (i = ARRAY_LEN (fib->adj_index_by_dst_address) - 1; i >= i_min; i--)
67 hash = fib->adj_index_by_dst_address[i];
71 key = dst_address & im->fib_masks[i];
72 if ((p = hash_get (hash, key)) != 0)
79 /* Nothing matches in table. */
80 ai = lm->miss_adj_index;
87 create_fib_with_table_id (ip4_main_t * im, u32 table_id)
90 hash_set (im->fib_index_by_table_id, table_id, vec_len (im->fibs));
91 vec_add2 (im->fibs, fib, 1);
92 fib->table_id = table_id;
93 fib->index = fib - im->fibs;
94 fib->flow_hash_config = IP_FLOW_HASH_DEFAULT;
95 fib->fwd_classify_table_index = ~0;
96 fib->rev_classify_table_index = ~0;
97 ip4_mtrie_init (&fib->mtrie);
102 find_ip4_fib_by_table_index_or_id (ip4_main_t * im,
103 u32 table_index_or_id, u32 flags)
105 uword * p, fib_index;
107 fib_index = table_index_or_id;
108 if (! (flags & IP4_ROUTE_FLAG_FIB_INDEX))
110 if (table_index_or_id == ~0) {
111 table_index_or_id = 0;
112 while ((p = hash_get (im->fib_index_by_table_id, table_index_or_id))) {
115 return create_fib_with_table_id (im, table_index_or_id);
118 p = hash_get (im->fib_index_by_table_id, table_index_or_id);
120 return create_fib_with_table_id (im, table_index_or_id);
123 return vec_elt_at_index (im->fibs, fib_index);
127 ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm,
134 ASSERT (lm->fib_result_n_bytes >= sizeof (uword));
135 lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword)) / sizeof (uword);
137 fib->adj_index_by_dst_address[address_length] =
138 hash_create (32 /* elts */, lm->fib_result_n_words * sizeof (uword));
140 hash_set_flags (fib->adj_index_by_dst_address[address_length],
141 HASH_FLAG_NO_AUTO_SHRINK);
143 h = hash_header (fib->adj_index_by_dst_address[address_length]);
144 max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1;
146 /* Initialize new/old hash value vectors. */
147 vec_validate_init_empty (fib->new_hash_values, max_index, ~0);
148 vec_validate_init_empty (fib->old_hash_values, max_index, ~0);
152 ip4_fib_set_adj_index (ip4_main_t * im,
156 u32 dst_address_length,
159 ip_lookup_main_t * lm = &im->lookup_main;
162 if (vec_bytes(fib->old_hash_values))
163 memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values));
164 if (vec_bytes(fib->new_hash_values))
165 memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values));
166 fib->new_hash_values[0] = adj_index;
168 /* Make sure adj index is valid. */
170 (void) ip_get_adjacency (lm, adj_index);
172 hash = fib->adj_index_by_dst_address[dst_address_length];
174 hash = _hash_set3 (hash, dst_address_u32,
175 fib->new_hash_values,
176 fib->old_hash_values);
178 fib->adj_index_by_dst_address[dst_address_length] = hash;
180 if (vec_len (im->add_del_route_callbacks) > 0)
182 ip4_add_del_route_callback_t * cb;
186 d.data_u32 = dst_address_u32;
187 vec_foreach (cb, im->add_del_route_callbacks)
188 if ((flags & cb->required_flags) == cb->required_flags)
189 cb->function (im, cb->function_opaque,
191 &d, dst_address_length,
192 fib->old_hash_values,
193 fib->new_hash_values);
195 p = hash_get (hash, dst_address_u32);
196 clib_memcpy (p, fib->new_hash_values, vec_bytes (fib->new_hash_values));
200 void ip4_add_del_route (ip4_main_t * im, ip4_add_del_route_args_t * a)
202 ip_lookup_main_t * lm = &im->lookup_main;
204 u32 dst_address, dst_address_length, adj_index, old_adj_index;
205 uword * hash, is_del;
206 ip4_add_del_route_callback_t * cb;
208 /* Either create new adjacency or use given one depending on arguments. */
209 if (a->n_add_adj > 0)
211 ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
212 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
215 adj_index = a->adj_index;
217 dst_address = a->dst_address.data_u32;
218 dst_address_length = a->dst_address_length;
219 fib = find_ip4_fib_by_table_index_or_id (im, a->table_index_or_table_id, a->flags);
221 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
222 dst_address &= im->fib_masks[dst_address_length];
224 if (! fib->adj_index_by_dst_address[dst_address_length])
225 ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length);
227 hash = fib->adj_index_by_dst_address[dst_address_length];
229 is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0;
233 fib->old_hash_values[0] = ~0;
234 hash = _hash_unset (hash, dst_address, fib->old_hash_values);
235 fib->adj_index_by_dst_address[dst_address_length] = hash;
237 if (vec_len (im->add_del_route_callbacks) > 0
238 && fib->old_hash_values[0] != ~0) /* make sure destination was found in hash */
240 fib->new_hash_values[0] = ~0;
241 vec_foreach (cb, im->add_del_route_callbacks)
242 if ((a->flags & cb->required_flags) == cb->required_flags)
243 cb->function (im, cb->function_opaque,
245 &a->dst_address, dst_address_length,
246 fib->old_hash_values,
247 fib->new_hash_values);
251 ip4_fib_set_adj_index (im, fib, a->flags, dst_address, dst_address_length,
254 old_adj_index = fib->old_hash_values[0];
256 /* Avoid spurious reference count increments */
257 if (old_adj_index == adj_index
259 && !(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY))
261 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
262 if (adj->share_count > 0)
266 ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length,
267 is_del ? old_adj_index : adj_index,
270 /* Delete old adjacency index if present and changed. */
271 if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
272 && old_adj_index != ~0
273 && old_adj_index != adj_index)
274 ip_del_adjacency (lm, old_adj_index);
279 ip4_route_get_next_hop_adj (ip4_main_t * im,
281 ip4_address_t *next_hop,
282 u32 next_hop_sw_if_index,
283 u32 explicit_fib_index)
285 ip_lookup_main_t * lm = &im->lookup_main;
286 vnet_main_t * vnm = vnet_get_main();
287 uword * nh_hash, * nh_result;
288 int is_interface_next_hop;
292 fib = vec_elt_at_index (im->fibs, fib_index);
294 is_interface_next_hop = next_hop->data_u32 == 0;
295 if (is_interface_next_hop)
297 nh_result = hash_get (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index);
299 nh_adj_index = *nh_result;
302 ip_adjacency_t * adj;
303 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
305 ip4_adjacency_set_interface_route (vnm, adj, next_hop_sw_if_index, /* if_address_index */ ~0);
306 ip_call_add_del_adjacency_callbacks (lm, nh_adj_index, /* is_del */ 0);
307 hash_set (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index, nh_adj_index);
310 else if (next_hop_sw_if_index == ~0)
312 /* next-hop is recursive. we always need a indirect adj
313 * for recursive paths. Any LPM we perform now will give
314 * us a valid adj, but without tracking the next-hop we
315 * have no way to keep it valid.
317 ip_adjacency_t add_adj;
318 memset (&add_adj, 0, sizeof(add_adj));
320 add_adj.lookup_next_index = IP_LOOKUP_NEXT_INDIRECT;
321 add_adj.indirect.next_hop.ip4.as_u32 = next_hop->as_u32;
322 add_adj.explicit_fib_index = explicit_fib_index;
323 ip_add_adjacency (lm, &add_adj, 1, &nh_adj_index);
327 nh_hash = fib->adj_index_by_dst_address[32];
328 nh_result = hash_get (nh_hash, next_hop->data_u32);
330 /* Next hop must be known. */
333 ip_adjacency_t * adj;
335 /* no /32 exists, get the longest prefix match */
336 nh_adj_index = ip4_fib_lookup_with_table (im, fib_index,
338 adj = ip_get_adjacency (lm, nh_adj_index);
339 /* if ARP interface adjacency is present, we need to
340 install ARP adjaceny for specific next hop */
341 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
342 adj->arp.next_hop.ip4.as_u32 == 0)
344 nh_adj_index = vnet_arp_glean_add(fib_index, next_hop);
349 nh_adj_index = *nh_result;
353 return (nh_adj_index);
357 ip4_add_del_route_next_hop (ip4_main_t * im,
359 ip4_address_t * dst_address,
360 u32 dst_address_length,
361 ip4_address_t * next_hop,
362 u32 next_hop_sw_if_index,
363 u32 next_hop_weight, u32 adj_index,
364 u32 explicit_fib_index)
366 vnet_main_t * vnm = vnet_get_main();
367 ip_lookup_main_t * lm = &im->lookup_main;
370 u32 dst_address_u32, old_mp_adj_index, new_mp_adj_index;
371 u32 dst_adj_index, nh_adj_index;
372 uword * dst_hash, * dst_result;
373 ip_adjacency_t * dst_adj;
374 ip_multipath_adjacency_t * old_mp, * new_mp;
375 int is_del = (flags & IP4_ROUTE_FLAG_DEL) != 0;
376 clib_error_t * error = 0;
378 if (explicit_fib_index == (u32)~0)
379 fib_index = vec_elt (im->fib_index_by_sw_if_index, next_hop_sw_if_index);
381 fib_index = explicit_fib_index;
383 fib = vec_elt_at_index (im->fibs, fib_index);
385 /* Lookup next hop to be added or deleted. */
386 if (adj_index == (u32)~0)
388 nh_adj_index = ip4_route_get_next_hop_adj(im, fib_index,
390 next_hop_sw_if_index,
395 nh_adj_index = adj_index;
397 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
398 dst_address_u32 = dst_address->data_u32 & im->fib_masks[dst_address_length];
400 dst_hash = fib->adj_index_by_dst_address[dst_address_length];
401 dst_result = hash_get (dst_hash, dst_address_u32);
404 dst_adj_index = dst_result[0];
405 dst_adj = ip_get_adjacency (lm, dst_adj_index);
409 /* For deletes destination must be known. */
412 vnm->api_errno = VNET_API_ERROR_UNKNOWN_DESTINATION;
413 error = clib_error_return (0, "unknown destination %U/%d",
414 format_ip4_address, dst_address,
423 /* Ignore adds of X/32 with next hop of X. */
425 && dst_address_length == 32
426 && dst_address->data_u32 == next_hop->data_u32
427 && adj_index != (u32)~0)
429 vnm->api_errno = VNET_API_ERROR_PREFIX_MATCHES_NEXT_HOP;
430 error = clib_error_return (0, "prefix matches next hop %U/%d",
431 format_ip4_address, dst_address,
436 /* Destination is not known and default weight is set so add route
437 to existing non-multipath adjacency */
438 if (dst_adj_index == ~0 && next_hop_weight == 1 && next_hop_sw_if_index == ~0)
440 /* create / delete additional mapping of existing adjacency */
441 ip4_add_del_route_args_t a;
442 ip_adjacency_t * nh_adj = ip_get_adjacency (lm, nh_adj_index);
444 a.table_index_or_table_id = fib_index;
445 a.flags = ((is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
446 | IP4_ROUTE_FLAG_FIB_INDEX
447 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
448 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE
449 | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
450 a.dst_address = dst_address[0];
451 a.dst_address_length = dst_address_length;
452 a.adj_index = nh_adj_index;
456 ip4_add_del_route (im, &a);
458 /* adjust share count. This cannot be the only use of the adjacency */
459 nh_adj->share_count += is_del ? -1 : 1;
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 = {"ipsec-input-ip4", 0},
1382 &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
1385 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
1386 .node_name = "ipsec-input-ip4",
1387 .runs_before = {"vpath-input-ip4", 0},
1388 .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
1391 VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
1392 .node_name = "vpath-input-ip4",
1393 .runs_before = {"ip4-lookup", 0},
1394 .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
1397 VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
1398 .node_name = "ip4-lookup",
1399 .runs_before = {0}, /* not before any other features */
1400 .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
1403 /* Built-in ip4 multicast rx feature path definition */
1404 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
1405 .node_name = "vpath-input-ip4",
1406 .runs_before = {"ip4-lookup-multicast", 0},
1407 .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
1410 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
1411 .node_name = "ip4-lookup-multicast",
1412 .runs_before = {0}, /* not before any other features */
1413 .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
1416 static char * feature_start_nodes[] =
1417 { "ip4-input", "ip4-input-no-checksum"};
1419 static clib_error_t *
1420 ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
1422 ip_lookup_main_t * lm = &im->lookup_main;
1423 clib_error_t * error;
1426 for (cast = 0; cast < VNET_N_CAST; cast++)
1428 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1429 vnet_config_main_t * vcm = &cm->config_main;
1431 if ((error = ip_feature_init_cast (vm, cm, vcm,
1432 feature_start_nodes,
1433 ARRAY_LEN(feature_start_nodes),
1441 static clib_error_t *
1442 ip4_sw_interface_add_del (vnet_main_t * vnm,
1446 vlib_main_t * vm = vnm->vlib_main;
1447 ip4_main_t * im = &ip4_main;
1448 ip_lookup_main_t * lm = &im->lookup_main;
1452 for (cast = 0; cast < VNET_N_CAST; cast++)
1454 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1455 vnet_config_main_t * vcm = &cm->config_main;
1457 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
1458 ci = cm->config_index_by_sw_if_index[sw_if_index];
1460 if (cast == VNET_UNICAST)
1461 feature_index = im->ip4_unicast_rx_feature_lookup;
1463 feature_index = im->ip4_multicast_rx_feature_lookup;
1466 ci = vnet_config_add_feature (vm, vcm,
1469 /* config data */ 0,
1470 /* # bytes of config data */ 0);
1472 ci = vnet_config_del_feature (vm, vcm,
1475 /* config data */ 0,
1476 /* # bytes of config data */ 0);
1478 cm->config_index_by_sw_if_index[sw_if_index] = ci;
1481 return /* no error */ 0;
1484 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1486 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args);
1488 VLIB_REGISTER_NODE (ip4_lookup_node) = {
1489 .function = ip4_lookup,
1490 .name = "ip4-lookup",
1491 .vector_size = sizeof (u32),
1493 .format_trace = format_ip4_lookup_trace,
1495 .n_next_nodes = IP4_LOOKUP_N_NEXT,
1496 .next_nodes = IP4_LOOKUP_NEXT_NODES,
1499 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
1502 ip4_indirect (vlib_main_t * vm,
1503 vlib_node_runtime_t * node,
1504 vlib_frame_t * frame)
1506 return ip4_lookup_inline (vm, node, frame,
1507 /* lookup_for_responses_to_locally_received_packets */ 0,
1508 /* is_indirect */ 1);
1511 VLIB_REGISTER_NODE (ip4_indirect_node) = {
1512 .function = ip4_indirect,
1513 .name = "ip4-indirect",
1514 .vector_size = sizeof (u32),
1515 .sibling_of = "ip4-lookup",
1516 .format_trace = format_ip4_lookup_trace,
1521 VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
1524 /* Global IP4 main. */
1525 ip4_main_t ip4_main;
1528 ip4_lookup_init (vlib_main_t * vm)
1530 ip4_main_t * im = &ip4_main;
1531 clib_error_t * error;
1534 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1539 m = pow2_mask (i) << (32 - i);
1542 im->fib_masks[i] = clib_host_to_net_u32 (m);
1545 /* Create FIB with index 0 and table id of 0. */
1546 find_ip4_fib_by_table_index_or_id (im, /* table id */ 0, IP4_ROUTE_FLAG_TABLE_ID);
1548 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1552 pn = pg_get_node (ip4_lookup_node.index);
1553 pn->unformat_edit = unformat_pg_ip4_header;
1557 ethernet_arp_header_t h;
1559 memset (&h, 0, sizeof (h));
1561 /* Set target ethernet address to all zeros. */
1562 memset (h.ip4_over_ethernet[1].ethernet, 0, sizeof (h.ip4_over_ethernet[1].ethernet));
1564 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1565 #define _8(f,v) h.f = v;
1566 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1567 _16 (l3_type, ETHERNET_TYPE_IP4);
1568 _8 (n_l2_address_bytes, 6);
1569 _8 (n_l3_address_bytes, 4);
1570 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1574 vlib_packet_template_init (vm,
1575 &im->ip4_arp_request_packet_template,
1578 /* alloc chunk size */ 8,
1582 error = ip4_feature_init (vm, im);
1587 VLIB_INIT_FUNCTION (ip4_lookup_init);
1590 /* Adjacency taken. */
1595 /* Packet data, possibly *after* rewrite. */
1596 u8 packet_data[64 - 1*sizeof(u32)];
1597 } ip4_forward_next_trace_t;
1599 static u8 * format_ip4_forward_next_trace (u8 * s, va_list * args)
1601 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1602 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1603 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1604 uword indent = format_get_indent (s);
1605 s = format (s, "%U%U",
1606 format_white_space, indent,
1607 format_ip4_header, t->packet_data);
1611 static u8 * format_ip4_lookup_trace (u8 * s, va_list * args)
1613 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1614 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1615 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1616 vnet_main_t * vnm = vnet_get_main();
1617 ip4_main_t * im = &ip4_main;
1618 uword indent = format_get_indent (s);
1620 s = format (s, "fib %d adj-idx %d : %U flow hash: 0x%08x",
1621 t->fib_index, t->adj_index, format_ip_adjacency,
1622 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1623 s = format (s, "\n%U%U",
1624 format_white_space, indent,
1625 format_ip4_header, t->packet_data);
1629 static u8 * format_ip4_rewrite_trace (u8 * s, va_list * args)
1631 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1632 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1633 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1634 vnet_main_t * vnm = vnet_get_main();
1635 ip4_main_t * im = &ip4_main;
1636 uword indent = format_get_indent (s);
1638 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1639 t->fib_index, t->adj_index, format_ip_adjacency,
1640 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1641 s = format (s, "\n%U%U",
1642 format_white_space, indent,
1643 format_ip_adjacency_packet_data,
1644 vnm, &im->lookup_main, t->adj_index,
1645 t->packet_data, sizeof (t->packet_data));
1649 /* Common trace function for all ip4-forward next nodes. */
1651 ip4_forward_next_trace (vlib_main_t * vm,
1652 vlib_node_runtime_t * node,
1653 vlib_frame_t * frame,
1654 vlib_rx_or_tx_t which_adj_index)
1657 ip4_main_t * im = &ip4_main;
1659 n_left = frame->n_vectors;
1660 from = vlib_frame_vector_args (frame);
1665 vlib_buffer_t * b0, * b1;
1666 ip4_forward_next_trace_t * t0, * t1;
1668 /* Prefetch next iteration. */
1669 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1670 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1675 b0 = vlib_get_buffer (vm, bi0);
1676 b1 = vlib_get_buffer (vm, bi1);
1678 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1680 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1681 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1682 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1683 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1684 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1685 vec_elt (im->fib_index_by_sw_if_index,
1686 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1688 clib_memcpy (t0->packet_data,
1689 vlib_buffer_get_current (b0),
1690 sizeof (t0->packet_data));
1692 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1694 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1695 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1696 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1697 t1->fib_index = (vnet_buffer(b1)->sw_if_index[VLIB_TX] != (u32)~0) ?
1698 vnet_buffer(b1)->sw_if_index[VLIB_TX] :
1699 vec_elt (im->fib_index_by_sw_if_index,
1700 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
1701 clib_memcpy (t1->packet_data,
1702 vlib_buffer_get_current (b1),
1703 sizeof (t1->packet_data));
1713 ip4_forward_next_trace_t * t0;
1717 b0 = vlib_get_buffer (vm, bi0);
1719 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1721 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1722 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1723 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1724 t0->fib_index = (vnet_buffer(b0)->sw_if_index[VLIB_TX] != (u32)~0) ?
1725 vnet_buffer(b0)->sw_if_index[VLIB_TX] :
1726 vec_elt (im->fib_index_by_sw_if_index,
1727 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1728 clib_memcpy (t0->packet_data,
1729 vlib_buffer_get_current (b0),
1730 sizeof (t0->packet_data));
1738 ip4_drop_or_punt (vlib_main_t * vm,
1739 vlib_node_runtime_t * node,
1740 vlib_frame_t * frame,
1741 ip4_error_t error_code)
1743 u32 * buffers = vlib_frame_vector_args (frame);
1744 uword n_packets = frame->n_vectors;
1746 vlib_error_drop_buffers (vm, node,
1751 ip4_input_node.index,
1754 if (node->flags & VLIB_NODE_FLAG_TRACE)
1755 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1761 ip4_drop (vlib_main_t * vm,
1762 vlib_node_runtime_t * node,
1763 vlib_frame_t * frame)
1764 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP); }
1767 ip4_punt (vlib_main_t * vm,
1768 vlib_node_runtime_t * node,
1769 vlib_frame_t * frame)
1770 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); }
1773 ip4_miss (vlib_main_t * vm,
1774 vlib_node_runtime_t * node,
1775 vlib_frame_t * frame)
1776 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_DST_LOOKUP_MISS); }
1778 VLIB_REGISTER_NODE (ip4_drop_node,static) = {
1779 .function = ip4_drop,
1781 .vector_size = sizeof (u32),
1783 .format_trace = format_ip4_forward_next_trace,
1791 VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
1793 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
1794 .function = ip4_punt,
1796 .vector_size = sizeof (u32),
1798 .format_trace = format_ip4_forward_next_trace,
1806 VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
1808 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
1809 .function = ip4_miss,
1811 .vector_size = sizeof (u32),
1813 .format_trace = format_ip4_forward_next_trace,
1821 VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
1823 /* Compute TCP/UDP/ICMP4 checksum in software. */
1825 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1829 u32 ip_header_length, payload_length_host_byte_order;
1830 u32 n_this_buffer, n_bytes_left;
1832 void * data_this_buffer;
1834 /* Initialize checksum with ip header. */
1835 ip_header_length = ip4_header_bytes (ip0);
1836 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->length) - ip_header_length;
1837 sum0 = clib_host_to_net_u32 (payload_length_host_byte_order + (ip0->protocol << 16));
1839 if (BITS (uword) == 32)
1841 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u32));
1842 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
1845 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1847 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1848 data_this_buffer = (void *) ip0 + ip_header_length;
1849 if (n_this_buffer + ip_header_length > p0->current_length)
1850 n_this_buffer = p0->current_length > ip_header_length ? p0->current_length - ip_header_length : 0;
1853 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1854 n_bytes_left -= n_this_buffer;
1855 if (n_bytes_left == 0)
1858 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1859 p0 = vlib_get_buffer (vm, p0->next_buffer);
1860 data_this_buffer = vlib_buffer_get_current (p0);
1861 n_this_buffer = p0->current_length;
1864 sum16 = ~ ip_csum_fold (sum0);
1870 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1872 ip4_header_t * ip0 = vlib_buffer_get_current (p0);
1873 udp_header_t * udp0;
1876 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1877 || ip0->protocol == IP_PROTOCOL_UDP);
1879 udp0 = (void *) (ip0 + 1);
1880 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1882 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1883 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1887 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1889 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1890 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1896 ip4_local (vlib_main_t * vm,
1897 vlib_node_runtime_t * node,
1898 vlib_frame_t * frame)
1900 ip4_main_t * im = &ip4_main;
1901 ip_lookup_main_t * lm = &im->lookup_main;
1902 ip_local_next_t next_index;
1903 u32 * from, * to_next, n_left_from, n_left_to_next;
1904 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
1906 from = vlib_frame_vector_args (frame);
1907 n_left_from = frame->n_vectors;
1908 next_index = node->cached_next_index;
1910 if (node->flags & VLIB_NODE_FLAG_TRACE)
1911 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1913 while (n_left_from > 0)
1915 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1917 while (n_left_from >= 4 && n_left_to_next >= 2)
1919 vlib_buffer_t * p0, * p1;
1920 ip4_header_t * ip0, * ip1;
1921 udp_header_t * udp0, * udp1;
1922 ip4_fib_mtrie_t * mtrie0, * mtrie1;
1923 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1924 ip_adjacency_t * adj0, * adj1;
1925 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, adj_index0;
1926 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, adj_index1;
1927 i32 len_diff0, len_diff1;
1928 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1929 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1932 pi0 = to_next[0] = from[0];
1933 pi1 = to_next[1] = from[1];
1937 n_left_to_next -= 2;
1939 p0 = vlib_get_buffer (vm, pi0);
1940 p1 = vlib_get_buffer (vm, pi1);
1942 ip0 = vlib_buffer_get_current (p0);
1943 ip1 = vlib_buffer_get_current (p1);
1945 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1946 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
1947 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1948 vnet_buffer(p1)->sw_if_index[VLIB_RX]);
1950 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
1951 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
1953 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1955 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1956 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
1958 /* Treat IP frag packets as "experimental" protocol for now
1959 until support of IP frag reassembly is implemented */
1960 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
1961 proto1 = ip4_is_fragment(ip1) ? 0xfe : ip1->protocol;
1962 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1963 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1964 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1965 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1970 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1971 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1973 udp0 = ip4_next_header (ip0);
1974 udp1 = ip4_next_header (ip1);
1976 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1977 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1978 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1980 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1981 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
1983 /* Verify UDP length. */
1984 ip_len0 = clib_net_to_host_u16 (ip0->length);
1985 ip_len1 = clib_net_to_host_u16 (ip1->length);
1986 udp_len0 = clib_net_to_host_u16 (udp0->length);
1987 udp_len1 = clib_net_to_host_u16 (udp1->length);
1989 len_diff0 = ip_len0 - udp_len0;
1990 len_diff1 = ip_len1 - udp_len1;
1992 len_diff0 = is_udp0 ? len_diff0 : 0;
1993 len_diff1 = is_udp1 ? len_diff1 : 0;
1995 if (PREDICT_FALSE (! (is_tcp_udp0 & is_tcp_udp1
1996 & good_tcp_udp0 & good_tcp_udp1)))
2001 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2002 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2004 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2005 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2010 && ! (flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2011 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
2013 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2014 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2018 good_tcp_udp0 &= len_diff0 >= 0;
2019 good_tcp_udp1 &= len_diff1 >= 0;
2021 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2022 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
2024 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
2026 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2027 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
2029 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2030 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2031 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2033 error1 = (is_tcp_udp1 && ! good_tcp_udp1
2034 ? IP4_ERROR_TCP_CHECKSUM + is_udp1
2037 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2038 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
2040 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2041 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2043 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
2044 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
2046 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2048 /* no_default_route */ 1));
2049 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
2051 /* no_default_route */ 1));
2053 adj0 = ip_get_adjacency (lm, adj_index0);
2054 adj1 = ip_get_adjacency (lm, adj_index1);
2057 * Must have a route to source otherwise we drop the packet.
2058 * ip4 broadcasts are accepted, e.g. to make dhcp client work
2060 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2061 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2062 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2063 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2064 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2065 ? IP4_ERROR_SRC_LOOKUP_MISS
2067 error1 = (error1 == IP4_ERROR_UNKNOWN_PROTOCOL
2068 && adj1->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2069 && adj1->lookup_next_index != IP_LOOKUP_NEXT_ARP
2070 && adj1->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2071 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2072 ? IP4_ERROR_SRC_LOOKUP_MISS
2075 next0 = lm->local_next_by_ip_protocol[proto0];
2076 next1 = lm->local_next_by_ip_protocol[proto1];
2078 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2079 next1 = error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
2081 p0->error = error0 ? error_node->errors[error0] : 0;
2082 p1->error = error1 ? error_node->errors[error1] : 0;
2084 enqueue_code = (next0 != next_index) + 2*(next1 != next_index);
2086 if (PREDICT_FALSE (enqueue_code != 0))
2088 switch (enqueue_code)
2094 n_left_to_next += 1;
2095 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2101 n_left_to_next += 1;
2102 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2106 /* A B B or A B C */
2108 n_left_to_next += 2;
2109 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2110 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2113 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2115 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2122 while (n_left_from > 0 && n_left_to_next > 0)
2126 udp_header_t * udp0;
2127 ip4_fib_mtrie_t * mtrie0;
2128 ip4_fib_mtrie_leaf_t leaf0;
2129 ip_adjacency_t * adj0;
2130 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, adj_index0;
2132 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2134 pi0 = to_next[0] = from[0];
2138 n_left_to_next -= 1;
2140 p0 = vlib_get_buffer (vm, pi0);
2142 ip0 = vlib_buffer_get_current (p0);
2144 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2145 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2147 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2149 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2151 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2153 /* Treat IP frag packets as "experimental" protocol for now
2154 until support of IP frag reassembly is implemented */
2155 proto0 = ip4_is_fragment(ip0) ? 0xfe : ip0->protocol;
2156 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2157 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2161 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2163 udp0 = ip4_next_header (ip0);
2165 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2166 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2168 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2170 /* Verify UDP length. */
2171 ip_len0 = clib_net_to_host_u16 (ip0->length);
2172 udp_len0 = clib_net_to_host_u16 (udp0->length);
2174 len_diff0 = ip_len0 - udp_len0;
2176 len_diff0 = is_udp0 ? len_diff0 : 0;
2178 if (PREDICT_FALSE (! (is_tcp_udp0 & good_tcp_udp0)))
2183 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2184 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2186 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2187 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2191 good_tcp_udp0 &= len_diff0 >= 0;
2193 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2195 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
2197 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2199 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2200 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2201 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2204 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2206 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2207 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2209 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2211 /* no_default_route */ 1));
2213 adj0 = ip_get_adjacency (lm, adj_index0);
2215 /* Must have a route to source otherwise we drop the packet. */
2216 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2217 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2218 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2219 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2220 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2221 ? IP4_ERROR_SRC_LOOKUP_MISS
2224 next0 = lm->local_next_by_ip_protocol[proto0];
2226 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2228 p0->error = error0? error_node->errors[error0] : 0;
2230 if (PREDICT_FALSE (next0 != next_index))
2232 n_left_to_next += 1;
2233 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2236 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2239 n_left_to_next -= 1;
2243 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2246 return frame->n_vectors;
2249 VLIB_REGISTER_NODE (ip4_local_node,static) = {
2250 .function = ip4_local,
2251 .name = "ip4-local",
2252 .vector_size = sizeof (u32),
2254 .format_trace = format_ip4_forward_next_trace,
2256 .n_next_nodes = IP_LOCAL_N_NEXT,
2258 [IP_LOCAL_NEXT_DROP] = "error-drop",
2259 [IP_LOCAL_NEXT_PUNT] = "error-punt",
2260 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
2261 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
2265 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
2267 void ip4_register_protocol (u32 protocol, u32 node_index)
2269 vlib_main_t * vm = vlib_get_main();
2270 ip4_main_t * im = &ip4_main;
2271 ip_lookup_main_t * lm = &im->lookup_main;
2273 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
2274 lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index);
2277 static clib_error_t *
2278 show_ip_local_command_fn (vlib_main_t * vm,
2279 unformat_input_t * input,
2280 vlib_cli_command_t * cmd)
2282 ip4_main_t * im = &ip4_main;
2283 ip_lookup_main_t * lm = &im->lookup_main;
2286 vlib_cli_output (vm, "Protocols handled by ip4_local");
2287 for (i = 0; i < ARRAY_LEN(lm->local_next_by_ip_protocol); i++)
2289 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2290 vlib_cli_output (vm, "%d", i);
2297 VLIB_CLI_COMMAND (show_ip_local, static) = {
2298 .path = "show ip local",
2299 .function = show_ip_local_command_fn,
2300 .short_help = "Show ip local protocol table",
2304 ip4_arp (vlib_main_t * vm,
2305 vlib_node_runtime_t * node,
2306 vlib_frame_t * frame)
2308 vnet_main_t * vnm = vnet_get_main();
2309 ip4_main_t * im = &ip4_main;
2310 ip_lookup_main_t * lm = &im->lookup_main;
2311 u32 * from, * to_next_drop;
2312 uword n_left_from, n_left_to_next_drop, next_index;
2313 static f64 time_last_seed_change = -1e100;
2314 static u32 hash_seeds[3];
2315 static uword hash_bitmap[256 / BITS (uword)];
2318 if (node->flags & VLIB_NODE_FLAG_TRACE)
2319 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2321 time_now = vlib_time_now (vm);
2322 if (time_now - time_last_seed_change > 1e-3)
2325 u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
2326 sizeof (hash_seeds));
2327 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2328 hash_seeds[i] = r[i];
2330 /* Mark all hash keys as been no-seen before. */
2331 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2334 time_last_seed_change = time_now;
2337 from = vlib_frame_vector_args (frame);
2338 n_left_from = frame->n_vectors;
2339 next_index = node->cached_next_index;
2340 if (next_index == IP4_ARP_NEXT_DROP)
2341 next_index = IP4_ARP_N_NEXT; /* point to first interface */
2343 while (n_left_from > 0)
2345 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2346 to_next_drop, n_left_to_next_drop);
2348 while (n_left_from > 0 && n_left_to_next_drop > 0)
2352 ethernet_header_t * eh0;
2353 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
2355 ip_adjacency_t * adj0;
2359 p0 = vlib_get_buffer (vm, pi0);
2361 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2362 adj0 = ip_get_adjacency (lm, adj_index0);
2363 ip0 = vlib_buffer_get_current (p0);
2365 /* If packet destination is not local, send ARP to next hop */
2366 if (adj0->arp.next_hop.ip4.as_u32)
2367 ip0->dst_address.data_u32 = adj0->arp.next_hop.ip4.as_u32;
2370 * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP
2371 * rewrite to this packet, we need to skip it here.
2372 * Note, to distinguish from src IP addr *.8.6.*, we
2373 * check for a bcast eth dest instead of IPv4 version.
2375 eh0 = (ethernet_header_t*)ip0;
2376 if ((ip0->ip_version_and_header_length & 0xF0) != 0x40)
2379 u16 * etype = &eh0->type;
2380 while ((*etype == clib_host_to_net_u16 (0x8100)) //dot1q
2381 || (*etype == clib_host_to_net_u16 (0x88a8)))//dot1ad
2384 etype += 2; //vlan tag also 16 bits, same as etype
2386 if (*etype == clib_host_to_net_u16 (0x0806)) //arp
2388 vlib_buffer_advance (
2389 p0, sizeof(ethernet_header_t) + (4*vlan_num));
2390 ip0 = vlib_buffer_get_current (p0);
2398 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2399 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2401 a0 ^= ip0->dst_address.data_u32;
2404 hash_v3_finalize32 (a0, b0, c0);
2406 c0 &= BITS (hash_bitmap) - 1;
2407 c0 = c0 / BITS (uword);
2408 m0 = (uword) 1 << (c0 % BITS (uword));
2410 bm0 = hash_bitmap[c0];
2411 drop0 = (bm0 & m0) != 0;
2413 /* Mark it as seen. */
2414 hash_bitmap[c0] = bm0 | m0;
2418 to_next_drop[0] = pi0;
2420 n_left_to_next_drop -= 1;
2422 p0->error = node->errors[drop0 ? IP4_ARP_ERROR_DROP : IP4_ARP_ERROR_REQUEST_SENT];
2428 * Can happen if the control-plane is programming tables
2429 * with traffic flowing; at least that's today's lame excuse.
2431 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
2433 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2436 /* Send ARP request. */
2440 ethernet_arp_header_t * h0;
2441 vnet_hw_interface_t * hw_if0;
2443 h0 = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi0);
2445 /* Add rewrite/encap string for ARP packet. */
2446 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2448 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2450 /* Src ethernet address in ARP header. */
2451 clib_memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address,
2452 sizeof (h0->ip4_over_ethernet[0].ethernet));
2454 if (ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0)) {
2455 //No source address available
2456 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2457 vlib_buffer_free(vm, &bi0, 1);
2461 /* Copy in destination address we are requesting. */
2462 h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32;
2464 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2465 b0 = vlib_get_buffer (vm, bi0);
2466 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2468 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2470 vlib_set_next_frame_buffer (vm, node, adj0->rewrite_header.next_index, bi0);
2474 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2477 return frame->n_vectors;
2480 static char * ip4_arp_error_strings[] = {
2481 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2482 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2483 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2484 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2485 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2486 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
2489 VLIB_REGISTER_NODE (ip4_arp_node) = {
2490 .function = ip4_arp,
2492 .vector_size = sizeof (u32),
2494 .format_trace = format_ip4_forward_next_trace,
2496 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2497 .error_strings = ip4_arp_error_strings,
2499 .n_next_nodes = IP4_ARP_N_NEXT,
2501 [IP4_ARP_NEXT_DROP] = "error-drop",
2505 #define foreach_notrace_ip4_arp_error \
2511 clib_error_t * arp_notrace_init (vlib_main_t * vm)
2513 vlib_node_runtime_t *rt =
2514 vlib_node_get_runtime (vm, ip4_arp_node.index);
2516 /* don't trace ARP request packets */
2518 vnet_pcap_drop_trace_filter_add_del \
2519 (rt->errors[IP4_ARP_ERROR_##a], \
2521 foreach_notrace_ip4_arp_error;
2526 VLIB_INIT_FUNCTION(arp_notrace_init);
2529 /* Send an ARP request to see if given destination is reachable on given interface. */
2531 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2533 vnet_main_t * vnm = vnet_get_main();
2534 ip4_main_t * im = &ip4_main;
2535 ethernet_arp_header_t * h;
2536 ip4_address_t * src;
2537 ip_interface_address_t * ia;
2538 ip_adjacency_t * adj;
2539 vnet_hw_interface_t * hi;
2540 vnet_sw_interface_t * si;
2544 si = vnet_get_sw_interface (vnm, sw_if_index);
2546 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2548 return clib_error_return (0, "%U: interface %U down",
2549 format_ip4_address, dst,
2550 format_vnet_sw_if_index_name, vnm,
2554 src = ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2557 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2558 return clib_error_return
2559 (0, "no matching interface address for destination %U (interface %U)",
2560 format_ip4_address, dst,
2561 format_vnet_sw_if_index_name, vnm, sw_if_index);
2564 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2566 h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi);
2568 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2570 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
2572 h->ip4_over_ethernet[0].ip4 = src[0];
2573 h->ip4_over_ethernet[1].ip4 = dst[0];
2575 b = vlib_get_buffer (vm, bi);
2576 vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2578 /* Add encapsulation string for software interface (e.g. ethernet header). */
2579 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2580 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2583 vlib_frame_t * f = vlib_get_frame_to_node (vm, hi->output_node_index);
2584 u32 * to_next = vlib_frame_vector_args (f);
2587 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2590 return /* no error */ 0;
2594 IP4_REWRITE_NEXT_DROP,
2595 IP4_REWRITE_NEXT_ARP,
2596 IP4_REWRITE_NEXT_ICMP_ERROR,
2597 } ip4_rewrite_next_t;
2600 ip4_rewrite_inline (vlib_main_t * vm,
2601 vlib_node_runtime_t * node,
2602 vlib_frame_t * frame,
2603 int rewrite_for_locally_received_packets)
2605 ip_lookup_main_t * lm = &ip4_main.lookup_main;
2606 u32 * from = vlib_frame_vector_args (frame);
2607 u32 n_left_from, n_left_to_next, * to_next, next_index;
2608 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2609 vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
2611 n_left_from = frame->n_vectors;
2612 next_index = node->cached_next_index;
2613 u32 cpu_index = os_get_cpu_number();
2615 while (n_left_from > 0)
2617 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2619 while (n_left_from >= 4 && n_left_to_next >= 2)
2621 ip_adjacency_t * adj0, * adj1;
2622 vlib_buffer_t * p0, * p1;
2623 ip4_header_t * ip0, * ip1;
2624 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2625 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2626 u32 next0_override, next1_override;
2628 if (rewrite_for_locally_received_packets)
2629 next0_override = next1_override = 0;
2631 /* Prefetch next iteration. */
2633 vlib_buffer_t * p2, * p3;
2635 p2 = vlib_get_buffer (vm, from[2]);
2636 p3 = vlib_get_buffer (vm, from[3]);
2638 vlib_prefetch_buffer_header (p2, STORE);
2639 vlib_prefetch_buffer_header (p3, STORE);
2641 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2642 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2645 pi0 = to_next[0] = from[0];
2646 pi1 = to_next[1] = from[1];
2651 n_left_to_next -= 2;
2653 p0 = vlib_get_buffer (vm, pi0);
2654 p1 = vlib_get_buffer (vm, pi1);
2656 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2657 adj_index1 = vnet_buffer (p1)->ip.adj_index[adj_rx_tx];
2659 /* We should never rewrite a pkt using the MISS adjacency */
2660 ASSERT(adj_index0 && adj_index1);
2662 ip0 = vlib_buffer_get_current (p0);
2663 ip1 = vlib_buffer_get_current (p1);
2665 error0 = error1 = IP4_ERROR_NONE;
2666 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2668 /* Decrement TTL & update checksum.
2669 Works either endian, so no need for byte swap. */
2670 if (! rewrite_for_locally_received_packets)
2672 i32 ttl0 = ip0->ttl, ttl1 = ip1->ttl;
2674 /* Input node should have reject packets with ttl 0. */
2675 ASSERT (ip0->ttl > 0);
2676 ASSERT (ip1->ttl > 0);
2678 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2679 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2681 checksum0 += checksum0 >= 0xffff;
2682 checksum1 += checksum1 >= 0xffff;
2684 ip0->checksum = checksum0;
2685 ip1->checksum = checksum1;
2694 * If the ttl drops below 1 when forwarding, generate
2697 if (PREDICT_FALSE(ttl0 <= 0))
2699 error0 = IP4_ERROR_TIME_EXPIRED;
2700 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2701 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2702 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2703 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2705 if (PREDICT_FALSE(ttl1 <= 0))
2707 error1 = IP4_ERROR_TIME_EXPIRED;
2708 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
2709 icmp4_error_set_vnet_buffer(p1, ICMP4_time_exceeded,
2710 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2711 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2714 /* Verify checksum. */
2715 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2716 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2719 /* Rewrite packet header and updates lengths. */
2720 adj0 = ip_get_adjacency (lm, adj_index0);
2721 adj1 = ip_get_adjacency (lm, adj_index1);
2723 if (rewrite_for_locally_received_packets)
2726 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2727 * we end up here with a local adjacency in hand
2728 * The local adj rewrite data is 0xfefe on purpose.
2729 * Bad engineer, no donut for you.
2731 if (PREDICT_FALSE(adj0->lookup_next_index
2732 == IP_LOOKUP_NEXT_LOCAL))
2733 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2734 if (PREDICT_FALSE(adj0->lookup_next_index
2735 == IP_LOOKUP_NEXT_ARP))
2736 next0_override = IP4_REWRITE_NEXT_ARP;
2737 if (PREDICT_FALSE(adj1->lookup_next_index
2738 == IP_LOOKUP_NEXT_LOCAL))
2739 error1 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2740 if (PREDICT_FALSE(adj1->lookup_next_index
2741 == IP_LOOKUP_NEXT_ARP))
2742 next1_override = IP4_REWRITE_NEXT_ARP;
2745 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2746 rw_len0 = adj0[0].rewrite_header.data_bytes;
2747 rw_len1 = adj1[0].rewrite_header.data_bytes;
2749 /* Check MTU of outgoing interface. */
2750 error0 = (vlib_buffer_length_in_chain (vm, p0) > adj0[0].rewrite_header.max_l3_packet_bytes
2751 ? IP4_ERROR_MTU_EXCEEDED
2753 error1 = (vlib_buffer_length_in_chain (vm, p1) > adj1[0].rewrite_header.max_l3_packet_bytes
2754 ? IP4_ERROR_MTU_EXCEEDED
2757 next0 = (error0 == IP4_ERROR_NONE)
2758 ? adj0[0].rewrite_header.next_index : next0;
2760 if (rewrite_for_locally_received_packets)
2761 next0 = next0 && next0_override ? next0_override : next0;
2763 next1 = (error1 == IP4_ERROR_NONE)
2764 ? adj1[0].rewrite_header.next_index : next1;
2766 if (rewrite_for_locally_received_packets)
2767 next1 = next1 && next1_override ? next1_override : next1;
2770 * We've already accounted for an ethernet_header_t elsewhere
2772 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2773 vlib_increment_combined_counter
2774 (&lm->adjacency_counters,
2775 cpu_index, adj_index0,
2776 /* packet increment */ 0,
2777 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2779 if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
2780 vlib_increment_combined_counter
2781 (&lm->adjacency_counters,
2782 cpu_index, adj_index1,
2783 /* packet increment */ 0,
2784 /* byte increment */ rw_len1-sizeof(ethernet_header_t));
2786 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2787 * to see the IP headerr */
2788 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2790 p0->current_data -= rw_len0;
2791 p0->current_length += rw_len0;
2792 p0->error = error_node->errors[error0];
2793 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2794 adj0[0].rewrite_header.sw_if_index;
2796 if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
2798 p1->current_data -= rw_len1;
2799 p1->current_length += rw_len1;
2800 p1->error = error_node->errors[error1];
2801 vnet_buffer (p1)->sw_if_index[VLIB_TX] =
2802 adj1[0].rewrite_header.sw_if_index;
2805 /* Guess we are only writing on simple Ethernet header. */
2806 vnet_rewrite_two_headers (adj0[0], adj1[0],
2808 sizeof (ethernet_header_t));
2810 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2811 to_next, n_left_to_next,
2812 pi0, pi1, next0, next1);
2815 while (n_left_from > 0 && n_left_to_next > 0)
2817 ip_adjacency_t * adj0;
2820 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2823 if (rewrite_for_locally_received_packets)
2826 pi0 = to_next[0] = from[0];
2828 p0 = vlib_get_buffer (vm, pi0);
2830 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2832 /* We should never rewrite a pkt using the MISS adjacency */
2835 adj0 = ip_get_adjacency (lm, adj_index0);
2837 ip0 = vlib_buffer_get_current (p0);
2839 error0 = IP4_ERROR_NONE;
2840 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2842 /* Decrement TTL & update checksum. */
2843 if (! rewrite_for_locally_received_packets)
2845 i32 ttl0 = ip0->ttl;
2847 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2849 checksum0 += checksum0 >= 0xffff;
2851 ip0->checksum = checksum0;
2853 ASSERT (ip0->ttl > 0);
2859 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2861 if (PREDICT_FALSE(ttl0 <= 0))
2864 * If the ttl drops below 1 when forwarding, generate
2867 error0 = IP4_ERROR_TIME_EXPIRED;
2868 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2869 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
2870 icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
2871 ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
2875 if (rewrite_for_locally_received_packets)
2878 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2879 * we end up here with a local adjacency in hand
2880 * The local adj rewrite data is 0xfefe on purpose.
2881 * Bad engineer, no donut for you.
2883 if (PREDICT_FALSE(adj0->lookup_next_index
2884 == IP_LOOKUP_NEXT_LOCAL))
2885 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2887 * We have to override the next_index in ARP adjacencies,
2888 * because they're set up for ip4-arp, not this node...
2890 if (PREDICT_FALSE(adj0->lookup_next_index
2891 == IP_LOOKUP_NEXT_ARP))
2892 next0_override = IP4_REWRITE_NEXT_ARP;
2895 /* Guess we are only writing on simple Ethernet header. */
2896 vnet_rewrite_one_header (adj0[0], ip0,
2897 sizeof (ethernet_header_t));
2899 /* Update packet buffer attributes/set output interface. */
2900 rw_len0 = adj0[0].rewrite_header.data_bytes;
2902 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2903 vlib_increment_combined_counter
2904 (&lm->adjacency_counters,
2905 cpu_index, adj_index0,
2906 /* packet increment */ 0,
2907 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2909 /* Check MTU of outgoing interface. */
2910 error0 = (vlib_buffer_length_in_chain (vm, p0)
2911 > adj0[0].rewrite_header.max_l3_packet_bytes
2912 ? IP4_ERROR_MTU_EXCEEDED
2915 p0->error = error_node->errors[error0];
2917 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2918 * to see the IP headerr */
2919 if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
2921 p0->current_data -= rw_len0;
2922 p0->current_length += rw_len0;
2924 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2925 adj0[0].rewrite_header.sw_if_index;
2926 next0 = adj0[0].rewrite_header.next_index;
2929 if (rewrite_for_locally_received_packets)
2930 next0 = next0 && next0_override ? next0_override : next0;
2935 n_left_to_next -= 1;
2937 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2938 to_next, n_left_to_next,
2942 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2945 /* Need to do trace after rewrites to pick up new packet data. */
2946 if (node->flags & VLIB_NODE_FLAG_TRACE)
2947 ip4_forward_next_trace (vm, node, frame, adj_rx_tx);
2949 return frame->n_vectors;
2953 /** \brief IPv4 transit rewrite node.
2954 @node ip4-rewrite-transit
2956 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2957 header checksum, fetch the ip adjacency, check the outbound mtu,
2958 apply the adjacency rewrite, and send pkts to the adjacency
2959 rewrite header's rewrite_next_index.
2961 @param vm vlib_main_t corresponding to the current thread
2962 @param node vlib_node_runtime_t
2963 @param frame vlib_frame_t whose contents should be dispatched
2965 @par Graph mechanics: buffer metadata, next index usage
2968 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2969 - the rewrite adjacency index
2970 - <code>adj->lookup_next_index</code>
2971 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2972 the packet will be dropped.
2973 - <code>adj->rewrite_header</code>
2974 - Rewrite string length, rewrite string, next_index
2977 - <code>b->current_data, b->current_length</code>
2978 - Updated net of applying the rewrite string
2980 <em>Next Indices:</em>
2981 - <code> adj->rewrite_header.next_index </code>
2985 ip4_rewrite_transit (vlib_main_t * vm,
2986 vlib_node_runtime_t * node,
2987 vlib_frame_t * frame)
2989 return ip4_rewrite_inline (vm, node, frame,
2990 /* rewrite_for_locally_received_packets */ 0);
2993 /** \brief IPv4 local rewrite node.
2994 @node ip4-rewrite-local
2996 This is the IPv4 local rewrite node. Fetch the ip adjacency, check
2997 the outbound interface mtu, apply the adjacency rewrite, and send
2998 pkts to the adjacency rewrite header's rewrite_next_index. Deal
2999 with hemorrhoids of the form "some clown sends an icmp4 w/ src =
3000 dst = interface addr."
3002 @param vm vlib_main_t corresponding to the current thread
3003 @param node vlib_node_runtime_t
3004 @param frame vlib_frame_t whose contents should be dispatched
3006 @par Graph mechanics: buffer metadata, next index usage
3009 - <code>vnet_buffer(b)->ip.adj_index[VLIB_RX]</code>
3010 - the rewrite adjacency index
3011 - <code>adj->lookup_next_index</code>
3012 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
3013 the packet will be dropped.
3014 - <code>adj->rewrite_header</code>
3015 - Rewrite string length, rewrite string, next_index
3018 - <code>b->current_data, b->current_length</code>
3019 - Updated net of applying the rewrite string
3021 <em>Next Indices:</em>
3022 - <code> adj->rewrite_header.next_index </code>
3027 ip4_rewrite_local (vlib_main_t * vm,
3028 vlib_node_runtime_t * node,
3029 vlib_frame_t * frame)
3031 return ip4_rewrite_inline (vm, node, frame,
3032 /* rewrite_for_locally_received_packets */ 1);
3035 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
3036 .function = ip4_rewrite_transit,
3037 .name = "ip4-rewrite-transit",
3038 .vector_size = sizeof (u32),
3040 .format_trace = format_ip4_rewrite_trace,
3044 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3045 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3046 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3050 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
3052 VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
3053 .function = ip4_rewrite_local,
3054 .name = "ip4-rewrite-local",
3055 .vector_size = sizeof (u32),
3057 .sibling_of = "ip4-rewrite-transit",
3059 .format_trace = format_ip4_rewrite_trace,
3064 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
3066 static clib_error_t *
3067 add_del_interface_table (vlib_main_t * vm,
3068 unformat_input_t * input,
3069 vlib_cli_command_t * cmd)
3071 vnet_main_t * vnm = vnet_get_main();
3072 clib_error_t * error = 0;
3073 u32 sw_if_index, table_id;
3077 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3079 error = clib_error_return (0, "unknown interface `%U'",
3080 format_unformat_error, input);
3084 if (unformat (input, "%d", &table_id))
3088 error = clib_error_return (0, "expected table id `%U'",
3089 format_unformat_error, input);
3094 ip4_main_t * im = &ip4_main;
3095 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
3099 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
3100 im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
3108 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
3109 .path = "set interface ip table",
3110 .function = add_del_interface_table,
3111 .short_help = "Add/delete FIB table id for interface",
3116 ip4_lookup_multicast (vlib_main_t * vm,
3117 vlib_node_runtime_t * node,
3118 vlib_frame_t * frame)
3120 ip4_main_t * im = &ip4_main;
3121 ip_lookup_main_t * lm = &im->lookup_main;
3122 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
3123 u32 n_left_from, n_left_to_next, * from, * to_next;
3124 ip_lookup_next_t next;
3125 u32 cpu_index = os_get_cpu_number();
3127 from = vlib_frame_vector_args (frame);
3128 n_left_from = frame->n_vectors;
3129 next = node->cached_next_index;
3131 while (n_left_from > 0)
3133 vlib_get_next_frame (vm, node, next,
3134 to_next, n_left_to_next);
3136 while (n_left_from >= 4 && n_left_to_next >= 2)
3138 vlib_buffer_t * p0, * p1;
3139 u32 pi0, pi1, adj_index0, adj_index1, wrong_next;
3140 ip_lookup_next_t next0, next1;
3141 ip4_header_t * ip0, * ip1;
3142 ip_adjacency_t * adj0, * adj1;
3143 u32 fib_index0, fib_index1;
3144 u32 flow_hash_config0, flow_hash_config1;
3146 /* Prefetch next iteration. */
3148 vlib_buffer_t * p2, * p3;
3150 p2 = vlib_get_buffer (vm, from[2]);
3151 p3 = vlib_get_buffer (vm, from[3]);
3153 vlib_prefetch_buffer_header (p2, LOAD);
3154 vlib_prefetch_buffer_header (p3, LOAD);
3156 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
3157 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
3160 pi0 = to_next[0] = from[0];
3161 pi1 = to_next[1] = from[1];
3163 p0 = vlib_get_buffer (vm, pi0);
3164 p1 = vlib_get_buffer (vm, pi1);
3166 ip0 = vlib_buffer_get_current (p0);
3167 ip1 = vlib_buffer_get_current (p1);
3169 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3170 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
3171 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3172 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3173 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
3174 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
3176 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3177 &ip0->dst_address, p0);
3178 adj_index1 = ip4_fib_lookup_buffer (im, fib_index1,
3179 &ip1->dst_address, p1);
3181 adj0 = ip_get_adjacency (lm, adj_index0);
3182 adj1 = ip_get_adjacency (lm, adj_index1);
3184 next0 = adj0->lookup_next_index;
3185 next1 = adj1->lookup_next_index;
3188 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3191 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
3193 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
3194 (ip0, flow_hash_config0);
3196 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
3197 (ip1, flow_hash_config1);
3199 ASSERT (adj0->n_adj > 0);
3200 ASSERT (adj1->n_adj > 0);
3201 ASSERT (is_pow2 (adj0->n_adj));
3202 ASSERT (is_pow2 (adj1->n_adj));
3203 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3204 adj_index1 += (vnet_buffer (p1)->ip.flow_hash & (adj1->n_adj - 1));
3206 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3207 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
3209 if (1) /* $$$$$$ HACK FIXME */
3210 vlib_increment_combined_counter
3211 (cm, cpu_index, adj_index0, 1,
3212 vlib_buffer_length_in_chain (vm, p0));
3213 if (1) /* $$$$$$ HACK FIXME */
3214 vlib_increment_combined_counter
3215 (cm, cpu_index, adj_index1, 1,
3216 vlib_buffer_length_in_chain (vm, p1));
3220 n_left_to_next -= 2;
3223 wrong_next = (next0 != next) + 2*(next1 != next);
3224 if (PREDICT_FALSE (wrong_next != 0))
3232 n_left_to_next += 1;
3233 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3239 n_left_to_next += 1;
3240 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3246 n_left_to_next += 2;
3247 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3248 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3252 vlib_put_next_frame (vm, node, next, n_left_to_next);
3254 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
3260 while (n_left_from > 0 && n_left_to_next > 0)
3264 u32 pi0, adj_index0;
3265 ip_lookup_next_t next0;
3266 ip_adjacency_t * adj0;
3268 u32 flow_hash_config0;
3273 p0 = vlib_get_buffer (vm, pi0);
3275 ip0 = vlib_buffer_get_current (p0);
3277 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
3278 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3279 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3280 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3282 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3283 &ip0->dst_address, p0);
3285 adj0 = ip_get_adjacency (lm, adj_index0);
3287 next0 = adj0->lookup_next_index;
3290 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3292 vnet_buffer (p0)->ip.flow_hash =
3293 ip4_compute_flow_hash (ip0, flow_hash_config0);
3295 ASSERT (adj0->n_adj > 0);
3296 ASSERT (is_pow2 (adj0->n_adj));
3297 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3299 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3301 if (1) /* $$$$$$ HACK FIXME */
3302 vlib_increment_combined_counter
3303 (cm, cpu_index, adj_index0, 1,
3304 vlib_buffer_length_in_chain (vm, p0));
3308 n_left_to_next -= 1;
3311 if (PREDICT_FALSE (next0 != next))
3313 n_left_to_next += 1;
3314 vlib_put_next_frame (vm, node, next, n_left_to_next);
3316 vlib_get_next_frame (vm, node, next,
3317 to_next, n_left_to_next);
3320 n_left_to_next -= 1;
3324 vlib_put_next_frame (vm, node, next, n_left_to_next);
3327 if (node->flags & VLIB_NODE_FLAG_TRACE)
3328 ip4_forward_next_trace(vm, node, frame, VLIB_TX);
3330 return frame->n_vectors;
3333 VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
3334 .function = ip4_lookup_multicast,
3335 .name = "ip4-lookup-multicast",
3336 .vector_size = sizeof (u32),
3337 .sibling_of = "ip4-lookup",
3338 .format_trace = format_ip4_lookup_trace,
3343 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
3345 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
3346 .function = ip4_drop,
3347 .name = "ip4-multicast",
3348 .vector_size = sizeof (u32),
3350 .format_trace = format_ip4_forward_next_trace,
3358 int ip4_lookup_validate (ip4_address_t *a, u32 fib_index0)
3360 ip4_main_t * im = &ip4_main;
3361 ip4_fib_mtrie_t * mtrie0;
3362 ip4_fib_mtrie_leaf_t leaf0;
3365 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
3367 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
3368 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
3369 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
3370 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
3371 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
3373 /* Handle default route. */
3374 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
3376 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
3378 return adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
3380 /* no_default_route */ 0);
3383 static clib_error_t *
3384 test_lookup_command_fn (vlib_main_t * vm,
3385 unformat_input_t * input,
3386 vlib_cli_command_t * cmd)
3392 ip4_address_t ip4_base_address;
3395 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3396 if (unformat (input, "table %d", &table_id))
3398 else if (unformat (input, "count %f", &count))
3401 else if (unformat (input, "%U",
3402 unformat_ip4_address, &ip4_base_address))
3405 return clib_error_return (0, "unknown input `%U'",
3406 format_unformat_error, input);
3411 for (i = 0; i < n; i++)
3413 if (!ip4_lookup_validate (&ip4_base_address, table_id))
3416 ip4_base_address.as_u32 =
3417 clib_host_to_net_u32 (1 +
3418 clib_net_to_host_u32 (ip4_base_address.as_u32));
3422 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3424 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3429 VLIB_CLI_COMMAND (lookup_test_command, static) = {
3430 .path = "test lookup",
3431 .short_help = "test lookup",
3432 .function = test_lookup_command_fn,
3435 int vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3437 ip4_main_t * im4 = &ip4_main;
3439 uword * p = hash_get (im4->fib_index_by_table_id, table_id);
3442 return VNET_API_ERROR_NO_SUCH_FIB;
3444 fib = vec_elt_at_index (im4->fibs, p[0]);
3446 fib->flow_hash_config = flow_hash_config;
3450 static clib_error_t *
3451 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3452 unformat_input_t * input,
3453 vlib_cli_command_t * cmd)
3457 u32 flow_hash_config = 0;
3460 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3461 if (unformat (input, "table %d", &table_id))
3464 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3465 foreach_flow_hash_bit
3471 return clib_error_return (0, "unknown input `%U'",
3472 format_unformat_error, input);
3474 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3480 case VNET_API_ERROR_NO_SUCH_FIB:
3481 return clib_error_return (0, "no such FIB table %d", table_id);
3484 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3491 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
3492 .path = "set ip flow-hash",
3494 "set ip table flow-hash table <fib-id> src dst sport dport proto reverse",
3495 .function = set_ip_flow_hash_command_fn,
3498 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3501 vnet_main_t * vnm = vnet_get_main();
3502 vnet_interface_main_t * im = &vnm->interface_main;
3503 ip4_main_t * ipm = &ip4_main;
3504 ip_lookup_main_t * lm = &ipm->lookup_main;
3505 vnet_classify_main_t * cm = &vnet_classify_main;
3507 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3508 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3510 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3511 return VNET_API_ERROR_NO_SUCH_ENTRY;
3513 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3514 lm->classify_table_index_by_sw_if_index [sw_if_index] = table_index;
3519 static clib_error_t *
3520 set_ip_classify_command_fn (vlib_main_t * vm,
3521 unformat_input_t * input,
3522 vlib_cli_command_t * cmd)
3524 u32 table_index = ~0;
3525 int table_index_set = 0;
3526 u32 sw_if_index = ~0;
3529 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3530 if (unformat (input, "table-index %d", &table_index))
3531 table_index_set = 1;
3532 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3533 vnet_get_main(), &sw_if_index))
3539 if (table_index_set == 0)
3540 return clib_error_return (0, "classify table-index must be specified");
3542 if (sw_if_index == ~0)
3543 return clib_error_return (0, "interface / subif must be specified");
3545 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3552 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3553 return clib_error_return (0, "No such interface");
3555 case VNET_API_ERROR_NO_SUCH_ENTRY:
3556 return clib_error_return (0, "No such classifier table");
3561 VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
3562 .path = "set ip classify",
3564 "set ip classify intfc <int> table-index <index>",
3565 .function = set_ip_classify_command_fn,