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/ip/ip_frag.h>
43 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44 #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
45 #include <vnet/ppp/ppp.h>
46 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
47 #include <vnet/api_errno.h> /* for API error numbers */
48 #include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
49 #include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
50 #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
51 #include <vnet/fib/ip4_fib.h>
52 #include <vnet/mfib/ip4_mfib.h>
53 #include <vnet/dpo/load_balance.h>
54 #include <vnet/dpo/load_balance_map.h>
55 #include <vnet/dpo/classify_dpo.h>
56 #include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
57 #include <vnet/adj/adj_dp.h>
59 #include <vnet/ip/ip4_forward.h>
60 #include <vnet/interface_output.h>
61 #include <vnet/classify/vnet_classify.h>
63 /** @brief IPv4 lookup node.
66 This is the main IPv4 lookup dispatch node.
68 @param vm vlib_main_t corresponding to the current thread
69 @param node vlib_node_runtime_t
70 @param frame vlib_frame_t whose contents should be dispatched
72 @par Graph mechanics: buffer metadata, next index usage
75 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
76 - Indicates the @c sw_if_index value of the interface that the
77 packet was received on.
78 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
79 - When the value is @c ~0 then the node performs a longest prefix
80 match (LPM) for the packet destination address in the FIB attached
81 to the receive interface.
82 - Otherwise perform LPM for the packet destination address in the
83 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
84 value (0, 1, ...) and not a VRF id.
87 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
88 - The lookup result adjacency index.
91 - Dispatches the packet to the node index found in
92 ip_adjacency_t @c adj->lookup_next_index
93 (where @c adj is the lookup result adjacency).
95 VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
98 return ip4_lookup_inline (vm, node, frame);
101 static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
104 VLIB_REGISTER_NODE (ip4_lookup_node) =
106 .name = "ip4-lookup",
107 .vector_size = sizeof (u32),
108 .format_trace = format_ip4_lookup_trace,
109 .n_next_nodes = IP_LOOKUP_N_NEXT,
110 .next_nodes = IP4_LOOKUP_NEXT_NODES,
114 VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
115 vlib_node_runtime_t * node,
116 vlib_frame_t * frame)
118 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
120 u32 thread_index = vm->thread_index;
121 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
122 u16 nexts[VLIB_FRAME_SIZE], *next;
124 from = vlib_frame_vector_args (frame);
125 n_left = frame->n_vectors;
128 vlib_get_buffers (vm, from, bufs, n_left);
132 const load_balance_t *lb0, *lb1;
133 const ip4_header_t *ip0, *ip1;
134 u32 lbi0, hc0, lbi1, hc1;
135 const dpo_id_t *dpo0, *dpo1;
137 /* Prefetch next iteration. */
139 vlib_prefetch_buffer_header (b[2], LOAD);
140 vlib_prefetch_buffer_header (b[3], LOAD);
142 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
143 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
146 ip0 = vlib_buffer_get_current (b[0]);
147 ip1 = vlib_buffer_get_current (b[1]);
148 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
149 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
151 lb0 = load_balance_get (lbi0);
152 lb1 = load_balance_get (lbi1);
155 * this node is for via FIBs we can re-use the hash value from the
156 * to node if present.
157 * We don't want to use the same hash value at each level in the recursion
158 * graph as that would lead to polarisation
162 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
164 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
166 hc0 = vnet_buffer (b[0])->ip.flow_hash =
167 vnet_buffer (b[0])->ip.flow_hash >> 1;
171 hc0 = vnet_buffer (b[0])->ip.flow_hash =
172 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
174 dpo0 = load_balance_get_fwd_bucket
175 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
179 dpo0 = load_balance_get_bucket_i (lb0, 0);
181 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
183 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
185 hc1 = vnet_buffer (b[1])->ip.flow_hash =
186 vnet_buffer (b[1])->ip.flow_hash >> 1;
190 hc1 = vnet_buffer (b[1])->ip.flow_hash =
191 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
193 dpo1 = load_balance_get_fwd_bucket
194 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
198 dpo1 = load_balance_get_bucket_i (lb1, 0);
201 next[0] = dpo0->dpoi_next_node;
202 next[1] = dpo1->dpoi_next_node;
204 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
205 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
207 vlib_increment_combined_counter
208 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
209 vlib_increment_combined_counter
210 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
219 const load_balance_t *lb0;
220 const ip4_header_t *ip0;
221 const dpo_id_t *dpo0;
224 ip0 = vlib_buffer_get_current (b[0]);
225 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
227 lb0 = load_balance_get (lbi0);
230 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
232 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
234 hc0 = vnet_buffer (b[0])->ip.flow_hash =
235 vnet_buffer (b[0])->ip.flow_hash >> 1;
239 hc0 = vnet_buffer (b[0])->ip.flow_hash =
240 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
242 dpo0 = load_balance_get_fwd_bucket
243 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
247 dpo0 = load_balance_get_bucket_i (lb0, 0);
250 next[0] = dpo0->dpoi_next_node;
251 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
253 vlib_increment_combined_counter
254 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
261 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
262 if (node->flags & VLIB_NODE_FLAG_TRACE)
263 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
265 return frame->n_vectors;
269 VLIB_REGISTER_NODE (ip4_load_balance_node) =
271 .name = "ip4-load-balance",
272 .vector_size = sizeof (u32),
273 .sibling_of = "ip4-lookup",
274 .format_trace = format_ip4_lookup_trace,
278 #ifndef CLIB_MARCH_VARIANT
279 /* get first interface address */
281 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
282 ip_interface_address_t ** result_ia)
284 ip_lookup_main_t *lm = &im->lookup_main;
285 ip_interface_address_t *ia = 0;
286 ip4_address_t *result = 0;
289 foreach_ip_interface_address
290 (lm, ia, sw_if_index,
291 1 /* honor unnumbered */ ,
294 ip_interface_address_get_address (lm, ia);
300 *result_ia = result ? ia : 0;
306 ip4_add_subnet_bcast_route (u32 fib_index,
310 vnet_sw_interface_flags_t iflags;
312 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
314 fib_table_entry_special_remove(fib_index,
316 FIB_SOURCE_INTERFACE);
318 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
320 fib_table_entry_update_one_path (fib_index, pfx,
321 FIB_SOURCE_INTERFACE,
324 /* No next-hop address */
330 // no out-label stack
332 FIB_ROUTE_PATH_FLAG_NONE);
336 fib_table_entry_special_add(fib_index,
338 FIB_SOURCE_INTERFACE,
339 (FIB_ENTRY_FLAG_DROP |
340 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
345 ip4_add_interface_prefix_routes (ip4_main_t *im,
348 ip_interface_address_t * a)
350 ip_lookup_main_t *lm = &im->lookup_main;
351 ip_interface_prefix_t *if_prefix;
352 ip4_address_t *address = ip_interface_address_get_address (lm, a);
354 ip_interface_prefix_key_t key = {
356 .fp_len = a->address_length,
357 .fp_proto = FIB_PROTOCOL_IP4,
358 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
360 .sw_if_index = sw_if_index,
363 fib_prefix_t pfx_special = {
364 .fp_proto = FIB_PROTOCOL_IP4,
367 /* If prefix already set on interface, just increment ref count & return */
368 if_prefix = ip_get_interface_prefix (lm, &key);
371 if_prefix->ref_count += 1;
375 /* New prefix - allocate a pool entry, initialize it, add to the hash */
376 pool_get (lm->if_prefix_pool, if_prefix);
377 if_prefix->ref_count = 1;
378 if_prefix->src_ia_index = a - lm->if_address_pool;
379 clib_memcpy (&if_prefix->key, &key, sizeof (key));
380 mhash_set (&lm->prefix_to_if_prefix_index, &key,
381 if_prefix - lm->if_prefix_pool, 0 /* old value */);
383 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
384 if (a->address_length <= 30)
386 pfx_special.fp_len = a->address_length;
387 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
389 /* set the glean route for the prefix */
390 fib_table_entry_update_one_path (fib_index, &pfx_special,
391 FIB_SOURCE_INTERFACE,
392 (FIB_ENTRY_FLAG_CONNECTED |
393 FIB_ENTRY_FLAG_ATTACHED),
395 /* No next-hop address */
398 /* invalid FIB index */
401 /* no out-label stack */
403 FIB_ROUTE_PATH_FLAG_NONE);
405 /* set a drop route for the base address of the prefix */
406 pfx_special.fp_len = 32;
407 pfx_special.fp_addr.ip4.as_u32 =
408 address->as_u32 & im->fib_masks[a->address_length];
410 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
411 fib_table_entry_special_add (fib_index, &pfx_special,
412 FIB_SOURCE_INTERFACE,
413 (FIB_ENTRY_FLAG_DROP |
414 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
416 /* set a route for the broadcast address of the prefix */
417 pfx_special.fp_len = 32;
418 pfx_special.fp_addr.ip4.as_u32 =
419 address->as_u32 | ~im->fib_masks[a->address_length];
420 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
421 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
425 /* length == 31 - add an attached route for the other address */
426 else if (a->address_length == 31)
428 pfx_special.fp_len = 32;
429 pfx_special.fp_addr.ip4.as_u32 =
430 address->as_u32 ^ clib_host_to_net_u32(1);
432 fib_table_entry_update_one_path (fib_index, &pfx_special,
433 FIB_SOURCE_INTERFACE,
434 (FIB_ENTRY_FLAG_ATTACHED),
436 &pfx_special.fp_addr,
438 /* invalid FIB index */
442 FIB_ROUTE_PATH_FLAG_NONE);
447 ip4_add_interface_routes (u32 sw_if_index,
448 ip4_main_t * im, u32 fib_index,
449 ip_interface_address_t * a)
451 ip_lookup_main_t *lm = &im->lookup_main;
452 ip4_address_t *address = ip_interface_address_get_address (lm, a);
455 .fp_proto = FIB_PROTOCOL_IP4,
456 .fp_addr.ip4 = *address,
459 /* set special routes for the prefix if needed */
460 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
462 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
464 u32 classify_table_index =
465 lm->classify_table_index_by_sw_if_index[sw_if_index];
466 if (classify_table_index != (u32) ~ 0)
468 dpo_id_t dpo = DPO_INVALID;
473 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
475 fib_table_entry_special_dpo_add (fib_index,
478 FIB_ENTRY_FLAG_NONE, &dpo);
483 fib_table_entry_update_one_path (fib_index, &pfx,
484 FIB_SOURCE_INTERFACE,
485 (FIB_ENTRY_FLAG_CONNECTED |
486 FIB_ENTRY_FLAG_LOCAL),
493 FIB_ROUTE_PATH_FLAG_NONE);
497 ip4_del_interface_prefix_routes (ip4_main_t * im,
500 ip4_address_t * address,
503 ip_lookup_main_t *lm = &im->lookup_main;
504 ip_interface_prefix_t *if_prefix;
506 ip_interface_prefix_key_t key = {
508 .fp_len = address_length,
509 .fp_proto = FIB_PROTOCOL_IP4,
510 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
512 .sw_if_index = sw_if_index,
515 fib_prefix_t pfx_special = {
517 .fp_proto = FIB_PROTOCOL_IP4,
520 if_prefix = ip_get_interface_prefix (lm, &key);
523 clib_warning ("Prefix not found while deleting %U",
524 format_ip4_address_and_length, address, address_length);
528 if_prefix->ref_count -= 1;
531 * Routes need to be adjusted if:
532 * - deleting last intf addr in prefix
533 * - deleting intf addr used as default source address in glean adjacency
535 * We're done now otherwise
537 if ((if_prefix->ref_count > 0) &&
538 !pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
541 /* length <= 30, delete glean route, first address, last address */
542 if (address_length <= 30)
545 /* remove glean route for prefix */
546 pfx_special.fp_addr.ip4 = *address;
547 pfx_special.fp_len = address_length;
548 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
550 /* if no more intf addresses in prefix, remove other special routes */
551 if (!if_prefix->ref_count)
553 /* first address in prefix */
554 pfx_special.fp_addr.ip4.as_u32 =
555 address->as_u32 & im->fib_masks[address_length];
556 pfx_special.fp_len = 32;
558 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
559 fib_table_entry_special_remove (fib_index,
561 FIB_SOURCE_INTERFACE);
563 /* prefix broadcast address */
564 pfx_special.fp_addr.ip4.as_u32 =
565 address->as_u32 | ~im->fib_masks[address_length];
566 pfx_special.fp_len = 32;
568 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
569 fib_table_entry_special_remove (fib_index,
571 FIB_SOURCE_INTERFACE);
574 /* default source addr just got deleted, find another */
576 ip_interface_address_t *new_src_ia = NULL;
577 ip4_address_t *new_src_addr = NULL;
580 ip4_interface_address_matching_destination
581 (im, address, sw_if_index, &new_src_ia);
583 if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
585 pfx_special.fp_len = address_length;
586 pfx_special.fp_addr.ip4 = *new_src_addr;
588 /* set new glean route for the prefix */
589 fib_table_entry_update_one_path (fib_index, &pfx_special,
590 FIB_SOURCE_INTERFACE,
591 (FIB_ENTRY_FLAG_CONNECTED |
592 FIB_ENTRY_FLAG_ATTACHED),
594 /* No next-hop address */
597 /* invalid FIB index */
600 /* no out-label stack */
602 FIB_ROUTE_PATH_FLAG_NONE);
606 /* length == 31, delete attached route for the other address */
607 else if (address_length == 31)
609 pfx_special.fp_addr.ip4.as_u32 =
610 address->as_u32 ^ clib_host_to_net_u32(1);
612 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
615 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
616 pool_put (lm->if_prefix_pool, if_prefix);
620 ip4_del_interface_routes (u32 sw_if_index,
623 ip4_address_t * address, u32 address_length)
626 .fp_len = address_length,
627 .fp_proto = FIB_PROTOCOL_IP4,
628 .fp_addr.ip4 = *address,
631 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
632 address, address_length);
635 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
638 #ifndef CLIB_MARCH_VARIANT
640 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
642 ip4_main_t *im = &ip4_main;
644 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
647 * enable/disable only on the 1<->0 transition
651 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
656 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
657 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
660 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
664 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
665 sw_if_index, !is_enable, 0, 0);
668 ip4_enable_disable_interface_callback_t *cb;
669 vec_foreach (cb, im->enable_disable_interface_callbacks)
670 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
674 static clib_error_t *
675 ip4_add_del_interface_address_internal (vlib_main_t * vm,
677 ip4_address_t * address,
678 u32 address_length, u32 is_del)
680 vnet_main_t *vnm = vnet_get_main ();
681 ip4_main_t *im = &ip4_main;
682 ip_lookup_main_t *lm = &im->lookup_main;
683 clib_error_t *error = 0;
684 u32 if_address_index;
685 ip4_address_fib_t ip4_af, *addr_fib = 0;
687 /* local0 interface doesn't support IP addressing */
688 if (sw_if_index == 0)
691 clib_error_create ("local0 interface doesn't support IP addressing");
694 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
695 ip4_addr_fib_init (&ip4_af, address,
696 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
697 vec_add1 (addr_fib, ip4_af);
700 * there is no support for adj-fib handling in the presence of overlapping
701 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
707 /* When adding an address check that it does not conflict
708 with an existing address on any interface in this table. */
709 ip_interface_address_t *ia;
710 vnet_sw_interface_t *sif;
712 pool_foreach(sif, vnm->interface_main.sw_interfaces,
714 if (im->fib_index_by_sw_if_index[sw_if_index] ==
715 im->fib_index_by_sw_if_index[sif->sw_if_index])
717 foreach_ip_interface_address
718 (&im->lookup_main, ia, sif->sw_if_index,
719 0 /* honor unnumbered */ ,
722 ip_interface_address_get_address
723 (&im->lookup_main, ia);
725 if (ip4_destination_matches_route
726 (im, address, x, ia->address_length) ||
727 ip4_destination_matches_route (im,
732 /* an intf may have >1 addr from the same prefix */
733 if ((sw_if_index == sif->sw_if_index) &&
734 (ia->address_length == address_length) &&
735 (x->as_u32 != address->as_u32))
738 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
739 /* if the address we're comparing against is stale
740 * then the CP has not added this one back yet, maybe
741 * it never will, so we have to assume it won't and
742 * ignore it. if it does add it back, then it will fail
743 * because this one is now present */
746 /* error if the length or intf was different */
747 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
749 error = clib_error_create
750 ("failed to add %U on %U which conflicts with %U for interface %U",
751 format_ip4_address_and_length, address,
753 format_vnet_sw_if_index_name, vnm,
755 format_ip4_address_and_length, x,
757 format_vnet_sw_if_index_name, vnm,
767 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
771 if (~0 == if_address_index)
773 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
774 error = clib_error_create ("%U not found for interface %U",
775 lm->format_address_and_length,
776 addr_fib, address_length,
777 format_vnet_sw_if_index_name, vnm,
782 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
783 address_length, sw_if_index);
789 if (~0 != if_address_index)
791 ip_interface_address_t *ia;
793 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
795 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
797 if (ia->sw_if_index == sw_if_index)
799 /* re-adding an address during the replace action.
800 * consdier this the update. clear the flag and
802 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
807 /* The prefix is moving from one interface to another.
808 * delete the stale and add the new */
809 ip4_add_del_interface_address_internal (vm,
814 error = ip_interface_address_add (lm, sw_if_index,
815 addr_fib, address_length,
821 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
822 error = clib_error_create
823 ("Prefix %U already found on interface %U",
824 lm->format_address_and_length, addr_fib, address_length,
825 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
829 error = ip_interface_address_add (lm, sw_if_index,
830 addr_fib, address_length,
837 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
838 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
840 /* intf addr routes are added/deleted on admin up/down */
841 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
844 ip4_del_interface_routes (sw_if_index,
845 im, ip4_af.fib_index, address,
848 ip4_add_interface_routes (sw_if_index,
849 im, ip4_af.fib_index,
851 (lm->if_address_pool, if_address_index));
854 ip4_add_del_interface_address_callback_t *cb;
855 vec_foreach (cb, im->add_del_interface_address_callbacks)
856 cb->function (im, cb->function_opaque, sw_if_index,
857 address, address_length, if_address_index, is_del);
865 ip4_add_del_interface_address (vlib_main_t * vm,
867 ip4_address_t * address,
868 u32 address_length, u32 is_del)
870 return ip4_add_del_interface_address_internal
871 (vm, sw_if_index, address, address_length, is_del);
875 ip4_directed_broadcast (u32 sw_if_index, u8 enable)
877 ip_interface_address_t *ia;
883 * when directed broadcast is enabled, the subnet braodcast route will forward
884 * packets using an adjacency with a broadcast MAC. otherwise it drops
887 foreach_ip_interface_address(&im->lookup_main, ia,
890 if (ia->address_length <= 30)
894 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
898 .fp_proto = FIB_PROTOCOL_IP4,
900 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
904 ip4_add_subnet_bcast_route
905 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
914 static clib_error_t *
915 ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
917 ip4_main_t *im = &ip4_main;
918 ip_interface_address_t *ia;
920 u32 is_admin_up, fib_index;
922 /* Fill in lookup tables with default table (0). */
923 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
925 vec_validate_init_empty (im->
926 lookup_main.if_address_pool_index_by_sw_if_index,
929 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
931 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
934 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
935 0 /* honor unnumbered */,
937 a = ip_interface_address_get_address (&im->lookup_main, ia);
939 ip4_add_interface_routes (sw_if_index,
943 ip4_del_interface_routes (sw_if_index,
945 a, ia->address_length);
952 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
954 /* Built-in ip4 unicast rx feature path definition */
956 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
958 .arc_name = "ip4-unicast",
959 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
960 .last_in_arc = "ip4-lookup",
961 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
964 VNET_FEATURE_INIT (ip4_flow_classify, static) =
966 .arc_name = "ip4-unicast",
967 .node_name = "ip4-flow-classify",
968 .runs_before = VNET_FEATURES ("ip4-inacl"),
971 VNET_FEATURE_INIT (ip4_inacl, static) =
973 .arc_name = "ip4-unicast",
974 .node_name = "ip4-inacl",
975 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
978 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
980 .arc_name = "ip4-unicast",
981 .node_name = "ip4-source-and-port-range-check-rx",
982 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
985 VNET_FEATURE_INIT (ip4_policer_classify, static) =
987 .arc_name = "ip4-unicast",
988 .node_name = "ip4-policer-classify",
989 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
992 VNET_FEATURE_INIT (ip4_ipsec, static) =
994 .arc_name = "ip4-unicast",
995 .node_name = "ipsec4-input-feature",
996 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
999 VNET_FEATURE_INIT (ip4_vpath, static) =
1001 .arc_name = "ip4-unicast",
1002 .node_name = "vpath-input-ip4",
1003 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1006 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1008 .arc_name = "ip4-unicast",
1009 .node_name = "ip4-vxlan-bypass",
1010 .runs_before = VNET_FEATURES ("ip4-lookup"),
1013 VNET_FEATURE_INIT (ip4_not_enabled, static) =
1015 .arc_name = "ip4-unicast",
1016 .node_name = "ip4-not-enabled",
1017 .runs_before = VNET_FEATURES ("ip4-lookup"),
1020 VNET_FEATURE_INIT (ip4_lookup, static) =
1022 .arc_name = "ip4-unicast",
1023 .node_name = "ip4-lookup",
1024 .runs_before = 0, /* not before any other features */
1027 /* Built-in ip4 multicast rx feature path definition */
1028 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1030 .arc_name = "ip4-multicast",
1031 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
1032 .last_in_arc = "ip4-mfib-forward-lookup",
1033 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1036 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1038 .arc_name = "ip4-multicast",
1039 .node_name = "vpath-input-ip4",
1040 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1043 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
1045 .arc_name = "ip4-multicast",
1046 .node_name = "ip4-not-enabled",
1047 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1050 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1052 .arc_name = "ip4-multicast",
1053 .node_name = "ip4-mfib-forward-lookup",
1054 .runs_before = 0, /* last feature */
1057 /* Source and port-range check ip4 tx feature path definition */
1058 VNET_FEATURE_ARC_INIT (ip4_output, static) =
1060 .arc_name = "ip4-output",
1061 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
1062 .last_in_arc = "interface-output",
1063 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1066 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1068 .arc_name = "ip4-output",
1069 .node_name = "ip4-source-and-port-range-check-tx",
1070 .runs_before = VNET_FEATURES ("ip4-outacl"),
1073 VNET_FEATURE_INIT (ip4_outacl, static) =
1075 .arc_name = "ip4-output",
1076 .node_name = "ip4-outacl",
1077 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
1080 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1082 .arc_name = "ip4-output",
1083 .node_name = "ipsec4-output-feature",
1084 .runs_before = VNET_FEATURES ("interface-output"),
1087 /* Built-in ip4 tx feature path definition */
1088 VNET_FEATURE_INIT (ip4_interface_output, static) =
1090 .arc_name = "ip4-output",
1091 .node_name = "interface-output",
1092 .runs_before = 0, /* not before any other features */
1096 static clib_error_t *
1097 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1099 ip4_main_t *im = &ip4_main;
1101 /* Fill in lookup tables with default table (0). */
1102 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1103 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
1107 ip4_main_t *im4 = &ip4_main;
1108 ip_lookup_main_t *lm4 = &im4->lookup_main;
1109 ip_interface_address_t *ia = 0;
1110 ip4_address_t *address;
1111 vlib_main_t *vm = vlib_get_main ();
1113 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
1115 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1117 address = ip_interface_address_get_address (lm4, ia);
1118 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1121 ip4_mfib_interface_enable_disable (sw_if_index, 0);
1124 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
1127 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1128 sw_if_index, is_add, 0, 0);
1130 return /* no error */ 0;
1133 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1135 /* Global IP4 main. */
1136 #ifndef CLIB_MARCH_VARIANT
1137 ip4_main_t ip4_main;
1138 #endif /* CLIB_MARCH_VARIANT */
1140 static clib_error_t *
1141 ip4_lookup_init (vlib_main_t * vm)
1143 ip4_main_t *im = &ip4_main;
1144 clib_error_t *error;
1147 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1149 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1151 if ((error = vlib_call_init_function (vm, fib_module_init)))
1153 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1156 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1161 m = pow2_mask (i) << (32 - i);
1164 im->fib_masks[i] = clib_host_to_net_u32 (m);
1167 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1169 /* Create FIB with index 0 and table id of 0. */
1170 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1171 FIB_SOURCE_DEFAULT_ROUTE);
1172 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1173 MFIB_SOURCE_DEFAULT_ROUTE);
1177 pn = pg_get_node (ip4_lookup_node.index);
1178 pn->unformat_edit = unformat_pg_ip4_header;
1182 ethernet_arp_header_t h;
1184 clib_memset (&h, 0, sizeof (h));
1186 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1187 #define _8(f,v) h.f = v;
1188 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1189 _16 (l3_type, ETHERNET_TYPE_IP4);
1190 _8 (n_l2_address_bytes, 6);
1191 _8 (n_l3_address_bytes, 4);
1192 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1196 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1199 /* alloc chunk size */ 8,
1206 VLIB_INIT_FUNCTION (ip4_lookup_init);
1210 /* Adjacency taken. */
1215 /* Packet data, possibly *after* rewrite. */
1216 u8 packet_data[64 - 1 * sizeof (u32)];
1218 ip4_forward_next_trace_t;
1220 #ifndef CLIB_MARCH_VARIANT
1222 format_ip4_forward_next_trace (u8 * s, va_list * args)
1224 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1225 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1226 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1227 u32 indent = format_get_indent (s);
1228 s = format (s, "%U%U",
1229 format_white_space, indent,
1230 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1236 format_ip4_lookup_trace (u8 * s, va_list * args)
1238 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1239 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1240 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1241 u32 indent = format_get_indent (s);
1243 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1244 t->fib_index, t->dpo_index, t->flow_hash);
1245 s = format (s, "\n%U%U",
1246 format_white_space, indent,
1247 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1252 format_ip4_rewrite_trace (u8 * s, va_list * args)
1254 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1255 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1256 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1257 u32 indent = format_get_indent (s);
1259 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1260 t->fib_index, t->dpo_index, format_ip_adjacency,
1261 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1262 s = format (s, "\n%U%U",
1263 format_white_space, indent,
1264 format_ip_adjacency_packet_data,
1265 t->packet_data, sizeof (t->packet_data));
1269 #ifndef CLIB_MARCH_VARIANT
1270 /* Common trace function for all ip4-forward next nodes. */
1272 ip4_forward_next_trace (vlib_main_t * vm,
1273 vlib_node_runtime_t * node,
1274 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1277 ip4_main_t *im = &ip4_main;
1279 n_left = frame->n_vectors;
1280 from = vlib_frame_vector_args (frame);
1285 vlib_buffer_t *b0, *b1;
1286 ip4_forward_next_trace_t *t0, *t1;
1288 /* Prefetch next iteration. */
1289 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1290 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1295 b0 = vlib_get_buffer (vm, bi0);
1296 b1 = vlib_get_buffer (vm, bi1);
1298 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1300 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1301 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1302 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1304 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1305 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1306 vec_elt (im->fib_index_by_sw_if_index,
1307 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1309 clib_memcpy_fast (t0->packet_data,
1310 vlib_buffer_get_current (b0),
1311 sizeof (t0->packet_data));
1313 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1315 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1316 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1317 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1319 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1320 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1321 vec_elt (im->fib_index_by_sw_if_index,
1322 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1323 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1324 sizeof (t1->packet_data));
1334 ip4_forward_next_trace_t *t0;
1338 b0 = vlib_get_buffer (vm, bi0);
1340 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1342 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1343 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1344 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1346 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1347 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1348 vec_elt (im->fib_index_by_sw_if_index,
1349 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1350 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1351 sizeof (t0->packet_data));
1358 /* Compute TCP/UDP/ICMP4 checksum in software. */
1360 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1364 u32 ip_header_length, payload_length_host_byte_order;
1366 /* Initialize checksum with ip header. */
1367 ip_header_length = ip4_header_bytes (ip0);
1368 payload_length_host_byte_order =
1369 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1371 clib_host_to_net_u32 (payload_length_host_byte_order +
1372 (ip0->protocol << 16));
1374 if (BITS (uword) == 32)
1377 ip_csum_with_carry (sum0,
1378 clib_mem_unaligned (&ip0->src_address, u32));
1380 ip_csum_with_carry (sum0,
1381 clib_mem_unaligned (&ip0->dst_address, u32));
1385 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1387 return ip_calculate_l4_checksum (vm, p0, sum0,
1388 payload_length_host_byte_order, (u8 *) ip0,
1389 ip_header_length, NULL);
1393 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1395 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1399 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1400 || ip0->protocol == IP_PROTOCOL_UDP);
1402 udp0 = (void *) (ip0 + 1);
1403 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1405 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1406 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1410 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1412 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1413 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1420 VNET_FEATURE_ARC_INIT (ip4_local) =
1422 .arc_name = "ip4-local",
1423 .start_nodes = VNET_FEATURES ("ip4-local"),
1424 .last_in_arc = "ip4-local-end-of-arc",
1429 ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1430 ip4_header_t * ip, u8 is_udp, u8 * error,
1434 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1435 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1439 u32 ip_len, udp_len;
1441 udp = ip4_next_header (ip);
1442 /* Verify UDP length. */
1443 ip_len = clib_net_to_host_u16 (ip->length);
1444 udp_len = clib_net_to_host_u16 (udp->length);
1446 len_diff = ip_len - udp_len;
1447 *good_tcp_udp &= len_diff >= 0;
1448 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1452 #define ip4_local_csum_is_offloaded(_b) \
1453 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1454 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1456 #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1457 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1458 || ip4_local_csum_is_offloaded (_b)))
1460 #define ip4_local_csum_is_valid(_b) \
1461 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1462 || (ip4_local_csum_is_offloaded (_b))) != 0
1465 ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1466 ip4_header_t * ih, u8 * error)
1468 u8 is_udp, is_tcp_udp, good_tcp_udp;
1470 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1471 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1473 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1474 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1476 good_tcp_udp = ip4_local_csum_is_valid (b);
1478 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1479 *error = (is_tcp_udp && !good_tcp_udp
1480 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1484 ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1485 ip4_header_t ** ih, u8 * error)
1487 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1489 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1490 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1492 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1493 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1495 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1496 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1498 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1499 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1502 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1505 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1509 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1510 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1511 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1512 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1516 ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1517 vlib_buffer_t * b, u16 * next, u8 error,
1518 u8 head_of_feature_arc)
1520 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1523 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1524 b->error = error ? error_node->errors[error] : 0;
1525 if (head_of_feature_arc)
1528 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1530 vnet_feature_arc_start (arc_index,
1531 vnet_buffer (b)->sw_if_index[VLIB_RX],
1544 } ip4_local_last_check_t;
1547 ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1548 ip4_local_last_check_t * last_check, u8 * error0)
1550 ip4_fib_mtrie_leaf_t leaf0;
1551 ip4_fib_mtrie_t *mtrie0;
1552 const dpo_id_t *dpo0;
1553 load_balance_t *lb0;
1556 vnet_buffer (b)->ip.fib_index =
1557 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1558 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1561 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1562 * adjacency for the destination address (the local interface address).
1563 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1564 * adjacency for the source address (the remote sender's address)
1566 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1569 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1570 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1571 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1572 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1573 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1575 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1576 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1577 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1579 lb0 = load_balance_get (lbi0);
1580 dpo0 = load_balance_get_bucket_i (lb0, 0);
1583 * Must have a route to source otherwise we drop the packet.
1584 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1587 * - the source is a recieve => it's from us => bogus, do this
1588 * first since it sets a different error code.
1589 * - uRPF check for any route to source - accept if passes.
1590 * - allow packets destined to the broadcast address from unknown sources
1593 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1594 && dpo0->dpoi_type == DPO_RECEIVE) ?
1595 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1596 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1597 && !fib_urpf_check_size (lb0->lb_urpf)
1598 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1599 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1601 last_check->src.as_u32 = ip0->src_address.as_u32;
1602 last_check->lbi = lbi0;
1603 last_check->error = *error0;
1604 last_check->first = 0;
1608 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1609 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1610 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1611 *error0 = last_check->error;
1616 ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1617 ip4_local_last_check_t * last_check, u8 * error)
1619 ip4_fib_mtrie_leaf_t leaf[2];
1620 ip4_fib_mtrie_t *mtrie[2];
1621 const dpo_id_t *dpo[2];
1622 load_balance_t *lb[2];
1626 not_last_hit = last_check->first;
1627 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1628 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1630 vnet_buffer (b[0])->ip.fib_index =
1631 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1632 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1633 vnet_buffer (b[0])->ip.fib_index;
1635 vnet_buffer (b[1])->ip.fib_index =
1636 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1637 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1638 vnet_buffer (b[1])->ip.fib_index;
1641 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1642 * adjacency for the destination address (the local interface address).
1643 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1644 * adjacency for the source address (the remote sender's address)
1646 if (PREDICT_TRUE (not_last_hit))
1648 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1649 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1651 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1652 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1654 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1655 &ip[0]->src_address, 2);
1656 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1657 &ip[1]->src_address, 2);
1659 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1660 &ip[0]->src_address, 3);
1661 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1662 &ip[1]->src_address, 3);
1664 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1665 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1667 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1668 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1669 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1671 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1672 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1673 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1675 lb[0] = load_balance_get (lbi[0]);
1676 lb[1] = load_balance_get (lbi[1]);
1678 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1679 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1681 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1682 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1683 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1684 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1685 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1686 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1687 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1689 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1690 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1691 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1692 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1693 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1694 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1695 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1697 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1698 last_check->lbi = lbi[1];
1699 last_check->error = error[1];
1700 last_check->first = 0;
1704 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1705 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1706 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1708 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1709 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1710 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1712 error[0] = last_check->error;
1713 error[1] = last_check->error;
1717 enum ip_local_packet_type_e
1719 IP_LOCAL_PACKET_TYPE_L4,
1720 IP_LOCAL_PACKET_TYPE_NAT,
1721 IP_LOCAL_PACKET_TYPE_FRAG,
1725 * Determine packet type and next node.
1727 * The expectation is that all packets that are not L4 will skip
1728 * checksums and source checks.
1731 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1733 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1735 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1737 *next = IP_LOCAL_NEXT_REASSEMBLY;
1738 return IP_LOCAL_PACKET_TYPE_FRAG;
1740 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1742 *next = lm->local_next_by_ip_protocol[ip->protocol];
1743 return IP_LOCAL_PACKET_TYPE_NAT;
1746 *next = lm->local_next_by_ip_protocol[ip->protocol];
1747 return IP_LOCAL_PACKET_TYPE_L4;
1751 ip4_local_inline (vlib_main_t * vm,
1752 vlib_node_runtime_t * node,
1753 vlib_frame_t * frame, int head_of_feature_arc)
1755 u32 *from, n_left_from;
1756 vlib_node_runtime_t *error_node =
1757 vlib_node_get_runtime (vm, ip4_local_node.index);
1758 u16 nexts[VLIB_FRAME_SIZE], *next;
1759 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1760 ip4_header_t *ip[2];
1763 ip4_local_last_check_t last_check = {
1765 * 0.0.0.0 can appear as the source address of an IP packet,
1766 * as can any other address, hence the need to use the 'first'
1767 * member to make sure the .lbi is initialised for the first
1770 .src = {.as_u32 = 0},
1772 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1776 from = vlib_frame_vector_args (frame);
1777 n_left_from = frame->n_vectors;
1779 if (node->flags & VLIB_NODE_FLAG_TRACE)
1780 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1782 vlib_get_buffers (vm, from, bufs, n_left_from);
1786 while (n_left_from >= 6)
1790 /* Prefetch next iteration. */
1792 vlib_prefetch_buffer_header (b[4], LOAD);
1793 vlib_prefetch_buffer_header (b[5], LOAD);
1795 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1796 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1799 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1801 ip[0] = vlib_buffer_get_current (b[0]);
1802 ip[1] = vlib_buffer_get_current (b[1]);
1804 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1805 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1807 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1808 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1810 not_batch = pt[0] ^ pt[1];
1812 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1815 if (PREDICT_TRUE (not_batch == 0))
1817 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1818 ip4_local_check_src_x2 (b, ip, &last_check, error);
1824 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1825 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1829 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1830 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
1836 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1837 head_of_feature_arc);
1838 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1839 head_of_feature_arc);
1846 while (n_left_from > 0)
1848 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1850 ip[0] = vlib_buffer_get_current (b[0]);
1851 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1852 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1854 if (head_of_feature_arc == 0 || pt[0])
1857 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1858 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1862 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1863 head_of_feature_arc);
1870 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1871 return frame->n_vectors;
1874 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1875 vlib_frame_t * frame)
1877 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1881 VLIB_REGISTER_NODE (ip4_local_node) =
1883 .name = "ip4-local",
1884 .vector_size = sizeof (u32),
1885 .format_trace = format_ip4_forward_next_trace,
1886 .n_errors = IP4_N_ERROR,
1887 .error_strings = ip4_error_strings,
1888 .n_next_nodes = IP_LOCAL_N_NEXT,
1891 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1892 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1893 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1894 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1895 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
1901 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1902 vlib_node_runtime_t * node,
1903 vlib_frame_t * frame)
1905 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1909 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1910 .name = "ip4-local-end-of-arc",
1911 .vector_size = sizeof (u32),
1913 .format_trace = format_ip4_forward_next_trace,
1914 .sibling_of = "ip4-local",
1917 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1918 .arc_name = "ip4-local",
1919 .node_name = "ip4-local-end-of-arc",
1920 .runs_before = 0, /* not before any other features */
1924 #ifndef CLIB_MARCH_VARIANT
1926 ip4_register_protocol (u32 protocol, u32 node_index)
1928 vlib_main_t *vm = vlib_get_main ();
1929 ip4_main_t *im = &ip4_main;
1930 ip_lookup_main_t *lm = &im->lookup_main;
1932 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1933 lm->local_next_by_ip_protocol[protocol] =
1934 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1938 ip4_unregister_protocol (u32 protocol)
1940 ip4_main_t *im = &ip4_main;
1941 ip_lookup_main_t *lm = &im->lookup_main;
1943 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1944 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1948 static clib_error_t *
1949 show_ip_local_command_fn (vlib_main_t * vm,
1950 unformat_input_t * input, vlib_cli_command_t * cmd)
1952 ip4_main_t *im = &ip4_main;
1953 ip_lookup_main_t *lm = &im->lookup_main;
1956 vlib_cli_output (vm, "Protocols handled by ip4_local");
1957 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1959 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1961 u32 node_index = vlib_get_node (vm,
1962 ip4_local_node.index)->
1963 next_nodes[lm->local_next_by_ip_protocol[i]];
1964 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1965 format_vlib_node_name, vm, node_index);
1974 * Display the set of protocols handled by the local IPv4 stack.
1977 * Example of how to display local protocol table:
1978 * @cliexstart{show ip local}
1979 * Protocols handled by ip4_local
1986 VLIB_CLI_COMMAND (show_ip_local, static) =
1988 .path = "show ip local",
1989 .function = show_ip_local_command_fn,
1990 .short_help = "show ip local",
1996 IP4_REWRITE_NEXT_DROP,
1997 IP4_REWRITE_NEXT_ICMP_ERROR,
1998 IP4_REWRITE_NEXT_FRAGMENT,
1999 IP4_REWRITE_N_NEXT /* Last */
2000 } ip4_rewrite_next_t;
2003 * This bits of an IPv4 address to mask to construct a multicast
2006 #if CLIB_ARCH_IS_BIG_ENDIAN
2007 #define IP4_MCAST_ADDR_MASK 0x007fffff
2009 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2013 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2014 u16 adj_packet_bytes, bool df, u16 * next,
2015 u8 is_midchain, u32 * error)
2017 if (packet_len > adj_packet_bytes)
2019 *error = IP4_ERROR_MTU_EXCEEDED;
2022 icmp4_error_set_vnet_buffer
2023 (b, ICMP4_destination_unreachable,
2024 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2026 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2030 /* IP fragmentation */
2031 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2033 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2034 IP_FRAG_NEXT_IP_REWRITE), 0);
2035 *next = IP4_REWRITE_NEXT_FRAGMENT;
2040 /* increment TTL & update checksum.
2041 Works either endian, so no need for byte swap. */
2042 static_always_inline void
2043 ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2047 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2052 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2053 checksum += checksum >= 0xffff;
2055 ip->checksum = checksum;
2059 ASSERT (ip->checksum == ip4_header_checksum (ip));
2062 /* Decrement TTL & update checksum.
2063 Works either endian, so no need for byte swap. */
2064 static_always_inline void
2065 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2070 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2075 /* Input node should have reject packets with ttl 0. */
2076 ASSERT (ip->ttl > 0);
2078 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2079 checksum += checksum >= 0xffff;
2081 ip->checksum = checksum;
2086 * If the ttl drops below 1 when forwarding, generate
2089 if (PREDICT_FALSE (ttl <= 0))
2091 *error = IP4_ERROR_TIME_EXPIRED;
2092 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2093 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2094 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2096 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2099 /* Verify checksum. */
2100 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2101 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2106 ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2107 vlib_node_runtime_t * node,
2108 vlib_frame_t * frame,
2109 int do_counters, int is_midchain, int is_mcast)
2111 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2112 u32 *from = vlib_frame_vector_args (frame);
2113 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2114 u16 nexts[VLIB_FRAME_SIZE], *next;
2116 vlib_node_runtime_t *error_node =
2117 vlib_node_get_runtime (vm, ip4_input_node.index);
2119 n_left_from = frame->n_vectors;
2120 u32 thread_index = vm->thread_index;
2122 vlib_get_buffers (vm, from, bufs, n_left_from);
2123 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2125 #if (CLIB_N_PREFETCHES >= 8)
2126 if (n_left_from >= 6)
2129 for (i = 2; i < 6; i++)
2130 vlib_prefetch_buffer_header (bufs[i], LOAD);
2135 while (n_left_from >= 8)
2137 const ip_adjacency_t *adj0, *adj1;
2138 ip4_header_t *ip0, *ip1;
2139 u32 rw_len0, error0, adj_index0;
2140 u32 rw_len1, error1, adj_index1;
2141 u32 tx_sw_if_index0, tx_sw_if_index1;
2144 vlib_prefetch_buffer_header (b[6], LOAD);
2145 vlib_prefetch_buffer_header (b[7], LOAD);
2147 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2148 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2151 * pre-fetch the per-adjacency counters
2155 vlib_prefetch_combined_counter (&adjacency_counters,
2156 thread_index, adj_index0);
2157 vlib_prefetch_combined_counter (&adjacency_counters,
2158 thread_index, adj_index1);
2161 ip0 = vlib_buffer_get_current (b[0]);
2162 ip1 = vlib_buffer_get_current (b[1]);
2164 error0 = error1 = IP4_ERROR_NONE;
2166 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2167 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2169 /* Rewrite packet header and updates lengths. */
2170 adj0 = adj_get (adj_index0);
2171 adj1 = adj_get (adj_index1);
2173 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2174 rw_len0 = adj0[0].rewrite_header.data_bytes;
2175 rw_len1 = adj1[0].rewrite_header.data_bytes;
2176 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2177 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2179 p = vlib_buffer_get_current (b[2]);
2180 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2181 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2183 p = vlib_buffer_get_current (b[3]);
2184 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2185 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2187 /* Check MTU of outgoing interface. */
2188 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2189 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2191 if (b[0]->flags & VNET_BUFFER_F_GSO)
2192 ip0_len = gso_mtu_sz (b[0]);
2193 if (b[1]->flags & VNET_BUFFER_F_GSO)
2194 ip1_len = gso_mtu_sz (b[1]);
2196 ip4_mtu_check (b[0], ip0_len,
2197 adj0[0].rewrite_header.max_l3_packet_bytes,
2198 ip0->flags_and_fragment_offset &
2199 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2200 next + 0, is_midchain, &error0);
2201 ip4_mtu_check (b[1], ip1_len,
2202 adj1[0].rewrite_header.max_l3_packet_bytes,
2203 ip1->flags_and_fragment_offset &
2204 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2205 next + 1, is_midchain, &error1);
2209 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2210 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2211 IP4_ERROR_SAME_INTERFACE : error0);
2212 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2213 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2214 IP4_ERROR_SAME_INTERFACE : error1);
2217 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2218 * to see the IP header */
2219 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2221 u32 next_index = adj0[0].rewrite_header.next_index;
2222 vlib_buffer_advance (b[0], -(word) rw_len0);
2224 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2225 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2228 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2229 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2232 adj0->ia_cfg_index);
2234 next[0] = next_index;
2236 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2242 b[0]->error = error_node->errors[error0];
2243 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2244 ip4_ttl_inc (b[0], ip0);
2246 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2248 u32 next_index = adj1[0].rewrite_header.next_index;
2249 vlib_buffer_advance (b[1], -(word) rw_len1);
2251 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2252 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2255 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2256 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2259 adj1->ia_cfg_index);
2260 next[1] = next_index;
2262 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2268 b[1]->error = error_node->errors[error1];
2269 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2270 ip4_ttl_inc (b[1], ip1);
2274 /* Guess we are only writing on ipv4 header. */
2275 vnet_rewrite_two_headers (adj0[0], adj1[0],
2276 ip0, ip1, sizeof (ip4_header_t));
2278 /* Guess we are only writing on simple Ethernet header. */
2279 vnet_rewrite_two_headers (adj0[0], adj1[0],
2280 ip0, ip1, sizeof (ethernet_header_t));
2284 if (error0 == IP4_ERROR_NONE)
2285 vlib_increment_combined_counter
2286 (&adjacency_counters,
2289 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2291 if (error1 == IP4_ERROR_NONE)
2292 vlib_increment_combined_counter
2293 (&adjacency_counters,
2296 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2301 if (error0 == IP4_ERROR_NONE)
2302 adj_midchain_fixup (vm, adj0, b[0]);
2303 if (error1 == IP4_ERROR_NONE)
2304 adj_midchain_fixup (vm, adj1, b[1]);
2309 /* copy bytes from the IP address into the MAC rewrite */
2310 if (error0 == IP4_ERROR_NONE)
2311 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2312 adj0->rewrite_header.dst_mcast_offset,
2313 &ip0->dst_address.as_u32, (u8 *) ip0);
2314 if (error1 == IP4_ERROR_NONE)
2315 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2316 adj1->rewrite_header.dst_mcast_offset,
2317 &ip1->dst_address.as_u32, (u8 *) ip1);
2324 #elif (CLIB_N_PREFETCHES >= 4)
2327 while (n_left_from >= 1)
2329 ip_adjacency_t *adj0;
2331 u32 rw_len0, error0, adj_index0;
2332 u32 tx_sw_if_index0;
2335 /* Prefetch next iteration */
2336 if (PREDICT_TRUE (n_left_from >= 4))
2338 ip_adjacency_t *adj2;
2341 vlib_prefetch_buffer_header (b[3], LOAD);
2342 vlib_prefetch_buffer_data (b[2], LOAD);
2344 /* Prefetch adj->rewrite_header */
2345 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2346 adj2 = adj_get (adj_index2);
2348 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2352 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2355 * Prefetch the per-adjacency counters
2359 vlib_prefetch_combined_counter (&adjacency_counters,
2360 thread_index, adj_index0);
2363 ip0 = vlib_buffer_get_current (b[0]);
2365 error0 = IP4_ERROR_NONE;
2367 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2369 /* Rewrite packet header and updates lengths. */
2370 adj0 = adj_get (adj_index0);
2372 /* Rewrite header was prefetched. */
2373 rw_len0 = adj0[0].rewrite_header.data_bytes;
2374 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2376 /* Check MTU of outgoing interface. */
2377 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2379 if (b[0]->flags & VNET_BUFFER_F_GSO)
2380 ip0_len = gso_mtu_sz (b[0]);
2382 ip4_mtu_check (b[0], ip0_len,
2383 adj0[0].rewrite_header.max_l3_packet_bytes,
2384 ip0->flags_and_fragment_offset &
2385 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2386 next + 0, is_midchain, &error0);
2390 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2391 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2392 IP4_ERROR_SAME_INTERFACE : error0);
2395 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2396 * to see the IP header */
2397 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2399 u32 next_index = adj0[0].rewrite_header.next_index;
2400 vlib_buffer_advance (b[0], -(word) rw_len0);
2401 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2402 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2405 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2406 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2409 adj0->ia_cfg_index);
2410 next[0] = next_index;
2414 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2418 /* Guess we are only writing on ipv4 header. */
2419 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2422 /* Guess we are only writing on simple Ethernet header. */
2423 vnet_rewrite_one_header (adj0[0], ip0,
2424 sizeof (ethernet_header_t));
2427 * Bump the per-adjacency counters
2430 vlib_increment_combined_counter
2431 (&adjacency_counters,
2433 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2437 adj_midchain_fixup (vm, adj0, b[0]);
2440 /* copy bytes from the IP address into the MAC rewrite */
2441 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2442 adj0->rewrite_header.dst_mcast_offset,
2443 &ip0->dst_address.as_u32, (u8 *) ip0);
2447 b[0]->error = error_node->errors[error0];
2448 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2449 ip4_ttl_inc (b[0], ip0);
2458 while (n_left_from > 0)
2460 ip_adjacency_t *adj0;
2462 u32 rw_len0, adj_index0, error0;
2463 u32 tx_sw_if_index0;
2465 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2467 adj0 = adj_get (adj_index0);
2470 vlib_prefetch_combined_counter (&adjacency_counters,
2471 thread_index, adj_index0);
2473 ip0 = vlib_buffer_get_current (b[0]);
2475 error0 = IP4_ERROR_NONE;
2477 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2480 /* Update packet buffer attributes/set output interface. */
2481 rw_len0 = adj0[0].rewrite_header.data_bytes;
2482 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2484 /* Check MTU of outgoing interface. */
2485 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2486 if (b[0]->flags & VNET_BUFFER_F_GSO)
2487 ip0_len = gso_mtu_sz (b[0]);
2489 ip4_mtu_check (b[0], ip0_len,
2490 adj0[0].rewrite_header.max_l3_packet_bytes,
2491 ip0->flags_and_fragment_offset &
2492 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2493 next + 0, is_midchain, &error0);
2497 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2498 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2499 IP4_ERROR_SAME_INTERFACE : error0);
2502 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2503 * to see the IP header */
2504 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2506 u32 next_index = adj0[0].rewrite_header.next_index;
2507 vlib_buffer_advance (b[0], -(word) rw_len0);
2508 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2509 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2512 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2513 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2516 adj0->ia_cfg_index);
2517 next[0] = next_index;
2521 /* this acts on the packet that is about to be encapped */
2522 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2526 /* Guess we are only writing on ipv4 header. */
2527 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2530 /* Guess we are only writing on simple Ethernet header. */
2531 vnet_rewrite_one_header (adj0[0], ip0,
2532 sizeof (ethernet_header_t));
2535 vlib_increment_combined_counter
2536 (&adjacency_counters,
2537 thread_index, adj_index0, 1,
2538 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2540 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2541 adj0->sub_type.midchain.fixup_func
2542 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2545 /* copy bytes from the IP address into the MAC rewrite */
2546 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2547 adj0->rewrite_header.dst_mcast_offset,
2548 &ip0->dst_address.as_u32, (u8 *) ip0);
2552 b[0]->error = error_node->errors[error0];
2553 /* undo the TTL decrement - we'll be back to do it again */
2554 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2555 ip4_ttl_inc (b[0], ip0);
2564 /* Need to do trace after rewrites to pick up new packet data. */
2565 if (node->flags & VLIB_NODE_FLAG_TRACE)
2566 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2568 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2569 return frame->n_vectors;
2573 ip4_rewrite_inline (vlib_main_t * vm,
2574 vlib_node_runtime_t * node,
2575 vlib_frame_t * frame,
2576 int do_counters, int is_midchain, int is_mcast)
2578 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2579 is_midchain, is_mcast);
2583 /** @brief IPv4 rewrite node.
2586 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2587 header checksum, fetch the ip adjacency, check the outbound mtu,
2588 apply the adjacency rewrite, and send pkts to the adjacency
2589 rewrite header's rewrite_next_index.
2591 @param vm vlib_main_t corresponding to the current thread
2592 @param node vlib_node_runtime_t
2593 @param frame vlib_frame_t whose contents should be dispatched
2595 @par Graph mechanics: buffer metadata, next index usage
2598 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2599 - the rewrite adjacency index
2600 - <code>adj->lookup_next_index</code>
2601 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2602 the packet will be dropped.
2603 - <code>adj->rewrite_header</code>
2604 - Rewrite string length, rewrite string, next_index
2607 - <code>b->current_data, b->current_length</code>
2608 - Updated net of applying the rewrite string
2610 <em>Next Indices:</em>
2611 - <code> adj->rewrite_header.next_index </code>
2615 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2616 vlib_frame_t * frame)
2618 if (adj_are_counters_enabled ())
2619 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2621 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2624 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2625 vlib_node_runtime_t * node,
2626 vlib_frame_t * frame)
2628 if (adj_are_counters_enabled ())
2629 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2631 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2634 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2635 vlib_node_runtime_t * node,
2636 vlib_frame_t * frame)
2638 if (adj_are_counters_enabled ())
2639 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2641 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2644 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2645 vlib_node_runtime_t * node,
2646 vlib_frame_t * frame)
2648 if (adj_are_counters_enabled ())
2649 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2651 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2654 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2655 vlib_node_runtime_t * node,
2656 vlib_frame_t * frame)
2658 if (adj_are_counters_enabled ())
2659 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2661 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2665 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2666 .name = "ip4-rewrite",
2667 .vector_size = sizeof (u32),
2669 .format_trace = format_ip4_rewrite_trace,
2671 .n_next_nodes = IP4_REWRITE_N_NEXT,
2673 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2674 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2675 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2679 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2680 .name = "ip4-rewrite-bcast",
2681 .vector_size = sizeof (u32),
2683 .format_trace = format_ip4_rewrite_trace,
2684 .sibling_of = "ip4-rewrite",
2687 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2688 .name = "ip4-rewrite-mcast",
2689 .vector_size = sizeof (u32),
2691 .format_trace = format_ip4_rewrite_trace,
2692 .sibling_of = "ip4-rewrite",
2695 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2696 .name = "ip4-mcast-midchain",
2697 .vector_size = sizeof (u32),
2699 .format_trace = format_ip4_rewrite_trace,
2700 .sibling_of = "ip4-rewrite",
2703 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2704 .name = "ip4-midchain",
2705 .vector_size = sizeof (u32),
2706 .format_trace = format_ip4_rewrite_trace,
2707 .sibling_of = "ip4-rewrite",
2712 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2714 ip4_fib_mtrie_t *mtrie0;
2715 ip4_fib_mtrie_leaf_t leaf0;
2718 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2720 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
2721 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2722 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2724 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2726 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2729 static clib_error_t *
2730 test_lookup_command_fn (vlib_main_t * vm,
2731 unformat_input_t * input, vlib_cli_command_t * cmd)
2738 ip4_address_t ip4_base_address;
2741 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2743 if (unformat (input, "table %d", &table_id))
2745 /* Make sure the entry exists. */
2746 fib = ip4_fib_get (table_id);
2747 if ((fib) && (fib->index != table_id))
2748 return clib_error_return (0, "<fib-index> %d does not exist",
2751 else if (unformat (input, "count %f", &count))
2754 else if (unformat (input, "%U",
2755 unformat_ip4_address, &ip4_base_address))
2758 return clib_error_return (0, "unknown input `%U'",
2759 format_unformat_error, input);
2764 for (i = 0; i < n; i++)
2766 if (!ip4_lookup_validate (&ip4_base_address, table_id))
2769 ip4_base_address.as_u32 =
2770 clib_host_to_net_u32 (1 +
2771 clib_net_to_host_u32 (ip4_base_address.as_u32));
2775 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2777 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2783 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2784 * given FIB table to determine if there is a conflict with the
2785 * adjacency table. The fib-id can be determined by using the
2786 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2789 * @todo This command uses fib-id, other commands use table-id (not
2790 * just a name, they are different indexes). Would like to change this
2791 * to table-id for consistency.
2794 * Example of how to run the test lookup command:
2795 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2796 * No errors in 2 lookups
2800 VLIB_CLI_COMMAND (lookup_test_command, static) =
2802 .path = "test lookup",
2803 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2804 .function = test_lookup_command_fn,
2808 #ifndef CLIB_MARCH_VARIANT
2810 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
2814 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2816 if (~0 == fib_index)
2817 return VNET_API_ERROR_NO_SUCH_FIB;
2819 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2826 static clib_error_t *
2827 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2828 unformat_input_t * input,
2829 vlib_cli_command_t * cmd)
2833 u32 flow_hash_config = 0;
2836 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2838 if (unformat (input, "table %d", &table_id))
2841 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2842 foreach_flow_hash_bit
2849 return clib_error_return (0, "unknown input `%U'",
2850 format_unformat_error, input);
2852 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2858 case VNET_API_ERROR_NO_SUCH_FIB:
2859 return clib_error_return (0, "no such FIB table %d", table_id);
2862 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2870 * Configure the set of IPv4 fields used by the flow hash.
2873 * Example of how to set the flow hash on a given table:
2874 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2875 * Example of display the configured flow hash:
2876 * @cliexstart{show ip fib}
2877 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2880 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2881 * [0] [@0]: dpo-drop ip6
2884 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2885 * [0] [@0]: dpo-drop ip6
2888 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2889 * [0] [@0]: dpo-drop ip6
2892 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2893 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2896 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2897 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2898 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2899 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2900 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2903 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2904 * [0] [@0]: dpo-drop ip6
2905 * 255.255.255.255/32
2907 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2908 * [0] [@0]: dpo-drop ip6
2909 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2912 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2913 * [0] [@0]: dpo-drop ip6
2916 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2917 * [0] [@0]: dpo-drop ip6
2920 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2921 * [0] [@4]: ipv4-glean: af_packet0
2924 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2925 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2928 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2929 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2932 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2933 * [0] [@4]: ipv4-glean: af_packet1
2936 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2937 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2940 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2941 * [0] [@0]: dpo-drop ip6
2944 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2945 * [0] [@0]: dpo-drop ip6
2946 * 255.255.255.255/32
2948 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2949 * [0] [@0]: dpo-drop ip6
2953 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2955 .path = "set ip flow-hash",
2957 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2958 .function = set_ip_flow_hash_command_fn,
2962 #ifndef CLIB_MARCH_VARIANT
2964 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2967 vnet_main_t *vnm = vnet_get_main ();
2968 vnet_interface_main_t *im = &vnm->interface_main;
2969 ip4_main_t *ipm = &ip4_main;
2970 ip_lookup_main_t *lm = &ipm->lookup_main;
2971 vnet_classify_main_t *cm = &vnet_classify_main;
2972 ip4_address_t *if_addr;
2974 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2975 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2977 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2978 return VNET_API_ERROR_NO_SUCH_ENTRY;
2980 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2981 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2983 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2985 if (NULL != if_addr)
2987 fib_prefix_t pfx = {
2989 .fp_proto = FIB_PROTOCOL_IP4,
2990 .fp_addr.ip4 = *if_addr,
2994 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2998 if (table_index != (u32) ~ 0)
3000 dpo_id_t dpo = DPO_INVALID;
3005 classify_dpo_create (DPO_PROTO_IP4, table_index));
3007 fib_table_entry_special_dpo_add (fib_index,
3009 FIB_SOURCE_CLASSIFY,
3010 FIB_ENTRY_FLAG_NONE, &dpo);
3015 fib_table_entry_special_remove (fib_index,
3016 &pfx, FIB_SOURCE_CLASSIFY);
3024 static clib_error_t *
3025 set_ip_classify_command_fn (vlib_main_t * vm,
3026 unformat_input_t * input,
3027 vlib_cli_command_t * cmd)
3029 u32 table_index = ~0;
3030 int table_index_set = 0;
3031 u32 sw_if_index = ~0;
3034 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3036 if (unformat (input, "table-index %d", &table_index))
3037 table_index_set = 1;
3038 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3039 vnet_get_main (), &sw_if_index))
3045 if (table_index_set == 0)
3046 return clib_error_return (0, "classify table-index must be specified");
3048 if (sw_if_index == ~0)
3049 return clib_error_return (0, "interface / subif must be specified");
3051 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3058 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3059 return clib_error_return (0, "No such interface");
3061 case VNET_API_ERROR_NO_SUCH_ENTRY:
3062 return clib_error_return (0, "No such classifier table");
3068 * Assign a classification table to an interface. The classification
3069 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3070 * commands. Once the table is create, use this command to filter packets
3074 * Example of how to assign a classification table to an interface:
3075 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3078 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3080 .path = "set ip classify",
3082 "set ip classify intfc <interface> table-index <classify-idx>",
3083 .function = set_ip_classify_command_fn,
3087 static clib_error_t *
3088 ip4_config (vlib_main_t * vm, unformat_input_t * input)
3090 ip4_main_t *im = &ip4_main;
3093 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3095 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3098 return clib_error_return (0,
3099 "invalid heap-size parameter `%U'",
3100 format_unformat_error, input);
3103 im->mtrie_heap_size = heapsize;
3108 VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3111 * fd.io coding-style-patch-verification: ON
3114 * eval: (c-set-style "gnu")