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 */
48 /* This is really, really simple but stupid fib. */
50 ip4_fib_lookup_with_table (ip4_main_t * im, u32 fib_index,
52 u32 disable_default_route)
54 ip_lookup_main_t * lm = &im->lookup_main;
55 ip4_fib_t * fib = vec_elt_at_index (im->fibs, fib_index);
56 uword * p, * hash, key;
57 i32 i, i_min, dst_address, ai;
59 i_min = disable_default_route ? 1 : 0;
60 dst_address = clib_mem_unaligned (&dst->data_u32, u32);
61 for (i = ARRAY_LEN (fib->adj_index_by_dst_address) - 1; i >= i_min; i--)
63 hash = fib->adj_index_by_dst_address[i];
67 key = dst_address & im->fib_masks[i];
68 if ((p = hash_get (hash, key)) != 0)
75 /* Nothing matches in table. */
76 ai = lm->miss_adj_index;
83 create_fib_with_table_id (ip4_main_t * im, u32 table_id)
86 hash_set (im->fib_index_by_table_id, table_id, vec_len (im->fibs));
87 vec_add2 (im->fibs, fib, 1);
88 fib->table_id = table_id;
89 fib->index = fib - im->fibs;
90 fib->flow_hash_config = IP_FLOW_HASH_DEFAULT;
91 fib->fwd_classify_table_index = ~0;
92 fib->rev_classify_table_index = ~0;
93 ip4_mtrie_init (&fib->mtrie);
98 find_ip4_fib_by_table_index_or_id (ip4_main_t * im,
99 u32 table_index_or_id, u32 flags)
101 uword * p, fib_index;
103 fib_index = table_index_or_id;
104 if (! (flags & IP4_ROUTE_FLAG_FIB_INDEX))
106 p = hash_get (im->fib_index_by_table_id, table_index_or_id);
108 return create_fib_with_table_id (im, table_index_or_id);
111 return vec_elt_at_index (im->fibs, fib_index);
115 ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm,
122 ASSERT (lm->fib_result_n_bytes >= sizeof (uword));
123 lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword)) / sizeof (uword);
125 fib->adj_index_by_dst_address[address_length] =
126 hash_create (32 /* elts */, lm->fib_result_n_words * sizeof (uword));
128 hash_set_flags (fib->adj_index_by_dst_address[address_length],
129 HASH_FLAG_NO_AUTO_SHRINK);
131 h = hash_header (fib->adj_index_by_dst_address[address_length]);
132 max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1;
134 /* Initialize new/old hash value vectors. */
135 vec_validate_init_empty (fib->new_hash_values, max_index, ~0);
136 vec_validate_init_empty (fib->old_hash_values, max_index, ~0);
139 static void serialize_ip4_address (serialize_main_t * m, va_list * va)
141 ip4_address_t * a = va_arg (*va, ip4_address_t *);
142 u8 * p = serialize_get (m, sizeof (a->as_u8));
143 memcpy (p, a->as_u8, sizeof (a->as_u8));
146 static void unserialize_ip4_address (serialize_main_t * m, va_list * va)
148 ip4_address_t * a = va_arg (*va, ip4_address_t *);
149 u8 * p = unserialize_get (m, sizeof (a->as_u8));
150 memcpy (a->as_u8, p, sizeof (a->as_u8));
153 static void serialize_ip4_address_and_length (serialize_main_t * m, va_list * va)
155 ip4_address_t * a = va_arg (*va, ip4_address_t *);
156 u32 l = va_arg (*va, u32);
157 u32 n_bytes = (l / 8) + ((l % 8) != 0);
158 u8 * p = serialize_get (m, 1 + n_bytes);
161 memcpy (p + 1, a->as_u8, n_bytes);
164 static void unserialize_ip4_address_and_length (serialize_main_t * m, va_list * va)
166 ip4_address_t * a = va_arg (*va, ip4_address_t *);
167 u32 * al = va_arg (*va, u32 *);
168 u8 * p = unserialize_get (m, 1);
173 n_bytes = (l / 8) + ((l % 8) != 0);
177 p = unserialize_get (m, n_bytes);
178 memcpy (a->as_u8, p, n_bytes);
182 static void serialize_ip4_add_del_route_msg (serialize_main_t * m, va_list * va)
184 ip4_add_del_route_args_t * a = va_arg (*va, ip4_add_del_route_args_t *);
186 serialize_likely_small_unsigned_integer (m, a->table_index_or_table_id);
187 serialize_likely_small_unsigned_integer (m, a->flags);
188 serialize (m, serialize_ip4_address_and_length, &a->dst_address, a->dst_address_length);
189 serialize_likely_small_unsigned_integer (m, a->adj_index);
190 serialize_likely_small_unsigned_integer (m, a->n_add_adj);
191 if (a->n_add_adj > 0)
192 serialize (m, serialize_vec_ip_adjacency, a->add_adj, a->n_add_adj);
195 /* Serialized adjacencies for arp/rewrite do not send graph next_index
196 since graph hookup is not guaranteed to be the same for both sides
197 of serialize/unserialize. */
199 unserialize_fixup_ip4_rewrite_adjacencies (vlib_main_t * vm,
200 ip_adjacency_t * adj,
203 vnet_main_t * vnm = vnet_get_main();
204 u32 i, ni, sw_if_index, is_arp;
205 vnet_hw_interface_t * hw;
207 for (i = 0; i < n_adj; i++)
209 switch (adj[i].lookup_next_index)
211 case IP_LOOKUP_NEXT_REWRITE:
212 case IP_LOOKUP_NEXT_ARP:
213 is_arp = adj[i].lookup_next_index == IP_LOOKUP_NEXT_ARP;
214 sw_if_index = adj[i].rewrite_header.sw_if_index;
215 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
216 ni = is_arp ? ip4_arp_node.index : ip4_rewrite_node.index;
217 adj[i].rewrite_header.node_index = ni;
218 adj[i].rewrite_header.next_index = vlib_node_add_next (vm, ni, hw->output_node_index);
220 vnet_rewrite_for_sw_interface
222 VNET_L3_PACKET_TYPE_ARP,
225 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST,
226 &adj[i].rewrite_header,
227 sizeof (adj->rewrite_data));
236 static void unserialize_ip4_add_del_route_msg (serialize_main_t * m, va_list * va)
238 ip4_main_t * i4m = &ip4_main;
239 ip4_add_del_route_args_t a;
241 a.table_index_or_table_id = unserialize_likely_small_unsigned_integer (m);
242 a.flags = unserialize_likely_small_unsigned_integer (m);
243 unserialize (m, unserialize_ip4_address_and_length, &a.dst_address, &a.dst_address_length);
244 a.adj_index = unserialize_likely_small_unsigned_integer (m);
245 a.n_add_adj = unserialize_likely_small_unsigned_integer (m);
249 vec_resize (a.add_adj, a.n_add_adj);
250 unserialize (m, unserialize_vec_ip_adjacency, a.add_adj, a.n_add_adj);
251 unserialize_fixup_ip4_rewrite_adjacencies (vlib_get_main(),
252 a.add_adj, a.n_add_adj);
255 /* Prevent re-re-distribution. */
256 a.flags |= IP4_ROUTE_FLAG_NO_REDISTRIBUTE;
258 ip4_add_del_route (i4m, &a);
260 vec_free (a.add_adj);
263 MC_SERIALIZE_MSG (ip4_add_del_route_msg, static) = {
264 .name = "vnet_ip4_add_del_route",
265 .serialize = serialize_ip4_add_del_route_msg,
266 .unserialize = unserialize_ip4_add_del_route_msg,
270 ip4_fib_set_adj_index (ip4_main_t * im,
274 u32 dst_address_length,
277 ip_lookup_main_t * lm = &im->lookup_main;
280 if (vec_bytes(fib->old_hash_values))
281 memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values));
282 if (vec_bytes(fib->new_hash_values))
283 memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values));
284 fib->new_hash_values[0] = adj_index;
286 /* Make sure adj index is valid. */
288 (void) ip_get_adjacency (lm, adj_index);
290 hash = fib->adj_index_by_dst_address[dst_address_length];
292 hash = _hash_set3 (hash, dst_address_u32,
293 fib->new_hash_values,
294 fib->old_hash_values);
296 fib->adj_index_by_dst_address[dst_address_length] = hash;
298 if (vec_len (im->add_del_route_callbacks) > 0)
300 ip4_add_del_route_callback_t * cb;
304 d.data_u32 = dst_address_u32;
305 vec_foreach (cb, im->add_del_route_callbacks)
306 if ((flags & cb->required_flags) == cb->required_flags)
307 cb->function (im, cb->function_opaque,
309 &d, dst_address_length,
310 fib->old_hash_values,
311 fib->new_hash_values);
313 p = hash_get (hash, dst_address_u32);
314 memcpy (p, fib->new_hash_values, vec_bytes (fib->new_hash_values));
318 void ip4_add_del_route (ip4_main_t * im, ip4_add_del_route_args_t * a)
320 vlib_main_t * vm = vlib_get_main();
321 ip_lookup_main_t * lm = &im->lookup_main;
323 u32 dst_address, dst_address_length, adj_index, old_adj_index;
324 uword * hash, is_del;
325 ip4_add_del_route_callback_t * cb;
327 if (vm->mc_main && ! (a->flags & IP4_ROUTE_FLAG_NO_REDISTRIBUTE))
329 u32 multiple_messages_per_vlib_buffer = (a->flags & IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP);
330 mc_serialize2 (vm->mc_main, multiple_messages_per_vlib_buffer,
331 &ip4_add_del_route_msg, a);
335 /* Either create new adjacency or use given one depending on arguments. */
336 if (a->n_add_adj > 0)
338 ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
339 ip_call_add_del_adjacency_callbacks (lm, adj_index, /* is_del */ 0);
342 adj_index = a->adj_index;
344 dst_address = a->dst_address.data_u32;
345 dst_address_length = a->dst_address_length;
346 fib = find_ip4_fib_by_table_index_or_id (im, a->table_index_or_table_id, a->flags);
348 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
349 dst_address &= im->fib_masks[dst_address_length];
351 if (! fib->adj_index_by_dst_address[dst_address_length])
352 ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length);
354 hash = fib->adj_index_by_dst_address[dst_address_length];
356 is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0;
360 fib->old_hash_values[0] = ~0;
361 hash = _hash_unset (hash, dst_address, fib->old_hash_values);
362 fib->adj_index_by_dst_address[dst_address_length] = hash;
364 if (vec_len (im->add_del_route_callbacks) > 0
365 && fib->old_hash_values[0] != ~0) /* make sure destination was found in hash */
367 fib->new_hash_values[0] = ~0;
368 vec_foreach (cb, im->add_del_route_callbacks)
369 if ((a->flags & cb->required_flags) == cb->required_flags)
370 cb->function (im, cb->function_opaque,
372 &a->dst_address, dst_address_length,
373 fib->old_hash_values,
374 fib->new_hash_values);
378 ip4_fib_set_adj_index (im, fib, a->flags, dst_address, dst_address_length,
381 old_adj_index = fib->old_hash_values[0];
383 /* Avoid spurious reference count increments */
384 if (old_adj_index == adj_index)
386 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
387 if (adj->share_count > 0)
391 ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length,
392 is_del ? old_adj_index : adj_index,
395 /* Delete old adjacency index if present and changed. */
396 if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
397 && old_adj_index != ~0
398 && old_adj_index != adj_index)
399 ip_del_adjacency (lm, old_adj_index);
402 static void serialize_ip4_add_del_route_next_hop_msg (serialize_main_t * m, va_list * va)
404 u32 flags = va_arg (*va, u32);
405 ip4_address_t * dst_address = va_arg (*va, ip4_address_t *);
406 u32 dst_address_length = va_arg (*va, u32);
407 ip4_address_t * next_hop_address = va_arg (*va, ip4_address_t *);
408 u32 next_hop_sw_if_index = va_arg (*va, u32);
409 u32 next_hop_weight = va_arg (*va, u32);
411 serialize_likely_small_unsigned_integer (m, flags);
412 serialize (m, serialize_ip4_address_and_length, dst_address, dst_address_length);
413 serialize (m, serialize_ip4_address, next_hop_address);
414 serialize_likely_small_unsigned_integer (m, next_hop_sw_if_index);
415 serialize_likely_small_unsigned_integer (m, next_hop_weight);
418 static void unserialize_ip4_add_del_route_next_hop_msg (serialize_main_t * m, va_list * va)
420 ip4_main_t * im = &ip4_main;
421 u32 flags, dst_address_length, next_hop_sw_if_index, next_hop_weight;
422 ip4_address_t dst_address, next_hop_address;
424 flags = unserialize_likely_small_unsigned_integer (m);
425 unserialize (m, unserialize_ip4_address_and_length, &dst_address, &dst_address_length);
426 unserialize (m, unserialize_ip4_address, &next_hop_address);
427 next_hop_sw_if_index = unserialize_likely_small_unsigned_integer (m);
428 next_hop_weight = unserialize_likely_small_unsigned_integer (m);
430 ip4_add_del_route_next_hop
432 flags | IP4_ROUTE_FLAG_NO_REDISTRIBUTE,
436 next_hop_sw_if_index,
437 next_hop_weight, (u32)~0,
438 (u32)~0 /* explicit FIB index */);
441 MC_SERIALIZE_MSG (ip4_add_del_route_next_hop_msg, static) = {
442 .name = "vnet_ip4_add_del_route_next_hop",
443 .serialize = serialize_ip4_add_del_route_next_hop_msg,
444 .unserialize = unserialize_ip4_add_del_route_next_hop_msg,
448 ip4_add_del_route_next_hop (ip4_main_t * im,
450 ip4_address_t * dst_address,
451 u32 dst_address_length,
452 ip4_address_t * next_hop,
453 u32 next_hop_sw_if_index,
454 u32 next_hop_weight, u32 adj_index,
455 u32 explicit_fib_index)
457 vnet_main_t * vnm = vnet_get_main();
458 vlib_main_t * vm = vlib_get_main();
459 ip_lookup_main_t * lm = &im->lookup_main;
462 u32 dst_address_u32, old_mp_adj_index, new_mp_adj_index;
463 u32 dst_adj_index, nh_adj_index;
464 uword * dst_hash, * dst_result;
465 uword * nh_hash, * nh_result;
466 ip_adjacency_t * dst_adj;
467 ip_multipath_adjacency_t * old_mp, * new_mp;
468 int is_del = (flags & IP4_ROUTE_FLAG_DEL) != 0;
469 int is_interface_next_hop;
470 clib_error_t * error = 0;
472 if (vm->mc_main && ! (flags & IP4_ROUTE_FLAG_NO_REDISTRIBUTE))
474 u32 multiple_messages_per_vlib_buffer = (flags & IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP);
475 mc_serialize2 (vm->mc_main,
476 multiple_messages_per_vlib_buffer,
477 &ip4_add_del_route_next_hop_msg,
479 dst_address, dst_address_length,
480 next_hop, next_hop_sw_if_index, next_hop_weight);
484 if (explicit_fib_index == (u32)~0)
485 fib_index = vec_elt (im->fib_index_by_sw_if_index, next_hop_sw_if_index);
487 fib_index = explicit_fib_index;
489 fib = vec_elt_at_index (im->fibs, fib_index);
491 /* Lookup next hop to be added or deleted. */
492 is_interface_next_hop = next_hop->data_u32 == 0;
493 if (adj_index == (u32)~0)
495 if (is_interface_next_hop)
497 nh_result = hash_get (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index);
499 nh_adj_index = *nh_result;
502 ip_adjacency_t * adj;
503 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
505 ip4_adjacency_set_interface_route (vnm, adj, next_hop_sw_if_index, /* if_address_index */ ~0);
506 ip_call_add_del_adjacency_callbacks (lm, nh_adj_index, /* is_del */ 0);
507 hash_set (im->interface_route_adj_index_by_sw_if_index, next_hop_sw_if_index, nh_adj_index);
512 nh_hash = fib->adj_index_by_dst_address[32];
513 nh_result = hash_get (nh_hash, next_hop->data_u32);
515 /* Next hop must be known. */
518 vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_IN_FIB;
519 error = clib_error_return (0, "next-hop %U/32 not in FIB",
520 format_ip4_address, next_hop);
523 nh_adj_index = *nh_result;
528 nh_adj_index = adj_index;
530 ASSERT (dst_address_length < ARRAY_LEN (im->fib_masks));
531 dst_address_u32 = dst_address->data_u32 & im->fib_masks[dst_address_length];
533 dst_hash = fib->adj_index_by_dst_address[dst_address_length];
534 dst_result = hash_get (dst_hash, dst_address_u32);
537 dst_adj_index = dst_result[0];
538 dst_adj = ip_get_adjacency (lm, dst_adj_index);
542 /* For deletes destination must be known. */
545 vnm->api_errno = VNET_API_ERROR_UNKNOWN_DESTINATION;
546 error = clib_error_return (0, "unknown destination %U/%d",
547 format_ip4_address, dst_address,
556 /* Ignore adds of X/32 with next hop of X. */
558 && dst_address_length == 32
559 && dst_address->data_u32 == next_hop->data_u32
560 && adj_index != (u32)~0)
562 vnm->api_errno = VNET_API_ERROR_PREFIX_MATCHES_NEXT_HOP;
563 error = clib_error_return (0, "prefix matches next hop %U/%d",
564 format_ip4_address, dst_address,
569 old_mp_adj_index = dst_adj ? dst_adj->heap_handle : ~0;
571 if (! ip_multipath_adjacency_add_del_next_hop
578 vnm->api_errno = VNET_API_ERROR_NEXT_HOP_NOT_FOUND_MP;
579 error = clib_error_return (0, "requested deleting next-hop %U not found in multi-path",
580 format_ip4_address, next_hop);
585 if (old_mp_adj_index != ~0)
586 old_mp = vec_elt_at_index (lm->multipath_adjacencies, old_mp_adj_index);
587 if (new_mp_adj_index != ~0)
588 new_mp = vec_elt_at_index (lm->multipath_adjacencies, new_mp_adj_index);
590 if (old_mp != new_mp)
592 ip4_add_del_route_args_t a;
593 a.table_index_or_table_id = fib_index;
594 a.flags = ((is_del && ! new_mp ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD)
595 | IP4_ROUTE_FLAG_FIB_INDEX
596 | IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY
597 | (flags & (IP4_ROUTE_FLAG_NO_REDISTRIBUTE | IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP)));
598 a.dst_address = dst_address[0];
599 a.dst_address_length = dst_address_length;
600 a.adj_index = new_mp ? new_mp->adj_index : dst_adj_index;
604 ip4_add_del_route (im, &a);
609 clib_error_report (error);
613 ip4_get_route (ip4_main_t * im,
614 u32 table_index_or_table_id,
619 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
620 u32 dst_address = * (u32 *) address;
623 ASSERT (address_length < ARRAY_LEN (im->fib_masks));
624 dst_address &= im->fib_masks[address_length];
626 hash = fib->adj_index_by_dst_address[address_length];
627 p = hash_get (hash, dst_address);
632 ip4_foreach_matching_route (ip4_main_t * im,
633 u32 table_index_or_table_id,
635 ip4_address_t * address,
637 ip4_address_t ** results,
638 u8 ** result_lengths)
640 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
641 u32 dst_address = address->data_u32;
642 u32 this_length = address_length;
645 _vec_len (*results) = 0;
647 _vec_len (*result_lengths) = 0;
649 while (this_length <= 32 && vec_len (results) == 0)
652 hash_foreach (k, v, fib->adj_index_by_dst_address[this_length], ({
653 if (0 == ((k ^ dst_address) & im->fib_masks[address_length]))
657 vec_add1 (*results, a);
658 vec_add1 (*result_lengths, this_length);
666 void ip4_maybe_remap_adjacencies (ip4_main_t * im,
667 u32 table_index_or_table_id,
670 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_index_or_table_id, flags);
671 ip_lookup_main_t * lm = &im->lookup_main;
674 ip4_add_del_route_callback_t * cb;
675 static ip4_address_t * to_delete;
677 if (lm->n_adjacency_remaps == 0)
680 for (l = 0; l <= 32; l++)
683 uword * hash = fib->adj_index_by_dst_address[l];
685 if (hash_elts (hash) == 0)
689 _vec_len (to_delete) = 0;
691 hash_foreach_pair (p, hash, ({
692 u32 adj_index = p->value[0];
693 u32 m = vec_elt (lm->adjacency_remap_table, adj_index);
697 /* Record destination address from hash key. */
700 /* New adjacency points to nothing: so delete prefix. */
702 vec_add1 (to_delete, a);
705 /* Remap to new adjacency. */
706 memcpy (fib->old_hash_values, p->value, vec_bytes (fib->old_hash_values));
708 /* Set new adjacency value. */
709 fib->new_hash_values[0] = p->value[0] = m - 1;
711 vec_foreach (cb, im->add_del_route_callbacks)
712 if ((flags & cb->required_flags) == cb->required_flags)
713 cb->function (im, cb->function_opaque,
714 fib, flags | IP4_ROUTE_FLAG_ADD,
716 fib->old_hash_values,
717 fib->new_hash_values);
722 fib->new_hash_values[0] = ~0;
723 for (i = 0; i < vec_len (to_delete); i++)
725 hash = _hash_unset (hash, to_delete[i].data_u32, fib->old_hash_values);
726 vec_foreach (cb, im->add_del_route_callbacks)
727 if ((flags & cb->required_flags) == cb->required_flags)
728 cb->function (im, cb->function_opaque,
729 fib, flags | IP4_ROUTE_FLAG_DEL,
731 fib->old_hash_values,
732 fib->new_hash_values);
736 /* Also remap adjacencies in mtrie. */
737 ip4_mtrie_maybe_remap_adjacencies (lm, &fib->mtrie);
739 /* Reset mapping table. */
740 vec_zero (lm->adjacency_remap_table);
742 /* All remaps have been performed. */
743 lm->n_adjacency_remaps = 0;
746 void ip4_delete_matching_routes (ip4_main_t * im,
747 u32 table_index_or_table_id,
749 ip4_address_t * address,
752 static ip4_address_t * matching_addresses;
753 static u8 * matching_address_lengths;
755 ip4_add_del_route_args_t a;
757 a.flags = IP4_ROUTE_FLAG_DEL | IP4_ROUTE_FLAG_NO_REDISTRIBUTE | flags;
758 a.table_index_or_table_id = table_index_or_table_id;
763 for (l = address_length + 1; l <= 32; l++)
765 ip4_foreach_matching_route (im, table_index_or_table_id, flags,
769 &matching_address_lengths);
770 for (i = 0; i < vec_len (matching_addresses); i++)
772 a.dst_address = matching_addresses[i];
773 a.dst_address_length = matching_address_lengths[i];
774 ip4_add_del_route (im, &a);
778 ip4_maybe_remap_adjacencies (im, table_index_or_table_id, flags);
782 ip4_lookup_inline (vlib_main_t * vm,
783 vlib_node_runtime_t * node,
784 vlib_frame_t * frame,
785 int lookup_for_responses_to_locally_received_packets)
787 ip4_main_t * im = &ip4_main;
788 ip_lookup_main_t * lm = &im->lookup_main;
789 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
790 u32 n_left_from, n_left_to_next, * from, * to_next;
791 ip_lookup_next_t next;
792 u32 cpu_index = os_get_cpu_number();
794 from = vlib_frame_vector_args (frame);
795 n_left_from = frame->n_vectors;
796 next = node->cached_next_index;
798 while (n_left_from > 0)
800 vlib_get_next_frame (vm, node, next,
801 to_next, n_left_to_next);
803 while (n_left_from >= 4 && n_left_to_next >= 2)
805 vlib_buffer_t * p0, * p1;
806 ip4_header_t * ip0, * ip1;
807 __attribute__((unused)) tcp_header_t * tcp0, * tcp1;
808 ip_lookup_next_t next0, next1;
809 ip_adjacency_t * adj0, * adj1;
810 ip4_fib_mtrie_t * mtrie0, * mtrie1;
811 ip4_fib_mtrie_leaf_t leaf0, leaf1;
812 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
813 __attribute__((unused)) u32 pi1, fib_index1, adj_index1, is_tcp_udp1;
814 u32 flow_hash_config0, flow_hash_config1;
815 u32 hash_c0, hash_c1;
818 /* Prefetch next iteration. */
820 vlib_buffer_t * p2, * p3;
822 p2 = vlib_get_buffer (vm, from[2]);
823 p3 = vlib_get_buffer (vm, from[3]);
825 vlib_prefetch_buffer_header (p2, LOAD);
826 vlib_prefetch_buffer_header (p3, LOAD);
828 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
829 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
832 pi0 = to_next[0] = from[0];
833 pi1 = to_next[1] = from[1];
835 p0 = vlib_get_buffer (vm, pi0);
836 p1 = vlib_get_buffer (vm, pi1);
838 ip0 = vlib_buffer_get_current (p0);
839 ip1 = vlib_buffer_get_current (p1);
841 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
842 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
843 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
844 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
845 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
846 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
849 if (! lookup_for_responses_to_locally_received_packets)
851 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
852 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
854 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
856 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 0);
857 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->dst_address, 0);
860 tcp0 = (void *) (ip0 + 1);
861 tcp1 = (void *) (ip1 + 1);
863 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
864 || ip0->protocol == IP_PROTOCOL_UDP);
865 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
866 || ip1->protocol == IP_PROTOCOL_UDP);
868 if (! lookup_for_responses_to_locally_received_packets)
870 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 1);
871 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->dst_address, 1);
874 if (! lookup_for_responses_to_locally_received_packets)
876 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 2);
877 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->dst_address, 2);
880 if (! lookup_for_responses_to_locally_received_packets)
882 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 3);
883 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->dst_address, 3);
886 if (lookup_for_responses_to_locally_received_packets)
888 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
889 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
893 /* Handle default route. */
894 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
895 leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
897 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
898 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
901 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
903 /* no_default_route */ 0));
904 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
906 /* no_default_route */ 0));
907 adj0 = ip_get_adjacency (lm, adj_index0);
908 adj1 = ip_get_adjacency (lm, adj_index1);
910 next0 = adj0->lookup_next_index;
911 next1 = adj1->lookup_next_index;
913 /* Use flow hash to compute multipath adjacency. */
914 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
915 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
916 if (PREDICT_FALSE (adj0->n_adj > 1))
919 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
920 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
921 ip4_compute_flow_hash (ip0, flow_hash_config0);
923 if (PREDICT_FALSE(adj1->n_adj > 1))
926 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
927 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
928 ip4_compute_flow_hash (ip1, flow_hash_config1);
931 ASSERT (adj0->n_adj > 0);
932 ASSERT (adj1->n_adj > 0);
933 ASSERT (is_pow2 (adj0->n_adj));
934 ASSERT (is_pow2 (adj1->n_adj));
935 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
936 adj_index1 += (hash_c1 & (adj1->n_adj - 1));
938 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
939 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
941 vlib_increment_combined_counter
942 (cm, cpu_index, adj_index0, 1,
943 vlib_buffer_length_in_chain (vm, p0)
944 + sizeof(ethernet_header_t));
945 vlib_increment_combined_counter
946 (cm, cpu_index, adj_index1, 1,
947 vlib_buffer_length_in_chain (vm, p1)
948 + sizeof(ethernet_header_t));
955 wrong_next = (next0 != next) + 2*(next1 != next);
956 if (PREDICT_FALSE (wrong_next != 0))
965 vlib_set_next_frame_buffer (vm, node, next0, pi0);
972 vlib_set_next_frame_buffer (vm, node, next1, pi1);
979 vlib_set_next_frame_buffer (vm, node, next0, pi0);
980 vlib_set_next_frame_buffer (vm, node, next1, pi1);
984 vlib_put_next_frame (vm, node, next, n_left_to_next);
986 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
992 while (n_left_from > 0 && n_left_to_next > 0)
996 __attribute__((unused)) tcp_header_t * tcp0;
997 ip_lookup_next_t next0;
998 ip_adjacency_t * adj0;
999 ip4_fib_mtrie_t * mtrie0;
1000 ip4_fib_mtrie_leaf_t leaf0;
1001 __attribute__((unused)) u32 pi0, fib_index0, adj_index0, is_tcp_udp0;
1002 u32 flow_hash_config0, hash_c0;
1007 p0 = vlib_get_buffer (vm, pi0);
1009 ip0 = vlib_buffer_get_current (p0);
1011 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1012 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
1013 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
1015 if (! lookup_for_responses_to_locally_received_packets)
1017 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
1019 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1021 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 0);
1024 tcp0 = (void *) (ip0 + 1);
1026 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
1027 || ip0->protocol == IP_PROTOCOL_UDP);
1029 if (! lookup_for_responses_to_locally_received_packets)
1030 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 1);
1032 if (! lookup_for_responses_to_locally_received_packets)
1033 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 2);
1035 if (! lookup_for_responses_to_locally_received_packets)
1036 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->dst_address, 3);
1038 if (lookup_for_responses_to_locally_received_packets)
1039 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
1042 /* Handle default route. */
1043 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1044 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1047 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
1049 /* no_default_route */ 0));
1051 adj0 = ip_get_adjacency (lm, adj_index0);
1053 next0 = adj0->lookup_next_index;
1055 /* Use flow hash to compute multipath adjacency. */
1056 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
1057 if (PREDICT_FALSE(adj0->n_adj > 1))
1060 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
1062 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
1063 ip4_compute_flow_hash (ip0, flow_hash_config0);
1066 ASSERT (adj0->n_adj > 0);
1067 ASSERT (is_pow2 (adj0->n_adj));
1068 adj_index0 += (hash_c0 & (adj0->n_adj - 1));
1070 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
1072 vlib_increment_combined_counter
1073 (cm, cpu_index, adj_index0, 1,
1074 vlib_buffer_length_in_chain (vm, p0)
1075 + sizeof(ethernet_header_t));
1079 n_left_to_next -= 1;
1082 if (PREDICT_FALSE (next0 != next))
1084 n_left_to_next += 1;
1085 vlib_put_next_frame (vm, node, next, n_left_to_next);
1087 vlib_get_next_frame (vm, node, next,
1088 to_next, n_left_to_next);
1091 n_left_to_next -= 1;
1095 vlib_put_next_frame (vm, node, next, n_left_to_next);
1098 return frame->n_vectors;
1102 ip4_lookup (vlib_main_t * vm,
1103 vlib_node_runtime_t * node,
1104 vlib_frame_t * frame)
1106 return ip4_lookup_inline (vm, node, frame, /* lookup_for_responses_to_locally_received_packets */ 0);
1110 void ip4_adjacency_set_interface_route (vnet_main_t * vnm,
1111 ip_adjacency_t * adj,
1113 u32 if_address_index)
1115 vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1117 vnet_l3_packet_type_t packet_type;
1120 if (hw->hw_class_index == ethernet_hw_interface_class.index
1121 || hw->hw_class_index == srp_hw_interface_class.index)
1124 * We have a bit of a problem in this case. ip4-arp uses
1125 * the rewrite_header.next_index to hand pkts to the
1126 * indicated inteface output node. We can end up in
1127 * ip4_rewrite_local, too, which also pays attention to
1128 * rewrite_header.next index. Net result: a hack in
1129 * ip4_rewrite_local...
1131 n = IP_LOOKUP_NEXT_ARP;
1132 node_index = ip4_arp_node.index;
1133 adj->if_address_index = if_address_index;
1134 packet_type = VNET_L3_PACKET_TYPE_ARP;
1138 n = IP_LOOKUP_NEXT_REWRITE;
1139 node_index = ip4_rewrite_node.index;
1140 packet_type = VNET_L3_PACKET_TYPE_IP4;
1143 adj->lookup_next_index = n;
1144 vnet_rewrite_for_sw_interface
1149 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST,
1150 &adj->rewrite_header,
1151 sizeof (adj->rewrite_data));
1155 ip4_add_interface_routes (u32 sw_if_index,
1156 ip4_main_t * im, u32 fib_index,
1157 ip_interface_address_t * a)
1159 vnet_main_t * vnm = vnet_get_main();
1160 ip_lookup_main_t * lm = &im->lookup_main;
1161 ip_adjacency_t * adj;
1162 ip4_address_t * address = ip_interface_address_get_address (lm, a);
1163 ip4_add_del_route_args_t x;
1164 vnet_hw_interface_t * hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
1165 u32 classify_table_index;
1167 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1168 x.table_index_or_table_id = fib_index;
1169 x.flags = (IP4_ROUTE_FLAG_ADD
1170 | IP4_ROUTE_FLAG_FIB_INDEX
1171 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1172 x.dst_address = address[0];
1173 x.dst_address_length = a->address_length;
1177 a->neighbor_probe_adj_index = ~0;
1178 if (a->address_length < 32)
1180 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1182 ip4_adjacency_set_interface_route (vnm, adj, sw_if_index, a - lm->if_address_pool);
1183 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1184 ip4_add_del_route (im, &x);
1185 a->neighbor_probe_adj_index = x.adj_index;
1188 /* Add e.g. 1.1.1.1/32 as local to this host. */
1189 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1192 classify_table_index = ~0;
1193 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
1194 classify_table_index = lm->classify_table_index_by_sw_if_index [sw_if_index];
1195 if (classify_table_index != (u32) ~0)
1197 adj->lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1198 adj->classify_table_index = classify_table_index;
1201 adj->lookup_next_index = IP_LOOKUP_NEXT_LOCAL;
1203 adj->if_address_index = a - lm->if_address_pool;
1204 adj->rewrite_header.sw_if_index = sw_if_index;
1205 adj->rewrite_header.max_l3_packet_bytes = hw_if->max_l3_packet_bytes[VLIB_RX];
1207 * Local adjs are never to be rewritten. Spoofed pkts w/ src = dst = local
1208 * fail an RPF-ish check, but still go thru the rewrite code...
1210 adj->rewrite_header.data_bytes = 0;
1212 ip_call_add_del_adjacency_callbacks (lm, x.adj_index, /* is_del */ 0);
1213 x.dst_address_length = 32;
1214 ip4_add_del_route (im, &x);
1218 ip4_del_interface_routes (ip4_main_t * im, u32 fib_index, ip4_address_t * address, u32 address_length)
1220 ip4_add_del_route_args_t x;
1222 /* Add e.g. 1.0.0.0/8 as interface route (arp for Ethernet). */
1223 x.table_index_or_table_id = fib_index;
1224 x.flags = (IP4_ROUTE_FLAG_DEL
1225 | IP4_ROUTE_FLAG_FIB_INDEX
1226 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE);
1227 x.dst_address = address[0];
1228 x.dst_address_length = address_length;
1233 if (address_length < 32)
1234 ip4_add_del_route (im, &x);
1236 x.dst_address_length = 32;
1237 ip4_add_del_route (im, &x);
1239 ip4_delete_matching_routes (im,
1241 IP4_ROUTE_FLAG_FIB_INDEX,
1248 ip4_address_t address;
1250 } ip4_interface_address_t;
1252 static void serialize_vec_ip4_set_interface_address (serialize_main_t * m, va_list * va)
1254 ip4_interface_address_t * a = va_arg (*va, ip4_interface_address_t *);
1255 u32 n = va_arg (*va, u32);
1257 for (i = 0; i < n; i++) {
1258 serialize_integer (m, a[i].sw_if_index, sizeof (a[i].sw_if_index));
1259 serialize (m, serialize_ip4_address, &a[i].address);
1260 serialize_integer (m, a[i].length, sizeof (a[i].length));
1264 static void unserialize_vec_ip4_set_interface_address (serialize_main_t * m, va_list * va)
1266 ip4_interface_address_t * a = va_arg (*va, ip4_interface_address_t *);
1267 u32 n = va_arg (*va, u32);
1269 for (i = 0; i < n; i++) {
1270 unserialize_integer (m, &a[i].sw_if_index, sizeof (a[i].sw_if_index));
1271 unserialize (m, unserialize_ip4_address, &a[i].address);
1272 unserialize_integer (m, &a[i].length, sizeof (a[i].length));
1276 static void serialize_ip4_set_interface_address_msg (serialize_main_t * m, va_list * va)
1278 ip4_interface_address_t * a = va_arg (*va, ip4_interface_address_t *);
1279 int is_del = va_arg (*va, int);
1280 serialize (m, serialize_vec_ip4_set_interface_address, a, 1);
1281 serialize_integer (m, is_del, sizeof (is_del));
1284 static clib_error_t *
1285 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1287 ip4_address_t * new_address,
1293 static void unserialize_ip4_set_interface_address_msg (serialize_main_t * m, va_list * va)
1295 mc_main_t * mcm = va_arg (*va, mc_main_t *);
1296 vlib_main_t * vm = mcm->vlib_main;
1297 ip4_interface_address_t a;
1298 clib_error_t * error;
1301 unserialize (m, unserialize_vec_ip4_set_interface_address, &a, 1);
1302 unserialize_integer (m, &is_del, sizeof (is_del));
1303 error = ip4_add_del_interface_address_internal
1304 (vm, a.sw_if_index, &a.address, a.length,
1305 /* redistribute */ 0,
1306 /* insert_routes */ 1,
1309 clib_error_report (error);
1312 MC_SERIALIZE_MSG (ip4_set_interface_address_msg, static) = {
1313 .name = "vnet_ip4_set_interface_address",
1314 .serialize = serialize_ip4_set_interface_address_msg,
1315 .unserialize = unserialize_ip4_set_interface_address_msg,
1318 static clib_error_t *
1319 ip4_add_del_interface_address_internal (vlib_main_t * vm,
1321 ip4_address_t * address,
1327 vnet_main_t * vnm = vnet_get_main();
1328 ip4_main_t * im = &ip4_main;
1329 ip_lookup_main_t * lm = &im->lookup_main;
1330 clib_error_t * error = 0;
1331 u32 if_address_index, elts_before;
1332 ip4_address_fib_t ip4_af, * addr_fib = 0;
1334 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1335 ip4_addr_fib_init (&ip4_af, address,
1336 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
1337 vec_add1 (addr_fib, ip4_af);
1339 /* When adding an address check that it does not conflict with an existing address. */
1342 ip_interface_address_t * ia;
1343 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1344 0 /* honor unnumbered */,
1346 ip4_address_t * x = ip_interface_address_get_address (&im->lookup_main, ia);
1348 if (ip4_destination_matches_route (im, address, x, ia->address_length)
1349 || ip4_destination_matches_route (im, x, address, address_length))
1350 return clib_error_create ("failed to add %U which conflicts with %U for interface %U",
1351 format_ip4_address_and_length, address, address_length,
1352 format_ip4_address_and_length, x, ia->address_length,
1353 format_vnet_sw_if_index_name, vnm, sw_if_index);
1357 if (vm->mc_main && redistribute)
1359 ip4_interface_address_t a;
1360 a.sw_if_index = sw_if_index;
1361 a.address = address[0];
1362 a.length = address_length;
1363 mc_serialize (vm->mc_main, &ip4_set_interface_address_msg,
1368 elts_before = pool_elts (lm->if_address_pool);
1370 error = ip_interface_address_add_del
1380 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index) && insert_routes)
1383 ip4_del_interface_routes (im, ip4_af.fib_index, address,
1387 ip4_add_interface_routes (sw_if_index,
1388 im, ip4_af.fib_index,
1390 (lm->if_address_pool, if_address_index));
1393 /* If pool did not grow/shrink: add duplicate address. */
1394 if (elts_before != pool_elts (lm->if_address_pool))
1396 ip4_add_del_interface_address_callback_t * cb;
1397 vec_foreach (cb, im->add_del_interface_address_callbacks)
1398 cb->function (im, cb->function_opaque, sw_if_index,
1399 address, address_length,
1405 vec_free (addr_fib);
1410 ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index,
1411 ip4_address_t * address, u32 address_length,
1414 return ip4_add_del_interface_address_internal
1415 (vm, sw_if_index, address, address_length,
1416 /* redistribute */ 1,
1417 /* insert_routes */ 1,
1421 static void serialize_ip4_fib (serialize_main_t * m, va_list * va)
1423 ip4_fib_t * f = va_arg (*va, ip4_fib_t *);
1424 u32 l, dst, adj_index;
1426 serialize_integer (m, f->table_id, sizeof (f->table_id));
1427 for (l = 0; l < ARRAY_LEN (f->adj_index_by_dst_address); l++)
1429 u32 n_elts = hash_elts (f->adj_index_by_dst_address[l]);
1431 serialize_integer (m, n_elts, sizeof (n_elts));
1432 hash_foreach (dst, adj_index, f->adj_index_by_dst_address[l], ({
1435 serialize (m, serialize_ip4_address, &tmp);
1436 serialize_integer (m, adj_index, sizeof (adj_index));
1441 static void unserialize_ip4_fib (serialize_main_t * m, va_list * va)
1443 ip4_add_del_route_args_t a;
1446 a.flags = (IP4_ROUTE_FLAG_ADD
1447 | IP4_ROUTE_FLAG_NO_REDISTRIBUTE
1448 | IP4_ROUTE_FLAG_TABLE_ID);
1452 unserialize_integer (m, &a.table_index_or_table_id,
1453 sizeof (a.table_index_or_table_id));
1455 for (i = 0; i < STRUCT_ARRAY_LEN (ip4_fib_t, adj_index_by_dst_address); i++)
1458 unserialize_integer (m, &n_elts, sizeof (u32));
1459 a.dst_address_length = i;
1462 unserialize (m, unserialize_ip4_address, &a.dst_address);
1463 unserialize_integer (m, &a.adj_index, sizeof (a.adj_index));
1464 ip4_add_del_route (&ip4_main, &a);
1470 void serialize_vnet_ip4_main (serialize_main_t * m, va_list * va)
1472 vnet_main_t * vnm = va_arg (*va, vnet_main_t *);
1473 vnet_interface_main_t * vim = &vnm->interface_main;
1474 vnet_sw_interface_t * si;
1475 ip4_main_t * i4m = &ip4_main;
1476 ip4_interface_address_t * as = 0, * a;
1478 /* Download adjacency tables & multipath stuff. */
1479 serialize (m, serialize_ip_lookup_main, &i4m->lookup_main);
1484 u32 n_fibs = vec_len (i4m->fibs);
1485 serialize_integer (m, n_fibs, sizeof (n_fibs));
1486 vec_foreach (f, i4m->fibs)
1487 serialize (m, serialize_ip4_fib, f);
1490 /* FIB interface config. */
1491 vec_serialize (m, i4m->fib_index_by_sw_if_index, serialize_vec_32);
1493 /* Interface ip4 addresses. */
1494 pool_foreach (si, vim->sw_interfaces, ({
1495 u32 sw_if_index = si->sw_if_index;
1496 ip_interface_address_t * ia;
1497 foreach_ip_interface_address (&i4m->lookup_main, ia, sw_if_index,
1498 0 /* honor unnumbered */,
1500 ip4_address_t * x = ip_interface_address_get_address (&i4m->lookup_main, ia);
1501 vec_add2 (as, a, 1);
1503 a->length = ia->address_length;
1504 a->sw_if_index = sw_if_index;
1507 vec_serialize (m, as, serialize_vec_ip4_set_interface_address);
1511 void unserialize_vnet_ip4_main (serialize_main_t * m, va_list * va)
1513 vlib_main_t * vm = va_arg (*va, vlib_main_t *);
1514 ip4_main_t * i4m = &ip4_main;
1515 ip4_interface_address_t * as = 0, * a;
1517 unserialize (m, unserialize_ip_lookup_main, &i4m->lookup_main);
1520 ip_adjacency_t * adj, * adj_heap;
1522 adj_heap = i4m->lookup_main.adjacency_heap;
1523 heap_foreach (adj, n_adj, adj_heap, ({
1524 unserialize_fixup_ip4_rewrite_adjacencies (vm, adj, n_adj);
1525 ip_call_add_del_adjacency_callbacks (&i4m->lookup_main, adj - adj_heap, /* is_del */ 0);
1532 unserialize_integer (m, &n_fibs, sizeof (n_fibs));
1533 for (i = 0; i < n_fibs; i++)
1534 unserialize (m, unserialize_ip4_fib);
1537 vec_unserialize (m, &i4m->fib_index_by_sw_if_index, unserialize_vec_32);
1539 vec_unserialize (m, &as, unserialize_vec_ip4_set_interface_address);
1540 vec_foreach (a, as) {
1541 ip4_add_del_interface_address_internal
1542 (vm, a->sw_if_index, &a->address, a->length,
1543 /* redistribute */ 0,
1544 /* insert_routes */ 0,
1550 static clib_error_t *
1551 ip4_sw_interface_admin_up_down (vnet_main_t * vnm,
1555 ip4_main_t * im = &ip4_main;
1556 ip_interface_address_t * ia;
1558 u32 is_admin_up, fib_index;
1560 /* Fill in lookup tables with default table (0). */
1561 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1563 vec_validate_init_empty (im->lookup_main.if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
1565 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1567 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
1569 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
1570 0 /* honor unnumbered */,
1572 a = ip_interface_address_get_address (&im->lookup_main, ia);
1574 ip4_add_interface_routes (sw_if_index,
1578 ip4_del_interface_routes (im, fib_index,
1579 a, ia->address_length);
1585 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
1587 static clib_error_t *
1588 ip4_sw_interface_add_del (vnet_main_t * vnm,
1592 vlib_main_t * vm = vnm->vlib_main;
1593 ip4_main_t * im = &ip4_main;
1594 ip_lookup_main_t * lm = &im->lookup_main;
1597 for (cast = 0; cast < VNET_N_CAST; cast++)
1599 ip_config_main_t * cm = &lm->rx_config_mains[cast];
1600 vnet_config_main_t * vcm = &cm->config_main;
1602 if (! vcm->node_index_by_feature_index)
1604 if (cast == VNET_UNICAST)
1606 static char * start_nodes[] = { "ip4-input", "ip4-input-no-checksum", };
1607 static char * feature_nodes[] = {
1608 [IP4_RX_FEATURE_CHECK_ACCESS] = "ip4-inacl",
1609 [IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_RX] = "ip4-source-check-via-rx",
1610 [IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_ANY] = "ip4-source-check-via-any",
1611 [IP4_RX_FEATURE_IPSEC] = "ipsec-input-ip4",
1612 [IP4_RX_FEATURE_VPATH] = "vpath-input-ip4",
1613 [IP4_RX_FEATURE_LOOKUP] = "ip4-lookup",
1616 vnet_config_init (vm, vcm,
1617 start_nodes, ARRAY_LEN (start_nodes),
1618 feature_nodes, ARRAY_LEN (feature_nodes));
1622 static char * start_nodes[] = { "ip4-input", "ip4-input-no-checksum", };
1623 static char * feature_nodes[] = {
1624 [IP4_RX_FEATURE_VPATH] = "vpath-input-ip4",
1625 [IP4_RX_FEATURE_LOOKUP] = "ip4-lookup-multicast",
1628 vnet_config_init (vm, vcm,
1629 start_nodes, ARRAY_LEN (start_nodes),
1630 feature_nodes, ARRAY_LEN (feature_nodes));
1634 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
1635 ci = cm->config_index_by_sw_if_index[sw_if_index];
1638 ci = vnet_config_add_feature (vm, vcm,
1640 IP4_RX_FEATURE_LOOKUP,
1641 /* config data */ 0,
1642 /* # bytes of config data */ 0);
1644 ci = vnet_config_del_feature (vm, vcm,
1646 IP4_RX_FEATURE_LOOKUP,
1647 /* config data */ 0,
1648 /* # bytes of config data */ 0);
1650 cm->config_index_by_sw_if_index[sw_if_index] = ci;
1653 return /* no error */ 0;
1656 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1658 VLIB_REGISTER_NODE (ip4_lookup_node) = {
1659 .function = ip4_lookup,
1660 .name = "ip4-lookup",
1661 .vector_size = sizeof (u32),
1663 .n_next_nodes = IP_LOOKUP_N_NEXT,
1665 [IP_LOOKUP_NEXT_MISS] = "ip4-miss",
1666 [IP_LOOKUP_NEXT_DROP] = "ip4-drop",
1667 [IP_LOOKUP_NEXT_PUNT] = "ip4-punt",
1668 [IP_LOOKUP_NEXT_LOCAL] = "ip4-local",
1669 [IP_LOOKUP_NEXT_ARP] = "ip4-arp",
1670 [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite-transit",
1671 [IP_LOOKUP_NEXT_CLASSIFY] = "ip4-classify",
1672 [IP_LOOKUP_NEXT_MAP] = "ip4-map",
1673 [IP_LOOKUP_NEXT_MAP_T] = "ip4-map-t",
1674 [IP_LOOKUP_NEXT_SIXRD] = "ip4-sixrd",
1675 [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip4-hop-by-hop",
1676 [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip4-add-hop-by-hop",
1677 [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip4-pop-hop-by-hop",
1681 /* Global IP4 main. */
1682 ip4_main_t ip4_main;
1685 ip4_lookup_init (vlib_main_t * vm)
1687 ip4_main_t * im = &ip4_main;
1690 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1695 m = pow2_mask (i) << (32 - i);
1698 im->fib_masks[i] = clib_host_to_net_u32 (m);
1701 /* Create FIB with index 0 and table id of 0. */
1702 find_ip4_fib_by_table_index_or_id (im, /* table id */ 0, IP4_ROUTE_FLAG_TABLE_ID);
1704 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1708 pn = pg_get_node (ip4_lookup_node.index);
1709 pn->unformat_edit = unformat_pg_ip4_header;
1713 ethernet_arp_header_t h;
1715 memset (&h, 0, sizeof (h));
1717 /* Set target ethernet address to all zeros. */
1718 memset (h.ip4_over_ethernet[1].ethernet, 0, sizeof (h.ip4_over_ethernet[1].ethernet));
1720 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1721 #define _8(f,v) h.f = v;
1722 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1723 _16 (l3_type, ETHERNET_TYPE_IP4);
1724 _8 (n_l2_address_bytes, 6);
1725 _8 (n_l3_address_bytes, 4);
1726 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1730 vlib_packet_template_init (vm,
1731 &im->ip4_arp_request_packet_template,
1734 /* alloc chunk size */ 8,
1741 VLIB_INIT_FUNCTION (ip4_lookup_init);
1744 /* Adjacency taken. */
1749 /* Packet data, possibly *after* rewrite. */
1750 u8 packet_data[64 - 1*sizeof(u32)];
1751 } ip4_forward_next_trace_t;
1753 static u8 * format_ip4_forward_next_trace (u8 * s, va_list * args)
1755 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1756 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1757 ip4_forward_next_trace_t * t = va_arg (*args, ip4_forward_next_trace_t *);
1758 vnet_main_t * vnm = vnet_get_main();
1759 ip4_main_t * im = &ip4_main;
1760 ip_adjacency_t * adj;
1761 uword indent = format_get_indent (s);
1763 adj = ip_get_adjacency (&im->lookup_main, t->adj_index);
1764 s = format (s, "fib %d adj-idx %d : %U flow hash: 0x%08x",
1765 t->fib_index, t->adj_index, format_ip_adjacency,
1766 vnm, &im->lookup_main, t->adj_index, t->flow_hash);
1767 switch (adj->lookup_next_index)
1769 case IP_LOOKUP_NEXT_REWRITE:
1770 s = format (s, "\n%U%U",
1771 format_white_space, indent,
1772 format_ip_adjacency_packet_data,
1773 vnm, &im->lookup_main, t->adj_index,
1774 t->packet_data, sizeof (t->packet_data));
1784 /* Common trace function for all ip4-forward next nodes. */
1786 ip4_forward_next_trace (vlib_main_t * vm,
1787 vlib_node_runtime_t * node,
1788 vlib_frame_t * frame,
1789 vlib_rx_or_tx_t which_adj_index)
1792 ip4_main_t * im = &ip4_main;
1794 n_left = frame->n_vectors;
1795 from = vlib_frame_vector_args (frame);
1800 vlib_buffer_t * b0, * b1;
1801 ip4_forward_next_trace_t * t0, * t1;
1803 /* Prefetch next iteration. */
1804 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1805 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1810 b0 = vlib_get_buffer (vm, bi0);
1811 b1 = vlib_get_buffer (vm, bi1);
1813 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1815 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1816 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1817 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1818 t0->fib_index = vec_elt (im->fib_index_by_sw_if_index,
1819 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1820 memcpy (t0->packet_data,
1821 vlib_buffer_get_current (b0),
1822 sizeof (t0->packet_data));
1824 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1826 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1827 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1828 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1829 t1->fib_index = vec_elt (im->fib_index_by_sw_if_index,
1830 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
1831 memcpy (t1->packet_data,
1832 vlib_buffer_get_current (b1),
1833 sizeof (t1->packet_data));
1843 ip4_forward_next_trace_t * t0;
1847 b0 = vlib_get_buffer (vm, bi0);
1849 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1851 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1852 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1853 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1854 t0->fib_index = vec_elt (im->fib_index_by_sw_if_index,
1855 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1856 memcpy (t0->packet_data,
1857 vlib_buffer_get_current (b0),
1858 sizeof (t0->packet_data));
1866 ip4_drop_or_punt (vlib_main_t * vm,
1867 vlib_node_runtime_t * node,
1868 vlib_frame_t * frame,
1869 ip4_error_t error_code)
1871 u32 * buffers = vlib_frame_vector_args (frame);
1872 uword n_packets = frame->n_vectors;
1874 vlib_error_drop_buffers (vm, node,
1879 ip4_input_node.index,
1882 if (node->flags & VLIB_NODE_FLAG_TRACE)
1883 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1889 ip4_drop (vlib_main_t * vm,
1890 vlib_node_runtime_t * node,
1891 vlib_frame_t * frame)
1892 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP); }
1895 ip4_punt (vlib_main_t * vm,
1896 vlib_node_runtime_t * node,
1897 vlib_frame_t * frame)
1898 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT); }
1901 ip4_miss (vlib_main_t * vm,
1902 vlib_node_runtime_t * node,
1903 vlib_frame_t * frame)
1904 { return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_DST_LOOKUP_MISS); }
1906 VLIB_REGISTER_NODE (ip4_drop_node,static) = {
1907 .function = ip4_drop,
1909 .vector_size = sizeof (u32),
1911 .format_trace = format_ip4_forward_next_trace,
1919 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
1920 .function = ip4_punt,
1922 .vector_size = sizeof (u32),
1924 .format_trace = format_ip4_forward_next_trace,
1932 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
1933 .function = ip4_miss,
1935 .vector_size = sizeof (u32),
1937 .format_trace = format_ip4_forward_next_trace,
1945 /* Compute TCP/UDP/ICMP4 checksum in software. */
1947 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1951 u32 ip_header_length, payload_length_host_byte_order;
1952 u32 n_this_buffer, n_bytes_left;
1954 void * data_this_buffer;
1956 /* Initialize checksum with ip header. */
1957 ip_header_length = ip4_header_bytes (ip0);
1958 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->length) - ip_header_length;
1959 sum0 = clib_host_to_net_u32 (payload_length_host_byte_order + (ip0->protocol << 16));
1961 if (BITS (uword) == 32)
1963 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u32));
1964 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
1967 sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1969 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1970 data_this_buffer = (void *) ip0 + ip_header_length;
1971 if (n_this_buffer + ip_header_length > p0->current_length)
1972 n_this_buffer = p0->current_length > ip_header_length ? p0->current_length - ip_header_length : 0;
1975 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1976 n_bytes_left -= n_this_buffer;
1977 if (n_bytes_left == 0)
1980 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1981 p0 = vlib_get_buffer (vm, p0->next_buffer);
1982 data_this_buffer = vlib_buffer_get_current (p0);
1983 n_this_buffer = p0->current_length;
1986 sum16 = ~ ip_csum_fold (sum0);
1992 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1994 ip4_header_t * ip0 = vlib_buffer_get_current (p0);
1995 udp_header_t * udp0;
1998 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1999 || ip0->protocol == IP_PROTOCOL_UDP);
2001 udp0 = (void *) (ip0 + 1);
2002 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
2004 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
2005 | IP_BUFFER_L4_CHECKSUM_CORRECT);
2009 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
2011 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
2012 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
2018 ip4_local (vlib_main_t * vm,
2019 vlib_node_runtime_t * node,
2020 vlib_frame_t * frame)
2022 ip4_main_t * im = &ip4_main;
2023 ip_lookup_main_t * lm = &im->lookup_main;
2024 ip_local_next_t next_index;
2025 u32 * from, * to_next, n_left_from, n_left_to_next;
2026 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2028 from = vlib_frame_vector_args (frame);
2029 n_left_from = frame->n_vectors;
2030 next_index = node->cached_next_index;
2032 if (node->flags & VLIB_NODE_FLAG_TRACE)
2033 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2035 while (n_left_from > 0)
2037 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2039 while (n_left_from >= 4 && n_left_to_next >= 2)
2041 vlib_buffer_t * p0, * p1;
2042 ip4_header_t * ip0, * ip1;
2043 udp_header_t * udp0, * udp1;
2044 ip4_fib_mtrie_t * mtrie0, * mtrie1;
2045 ip4_fib_mtrie_leaf_t leaf0, leaf1;
2046 ip_adjacency_t * adj0, * adj1;
2047 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, adj_index0;
2048 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, adj_index1;
2049 i32 len_diff0, len_diff1;
2050 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2051 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
2054 pi0 = to_next[0] = from[0];
2055 pi1 = to_next[1] = from[1];
2059 n_left_to_next -= 2;
2061 p0 = vlib_get_buffer (vm, pi0);
2062 p1 = vlib_get_buffer (vm, pi1);
2064 ip0 = vlib_buffer_get_current (p0);
2065 ip1 = vlib_buffer_get_current (p1);
2067 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2068 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2069 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
2070 vnet_buffer(p1)->sw_if_index[VLIB_RX]);
2072 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2073 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
2075 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
2077 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2078 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
2080 proto0 = ip0->protocol;
2081 proto1 = ip1->protocol;
2082 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2083 is_udp1 = proto1 == IP_PROTOCOL_UDP;
2084 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2085 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
2090 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2091 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2093 udp0 = ip4_next_header (ip0);
2094 udp1 = ip4_next_header (ip1);
2096 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2097 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2098 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2100 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2101 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
2103 /* Verify UDP length. */
2104 ip_len0 = clib_net_to_host_u16 (ip0->length);
2105 ip_len1 = clib_net_to_host_u16 (ip1->length);
2106 udp_len0 = clib_net_to_host_u16 (udp0->length);
2107 udp_len1 = clib_net_to_host_u16 (udp1->length);
2109 len_diff0 = ip_len0 - udp_len0;
2110 len_diff1 = ip_len1 - udp_len1;
2112 len_diff0 = is_udp0 ? len_diff0 : 0;
2113 len_diff1 = is_udp1 ? len_diff1 : 0;
2115 if (PREDICT_FALSE (! (is_tcp_udp0 & is_tcp_udp1
2116 & good_tcp_udp0 & good_tcp_udp1)))
2121 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2122 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2124 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2125 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2130 && ! (flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2131 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
2133 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2134 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
2138 good_tcp_udp0 &= len_diff0 >= 0;
2139 good_tcp_udp1 &= len_diff1 >= 0;
2141 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2142 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
2144 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
2146 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2147 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
2149 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2150 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2151 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2153 error1 = (is_tcp_udp1 && ! good_tcp_udp1
2154 ? IP4_ERROR_TCP_CHECKSUM + is_udp1
2157 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2158 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
2160 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2161 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2163 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
2164 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
2166 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2168 /* no_default_route */ 1));
2169 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
2171 /* no_default_route */ 1));
2173 adj0 = ip_get_adjacency (lm, adj_index0);
2174 adj1 = ip_get_adjacency (lm, adj_index1);
2177 * Must have a route to source otherwise we drop the packet.
2178 * ip4 broadcasts are accepted, e.g. to make dhcp client work
2180 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2181 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2182 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2183 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2184 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2185 ? IP4_ERROR_SRC_LOOKUP_MISS
2187 error1 = (error1 == IP4_ERROR_UNKNOWN_PROTOCOL
2188 && adj1->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2189 && adj1->lookup_next_index != IP_LOOKUP_NEXT_ARP
2190 && adj1->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2191 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2192 ? IP4_ERROR_SRC_LOOKUP_MISS
2195 next0 = lm->local_next_by_ip_protocol[proto0];
2196 next1 = lm->local_next_by_ip_protocol[proto1];
2198 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2199 next1 = error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
2201 p0->error = error0 ? error_node->errors[error0] : 0;
2202 p1->error = error1 ? error_node->errors[error1] : 0;
2204 enqueue_code = (next0 != next_index) + 2*(next1 != next_index);
2206 if (PREDICT_FALSE (enqueue_code != 0))
2208 switch (enqueue_code)
2214 n_left_to_next += 1;
2215 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2221 n_left_to_next += 1;
2222 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2226 /* A B B or A B C */
2228 n_left_to_next += 2;
2229 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2230 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2233 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2235 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2242 while (n_left_from > 0 && n_left_to_next > 0)
2246 udp_header_t * udp0;
2247 ip4_fib_mtrie_t * mtrie0;
2248 ip4_fib_mtrie_leaf_t leaf0;
2249 ip_adjacency_t * adj0;
2250 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, adj_index0;
2252 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
2254 pi0 = to_next[0] = from[0];
2258 n_left_to_next -= 1;
2260 p0 = vlib_get_buffer (vm, pi0);
2262 ip0 = vlib_buffer_get_current (p0);
2264 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2265 vnet_buffer(p0)->sw_if_index[VLIB_RX]);
2267 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
2269 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2271 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
2273 proto0 = ip0->protocol;
2274 is_udp0 = proto0 == IP_PROTOCOL_UDP;
2275 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
2279 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2281 udp0 = ip4_next_header (ip0);
2283 /* Don't verify UDP checksum for packets with explicit zero checksum. */
2284 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2286 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
2288 /* Verify UDP length. */
2289 ip_len0 = clib_net_to_host_u16 (ip0->length);
2290 udp_len0 = clib_net_to_host_u16 (udp0->length);
2292 len_diff0 = ip_len0 - udp_len0;
2294 len_diff0 = is_udp0 ? len_diff0 : 0;
2296 if (PREDICT_FALSE (! (is_tcp_udp0 & good_tcp_udp0)))
2301 && ! (flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
2302 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
2304 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
2305 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
2309 good_tcp_udp0 &= len_diff0 >= 0;
2311 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
2313 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
2315 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
2317 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
2318 error0 = (is_tcp_udp0 && ! good_tcp_udp0
2319 ? IP4_ERROR_TCP_CHECKSUM + is_udp0
2322 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
2324 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2325 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
2327 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
2329 /* no_default_route */ 1));
2331 adj0 = ip_get_adjacency (lm, adj_index0);
2333 /* Must have a route to source otherwise we drop the packet. */
2334 error0 = (error0 == IP4_ERROR_UNKNOWN_PROTOCOL
2335 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE
2336 && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
2337 && adj0->lookup_next_index != IP_LOOKUP_NEXT_LOCAL
2338 && ip0->dst_address.as_u32 != 0xFFFFFFFF
2339 ? IP4_ERROR_SRC_LOOKUP_MISS
2342 next0 = lm->local_next_by_ip_protocol[proto0];
2344 next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
2346 p0->error = error0? error_node->errors[error0] : 0;
2348 if (PREDICT_FALSE (next0 != next_index))
2350 n_left_to_next += 1;
2351 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2354 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2357 n_left_to_next -= 1;
2361 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2364 return frame->n_vectors;
2367 VLIB_REGISTER_NODE (ip4_local_node,static) = {
2368 .function = ip4_local,
2369 .name = "ip4-local",
2370 .vector_size = sizeof (u32),
2372 .format_trace = format_ip4_forward_next_trace,
2374 .n_next_nodes = IP_LOCAL_N_NEXT,
2376 [IP_LOCAL_NEXT_DROP] = "error-drop",
2377 [IP_LOCAL_NEXT_PUNT] = "error-punt",
2378 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
2379 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
2383 void ip4_register_protocol (u32 protocol, u32 node_index)
2385 vlib_main_t * vm = vlib_get_main();
2386 ip4_main_t * im = &ip4_main;
2387 ip_lookup_main_t * lm = &im->lookup_main;
2389 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
2390 lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index);
2393 static clib_error_t *
2394 show_ip_local_command_fn (vlib_main_t * vm,
2395 unformat_input_t * input,
2396 vlib_cli_command_t * cmd)
2398 ip4_main_t * im = &ip4_main;
2399 ip_lookup_main_t * lm = &im->lookup_main;
2402 vlib_cli_output (vm, "Protocols handled by ip4_local");
2403 for (i = 0; i < ARRAY_LEN(lm->local_next_by_ip_protocol); i++)
2405 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2406 vlib_cli_output (vm, "%d", i);
2413 VLIB_CLI_COMMAND (show_ip_local, static) = {
2414 .path = "show ip local",
2415 .function = show_ip_local_command_fn,
2416 .short_help = "Show ip local protocol table",
2420 ip4_arp (vlib_main_t * vm,
2421 vlib_node_runtime_t * node,
2422 vlib_frame_t * frame)
2424 vnet_main_t * vnm = vnet_get_main();
2425 ip4_main_t * im = &ip4_main;
2426 ip_lookup_main_t * lm = &im->lookup_main;
2427 u32 * from, * to_next_drop;
2428 uword n_left_from, n_left_to_next_drop, next_index;
2429 static f64 time_last_seed_change = -1e100;
2430 static u32 hash_seeds[3];
2431 static uword hash_bitmap[256 / BITS (uword)];
2434 if (node->flags & VLIB_NODE_FLAG_TRACE)
2435 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2437 time_now = vlib_time_now (vm);
2438 if (time_now - time_last_seed_change > 1e-3)
2441 u32 * r = clib_random_buffer_get_data (&vm->random_buffer,
2442 sizeof (hash_seeds));
2443 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2444 hash_seeds[i] = r[i];
2446 /* Mark all hash keys as been no-seen before. */
2447 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2450 time_last_seed_change = time_now;
2453 from = vlib_frame_vector_args (frame);
2454 n_left_from = frame->n_vectors;
2455 next_index = node->cached_next_index;
2456 if (next_index == IP4_ARP_NEXT_DROP)
2457 next_index = IP4_ARP_N_NEXT; /* point to first interface */
2459 while (n_left_from > 0)
2461 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2462 to_next_drop, n_left_to_next_drop);
2464 while (n_left_from > 0 && n_left_to_next_drop > 0)
2468 ethernet_header_t * eh0;
2469 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
2471 ip_adjacency_t * adj0;
2475 p0 = vlib_get_buffer (vm, pi0);
2477 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2478 adj0 = ip_get_adjacency (lm, adj_index0);
2479 ip0 = vlib_buffer_get_current (p0);
2482 * if ip4_rewrite_local applied the IP_LOOKUP_NEXT_ARP
2483 * rewrite to this packet, we need to skip it here.
2484 * Note, to distinguish from src IP addr *.8.6.*, we
2485 * check for a bcast eth dest instead of IPv4 version.
2487 eh0 = (ethernet_header_t*)ip0;
2488 if ((ip0->ip_version_and_header_length & 0xF0) != 0x40)
2491 u16 * etype = &eh0->type;
2492 while ((*etype == clib_host_to_net_u16 (0x8100)) //dot1q
2493 || (*etype == clib_host_to_net_u16 (0x88a8)))//dot1ad
2496 etype += 2; //vlan tag also 16 bits, same as etype
2498 if (*etype == clib_host_to_net_u16 (0x0806)) //arp
2500 vlib_buffer_advance (
2501 p0, sizeof(ethernet_header_t) + (4*vlan_num));
2502 ip0 = vlib_buffer_get_current (p0);
2510 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2511 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2513 a0 ^= ip0->dst_address.data_u32;
2516 hash_v3_finalize32 (a0, b0, c0);
2518 c0 &= BITS (hash_bitmap) - 1;
2519 c0 = c0 / BITS (uword);
2520 m0 = (uword) 1 << (c0 % BITS (uword));
2522 bm0 = hash_bitmap[c0];
2523 drop0 = (bm0 & m0) != 0;
2525 /* Mark it as seen. */
2526 hash_bitmap[c0] = bm0 | m0;
2530 to_next_drop[0] = pi0;
2532 n_left_to_next_drop -= 1;
2534 p0->error = node->errors[drop0 ? IP4_ARP_ERROR_DROP : IP4_ARP_ERROR_REQUEST_SENT];
2540 * Can happen if the control-plane is programming tables
2541 * with traffic flowing; at least that's today's lame excuse.
2543 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
2545 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2548 /* Send ARP request. */
2552 ethernet_arp_header_t * h0;
2553 vnet_hw_interface_t * hw_if0;
2555 h0 = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi0);
2557 /* Add rewrite/encap string for ARP packet. */
2558 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2560 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2562 /* Src ethernet address in ARP header. */
2563 memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address,
2564 sizeof (h0->ip4_over_ethernet[0].ethernet));
2566 ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0);
2568 /* Copy in destination address we are requesting. */
2569 h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32;
2571 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2572 b0 = vlib_get_buffer (vm, bi0);
2573 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2575 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2577 vlib_set_next_frame_buffer (vm, node, adj0->rewrite_header.next_index, bi0);
2581 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2584 return frame->n_vectors;
2587 static char * ip4_arp_error_strings[] = {
2588 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2589 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2590 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2591 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2592 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2595 VLIB_REGISTER_NODE (ip4_arp_node) = {
2596 .function = ip4_arp,
2598 .vector_size = sizeof (u32),
2600 .format_trace = format_ip4_forward_next_trace,
2602 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2603 .error_strings = ip4_arp_error_strings,
2605 .n_next_nodes = IP4_ARP_N_NEXT,
2607 [IP4_ARP_NEXT_DROP] = "error-drop",
2611 #define foreach_notrace_ip4_arp_error \
2617 clib_error_t * arp_notrace_init (vlib_main_t * vm)
2619 vlib_node_runtime_t *rt =
2620 vlib_node_get_runtime (vm, ip4_arp_node.index);
2622 /* don't trace ARP request packets */
2624 vnet_pcap_drop_trace_filter_add_del \
2625 (rt->errors[IP4_ARP_ERROR_##a], \
2627 foreach_notrace_ip4_arp_error;
2632 VLIB_INIT_FUNCTION(arp_notrace_init);
2635 /* Send an ARP request to see if given destination is reachable on given interface. */
2637 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2639 vnet_main_t * vnm = vnet_get_main();
2640 ip4_main_t * im = &ip4_main;
2641 ethernet_arp_header_t * h;
2642 ip4_address_t * src;
2643 ip_interface_address_t * ia;
2644 ip_adjacency_t * adj;
2645 vnet_hw_interface_t * hi;
2646 vnet_sw_interface_t * si;
2650 si = vnet_get_sw_interface (vnm, sw_if_index);
2652 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2654 return clib_error_return (0, "%U: interface %U down",
2655 format_ip4_address, dst,
2656 format_vnet_sw_if_index_name, vnm,
2660 src = ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2663 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2664 return clib_error_return
2665 (0, "no matching interface address for destination %U (interface %U)",
2666 format_ip4_address, dst,
2667 format_vnet_sw_if_index_name, vnm, sw_if_index);
2670 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2672 h = vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template, &bi);
2674 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2676 memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
2678 h->ip4_over_ethernet[0].ip4 = src[0];
2679 h->ip4_over_ethernet[1].ip4 = dst[0];
2681 b = vlib_get_buffer (vm, bi);
2682 vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2684 /* Add encapsulation string for software interface (e.g. ethernet header). */
2685 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2686 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2689 vlib_frame_t * f = vlib_get_frame_to_node (vm, hi->output_node_index);
2690 u32 * to_next = vlib_frame_vector_args (f);
2693 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2696 return /* no error */ 0;
2700 IP4_REWRITE_NEXT_DROP,
2701 IP4_REWRITE_NEXT_ARP,
2702 } ip4_rewrite_next_t;
2705 ip4_rewrite_inline (vlib_main_t * vm,
2706 vlib_node_runtime_t * node,
2707 vlib_frame_t * frame,
2708 int rewrite_for_locally_received_packets)
2710 ip_lookup_main_t * lm = &ip4_main.lookup_main;
2711 u32 * from = vlib_frame_vector_args (frame);
2712 u32 n_left_from, n_left_to_next, * to_next, next_index;
2713 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
2714 vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
2716 n_left_from = frame->n_vectors;
2717 next_index = node->cached_next_index;
2718 u32 cpu_index = os_get_cpu_number();
2720 while (n_left_from > 0)
2722 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2724 while (n_left_from >= 4 && n_left_to_next >= 2)
2726 ip_adjacency_t * adj0, * adj1;
2727 vlib_buffer_t * p0, * p1;
2728 ip4_header_t * ip0, * ip1;
2729 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2730 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2731 u32 next0_override, next1_override;
2733 if (rewrite_for_locally_received_packets)
2734 next0_override = next1_override = 0;
2736 /* Prefetch next iteration. */
2738 vlib_buffer_t * p2, * p3;
2740 p2 = vlib_get_buffer (vm, from[2]);
2741 p3 = vlib_get_buffer (vm, from[3]);
2743 vlib_prefetch_buffer_header (p2, STORE);
2744 vlib_prefetch_buffer_header (p3, STORE);
2746 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2747 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2750 pi0 = to_next[0] = from[0];
2751 pi1 = to_next[1] = from[1];
2756 n_left_to_next -= 2;
2758 p0 = vlib_get_buffer (vm, pi0);
2759 p1 = vlib_get_buffer (vm, pi1);
2761 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2762 adj_index1 = vnet_buffer (p1)->ip.adj_index[adj_rx_tx];
2764 /* We should never rewrite a pkt using the MISS adjacency */
2765 ASSERT(adj_index0 && adj_index1);
2767 ip0 = vlib_buffer_get_current (p0);
2768 ip1 = vlib_buffer_get_current (p1);
2770 error0 = error1 = IP4_ERROR_NONE;
2772 /* Decrement TTL & update checksum.
2773 Works either endian, so no need for byte swap. */
2774 if (! rewrite_for_locally_received_packets)
2776 i32 ttl0 = ip0->ttl, ttl1 = ip1->ttl;
2778 /* Input node should have reject packets with ttl 0. */
2779 ASSERT (ip0->ttl > 0);
2780 ASSERT (ip1->ttl > 0);
2782 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2783 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2785 checksum0 += checksum0 >= 0xffff;
2786 checksum1 += checksum1 >= 0xffff;
2788 ip0->checksum = checksum0;
2789 ip1->checksum = checksum1;
2797 error0 = ttl0 <= 0 ? IP4_ERROR_TIME_EXPIRED : error0;
2798 error1 = ttl1 <= 0 ? IP4_ERROR_TIME_EXPIRED : error1;
2800 /* Verify checksum. */
2801 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2802 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2805 /* Rewrite packet header and updates lengths. */
2806 adj0 = ip_get_adjacency (lm, adj_index0);
2807 adj1 = ip_get_adjacency (lm, adj_index1);
2809 if (rewrite_for_locally_received_packets)
2812 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2813 * we end up here with a local adjacency in hand
2814 * The local adj rewrite data is 0xfefe on purpose.
2815 * Bad engineer, no donut for you.
2817 if (PREDICT_FALSE(adj0->lookup_next_index
2818 == IP_LOOKUP_NEXT_LOCAL))
2819 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2820 if (PREDICT_FALSE(adj0->lookup_next_index
2821 == IP_LOOKUP_NEXT_ARP))
2822 next0_override = IP4_REWRITE_NEXT_ARP;
2823 if (PREDICT_FALSE(adj1->lookup_next_index
2824 == IP_LOOKUP_NEXT_LOCAL))
2825 error1 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2826 if (PREDICT_FALSE(adj1->lookup_next_index
2827 == IP_LOOKUP_NEXT_ARP))
2828 next1_override = IP4_REWRITE_NEXT_ARP;
2831 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2832 rw_len0 = adj0[0].rewrite_header.data_bytes;
2833 rw_len1 = adj1[0].rewrite_header.data_bytes;
2834 next0 = (error0 == IP4_ERROR_NONE)
2835 ? adj0[0].rewrite_header.next_index : 0;
2837 if (rewrite_for_locally_received_packets)
2838 next0 = next0 && next0_override ? next0_override : next0;
2840 next1 = (error1 == IP4_ERROR_NONE)
2841 ? adj1[0].rewrite_header.next_index : 0;
2843 if (rewrite_for_locally_received_packets)
2844 next1 = next1 && next1_override ? next1_override : next1;
2847 * We've already accounted for an ethernet_header_t elsewhere
2849 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2850 vlib_increment_combined_counter
2851 (&lm->adjacency_counters,
2852 cpu_index, adj_index0,
2853 /* packet increment */ 0,
2854 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2856 if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
2857 vlib_increment_combined_counter
2858 (&lm->adjacency_counters,
2859 cpu_index, adj_index1,
2860 /* packet increment */ 0,
2861 /* byte increment */ rw_len1-sizeof(ethernet_header_t));
2863 /* Check MTU of outgoing interface. */
2864 error0 = (vlib_buffer_length_in_chain (vm, p0) > adj0[0].rewrite_header.max_l3_packet_bytes
2865 ? IP4_ERROR_MTU_EXCEEDED
2867 error1 = (vlib_buffer_length_in_chain (vm, p1) > adj1[0].rewrite_header.max_l3_packet_bytes
2868 ? IP4_ERROR_MTU_EXCEEDED
2871 p0->current_data -= rw_len0;
2872 p1->current_data -= rw_len1;
2874 p0->current_length += rw_len0;
2875 p1->current_length += rw_len1;
2877 vnet_buffer (p0)->sw_if_index[VLIB_TX] = adj0[0].rewrite_header.sw_if_index;
2878 vnet_buffer (p1)->sw_if_index[VLIB_TX] = adj1[0].rewrite_header.sw_if_index;
2880 p0->error = error_node->errors[error0];
2881 p1->error = error_node->errors[error1];
2883 /* Guess we are only writing on simple Ethernet header. */
2884 vnet_rewrite_two_headers (adj0[0], adj1[0],
2886 sizeof (ethernet_header_t));
2888 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2889 to_next, n_left_to_next,
2890 pi0, pi1, next0, next1);
2893 while (n_left_from > 0 && n_left_to_next > 0)
2895 ip_adjacency_t * adj0;
2898 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2901 if (rewrite_for_locally_received_packets)
2904 pi0 = to_next[0] = from[0];
2906 p0 = vlib_get_buffer (vm, pi0);
2908 adj_index0 = vnet_buffer (p0)->ip.adj_index[adj_rx_tx];
2910 /* We should never rewrite a pkt using the MISS adjacency */
2913 adj0 = ip_get_adjacency (lm, adj_index0);
2915 ip0 = vlib_buffer_get_current (p0);
2917 error0 = IP4_ERROR_NONE;
2918 next0 = 0; /* drop on error */
2920 /* Decrement TTL & update checksum. */
2921 if (! rewrite_for_locally_received_packets)
2923 i32 ttl0 = ip0->ttl;
2925 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2927 checksum0 += checksum0 >= 0xffff;
2929 ip0->checksum = checksum0;
2931 ASSERT (ip0->ttl > 0);
2937 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2939 error0 = ttl0 <= 0 ? IP4_ERROR_TIME_EXPIRED : error0;
2942 if (rewrite_for_locally_received_packets)
2945 * If someone sends e.g. an icmp4 w/ src = dst = interface addr,
2946 * we end up here with a local adjacency in hand
2947 * The local adj rewrite data is 0xfefe on purpose.
2948 * Bad engineer, no donut for you.
2950 if (PREDICT_FALSE(adj0->lookup_next_index
2951 == IP_LOOKUP_NEXT_LOCAL))
2952 error0 = IP4_ERROR_SPOOFED_LOCAL_PACKETS;
2954 * We have to override the next_index in ARP adjacencies,
2955 * because they're set up for ip4-arp, not this node...
2957 if (PREDICT_FALSE(adj0->lookup_next_index
2958 == IP_LOOKUP_NEXT_ARP))
2959 next0_override = IP4_REWRITE_NEXT_ARP;
2962 /* Guess we are only writing on simple Ethernet header. */
2963 vnet_rewrite_one_header (adj0[0], ip0,
2964 sizeof (ethernet_header_t));
2966 /* Update packet buffer attributes/set output interface. */
2967 rw_len0 = adj0[0].rewrite_header.data_bytes;
2969 if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
2970 vlib_increment_combined_counter
2971 (&lm->adjacency_counters,
2972 cpu_index, adj_index0,
2973 /* packet increment */ 0,
2974 /* byte increment */ rw_len0-sizeof(ethernet_header_t));
2976 /* Check MTU of outgoing interface. */
2977 error0 = (vlib_buffer_length_in_chain (vm, p0)
2978 > adj0[0].rewrite_header.max_l3_packet_bytes
2979 ? IP4_ERROR_MTU_EXCEEDED
2982 p0->error = error_node->errors[error0];
2983 p0->current_data -= rw_len0;
2984 p0->current_length += rw_len0;
2985 vnet_buffer (p0)->sw_if_index[VLIB_TX] =
2986 adj0[0].rewrite_header.sw_if_index;
2988 next0 = (error0 == IP4_ERROR_NONE)
2989 ? adj0[0].rewrite_header.next_index : 0;
2991 if (rewrite_for_locally_received_packets)
2992 next0 = next0 && next0_override ? next0_override : next0;
2997 n_left_to_next -= 1;
2999 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3000 to_next, n_left_to_next,
3004 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3007 /* Need to do trace after rewrites to pick up new packet data. */
3008 if (node->flags & VLIB_NODE_FLAG_TRACE)
3009 ip4_forward_next_trace (vm, node, frame, adj_rx_tx);
3011 return frame->n_vectors;
3015 ip4_rewrite_transit (vlib_main_t * vm,
3016 vlib_node_runtime_t * node,
3017 vlib_frame_t * frame)
3019 return ip4_rewrite_inline (vm, node, frame,
3020 /* rewrite_for_locally_received_packets */ 0);
3024 ip4_rewrite_local (vlib_main_t * vm,
3025 vlib_node_runtime_t * node,
3026 vlib_frame_t * frame)
3028 return ip4_rewrite_inline (vm, node, frame,
3029 /* rewrite_for_locally_received_packets */ 1);
3032 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
3033 .function = ip4_rewrite_transit,
3034 .name = "ip4-rewrite-transit",
3035 .vector_size = sizeof (u32),
3037 .format_trace = format_ip4_forward_next_trace,
3041 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3042 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3046 VLIB_REGISTER_NODE (ip4_rewrite_local_node,static) = {
3047 .function = ip4_rewrite_local,
3048 .name = "ip4-rewrite-local",
3049 .vector_size = sizeof (u32),
3051 .sibling_of = "ip4-rewrite-transit",
3053 .format_trace = format_ip4_forward_next_trace,
3057 [IP4_REWRITE_NEXT_DROP] = "error-drop",
3058 [IP4_REWRITE_NEXT_ARP] = "ip4-arp",
3062 static clib_error_t *
3063 add_del_interface_table (vlib_main_t * vm,
3064 unformat_input_t * input,
3065 vlib_cli_command_t * cmd)
3067 vnet_main_t * vnm = vnet_get_main();
3068 clib_error_t * error = 0;
3069 u32 sw_if_index, table_id;
3073 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3075 error = clib_error_return (0, "unknown interface `%U'",
3076 format_unformat_error, input);
3080 if (unformat (input, "%d", &table_id))
3084 error = clib_error_return (0, "expected table id `%U'",
3085 format_unformat_error, input);
3090 ip4_main_t * im = &ip4_main;
3091 ip4_fib_t * fib = find_ip4_fib_by_table_index_or_id (im, table_id, IP4_ROUTE_FLAG_TABLE_ID);
3095 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
3096 im->fib_index_by_sw_if_index[sw_if_index] = fib->index;
3104 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
3105 .path = "set interface ip table",
3106 .function = add_del_interface_table,
3107 .short_help = "Add/delete FIB table id for interface",
3112 ip4_lookup_multicast (vlib_main_t * vm,
3113 vlib_node_runtime_t * node,
3114 vlib_frame_t * frame)
3116 ip4_main_t * im = &ip4_main;
3117 ip_lookup_main_t * lm = &im->lookup_main;
3118 vlib_combined_counter_main_t * cm = &im->lookup_main.adjacency_counters;
3119 u32 n_left_from, n_left_to_next, * from, * to_next;
3120 ip_lookup_next_t next;
3121 u32 cpu_index = os_get_cpu_number();
3123 from = vlib_frame_vector_args (frame);
3124 n_left_from = frame->n_vectors;
3125 next = node->cached_next_index;
3127 while (n_left_from > 0)
3129 vlib_get_next_frame (vm, node, next,
3130 to_next, n_left_to_next);
3132 while (n_left_from >= 4 && n_left_to_next >= 2)
3134 vlib_buffer_t * p0, * p1;
3135 u32 pi0, pi1, adj_index0, adj_index1, wrong_next;
3136 ip_lookup_next_t next0, next1;
3137 ip4_header_t * ip0, * ip1;
3138 ip_adjacency_t * adj0, * adj1;
3139 u32 fib_index0, fib_index1;
3140 u32 flow_hash_config0, flow_hash_config1;
3142 /* Prefetch next iteration. */
3144 vlib_buffer_t * p2, * p3;
3146 p2 = vlib_get_buffer (vm, from[2]);
3147 p3 = vlib_get_buffer (vm, from[3]);
3149 vlib_prefetch_buffer_header (p2, LOAD);
3150 vlib_prefetch_buffer_header (p3, LOAD);
3152 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
3153 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
3156 pi0 = to_next[0] = from[0];
3157 pi1 = to_next[1] = from[1];
3159 p0 = vlib_get_buffer (vm, pi0);
3160 p1 = vlib_get_buffer (vm, pi1);
3162 ip0 = vlib_buffer_get_current (p0);
3163 ip1 = vlib_buffer_get_current (p1);
3165 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3166 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (p1)->sw_if_index[VLIB_RX]);
3167 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3168 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3169 fib_index1 = (vnet_buffer(p1)->sw_if_index[VLIB_TX] == (u32)~0) ?
3170 fib_index1 : vnet_buffer(p1)->sw_if_index[VLIB_TX];
3172 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3173 &ip0->dst_address, p0);
3174 adj_index1 = ip4_fib_lookup_buffer (im, fib_index1,
3175 &ip1->dst_address, p1);
3177 adj0 = ip_get_adjacency (lm, adj_index0);
3178 adj1 = ip_get_adjacency (lm, adj_index1);
3180 next0 = adj0->lookup_next_index;
3181 next1 = adj1->lookup_next_index;
3184 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3187 vec_elt_at_index (im->fibs, fib_index1)->flow_hash_config;
3189 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
3190 (ip0, flow_hash_config0);
3192 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
3193 (ip1, flow_hash_config1);
3195 ASSERT (adj0->n_adj > 0);
3196 ASSERT (adj1->n_adj > 0);
3197 ASSERT (is_pow2 (adj0->n_adj));
3198 ASSERT (is_pow2 (adj1->n_adj));
3199 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3200 adj_index1 += (vnet_buffer (p1)->ip.flow_hash & (adj1->n_adj - 1));
3202 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3203 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = adj_index1;
3205 if (1) /* $$$$$$ HACK FIXME */
3206 vlib_increment_combined_counter
3207 (cm, cpu_index, adj_index0, 1,
3208 vlib_buffer_length_in_chain (vm, p0));
3209 if (1) /* $$$$$$ HACK FIXME */
3210 vlib_increment_combined_counter
3211 (cm, cpu_index, adj_index1, 1,
3212 vlib_buffer_length_in_chain (vm, p1));
3216 n_left_to_next -= 2;
3219 wrong_next = (next0 != next) + 2*(next1 != next);
3220 if (PREDICT_FALSE (wrong_next != 0))
3228 n_left_to_next += 1;
3229 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3235 n_left_to_next += 1;
3236 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3242 n_left_to_next += 2;
3243 vlib_set_next_frame_buffer (vm, node, next0, pi0);
3244 vlib_set_next_frame_buffer (vm, node, next1, pi1);
3248 vlib_put_next_frame (vm, node, next, n_left_to_next);
3250 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
3256 while (n_left_from > 0 && n_left_to_next > 0)
3260 u32 pi0, adj_index0;
3261 ip_lookup_next_t next0;
3262 ip_adjacency_t * adj0;
3264 u32 flow_hash_config0;
3269 p0 = vlib_get_buffer (vm, pi0);
3271 ip0 = vlib_buffer_get_current (p0);
3273 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
3274 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
3275 fib_index0 = (vnet_buffer(p0)->sw_if_index[VLIB_TX] == (u32)~0) ?
3276 fib_index0 : vnet_buffer(p0)->sw_if_index[VLIB_TX];
3278 adj_index0 = ip4_fib_lookup_buffer (im, fib_index0,
3279 &ip0->dst_address, p0);
3281 adj0 = ip_get_adjacency (lm, adj_index0);
3283 next0 = adj0->lookup_next_index;
3286 vec_elt_at_index (im->fibs, fib_index0)->flow_hash_config;
3288 vnet_buffer (p0)->ip.flow_hash =
3289 ip4_compute_flow_hash (ip0, flow_hash_config0);
3291 ASSERT (adj0->n_adj > 0);
3292 ASSERT (is_pow2 (adj0->n_adj));
3293 adj_index0 += (vnet_buffer (p0)->ip.flow_hash & (adj0->n_adj - 1));
3295 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
3297 if (1) /* $$$$$$ HACK FIXME */
3298 vlib_increment_combined_counter
3299 (cm, cpu_index, adj_index0, 1,
3300 vlib_buffer_length_in_chain (vm, p0));
3304 n_left_to_next -= 1;
3307 if (PREDICT_FALSE (next0 != next))
3309 n_left_to_next += 1;
3310 vlib_put_next_frame (vm, node, next, n_left_to_next);
3312 vlib_get_next_frame (vm, node, next,
3313 to_next, n_left_to_next);
3316 n_left_to_next -= 1;
3320 vlib_put_next_frame (vm, node, next, n_left_to_next);
3323 return frame->n_vectors;
3326 VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
3327 .function = ip4_lookup_multicast,
3328 .name = "ip4-lookup-multicast",
3329 .vector_size = sizeof (u32),
3331 .n_next_nodes = IP_LOOKUP_N_NEXT,
3333 [IP_LOOKUP_NEXT_MISS] = "ip4-miss",
3334 [IP_LOOKUP_NEXT_DROP] = "ip4-drop",
3335 [IP_LOOKUP_NEXT_PUNT] = "ip4-punt",
3336 [IP_LOOKUP_NEXT_LOCAL] = "ip4-local",
3337 [IP_LOOKUP_NEXT_ARP] = "ip4-arp",
3338 [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite-transit",
3339 [IP_LOOKUP_NEXT_CLASSIFY] = "ip4-classify",
3340 [IP_LOOKUP_NEXT_MAP] = "ip4-map",
3341 [IP_LOOKUP_NEXT_MAP_T] = "ip4-map-t",
3342 [IP_LOOKUP_NEXT_SIXRD] = "ip4-sixrd",
3343 [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip4-hop-by-hop",
3344 [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip4-add-hop-by-hop",
3345 [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip4-pop-hop-by-hop",
3349 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
3350 .function = ip4_drop,
3351 .name = "ip4-multicast",
3352 .vector_size = sizeof (u32),
3354 .format_trace = format_ip4_forward_next_trace,
3362 int ip4_lookup_validate (ip4_address_t *a, u32 fib_index0)
3364 ip4_main_t * im = &ip4_main;
3365 ip4_fib_mtrie_t * mtrie0;
3366 ip4_fib_mtrie_leaf_t leaf0;
3369 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
3371 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
3372 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
3373 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
3374 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
3375 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
3377 /* Handle default route. */
3378 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
3380 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
3382 return adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
3384 /* no_default_route */ 0);
3387 static clib_error_t *
3388 test_lookup_command_fn (vlib_main_t * vm,
3389 unformat_input_t * input,
3390 vlib_cli_command_t * cmd)
3396 ip4_address_t ip4_base_address;
3399 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3400 if (unformat (input, "table %d", &table_id))
3402 else if (unformat (input, "count %f", &count))
3405 else if (unformat (input, "%U",
3406 unformat_ip4_address, &ip4_base_address))
3409 return clib_error_return (0, "unknown input `%U'",
3410 format_unformat_error, input);
3415 for (i = 0; i < n; i++)
3417 if (!ip4_lookup_validate (&ip4_base_address, table_id))
3420 ip4_base_address.as_u32 =
3421 clib_host_to_net_u32 (1 +
3422 clib_net_to_host_u32 (ip4_base_address.as_u32));
3426 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3428 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3433 VLIB_CLI_COMMAND (lookup_test_command, static) = {
3434 .path = "test lookup",
3435 .short_help = "test lookup",
3436 .function = test_lookup_command_fn,
3439 int vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3441 ip4_main_t * im4 = &ip4_main;
3443 uword * p = hash_get (im4->fib_index_by_table_id, table_id);
3446 return VNET_API_ERROR_NO_SUCH_FIB;
3448 fib = vec_elt_at_index (im4->fibs, p[0]);
3450 fib->flow_hash_config = flow_hash_config;
3454 static clib_error_t *
3455 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3456 unformat_input_t * input,
3457 vlib_cli_command_t * cmd)
3461 u32 flow_hash_config = 0;
3464 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3465 if (unformat (input, "table %d", &table_id))
3468 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3469 foreach_flow_hash_bit
3475 return clib_error_return (0, "unknown input `%U'",
3476 format_unformat_error, input);
3478 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3484 case VNET_API_ERROR_NO_SUCH_FIB:
3485 return clib_error_return (0, "no such FIB table %d", table_id);
3488 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3495 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
3496 .path = "set ip flow-hash",
3498 "set ip table flow-hash table <fib-id> src dst sport dport proto reverse",
3499 .function = set_ip_flow_hash_command_fn,
3502 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3505 vnet_main_t * vnm = vnet_get_main();
3506 vnet_interface_main_t * im = &vnm->interface_main;
3507 ip4_main_t * ipm = &ip4_main;
3508 ip_lookup_main_t * lm = &ipm->lookup_main;
3509 vnet_classify_main_t * cm = &vnet_classify_main;
3511 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3512 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3514 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3515 return VNET_API_ERROR_NO_SUCH_ENTRY;
3517 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3518 lm->classify_table_index_by_sw_if_index [sw_if_index] = table_index;
3523 static clib_error_t *
3524 set_ip_classify_command_fn (vlib_main_t * vm,
3525 unformat_input_t * input,
3526 vlib_cli_command_t * cmd)
3528 u32 table_index = ~0;
3529 int table_index_set = 0;
3530 u32 sw_if_index = ~0;
3533 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
3534 if (unformat (input, "table-index %d", &table_index))
3535 table_index_set = 1;
3536 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3537 vnet_get_main(), &sw_if_index))
3543 if (table_index_set == 0)
3544 return clib_error_return (0, "classify table-index must be specified");
3546 if (sw_if_index == ~0)
3547 return clib_error_return (0, "interface / subif must be specified");
3549 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3556 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3557 return clib_error_return (0, "No such interface");
3559 case VNET_API_ERROR_NO_SUCH_ENTRY:
3560 return clib_error_return (0, "No such classifier table");
3565 VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
3566 .path = "set ip classify",
3568 "set ip classify intfc <int> table-index <index>",
3569 .function = set_ip_classify_command_fn,