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/dpo/load_balance.h>
53 #include <vnet/dpo/load_balance_map.h>
54 #include <vnet/dpo/classify_dpo.h>
55 #include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
57 #include <vnet/ip/ip4_forward.h>
58 #include <vnet/interface_output.h>
60 /** @brief IPv4 lookup node.
63 This is the main IPv4 lookup dispatch node.
65 @param vm vlib_main_t corresponding to the current thread
66 @param node vlib_node_runtime_t
67 @param frame vlib_frame_t whose contents should be dispatched
69 @par Graph mechanics: buffer metadata, next index usage
72 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
73 - Indicates the @c sw_if_index value of the interface that the
74 packet was received on.
75 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
76 - When the value is @c ~0 then the node performs a longest prefix
77 match (LPM) for the packet destination address in the FIB attached
78 to the receive interface.
79 - Otherwise perform LPM for the packet destination address in the
80 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
81 value (0, 1, ...) and not a VRF id.
84 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
85 - The lookup result adjacency index.
88 - Dispatches the packet to the node index found in
89 ip_adjacency_t @c adj->lookup_next_index
90 (where @c adj is the lookup result adjacency).
92 VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
95 return ip4_lookup_inline (vm, node, frame,
96 /* lookup_for_responses_to_locally_received_packets */
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;
119 u32 n_left_from, n_left_to_next, *from, *to_next;
120 ip_lookup_next_t next;
121 u32 thread_index = vm->thread_index;
123 from = vlib_frame_vector_args (frame);
124 n_left_from = frame->n_vectors;
125 next = node->cached_next_index;
127 while (n_left_from > 0)
129 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
132 while (n_left_from >= 4 && n_left_to_next >= 2)
134 ip_lookup_next_t next0, next1;
135 const load_balance_t *lb0, *lb1;
136 vlib_buffer_t *p0, *p1;
137 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
138 const ip4_header_t *ip0, *ip1;
139 const dpo_id_t *dpo0, *dpo1;
141 /* Prefetch next iteration. */
143 vlib_buffer_t *p2, *p3;
145 p2 = vlib_get_buffer (vm, from[2]);
146 p3 = vlib_get_buffer (vm, from[3]);
148 vlib_prefetch_buffer_header (p2, STORE);
149 vlib_prefetch_buffer_header (p3, STORE);
151 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
152 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
155 pi0 = to_next[0] = from[0];
156 pi1 = to_next[1] = from[1];
163 p0 = vlib_get_buffer (vm, pi0);
164 p1 = vlib_get_buffer (vm, pi1);
166 ip0 = vlib_buffer_get_current (p0);
167 ip1 = vlib_buffer_get_current (p1);
168 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
169 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
171 lb0 = load_balance_get (lbi0);
172 lb1 = load_balance_get (lbi1);
175 * this node is for via FIBs we can re-use the hash value from the
176 * to node if present.
177 * We don't want to use the same hash value at each level in the recursion
178 * graph as that would lead to polarisation
182 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
184 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
186 hc0 = vnet_buffer (p0)->ip.flow_hash =
187 vnet_buffer (p0)->ip.flow_hash >> 1;
191 hc0 = vnet_buffer (p0)->ip.flow_hash =
192 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
194 dpo0 = load_balance_get_fwd_bucket
195 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
199 dpo0 = load_balance_get_bucket_i (lb0, 0);
201 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
203 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
205 hc1 = vnet_buffer (p1)->ip.flow_hash =
206 vnet_buffer (p1)->ip.flow_hash >> 1;
210 hc1 = vnet_buffer (p1)->ip.flow_hash =
211 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
213 dpo1 = load_balance_get_fwd_bucket
214 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
218 dpo1 = load_balance_get_bucket_i (lb1, 0);
221 next0 = dpo0->dpoi_next_node;
222 next1 = dpo1->dpoi_next_node;
224 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
225 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
227 vlib_increment_combined_counter
228 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
229 vlib_increment_combined_counter
230 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
232 vlib_validate_buffer_enqueue_x2 (vm, node, next,
233 to_next, n_left_to_next,
234 pi0, pi1, next0, next1);
237 while (n_left_from > 0 && n_left_to_next > 0)
239 ip_lookup_next_t next0;
240 const load_balance_t *lb0;
243 const ip4_header_t *ip0;
244 const dpo_id_t *dpo0;
253 p0 = vlib_get_buffer (vm, pi0);
255 ip0 = vlib_buffer_get_current (p0);
256 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
258 lb0 = load_balance_get (lbi0);
261 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
263 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
265 hc0 = vnet_buffer (p0)->ip.flow_hash =
266 vnet_buffer (p0)->ip.flow_hash >> 1;
270 hc0 = vnet_buffer (p0)->ip.flow_hash =
271 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
273 dpo0 = load_balance_get_fwd_bucket
274 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
278 dpo0 = load_balance_get_bucket_i (lb0, 0);
281 next0 = dpo0->dpoi_next_node;
282 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
284 vlib_increment_combined_counter
285 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
287 vlib_validate_buffer_enqueue_x1 (vm, node, next,
288 to_next, n_left_to_next,
292 vlib_put_next_frame (vm, node, next, n_left_to_next);
295 if (node->flags & VLIB_NODE_FLAG_TRACE)
296 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
298 return frame->n_vectors;
302 VLIB_REGISTER_NODE (ip4_load_balance_node) =
304 .name = "ip4-load-balance",
305 .vector_size = sizeof (u32),
306 .sibling_of = "ip4-lookup",
307 .format_trace = format_ip4_lookup_trace,
311 #ifndef CLIB_MARCH_VARIANT
312 /* get first interface address */
314 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
315 ip_interface_address_t ** result_ia)
317 ip_lookup_main_t *lm = &im->lookup_main;
318 ip_interface_address_t *ia = 0;
319 ip4_address_t *result = 0;
322 foreach_ip_interface_address
323 (lm, ia, sw_if_index,
324 1 /* honor unnumbered */ ,
327 ip_interface_address_get_address (lm, ia);
333 *result_ia = result ? ia : 0;
338 ip4_add_subnet_bcast_route (u32 fib_index,
342 vnet_sw_interface_flags_t iflags;
344 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
346 fib_table_entry_special_remove(fib_index,
348 FIB_SOURCE_INTERFACE);
350 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
352 fib_table_entry_update_one_path (fib_index, pfx,
353 FIB_SOURCE_INTERFACE,
356 /* No next-hop address */
362 // no out-label stack
364 FIB_ROUTE_PATH_FLAG_NONE);
368 fib_table_entry_special_add(fib_index,
370 FIB_SOURCE_INTERFACE,
371 (FIB_ENTRY_FLAG_DROP |
372 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
377 ip4_add_interface_routes (u32 sw_if_index,
378 ip4_main_t * im, u32 fib_index,
379 ip_interface_address_t * a)
381 ip_lookup_main_t *lm = &im->lookup_main;
382 ip4_address_t *address = ip_interface_address_get_address (lm, a);
384 .fp_len = a->address_length,
385 .fp_proto = FIB_PROTOCOL_IP4,
386 .fp_addr.ip4 = *address,
389 if (pfx.fp_len <= 30)
391 /* a /30 or shorter - add a glean for the network address */
392 fib_table_entry_update_one_path (fib_index, &pfx,
393 FIB_SOURCE_INTERFACE,
394 (FIB_ENTRY_FLAG_CONNECTED |
395 FIB_ENTRY_FLAG_ATTACHED),
397 /* No next-hop address */
403 // no out-label stack
405 FIB_ROUTE_PATH_FLAG_NONE);
407 /* Add the two broadcast addresses as drop */
408 fib_prefix_t net_pfx = {
410 .fp_proto = FIB_PROTOCOL_IP4,
411 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
413 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
414 fib_table_entry_special_add(fib_index,
416 FIB_SOURCE_INTERFACE,
417 (FIB_ENTRY_FLAG_DROP |
418 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
419 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
420 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
421 ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
423 else if (pfx.fp_len == 31)
425 u32 mask = clib_host_to_net_u32(1);
426 fib_prefix_t net_pfx = pfx;
429 net_pfx.fp_addr.ip4.as_u32 ^= mask;
431 /* a /31 - add the other end as an attached host */
432 fib_table_entry_update_one_path (fib_index, &net_pfx,
433 FIB_SOURCE_INTERFACE,
434 (FIB_ENTRY_FLAG_ATTACHED),
442 FIB_ROUTE_PATH_FLAG_NONE);
446 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
448 u32 classify_table_index =
449 lm->classify_table_index_by_sw_if_index[sw_if_index];
450 if (classify_table_index != (u32) ~ 0)
452 dpo_id_t dpo = DPO_INVALID;
457 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
459 fib_table_entry_special_dpo_add (fib_index,
462 FIB_ENTRY_FLAG_NONE, &dpo);
467 fib_table_entry_update_one_path (fib_index, &pfx,
468 FIB_SOURCE_INTERFACE,
469 (FIB_ENTRY_FLAG_CONNECTED |
470 FIB_ENTRY_FLAG_LOCAL),
477 FIB_ROUTE_PATH_FLAG_NONE);
481 ip4_del_interface_routes (ip4_main_t * im,
483 ip4_address_t * address, u32 address_length)
486 .fp_len = address_length,
487 .fp_proto = FIB_PROTOCOL_IP4,
488 .fp_addr.ip4 = *address,
491 if (pfx.fp_len <= 30)
493 fib_prefix_t net_pfx = {
495 .fp_proto = FIB_PROTOCOL_IP4,
496 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
498 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
499 fib_table_entry_special_remove(fib_index,
501 FIB_SOURCE_INTERFACE);
502 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
503 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
504 fib_table_entry_special_remove(fib_index,
506 FIB_SOURCE_INTERFACE);
507 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
509 else if (pfx.fp_len == 31)
511 u32 mask = clib_host_to_net_u32(1);
512 fib_prefix_t net_pfx = pfx;
515 net_pfx.fp_addr.ip4.as_u32 ^= mask;
517 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
521 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
525 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
527 ip4_main_t *im = &ip4_main;
529 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
532 * enable/disable only on the 1<->0 transition
536 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
541 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
542 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
545 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
549 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
550 sw_if_index, !is_enable, 0, 0);
553 static clib_error_t *
554 ip4_add_del_interface_address_internal (vlib_main_t * vm,
556 ip4_address_t * address,
557 u32 address_length, u32 is_del)
559 vnet_main_t *vnm = vnet_get_main ();
560 ip4_main_t *im = &ip4_main;
561 ip_lookup_main_t *lm = &im->lookup_main;
562 clib_error_t *error = 0;
563 u32 if_address_index, elts_before;
564 ip4_address_fib_t ip4_af, *addr_fib = 0;
566 /* local0 interface doesn't support IP addressing */
567 if (sw_if_index == 0)
570 clib_error_create ("local0 interface doesn't support IP addressing");
573 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
574 ip4_addr_fib_init (&ip4_af, address,
575 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
576 vec_add1 (addr_fib, ip4_af);
579 * there is no support for adj-fib handling in the presence of overlapping
580 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
586 /* When adding an address check that it does not conflict
587 with an existing address on any interface in this table. */
588 ip_interface_address_t *ia;
589 vnet_sw_interface_t *sif;
591 pool_foreach(sif, vnm->interface_main.sw_interfaces,
593 if (im->fib_index_by_sw_if_index[sw_if_index] ==
594 im->fib_index_by_sw_if_index[sif->sw_if_index])
596 foreach_ip_interface_address
597 (&im->lookup_main, ia, sif->sw_if_index,
598 0 /* honor unnumbered */ ,
601 ip_interface_address_get_address
602 (&im->lookup_main, ia);
603 if (ip4_destination_matches_route
604 (im, address, x, ia->address_length) ||
605 ip4_destination_matches_route (im,
610 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
614 ("failed to add %U which conflicts with %U for interface %U",
615 format_ip4_address_and_length, address,
617 format_ip4_address_and_length, x,
619 format_vnet_sw_if_index_name, vnm,
628 elts_before = pool_elts (lm->if_address_pool);
630 error = ip_interface_address_add_del
631 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
635 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
638 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
640 ip4_add_interface_routes (sw_if_index,
641 im, ip4_af.fib_index,
643 (lm->if_address_pool, if_address_index));
645 /* If pool did not grow/shrink: add duplicate address. */
646 if (elts_before != pool_elts (lm->if_address_pool))
648 ip4_add_del_interface_address_callback_t *cb;
649 vec_foreach (cb, im->add_del_interface_address_callbacks)
650 cb->function (im, cb->function_opaque, sw_if_index,
651 address, address_length, if_address_index, is_del);
660 ip4_add_del_interface_address (vlib_main_t * vm,
662 ip4_address_t * address,
663 u32 address_length, u32 is_del)
665 return ip4_add_del_interface_address_internal
666 (vm, sw_if_index, address, address_length, is_del);
670 ip4_directed_broadcast (u32 sw_if_index, u8 enable)
672 ip_interface_address_t *ia;
678 * when directed broadcast is enabled, the subnet braodcast route will forward
679 * packets using an adjacency with a broadcast MAC. otherwise it drops
682 foreach_ip_interface_address(&im->lookup_main, ia,
685 if (ia->address_length <= 30)
689 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
693 .fp_proto = FIB_PROTOCOL_IP4,
695 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
699 ip4_add_subnet_bcast_route
700 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
709 /* Built-in ip4 unicast rx feature path definition */
711 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
713 .arc_name = "ip4-unicast",
714 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
715 .last_in_arc = "ip4-lookup",
716 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
719 VNET_FEATURE_INIT (ip4_flow_classify, static) =
721 .arc_name = "ip4-unicast",
722 .node_name = "ip4-flow-classify",
723 .runs_before = VNET_FEATURES ("ip4-inacl"),
726 VNET_FEATURE_INIT (ip4_inacl, static) =
728 .arc_name = "ip4-unicast",
729 .node_name = "ip4-inacl",
730 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
733 VNET_FEATURE_INIT (ip4_source_check_1, static) =
735 .arc_name = "ip4-unicast",
736 .node_name = "ip4-source-check-via-rx",
737 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
740 VNET_FEATURE_INIT (ip4_source_check_2, static) =
742 .arc_name = "ip4-unicast",
743 .node_name = "ip4-source-check-via-any",
744 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
747 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
749 .arc_name = "ip4-unicast",
750 .node_name = "ip4-source-and-port-range-check-rx",
751 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
754 VNET_FEATURE_INIT (ip4_policer_classify, static) =
756 .arc_name = "ip4-unicast",
757 .node_name = "ip4-policer-classify",
758 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
761 VNET_FEATURE_INIT (ip4_ipsec, static) =
763 .arc_name = "ip4-unicast",
764 .node_name = "ipsec4-input-feature",
765 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
768 VNET_FEATURE_INIT (ip4_vpath, static) =
770 .arc_name = "ip4-unicast",
771 .node_name = "vpath-input-ip4",
772 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
775 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
777 .arc_name = "ip4-unicast",
778 .node_name = "ip4-vxlan-bypass",
779 .runs_before = VNET_FEATURES ("ip4-lookup"),
782 VNET_FEATURE_INIT (ip4_not_enabled, static) =
784 .arc_name = "ip4-unicast",
785 .node_name = "ip4-not-enabled",
786 .runs_before = VNET_FEATURES ("ip4-lookup"),
789 VNET_FEATURE_INIT (ip4_lookup, static) =
791 .arc_name = "ip4-unicast",
792 .node_name = "ip4-lookup",
793 .runs_before = 0, /* not before any other features */
796 /* Built-in ip4 multicast rx feature path definition */
797 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
799 .arc_name = "ip4-multicast",
800 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
801 .last_in_arc = "ip4-mfib-forward-lookup",
802 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
805 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
807 .arc_name = "ip4-multicast",
808 .node_name = "vpath-input-ip4",
809 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
812 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
814 .arc_name = "ip4-multicast",
815 .node_name = "ip4-not-enabled",
816 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
819 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
821 .arc_name = "ip4-multicast",
822 .node_name = "ip4-mfib-forward-lookup",
823 .runs_before = 0, /* last feature */
826 /* Source and port-range check ip4 tx feature path definition */
827 VNET_FEATURE_ARC_INIT (ip4_output, static) =
829 .arc_name = "ip4-output",
830 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
831 .last_in_arc = "interface-output",
832 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
835 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
837 .arc_name = "ip4-output",
838 .node_name = "ip4-source-and-port-range-check-tx",
839 .runs_before = VNET_FEATURES ("ip4-outacl"),
842 VNET_FEATURE_INIT (ip4_outacl, static) =
844 .arc_name = "ip4-output",
845 .node_name = "ip4-outacl",
846 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
849 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
851 .arc_name = "ip4-output",
852 .node_name = "ipsec4-output-feature",
853 .runs_before = VNET_FEATURES ("interface-output"),
856 /* Built-in ip4 tx feature path definition */
857 VNET_FEATURE_INIT (ip4_interface_output, static) =
859 .arc_name = "ip4-output",
860 .node_name = "interface-output",
861 .runs_before = 0, /* not before any other features */
865 static clib_error_t *
866 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
868 ip4_main_t *im = &ip4_main;
870 /* Fill in lookup tables with default table (0). */
871 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
872 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
876 ip4_main_t *im4 = &ip4_main;
877 ip_lookup_main_t *lm4 = &im4->lookup_main;
878 ip_interface_address_t *ia = 0;
879 ip4_address_t *address;
880 vlib_main_t *vm = vlib_get_main ();
882 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
884 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
886 address = ip_interface_address_get_address (lm4, ia);
887 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
892 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
895 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
896 sw_if_index, is_add, 0, 0);
898 return /* no error */ 0;
901 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
903 /* Global IP4 main. */
904 #ifndef CLIB_MARCH_VARIANT
906 #endif /* CLIB_MARCH_VARIANT */
908 static clib_error_t *
909 ip4_lookup_init (vlib_main_t * vm)
911 ip4_main_t *im = &ip4_main;
915 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
917 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
919 if ((error = vlib_call_init_function (vm, fib_module_init)))
921 if ((error = vlib_call_init_function (vm, mfib_module_init)))
924 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
929 m = pow2_mask (i) << (32 - i);
932 im->fib_masks[i] = clib_host_to_net_u32 (m);
935 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
937 /* Create FIB with index 0 and table id of 0. */
938 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
939 FIB_SOURCE_DEFAULT_ROUTE);
940 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
941 MFIB_SOURCE_DEFAULT_ROUTE);
945 pn = pg_get_node (ip4_lookup_node.index);
946 pn->unformat_edit = unformat_pg_ip4_header;
950 ethernet_arp_header_t h;
952 clib_memset (&h, 0, sizeof (h));
954 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
955 #define _8(f,v) h.f = v;
956 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
957 _16 (l3_type, ETHERNET_TYPE_IP4);
958 _8 (n_l2_address_bytes, 6);
959 _8 (n_l3_address_bytes, 4);
960 _16 (opcode, ETHERNET_ARP_OPCODE_request);
964 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
967 /* alloc chunk size */ 8,
974 VLIB_INIT_FUNCTION (ip4_lookup_init);
978 /* Adjacency taken. */
983 /* Packet data, possibly *after* rewrite. */
984 u8 packet_data[64 - 1 * sizeof (u32)];
986 ip4_forward_next_trace_t;
988 #ifndef CLIB_MARCH_VARIANT
990 format_ip4_forward_next_trace (u8 * s, va_list * args)
992 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
993 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
994 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
995 u32 indent = format_get_indent (s);
996 s = format (s, "%U%U",
997 format_white_space, indent,
998 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1004 format_ip4_lookup_trace (u8 * s, va_list * args)
1006 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1007 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1008 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1009 u32 indent = format_get_indent (s);
1011 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1012 t->fib_index, t->dpo_index, t->flow_hash);
1013 s = format (s, "\n%U%U",
1014 format_white_space, indent,
1015 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1020 format_ip4_rewrite_trace (u8 * s, va_list * args)
1022 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1023 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1024 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1025 u32 indent = format_get_indent (s);
1027 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1028 t->fib_index, t->dpo_index, format_ip_adjacency,
1029 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1030 s = format (s, "\n%U%U",
1031 format_white_space, indent,
1032 format_ip_adjacency_packet_data,
1033 t->dpo_index, t->packet_data, sizeof (t->packet_data));
1037 #ifndef CLIB_MARCH_VARIANT
1038 /* Common trace function for all ip4-forward next nodes. */
1040 ip4_forward_next_trace (vlib_main_t * vm,
1041 vlib_node_runtime_t * node,
1042 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1045 ip4_main_t *im = &ip4_main;
1047 n_left = frame->n_vectors;
1048 from = vlib_frame_vector_args (frame);
1053 vlib_buffer_t *b0, *b1;
1054 ip4_forward_next_trace_t *t0, *t1;
1056 /* Prefetch next iteration. */
1057 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1058 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1063 b0 = vlib_get_buffer (vm, bi0);
1064 b1 = vlib_get_buffer (vm, bi1);
1066 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1068 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1069 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1070 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1072 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1073 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1074 vec_elt (im->fib_index_by_sw_if_index,
1075 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1077 clib_memcpy_fast (t0->packet_data,
1078 vlib_buffer_get_current (b0),
1079 sizeof (t0->packet_data));
1081 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1083 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1084 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1085 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1087 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1088 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1089 vec_elt (im->fib_index_by_sw_if_index,
1090 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1091 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1092 sizeof (t1->packet_data));
1102 ip4_forward_next_trace_t *t0;
1106 b0 = vlib_get_buffer (vm, bi0);
1108 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1110 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1111 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1112 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1114 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1115 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1116 vec_elt (im->fib_index_by_sw_if_index,
1117 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1118 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1119 sizeof (t0->packet_data));
1126 /* Compute TCP/UDP/ICMP4 checksum in software. */
1128 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1132 u32 ip_header_length, payload_length_host_byte_order;
1133 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
1135 void *data_this_buffer;
1137 /* Initialize checksum with ip header. */
1138 ip_header_length = ip4_header_bytes (ip0);
1139 payload_length_host_byte_order =
1140 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1142 clib_host_to_net_u32 (payload_length_host_byte_order +
1143 (ip0->protocol << 16));
1145 if (BITS (uword) == 32)
1148 ip_csum_with_carry (sum0,
1149 clib_mem_unaligned (&ip0->src_address, u32));
1151 ip_csum_with_carry (sum0,
1152 clib_mem_unaligned (&ip0->dst_address, u32));
1156 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1158 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1159 data_this_buffer = (void *) ip0 + ip_header_length;
1160 n_ip_bytes_this_buffer =
1161 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1162 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1164 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
1165 n_ip_bytes_this_buffer - ip_header_length : 0;
1169 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1170 n_bytes_left -= n_this_buffer;
1171 if (n_bytes_left == 0)
1174 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1175 p0 = vlib_get_buffer (vm, p0->next_buffer);
1176 data_this_buffer = vlib_buffer_get_current (p0);
1177 n_this_buffer = clib_min (p0->current_length, n_bytes_left);
1180 sum16 = ~ip_csum_fold (sum0);
1186 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1188 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1192 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1193 || ip0->protocol == IP_PROTOCOL_UDP);
1195 udp0 = (void *) (ip0 + 1);
1196 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1198 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1199 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1203 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1205 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1206 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1213 VNET_FEATURE_ARC_INIT (ip4_local) =
1215 .arc_name = "ip4-local",
1216 .start_nodes = VNET_FEATURES ("ip4-local"),
1217 .last_in_arc = "ip4-local-end-of-arc",
1222 ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1223 ip4_header_t * ip, u8 is_udp, u8 * error,
1227 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1228 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1232 u32 ip_len, udp_len;
1234 udp = ip4_next_header (ip);
1235 /* Verify UDP length. */
1236 ip_len = clib_net_to_host_u16 (ip->length);
1237 udp_len = clib_net_to_host_u16 (udp->length);
1239 len_diff = ip_len - udp_len;
1240 *good_tcp_udp &= len_diff >= 0;
1241 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1245 #define ip4_local_csum_is_offloaded(_b) \
1246 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1247 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1249 #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1250 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1251 || ip4_local_csum_is_offloaded (_b)))
1253 #define ip4_local_csum_is_valid(_b) \
1254 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1255 || (ip4_local_csum_is_offloaded (_b))) != 0
1258 ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1259 ip4_header_t * ih, u8 * error)
1261 u8 is_udp, is_tcp_udp, good_tcp_udp;
1263 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1264 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1266 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1267 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1269 good_tcp_udp = ip4_local_csum_is_valid (b);
1271 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1272 *error = (is_tcp_udp && !good_tcp_udp
1273 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1277 ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1278 ip4_header_t ** ih, u8 * error)
1280 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1282 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1283 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1285 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1286 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1288 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1289 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1291 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1292 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1295 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1298 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1302 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1303 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1304 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1305 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1309 ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1310 vlib_buffer_t * b, u16 * next, u8 error,
1311 u8 head_of_feature_arc)
1313 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1316 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1317 b->error = error ? error_node->errors[error] : 0;
1318 if (head_of_feature_arc)
1321 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1323 vnet_feature_arc_start (arc_index,
1324 vnet_buffer (b)->sw_if_index[VLIB_RX],
1337 } ip4_local_last_check_t;
1340 ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1341 ip4_local_last_check_t * last_check, u8 * error0)
1343 ip4_fib_mtrie_leaf_t leaf0;
1344 ip4_fib_mtrie_t *mtrie0;
1345 const dpo_id_t *dpo0;
1346 load_balance_t *lb0;
1349 vnet_buffer (b)->ip.fib_index =
1350 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1351 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1353 if (PREDICT_FALSE (last_check->first ||
1354 (last_check->src.as_u32 != ip0->src_address.as_u32)))
1356 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1357 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1358 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1359 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1360 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1362 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1363 vnet_buffer (b)->ip.adj_index[VLIB_RX] = lbi0;
1365 lb0 = load_balance_get (lbi0);
1366 dpo0 = load_balance_get_bucket_i (lb0, 0);
1369 * Must have a route to source otherwise we drop the packet.
1370 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1373 * - the source is a recieve => it's from us => bogus, do this
1374 * first since it sets a different error code.
1375 * - uRPF check for any route to source - accept if passes.
1376 * - allow packets destined to the broadcast address from unknown sources
1379 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1380 && dpo0->dpoi_type == DPO_RECEIVE) ?
1381 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1382 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1383 && !fib_urpf_check_size (lb0->lb_urpf)
1384 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1385 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1387 last_check->src.as_u32 = ip0->src_address.as_u32;
1388 last_check->lbi = lbi0;
1389 last_check->error = *error0;
1393 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1394 vnet_buffer (b)->ip.adj_index[VLIB_RX] = last_check->lbi;
1395 *error0 = last_check->error;
1396 last_check->first = 0;
1401 ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1402 ip4_local_last_check_t * last_check, u8 * error)
1404 ip4_fib_mtrie_leaf_t leaf[2];
1405 ip4_fib_mtrie_t *mtrie[2];
1406 const dpo_id_t *dpo[2];
1407 load_balance_t *lb[2];
1411 not_last_hit = last_check->first;
1412 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1413 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1415 vnet_buffer (b[0])->ip.fib_index =
1416 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1417 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1418 vnet_buffer (b[0])->ip.fib_index;
1420 vnet_buffer (b[1])->ip.fib_index =
1421 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1422 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1423 vnet_buffer (b[1])->ip.fib_index;
1425 if (PREDICT_FALSE (not_last_hit))
1427 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1428 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1430 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1431 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1433 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1434 &ip[0]->src_address, 2);
1435 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1436 &ip[1]->src_address, 2);
1438 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1439 &ip[0]->src_address, 3);
1440 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1441 &ip[1]->src_address, 3);
1443 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1444 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1446 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1447 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = lbi[0];
1449 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1450 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = lbi[1];
1452 lb[0] = load_balance_get (lbi[0]);
1453 lb[1] = load_balance_get (lbi[1]);
1455 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1456 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1458 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1459 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1460 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1461 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1462 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1463 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1464 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1466 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1467 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1468 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1469 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1470 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1471 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1472 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1474 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1475 last_check->lbi = lbi[1];
1476 last_check->error = error[1];
1480 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1481 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = last_check->lbi;
1483 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1484 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = last_check->lbi;
1486 error[0] = last_check->error;
1487 error[1] = last_check->error;
1488 last_check->first = 0;
1492 enum ip_local_packet_type_e
1494 IP_LOCAL_PACKET_TYPE_L4,
1495 IP_LOCAL_PACKET_TYPE_NAT,
1496 IP_LOCAL_PACKET_TYPE_FRAG,
1500 * Determine packet type and next node.
1502 * The expectation is that all packets that are not L4 will skip
1503 * checksums and source checks.
1506 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1508 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1510 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1512 *next = IP_LOCAL_NEXT_REASSEMBLY;
1513 return IP_LOCAL_PACKET_TYPE_FRAG;
1515 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1517 *next = lm->local_next_by_ip_protocol[ip->protocol];
1518 return IP_LOCAL_PACKET_TYPE_NAT;
1521 *next = lm->local_next_by_ip_protocol[ip->protocol];
1522 return IP_LOCAL_PACKET_TYPE_L4;
1526 ip4_local_inline (vlib_main_t * vm,
1527 vlib_node_runtime_t * node,
1528 vlib_frame_t * frame, int head_of_feature_arc)
1530 u32 *from, n_left_from;
1531 vlib_node_runtime_t *error_node =
1532 vlib_node_get_runtime (vm, ip4_input_node.index);
1533 u16 nexts[VLIB_FRAME_SIZE], *next;
1534 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1535 ip4_header_t *ip[2];
1538 ip4_local_last_check_t last_check = {
1540 * 0.0.0.0 can appear as the source address of an IP packet,
1541 * as can any other address, hence the need to use the 'first'
1542 * member to make sure the .lbi is initialised for the first
1545 .src = {.as_u32 = 0},
1547 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1551 from = vlib_frame_vector_args (frame);
1552 n_left_from = frame->n_vectors;
1554 if (node->flags & VLIB_NODE_FLAG_TRACE)
1555 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1557 vlib_get_buffers (vm, from, bufs, n_left_from);
1561 while (n_left_from >= 6)
1565 /* Prefetch next iteration. */
1567 vlib_prefetch_buffer_header (b[4], LOAD);
1568 vlib_prefetch_buffer_header (b[5], LOAD);
1570 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1571 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1574 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1576 ip[0] = vlib_buffer_get_current (b[0]);
1577 ip[1] = vlib_buffer_get_current (b[1]);
1579 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1580 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1582 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1583 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1585 not_batch = pt[0] ^ pt[1];
1587 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1590 if (PREDICT_TRUE (not_batch == 0))
1592 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1593 ip4_local_check_src_x2 (b, ip, &last_check, error);
1599 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1600 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1604 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1605 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
1611 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1612 head_of_feature_arc);
1613 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1614 head_of_feature_arc);
1621 while (n_left_from > 0)
1623 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1625 ip[0] = vlib_buffer_get_current (b[0]);
1626 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1627 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1629 if (head_of_feature_arc == 0 || pt[0])
1632 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1633 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1637 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1638 head_of_feature_arc);
1645 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1646 return frame->n_vectors;
1649 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1650 vlib_frame_t * frame)
1652 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1656 VLIB_REGISTER_NODE (ip4_local_node) =
1658 .name = "ip4-local",
1659 .vector_size = sizeof (u32),
1660 .format_trace = format_ip4_forward_next_trace,
1661 .n_next_nodes = IP_LOCAL_N_NEXT,
1664 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1665 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1666 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1667 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1668 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
1674 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1675 vlib_node_runtime_t * node,
1676 vlib_frame_t * frame)
1678 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1682 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1683 .name = "ip4-local-end-of-arc",
1684 .vector_size = sizeof (u32),
1686 .format_trace = format_ip4_forward_next_trace,
1687 .sibling_of = "ip4-local",
1690 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1691 .arc_name = "ip4-local",
1692 .node_name = "ip4-local-end-of-arc",
1693 .runs_before = 0, /* not before any other features */
1697 #ifndef CLIB_MARCH_VARIANT
1699 ip4_register_protocol (u32 protocol, u32 node_index)
1701 vlib_main_t *vm = vlib_get_main ();
1702 ip4_main_t *im = &ip4_main;
1703 ip_lookup_main_t *lm = &im->lookup_main;
1705 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1706 lm->local_next_by_ip_protocol[protocol] =
1707 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1711 static clib_error_t *
1712 show_ip_local_command_fn (vlib_main_t * vm,
1713 unformat_input_t * input, vlib_cli_command_t * cmd)
1715 ip4_main_t *im = &ip4_main;
1716 ip_lookup_main_t *lm = &im->lookup_main;
1719 vlib_cli_output (vm, "Protocols handled by ip4_local");
1720 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1722 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1724 u32 node_index = vlib_get_node (vm,
1725 ip4_local_node.index)->
1726 next_nodes[lm->local_next_by_ip_protocol[i]];
1727 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1737 * Display the set of protocols handled by the local IPv4 stack.
1740 * Example of how to display local protocol table:
1741 * @cliexstart{show ip local}
1742 * Protocols handled by ip4_local
1749 VLIB_CLI_COMMAND (show_ip_local, static) =
1751 .path = "show ip local",
1752 .function = show_ip_local_command_fn,
1753 .short_help = "show ip local",
1758 ip4_arp_inline (vlib_main_t * vm,
1759 vlib_node_runtime_t * node,
1760 vlib_frame_t * frame, int is_glean)
1762 vnet_main_t *vnm = vnet_get_main ();
1763 ip4_main_t *im = &ip4_main;
1764 ip_lookup_main_t *lm = &im->lookup_main;
1765 u32 *from, *to_next_drop;
1766 uword n_left_from, n_left_to_next_drop, next_index;
1767 u32 thread_index = vm->thread_index;
1770 if (node->flags & VLIB_NODE_FLAG_TRACE)
1771 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1773 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
1775 from = vlib_frame_vector_args (frame);
1776 n_left_from = frame->n_vectors;
1777 next_index = node->cached_next_index;
1778 if (next_index == IP4_ARP_NEXT_DROP)
1779 next_index = IP4_ARP_N_NEXT; /* point to first interface */
1781 while (n_left_from > 0)
1783 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1784 to_next_drop, n_left_to_next_drop);
1786 while (n_left_from > 0 && n_left_to_next_drop > 0)
1788 u32 pi0, bi0, adj_index0, sw_if_index0;
1789 ip_adjacency_t *adj0;
1790 vlib_buffer_t *p0, *b0;
1791 ip4_address_t resolve0;
1792 ethernet_arp_header_t *h0;
1793 vnet_hw_interface_t *hw_if0;
1797 p0 = vlib_get_buffer (vm, pi0);
1801 to_next_drop[0] = pi0;
1803 n_left_to_next_drop -= 1;
1805 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1806 adj0 = adj_get (adj_index0);
1810 /* resolve the packet's destination */
1811 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1812 resolve0 = ip0->dst_address;
1816 /* resolve the incomplete adj */
1817 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
1820 /* combine the address and interface for the hash key */
1821 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1822 r0 = (u64) resolve0.data_u32 << 32;
1825 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
1827 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
1832 * the adj has been updated to a rewrite but the node the DPO that got
1833 * us here hasn't - yet. no big deal. we'll drop while we wait.
1835 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1837 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
1842 * Can happen if the control-plane is programming tables
1843 * with traffic flowing; at least that's today's lame excuse.
1845 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1846 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
1848 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
1851 /* Send ARP request. */
1853 vlib_packet_template_get_packet (vm,
1854 &im->ip4_arp_request_packet_template,
1856 b0 = vlib_get_buffer (vm, bi0);
1858 /* copy the persistent fields from the original */
1859 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
1861 /* Seems we're out of buffers */
1862 if (PREDICT_FALSE (!h0))
1864 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
1868 /* Add rewrite/encap string for ARP packet. */
1869 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1871 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1873 /* Src ethernet address in ARP header. */
1874 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
1875 hw_if0->hw_address);
1878 /* The interface's source address is stashed in the Glean Adj */
1879 h0->ip4_over_ethernet[0].ip4 =
1880 adj0->sub_type.glean.receive_addr.ip4;
1884 /* Src IP address in ARP header. */
1885 if (ip4_src_address_for_packet (lm, sw_if_index0,
1886 &h0->ip4_over_ethernet[0].ip4))
1888 /* No source address available */
1889 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1890 vlib_buffer_free (vm, &bi0, 1);
1894 h0->ip4_over_ethernet[1].ip4 = resolve0;
1896 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
1898 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1899 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1900 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1902 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1904 vlib_set_next_frame_buffer (vm, node,
1905 adj0->rewrite_header.next_index, bi0);
1908 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1911 return frame->n_vectors;
1914 VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1915 vlib_frame_t * frame)
1917 return (ip4_arp_inline (vm, node, frame, 0));
1920 VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1921 vlib_frame_t * frame)
1923 return (ip4_arp_inline (vm, node, frame, 1));
1926 static char *ip4_arp_error_strings[] = {
1927 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
1928 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
1929 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
1930 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1931 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
1932 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
1936 VLIB_REGISTER_NODE (ip4_arp_node) =
1939 .vector_size = sizeof (u32),
1940 .format_trace = format_ip4_forward_next_trace,
1941 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1942 .error_strings = ip4_arp_error_strings,
1943 .n_next_nodes = IP4_ARP_N_NEXT,
1946 [IP4_ARP_NEXT_DROP] = "error-drop",
1950 VLIB_REGISTER_NODE (ip4_glean_node) =
1952 .name = "ip4-glean",
1953 .vector_size = sizeof (u32),
1954 .format_trace = format_ip4_forward_next_trace,
1955 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1956 .error_strings = ip4_arp_error_strings,
1957 .n_next_nodes = IP4_ARP_N_NEXT,
1959 [IP4_ARP_NEXT_DROP] = "error-drop",
1964 #define foreach_notrace_ip4_arp_error \
1970 _(NO_SOURCE_ADDRESS)
1972 static clib_error_t *
1973 arp_notrace_init (vlib_main_t * vm)
1975 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
1977 /* don't trace ARP request packets */
1979 vnet_pcap_drop_trace_filter_add_del \
1980 (rt->errors[IP4_ARP_ERROR_##a], \
1982 foreach_notrace_ip4_arp_error;
1987 VLIB_INIT_FUNCTION (arp_notrace_init);
1990 #ifndef CLIB_MARCH_VARIANT
1991 /* Send an ARP request to see if given destination is reachable on given interface. */
1993 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
1996 vnet_main_t *vnm = vnet_get_main ();
1997 ip4_main_t *im = &ip4_main;
1998 ethernet_arp_header_t *h;
2000 ip_interface_address_t *ia;
2001 ip_adjacency_t *adj;
2002 vnet_hw_interface_t *hi;
2003 vnet_sw_interface_t *si;
2007 u8 unicast_rewrite = 0;
2009 si = vnet_get_sw_interface (vnm, sw_if_index);
2011 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2013 return clib_error_return (0, "%U: interface %U down",
2014 format_ip4_address, dst,
2015 format_vnet_sw_if_index_name, vnm,
2020 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2023 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2024 return clib_error_return
2026 "no matching interface address for destination %U (interface %U)",
2027 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2031 h = vlib_packet_template_get_packet (vm,
2032 &im->ip4_arp_request_packet_template,
2036 return clib_error_return (0, "ARP request packet allocation failed");
2038 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2039 if (PREDICT_FALSE (!hi->hw_address))
2041 return clib_error_return (0, "%U: interface %U do not support ip probe",
2042 format_ip4_address, dst,
2043 format_vnet_sw_if_index_name, vnm,
2047 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
2049 h->ip4_over_ethernet[0].ip4 = src[0];
2050 h->ip4_over_ethernet[1].ip4 = dst[0];
2052 b = vlib_get_buffer (vm, bi);
2053 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2054 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2056 ip46_address_t nh = {
2060 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2061 VNET_LINK_IP4, &nh, sw_if_index);
2064 /* Peer has been previously resolved, retrieve glean adj instead */
2065 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2068 unicast_rewrite = 1;
2072 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2073 VNET_LINK_IP4, sw_if_index, &nh);
2078 /* Add encapsulation string for software interface (e.g. ethernet header). */
2079 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2080 if (unicast_rewrite)
2082 u16 *etype = vlib_buffer_get_current (b) - 2;
2083 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2085 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2088 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2089 u32 *to_next = vlib_frame_vector_args (f);
2092 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2096 return /* no error */ 0;
2102 IP4_REWRITE_NEXT_DROP,
2103 IP4_REWRITE_NEXT_ICMP_ERROR,
2104 IP4_REWRITE_NEXT_FRAGMENT,
2105 IP4_REWRITE_N_NEXT /* Last */
2106 } ip4_rewrite_next_t;
2109 * This bits of an IPv4 address to mask to construct a multicast
2112 #if CLIB_ARCH_IS_BIG_ENDIAN
2113 #define IP4_MCAST_ADDR_MASK 0x007fffff
2115 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2119 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2120 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
2122 if (packet_len > adj_packet_bytes)
2124 *error = IP4_ERROR_MTU_EXCEEDED;
2127 icmp4_error_set_vnet_buffer
2128 (b, ICMP4_destination_unreachable,
2129 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2131 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2135 /* IP fragmentation */
2136 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2137 IP4_FRAG_NEXT_IP4_REWRITE, 0);
2138 *next = IP4_REWRITE_NEXT_FRAGMENT;
2143 /* Decrement TTL & update checksum.
2144 Works either endian, so no need for byte swap. */
2145 static_always_inline void
2146 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2151 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2153 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2159 /* Input node should have reject packets with ttl 0. */
2160 ASSERT (ip->ttl > 0);
2162 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2163 checksum += checksum >= 0xffff;
2165 ip->checksum = checksum;
2170 * If the ttl drops below 1 when forwarding, generate
2173 if (PREDICT_FALSE (ttl <= 0))
2175 *error = IP4_ERROR_TIME_EXPIRED;
2176 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2177 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2178 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2180 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2183 /* Verify checksum. */
2184 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2185 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2190 ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2191 vlib_node_runtime_t * node,
2192 vlib_frame_t * frame,
2193 int do_counters, int is_midchain, int is_mcast,
2196 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2197 u32 *from = vlib_frame_vector_args (frame);
2198 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2199 u16 nexts[VLIB_FRAME_SIZE], *next;
2201 vlib_node_runtime_t *error_node =
2202 vlib_node_get_runtime (vm, ip4_input_node.index);
2204 n_left_from = frame->n_vectors;
2205 u32 thread_index = vm->thread_index;
2207 vlib_get_buffers (vm, from, bufs, n_left_from);
2208 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2210 if (n_left_from >= 6)
2213 for (i = 2; i < 6; i++)
2214 vlib_prefetch_buffer_header (bufs[i], LOAD);
2219 while (n_left_from >= 8)
2221 ip_adjacency_t *adj0, *adj1;
2222 ip4_header_t *ip0, *ip1;
2223 u32 rw_len0, error0, adj_index0;
2224 u32 rw_len1, error1, adj_index1;
2225 u32 tx_sw_if_index0, tx_sw_if_index1;
2228 vlib_prefetch_buffer_header (b[6], LOAD);
2229 vlib_prefetch_buffer_header (b[7], LOAD);
2231 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2232 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2235 * pre-fetch the per-adjacency counters
2239 vlib_prefetch_combined_counter (&adjacency_counters,
2240 thread_index, adj_index0);
2241 vlib_prefetch_combined_counter (&adjacency_counters,
2242 thread_index, adj_index1);
2245 ip0 = vlib_buffer_get_current (b[0]);
2246 ip1 = vlib_buffer_get_current (b[1]);
2248 error0 = error1 = IP4_ERROR_NONE;
2250 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2251 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2253 /* Rewrite packet header and updates lengths. */
2254 adj0 = adj_get (adj_index0);
2255 adj1 = adj_get (adj_index1);
2257 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2258 rw_len0 = adj0[0].rewrite_header.data_bytes;
2259 rw_len1 = adj1[0].rewrite_header.data_bytes;
2260 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2261 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2263 p = vlib_buffer_get_current (b[2]);
2264 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2265 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2267 p = vlib_buffer_get_current (b[3]);
2268 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2269 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2271 /* Check MTU of outgoing interface. */
2272 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2273 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2275 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2276 ip0_len = gso_mtu_sz (b[0]);
2277 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2278 ip1_len = gso_mtu_sz (b[1]);
2280 ip4_mtu_check (b[0], ip0_len,
2281 adj0[0].rewrite_header.max_l3_packet_bytes,
2282 ip0->flags_and_fragment_offset &
2283 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2285 ip4_mtu_check (b[1], ip1_len,
2286 adj1[0].rewrite_header.max_l3_packet_bytes,
2287 ip1->flags_and_fragment_offset &
2288 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2293 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2294 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2295 IP4_ERROR_SAME_INTERFACE : error0);
2296 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2297 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2298 IP4_ERROR_SAME_INTERFACE : error1);
2301 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2302 * to see the IP header */
2303 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2305 u32 next_index = adj0[0].rewrite_header.next_index;
2306 b[0]->current_data -= rw_len0;
2307 b[0]->current_length += rw_len0;
2308 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2309 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2312 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2313 vnet_feature_arc_start (lm->output_feature_arc_index,
2314 tx_sw_if_index0, &next_index, b[0]);
2315 next[0] = next_index;
2319 b[0]->error = error_node->errors[error0];
2321 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2323 u32 next_index = adj1[0].rewrite_header.next_index;
2324 b[1]->current_data -= rw_len1;
2325 b[1]->current_length += rw_len1;
2327 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2328 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2331 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2332 vnet_feature_arc_start (lm->output_feature_arc_index,
2333 tx_sw_if_index1, &next_index, b[1]);
2334 next[1] = next_index;
2338 b[1]->error = error_node->errors[error1];
2342 calc_checksums (vm, b[0]);
2343 calc_checksums (vm, b[1]);
2345 /* Guess we are only writing on simple Ethernet header. */
2346 vnet_rewrite_two_headers (adj0[0], adj1[0],
2347 ip0, ip1, sizeof (ethernet_header_t));
2350 * Bump the per-adjacency counters
2354 vlib_increment_combined_counter
2355 (&adjacency_counters,
2357 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2359 vlib_increment_combined_counter
2360 (&adjacency_counters,
2362 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2367 if (adj0->sub_type.midchain.fixup_func)
2368 adj0->sub_type.midchain.fixup_func
2369 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2370 if (adj1->sub_type.midchain.fixup_func)
2371 adj1->sub_type.midchain.fixup_func
2372 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
2378 * copy bytes from the IP address into the MAC rewrite
2380 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2381 adj0->rewrite_header.dst_mcast_offset,
2382 &ip0->dst_address.as_u32, (u8 *) ip0);
2383 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2384 adj1->rewrite_header.dst_mcast_offset,
2385 &ip1->dst_address.as_u32, (u8 *) ip1);
2393 while (n_left_from > 0)
2395 ip_adjacency_t *adj0;
2397 u32 rw_len0, adj_index0, error0;
2398 u32 tx_sw_if_index0;
2400 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2402 adj0 = adj_get (adj_index0);
2405 vlib_prefetch_combined_counter (&adjacency_counters,
2406 thread_index, adj_index0);
2408 ip0 = vlib_buffer_get_current (b[0]);
2410 error0 = IP4_ERROR_NONE;
2412 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2415 /* Update packet buffer attributes/set output interface. */
2416 rw_len0 = adj0[0].rewrite_header.data_bytes;
2417 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2419 /* Check MTU of outgoing interface. */
2420 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2421 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2422 ip0_len = gso_mtu_sz (b[0]);
2424 ip4_mtu_check (b[0], ip0_len,
2425 adj0[0].rewrite_header.max_l3_packet_bytes,
2426 ip0->flags_and_fragment_offset &
2427 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2432 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2433 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2434 IP4_ERROR_SAME_INTERFACE : error0);
2437 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2438 * to see the IP header */
2439 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2441 u32 next_index = adj0[0].rewrite_header.next_index;
2442 b[0]->current_data -= rw_len0;
2443 b[0]->current_length += rw_len0;
2444 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2445 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2448 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2449 vnet_feature_arc_start (lm->output_feature_arc_index,
2450 tx_sw_if_index0, &next_index, b[0]);
2451 next[0] = next_index;
2455 b[0]->error = error_node->errors[error0];
2459 calc_checksums (vm, b[0]);
2461 /* Guess we are only writing on simple Ethernet header. */
2462 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2465 vlib_increment_combined_counter
2466 (&adjacency_counters,
2467 thread_index, adj_index0, 1,
2468 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2472 if (adj0->sub_type.midchain.fixup_func)
2473 adj0->sub_type.midchain.fixup_func
2474 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2480 * copy bytes from the IP address into the MAC rewrite
2482 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2483 adj0->rewrite_header.dst_mcast_offset,
2484 &ip0->dst_address.as_u32, (u8 *) ip0);
2493 /* Need to do trace after rewrites to pick up new packet data. */
2494 if (node->flags & VLIB_NODE_FLAG_TRACE)
2495 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2497 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2498 return frame->n_vectors;
2502 ip4_rewrite_inline (vlib_main_t * vm,
2503 vlib_node_runtime_t * node,
2504 vlib_frame_t * frame,
2505 int do_counters, int is_midchain, int is_mcast)
2507 vnet_main_t *vnm = vnet_get_main ();
2508 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2509 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2510 is_midchain, is_mcast,
2513 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2514 is_midchain, is_mcast,
2515 0 /* no do_gso */ );
2519 /** @brief IPv4 rewrite node.
2522 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2523 header checksum, fetch the ip adjacency, check the outbound mtu,
2524 apply the adjacency rewrite, and send pkts to the adjacency
2525 rewrite header's rewrite_next_index.
2527 @param vm vlib_main_t corresponding to the current thread
2528 @param node vlib_node_runtime_t
2529 @param frame vlib_frame_t whose contents should be dispatched
2531 @par Graph mechanics: buffer metadata, next index usage
2534 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2535 - the rewrite adjacency index
2536 - <code>adj->lookup_next_index</code>
2537 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2538 the packet will be dropped.
2539 - <code>adj->rewrite_header</code>
2540 - Rewrite string length, rewrite string, next_index
2543 - <code>b->current_data, b->current_length</code>
2544 - Updated net of applying the rewrite string
2546 <em>Next Indices:</em>
2547 - <code> adj->rewrite_header.next_index </code>
2551 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2552 vlib_frame_t * frame)
2554 if (adj_are_counters_enabled ())
2555 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2557 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2560 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2561 vlib_node_runtime_t * node,
2562 vlib_frame_t * frame)
2564 if (adj_are_counters_enabled ())
2565 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2567 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2570 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2571 vlib_node_runtime_t * node,
2572 vlib_frame_t * frame)
2574 if (adj_are_counters_enabled ())
2575 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2577 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2580 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2581 vlib_node_runtime_t * node,
2582 vlib_frame_t * frame)
2584 if (adj_are_counters_enabled ())
2585 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2587 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2590 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2591 vlib_node_runtime_t * node,
2592 vlib_frame_t * frame)
2594 if (adj_are_counters_enabled ())
2595 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2597 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2601 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2602 .name = "ip4-rewrite",
2603 .vector_size = sizeof (u32),
2605 .format_trace = format_ip4_rewrite_trace,
2607 .n_next_nodes = IP4_REWRITE_N_NEXT,
2609 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2610 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2611 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2615 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2616 .name = "ip4-rewrite-bcast",
2617 .vector_size = sizeof (u32),
2619 .format_trace = format_ip4_rewrite_trace,
2620 .sibling_of = "ip4-rewrite",
2623 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2624 .name = "ip4-rewrite-mcast",
2625 .vector_size = sizeof (u32),
2627 .format_trace = format_ip4_rewrite_trace,
2628 .sibling_of = "ip4-rewrite",
2631 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2632 .name = "ip4-mcast-midchain",
2633 .vector_size = sizeof (u32),
2635 .format_trace = format_ip4_rewrite_trace,
2636 .sibling_of = "ip4-rewrite",
2639 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2640 .name = "ip4-midchain",
2641 .vector_size = sizeof (u32),
2642 .format_trace = format_ip4_forward_next_trace,
2643 .sibling_of = "ip4-rewrite",
2648 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2650 ip4_fib_mtrie_t *mtrie0;
2651 ip4_fib_mtrie_leaf_t leaf0;
2654 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2656 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
2657 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2658 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2660 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2662 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2665 static clib_error_t *
2666 test_lookup_command_fn (vlib_main_t * vm,
2667 unformat_input_t * input, vlib_cli_command_t * cmd)
2674 ip4_address_t ip4_base_address;
2677 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2679 if (unformat (input, "table %d", &table_id))
2681 /* Make sure the entry exists. */
2682 fib = ip4_fib_get (table_id);
2683 if ((fib) && (fib->index != table_id))
2684 return clib_error_return (0, "<fib-index> %d does not exist",
2687 else if (unformat (input, "count %f", &count))
2690 else if (unformat (input, "%U",
2691 unformat_ip4_address, &ip4_base_address))
2694 return clib_error_return (0, "unknown input `%U'",
2695 format_unformat_error, input);
2700 for (i = 0; i < n; i++)
2702 if (!ip4_lookup_validate (&ip4_base_address, table_id))
2705 ip4_base_address.as_u32 =
2706 clib_host_to_net_u32 (1 +
2707 clib_net_to_host_u32 (ip4_base_address.as_u32));
2711 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2713 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2719 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2720 * given FIB table to determine if there is a conflict with the
2721 * adjacency table. The fib-id can be determined by using the
2722 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2725 * @todo This command uses fib-id, other commands use table-id (not
2726 * just a name, they are different indexes). Would like to change this
2727 * to table-id for consistency.
2730 * Example of how to run the test lookup command:
2731 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2732 * No errors in 2 lookups
2736 VLIB_CLI_COMMAND (lookup_test_command, static) =
2738 .path = "test lookup",
2739 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2740 .function = test_lookup_command_fn,
2744 #ifndef CLIB_MARCH_VARIANT
2746 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
2750 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2752 if (~0 == fib_index)
2753 return VNET_API_ERROR_NO_SUCH_FIB;
2755 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2762 static clib_error_t *
2763 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2764 unformat_input_t * input,
2765 vlib_cli_command_t * cmd)
2769 u32 flow_hash_config = 0;
2772 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2774 if (unformat (input, "table %d", &table_id))
2777 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2778 foreach_flow_hash_bit
2785 return clib_error_return (0, "unknown input `%U'",
2786 format_unformat_error, input);
2788 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2794 case VNET_API_ERROR_NO_SUCH_FIB:
2795 return clib_error_return (0, "no such FIB table %d", table_id);
2798 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2806 * Configure the set of IPv4 fields used by the flow hash.
2809 * Example of how to set the flow hash on a given table:
2810 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2811 * Example of display the configured flow hash:
2812 * @cliexstart{show ip fib}
2813 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2816 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2817 * [0] [@0]: dpo-drop ip6
2820 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2821 * [0] [@0]: dpo-drop ip6
2824 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2825 * [0] [@0]: dpo-drop ip6
2828 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2829 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2832 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2833 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2834 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2835 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2836 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2839 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2840 * [0] [@0]: dpo-drop ip6
2841 * 255.255.255.255/32
2843 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2844 * [0] [@0]: dpo-drop ip6
2845 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2848 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2849 * [0] [@0]: dpo-drop ip6
2852 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2853 * [0] [@0]: dpo-drop ip6
2856 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2857 * [0] [@4]: ipv4-glean: af_packet0
2860 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2861 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2864 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2865 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2868 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2869 * [0] [@4]: ipv4-glean: af_packet1
2872 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2873 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2876 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2877 * [0] [@0]: dpo-drop ip6
2880 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2881 * [0] [@0]: dpo-drop ip6
2882 * 255.255.255.255/32
2884 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2885 * [0] [@0]: dpo-drop ip6
2889 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2891 .path = "set ip flow-hash",
2893 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2894 .function = set_ip_flow_hash_command_fn,
2898 #ifndef CLIB_MARCH_VARIANT
2900 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2903 vnet_main_t *vnm = vnet_get_main ();
2904 vnet_interface_main_t *im = &vnm->interface_main;
2905 ip4_main_t *ipm = &ip4_main;
2906 ip_lookup_main_t *lm = &ipm->lookup_main;
2907 vnet_classify_main_t *cm = &vnet_classify_main;
2908 ip4_address_t *if_addr;
2910 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2911 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2913 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2914 return VNET_API_ERROR_NO_SUCH_ENTRY;
2916 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2917 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2919 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2921 if (NULL != if_addr)
2923 fib_prefix_t pfx = {
2925 .fp_proto = FIB_PROTOCOL_IP4,
2926 .fp_addr.ip4 = *if_addr,
2930 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2934 if (table_index != (u32) ~ 0)
2936 dpo_id_t dpo = DPO_INVALID;
2941 classify_dpo_create (DPO_PROTO_IP4, table_index));
2943 fib_table_entry_special_dpo_add (fib_index,
2945 FIB_SOURCE_CLASSIFY,
2946 FIB_ENTRY_FLAG_NONE, &dpo);
2951 fib_table_entry_special_remove (fib_index,
2952 &pfx, FIB_SOURCE_CLASSIFY);
2960 static clib_error_t *
2961 set_ip_classify_command_fn (vlib_main_t * vm,
2962 unformat_input_t * input,
2963 vlib_cli_command_t * cmd)
2965 u32 table_index = ~0;
2966 int table_index_set = 0;
2967 u32 sw_if_index = ~0;
2970 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2972 if (unformat (input, "table-index %d", &table_index))
2973 table_index_set = 1;
2974 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2975 vnet_get_main (), &sw_if_index))
2981 if (table_index_set == 0)
2982 return clib_error_return (0, "classify table-index must be specified");
2984 if (sw_if_index == ~0)
2985 return clib_error_return (0, "interface / subif must be specified");
2987 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2994 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2995 return clib_error_return (0, "No such interface");
2997 case VNET_API_ERROR_NO_SUCH_ENTRY:
2998 return clib_error_return (0, "No such classifier table");
3004 * Assign a classification table to an interface. The classification
3005 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3006 * commands. Once the table is create, use this command to filter packets
3010 * Example of how to assign a classification table to an interface:
3011 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3014 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3016 .path = "set ip classify",
3018 "set ip classify intfc <interface> table-index <classify-idx>",
3019 .function = set_ip_classify_command_fn,
3023 static clib_error_t *
3024 ip4_config (vlib_main_t * vm, unformat_input_t * input)
3026 ip4_main_t *im = &ip4_main;
3029 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3031 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3034 return clib_error_return (0,
3035 "invalid heap-size parameter `%U'",
3036 format_unformat_error, input);
3039 im->mtrie_heap_size = heapsize;
3044 VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3047 * fd.io coding-style-patch-verification: ON
3050 * eval: (c-set-style "gnu")