2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 * ip/ip4_forward.c: IP v4 forwarding
18 * Copyright (c) 2008 Eliot Dresselhaus
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #include <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43 #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
44 #include <vnet/ppp/ppp.h>
45 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46 #include <vnet/api_errno.h> /* for API error numbers */
47 #include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
48 #include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
49 #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
50 #include <vnet/fib/ip4_fib.h>
51 #include <vnet/dpo/load_balance.h>
52 #include <vnet/dpo/load_balance_map.h>
53 #include <vnet/dpo/classify_dpo.h>
54 #include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
56 #include <vnet/ip/ip4_forward.h>
58 /** @brief IPv4 lookup node.
61 This is the main IPv4 lookup dispatch node.
63 @param vm vlib_main_t corresponding to the current thread
64 @param node vlib_node_runtime_t
65 @param frame vlib_frame_t whose contents should be dispatched
67 @par Graph mechanics: buffer metadata, next index usage
70 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
71 - Indicates the @c sw_if_index value of the interface that the
72 packet was received on.
73 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
74 - When the value is @c ~0 then the node performs a longest prefix
75 match (LPM) for the packet destination address in the FIB attached
76 to the receive interface.
77 - Otherwise perform LPM for the packet destination address in the
78 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
79 value (0, 1, ...) and not a VRF id.
82 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
83 - The lookup result adjacency index.
86 - Dispatches the packet to the node index found in
87 ip_adjacency_t @c adj->lookup_next_index
88 (where @c adj is the lookup result adjacency).
91 ip4_lookup (vlib_main_t * vm,
92 vlib_node_runtime_t * node, vlib_frame_t * frame)
94 return ip4_lookup_inline (vm, node, frame,
95 /* lookup_for_responses_to_locally_received_packets */
100 static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
103 VLIB_REGISTER_NODE (ip4_lookup_node) =
105 .function = ip4_lookup,
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_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
117 ip4_load_balance (vlib_main_t * vm,
118 vlib_node_runtime_t * node, vlib_frame_t * frame)
120 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
121 u32 n_left_from, n_left_to_next, *from, *to_next;
122 ip_lookup_next_t next;
123 u32 thread_index = vlib_get_thread_index ();
125 from = vlib_frame_vector_args (frame);
126 n_left_from = frame->n_vectors;
127 next = node->cached_next_index;
129 if (node->flags & VLIB_NODE_FLAG_TRACE)
130 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
132 while (n_left_from > 0)
134 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
137 while (n_left_from >= 4 && n_left_to_next >= 2)
139 ip_lookup_next_t next0, next1;
140 const load_balance_t *lb0, *lb1;
141 vlib_buffer_t *p0, *p1;
142 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
143 const ip4_header_t *ip0, *ip1;
144 const dpo_id_t *dpo0, *dpo1;
146 /* Prefetch next iteration. */
148 vlib_buffer_t *p2, *p3;
150 p2 = vlib_get_buffer (vm, from[2]);
151 p3 = vlib_get_buffer (vm, from[3]);
153 vlib_prefetch_buffer_header (p2, STORE);
154 vlib_prefetch_buffer_header (p3, STORE);
156 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
157 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
160 pi0 = to_next[0] = from[0];
161 pi1 = to_next[1] = from[1];
168 p0 = vlib_get_buffer (vm, pi0);
169 p1 = vlib_get_buffer (vm, pi1);
171 ip0 = vlib_buffer_get_current (p0);
172 ip1 = vlib_buffer_get_current (p1);
173 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
174 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
176 lb0 = load_balance_get (lbi0);
177 lb1 = load_balance_get (lbi1);
180 * this node is for via FIBs we can re-use the hash value from the
181 * to node if present.
182 * We don't want to use the same hash value at each level in the recursion
183 * graph as that would lead to polarisation
187 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
189 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
191 hc0 = vnet_buffer (p0)->ip.flow_hash =
192 vnet_buffer (p0)->ip.flow_hash >> 1;
196 hc0 = vnet_buffer (p0)->ip.flow_hash =
197 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
199 dpo0 = load_balance_get_fwd_bucket
200 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
204 dpo0 = load_balance_get_bucket_i (lb0, 0);
206 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
208 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
210 hc1 = vnet_buffer (p1)->ip.flow_hash =
211 vnet_buffer (p1)->ip.flow_hash >> 1;
215 hc1 = vnet_buffer (p1)->ip.flow_hash =
216 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
218 dpo1 = load_balance_get_fwd_bucket
219 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
223 dpo1 = load_balance_get_bucket_i (lb1, 0);
226 next0 = dpo0->dpoi_next_node;
227 next1 = dpo1->dpoi_next_node;
229 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
230 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
232 vlib_increment_combined_counter
233 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
234 vlib_increment_combined_counter
235 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
237 vlib_validate_buffer_enqueue_x2 (vm, node, next,
238 to_next, n_left_to_next,
239 pi0, pi1, next0, next1);
242 while (n_left_from > 0 && n_left_to_next > 0)
244 ip_lookup_next_t next0;
245 const load_balance_t *lb0;
248 const ip4_header_t *ip0;
249 const dpo_id_t *dpo0;
258 p0 = vlib_get_buffer (vm, pi0);
260 ip0 = vlib_buffer_get_current (p0);
261 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
263 lb0 = load_balance_get (lbi0);
266 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
268 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
270 hc0 = vnet_buffer (p0)->ip.flow_hash =
271 vnet_buffer (p0)->ip.flow_hash >> 1;
275 hc0 = vnet_buffer (p0)->ip.flow_hash =
276 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
278 dpo0 = load_balance_get_fwd_bucket
279 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
283 dpo0 = load_balance_get_bucket_i (lb0, 0);
286 next0 = dpo0->dpoi_next_node;
287 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
289 vlib_increment_combined_counter
290 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
292 vlib_validate_buffer_enqueue_x1 (vm, node, next,
293 to_next, n_left_to_next,
297 vlib_put_next_frame (vm, node, next, n_left_to_next);
300 return frame->n_vectors;
304 VLIB_REGISTER_NODE (ip4_load_balance_node) =
306 .function = ip4_load_balance,
307 .name = "ip4-load-balance",
308 .vector_size = sizeof (u32),
309 .sibling_of = "ip4-lookup",
311 format_ip4_lookup_trace,
315 VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
317 /* get first interface address */
319 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
320 ip_interface_address_t ** result_ia)
322 ip_lookup_main_t *lm = &im->lookup_main;
323 ip_interface_address_t *ia = 0;
324 ip4_address_t *result = 0;
327 foreach_ip_interface_address
328 (lm, ia, sw_if_index,
329 1 /* honor unnumbered */ ,
332 ip_interface_address_get_address (lm, ia);
338 *result_ia = result ? ia : 0;
343 ip4_add_interface_routes (u32 sw_if_index,
344 ip4_main_t * im, u32 fib_index,
345 ip_interface_address_t * a)
347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip4_address_t *address = ip_interface_address_get_address (lm, a);
350 .fp_len = a->address_length,
351 .fp_proto = FIB_PROTOCOL_IP4,
352 .fp_addr.ip4 = *address,
355 if (pfx.fp_len <= 30)
357 /* a /30 or shorter - add a glean for the network address */
358 fib_table_entry_update_one_path (fib_index, &pfx,
359 FIB_SOURCE_INTERFACE,
360 (FIB_ENTRY_FLAG_CONNECTED |
361 FIB_ENTRY_FLAG_ATTACHED),
363 /* No next-hop address */
369 // no out-label stack
371 FIB_ROUTE_PATH_FLAG_NONE);
373 /* Add the two broadcast addresses as drop */
374 fib_prefix_t net_pfx = {
376 .fp_proto = FIB_PROTOCOL_IP4,
377 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
379 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
380 fib_table_entry_special_add(fib_index,
382 FIB_SOURCE_INTERFACE,
383 (FIB_ENTRY_FLAG_DROP |
384 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
385 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
386 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
387 fib_table_entry_special_add(fib_index,
389 FIB_SOURCE_INTERFACE,
390 (FIB_ENTRY_FLAG_DROP |
391 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
393 else if (pfx.fp_len == 31)
395 u32 mask = clib_host_to_net_u32(1);
396 fib_prefix_t net_pfx = pfx;
399 net_pfx.fp_addr.ip4.as_u32 ^= mask;
401 /* a /31 - add the other end as an attached host */
402 fib_table_entry_update_one_path (fib_index, &net_pfx,
403 FIB_SOURCE_INTERFACE,
404 (FIB_ENTRY_FLAG_ATTACHED),
412 FIB_ROUTE_PATH_FLAG_NONE);
416 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
418 u32 classify_table_index =
419 lm->classify_table_index_by_sw_if_index[sw_if_index];
420 if (classify_table_index != (u32) ~ 0)
422 dpo_id_t dpo = DPO_INVALID;
427 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
429 fib_table_entry_special_dpo_add (fib_index,
432 FIB_ENTRY_FLAG_NONE, &dpo);
437 fib_table_entry_update_one_path (fib_index, &pfx,
438 FIB_SOURCE_INTERFACE,
439 (FIB_ENTRY_FLAG_CONNECTED |
440 FIB_ENTRY_FLAG_LOCAL),
447 FIB_ROUTE_PATH_FLAG_NONE);
451 ip4_del_interface_routes (ip4_main_t * im,
453 ip4_address_t * address, u32 address_length)
456 .fp_len = address_length,
457 .fp_proto = FIB_PROTOCOL_IP4,
458 .fp_addr.ip4 = *address,
461 if (pfx.fp_len <= 30)
463 fib_prefix_t net_pfx = {
465 .fp_proto = FIB_PROTOCOL_IP4,
466 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
468 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
469 fib_table_entry_special_remove(fib_index,
471 FIB_SOURCE_INTERFACE);
472 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
473 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
474 fib_table_entry_special_remove(fib_index,
476 FIB_SOURCE_INTERFACE);
477 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
479 else if (pfx.fp_len == 31)
481 u32 mask = clib_host_to_net_u32(1);
482 fib_prefix_t net_pfx = pfx;
485 net_pfx.fp_addr.ip4.as_u32 ^= mask;
487 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
491 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
495 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
497 ip4_main_t *im = &ip4_main;
499 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
502 * enable/disable only on the 1<->0 transition
506 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
511 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
512 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
515 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
519 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
520 sw_if_index, !is_enable, 0, 0);
523 static clib_error_t *
524 ip4_add_del_interface_address_internal (vlib_main_t * vm,
526 ip4_address_t * address,
527 u32 address_length, u32 is_del)
529 vnet_main_t *vnm = vnet_get_main ();
530 ip4_main_t *im = &ip4_main;
531 ip_lookup_main_t *lm = &im->lookup_main;
532 clib_error_t *error = 0;
533 u32 if_address_index, elts_before;
534 ip4_address_fib_t ip4_af, *addr_fib = 0;
536 /* local0 interface doesn't support IP addressing */
537 if (sw_if_index == 0)
540 clib_error_create ("local0 interface doesn't support IP addressing");
543 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
544 ip4_addr_fib_init (&ip4_af, address,
545 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
546 vec_add1 (addr_fib, ip4_af);
549 * there is no support for adj-fib handling in the presence of overlapping
550 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
556 /* When adding an address check that it does not conflict
557 with an existing address on any interface in this table. */
558 ip_interface_address_t *ia;
559 vnet_sw_interface_t *sif;
561 pool_foreach(sif, vnm->interface_main.sw_interfaces,
563 if (im->fib_index_by_sw_if_index[sw_if_index] ==
564 im->fib_index_by_sw_if_index[sif->sw_if_index])
566 foreach_ip_interface_address
567 (&im->lookup_main, ia, sif->sw_if_index,
568 0 /* honor unnumbered */ ,
571 ip_interface_address_get_address
572 (&im->lookup_main, ia);
573 if (ip4_destination_matches_route
574 (im, address, x, ia->address_length) ||
575 ip4_destination_matches_route (im,
580 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
584 ("failed to add %U which conflicts with %U for interface %U",
585 format_ip4_address_and_length, address,
587 format_ip4_address_and_length, x,
589 format_vnet_sw_if_index_name, vnm,
598 elts_before = pool_elts (lm->if_address_pool);
600 error = ip_interface_address_add_del
601 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
605 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
608 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
610 ip4_add_interface_routes (sw_if_index,
611 im, ip4_af.fib_index,
613 (lm->if_address_pool, if_address_index));
615 /* If pool did not grow/shrink: add duplicate address. */
616 if (elts_before != pool_elts (lm->if_address_pool))
618 ip4_add_del_interface_address_callback_t *cb;
619 vec_foreach (cb, im->add_del_interface_address_callbacks)
620 cb->function (im, cb->function_opaque, sw_if_index,
621 address, address_length, if_address_index, is_del);
630 ip4_add_del_interface_address (vlib_main_t * vm,
632 ip4_address_t * address,
633 u32 address_length, u32 is_del)
635 return ip4_add_del_interface_address_internal
636 (vm, sw_if_index, address, address_length, is_del);
639 /* Built-in ip4 unicast rx feature path definition */
641 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
643 .arc_name = "ip4-unicast",
644 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
645 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
648 VNET_FEATURE_INIT (ip4_flow_classify, static) =
650 .arc_name = "ip4-unicast",
651 .node_name = "ip4-flow-classify",
652 .runs_before = VNET_FEATURES ("ip4-inacl"),
655 VNET_FEATURE_INIT (ip4_inacl, static) =
657 .arc_name = "ip4-unicast",
658 .node_name = "ip4-inacl",
659 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
662 VNET_FEATURE_INIT (ip4_source_check_1, static) =
664 .arc_name = "ip4-unicast",
665 .node_name = "ip4-source-check-via-rx",
666 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
669 VNET_FEATURE_INIT (ip4_source_check_2, static) =
671 .arc_name = "ip4-unicast",
672 .node_name = "ip4-source-check-via-any",
673 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
676 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
678 .arc_name = "ip4-unicast",
679 .node_name = "ip4-source-and-port-range-check-rx",
680 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
683 VNET_FEATURE_INIT (ip4_policer_classify, static) =
685 .arc_name = "ip4-unicast",
686 .node_name = "ip4-policer-classify",
687 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
690 VNET_FEATURE_INIT (ip4_ipsec, static) =
692 .arc_name = "ip4-unicast",
693 .node_name = "ipsec-input-ip4",
694 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
697 VNET_FEATURE_INIT (ip4_vpath, static) =
699 .arc_name = "ip4-unicast",
700 .node_name = "vpath-input-ip4",
701 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
704 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
706 .arc_name = "ip4-unicast",
707 .node_name = "ip4-vxlan-bypass",
708 .runs_before = VNET_FEATURES ("ip4-lookup"),
711 VNET_FEATURE_INIT (ip4_not_enabled, static) =
713 .arc_name = "ip4-unicast",
714 .node_name = "ip4-not-enabled",
715 .runs_before = VNET_FEATURES ("ip4-lookup"),
718 VNET_FEATURE_INIT (ip4_lookup, static) =
720 .arc_name = "ip4-unicast",
721 .node_name = "ip4-lookup",
722 .runs_before = 0, /* not before any other features */
725 /* Built-in ip4 multicast rx feature path definition */
726 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
728 .arc_name = "ip4-multicast",
729 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
730 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
733 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
735 .arc_name = "ip4-multicast",
736 .node_name = "vpath-input-ip4",
737 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
740 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
742 .arc_name = "ip4-multicast",
743 .node_name = "ip4-not-enabled",
744 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
747 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
749 .arc_name = "ip4-multicast",
750 .node_name = "ip4-mfib-forward-lookup",
751 .runs_before = 0, /* last feature */
754 /* Source and port-range check ip4 tx feature path definition */
755 VNET_FEATURE_ARC_INIT (ip4_output, static) =
757 .arc_name = "ip4-output",
758 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
759 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
762 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
764 .arc_name = "ip4-output",
765 .node_name = "ip4-source-and-port-range-check-tx",
766 .runs_before = VNET_FEATURES ("ip4-outacl"),
769 VNET_FEATURE_INIT (ip4_outacl, static) =
771 .arc_name = "ip4-output",
772 .node_name = "ip4-outacl",
773 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
776 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
778 .arc_name = "ip4-output",
779 .node_name = "ipsec-output-ip4",
780 .runs_before = VNET_FEATURES ("interface-output"),
783 /* Built-in ip4 tx feature path definition */
784 VNET_FEATURE_INIT (ip4_interface_output, static) =
786 .arc_name = "ip4-output",
787 .node_name = "interface-output",
788 .runs_before = 0, /* not before any other features */
792 static clib_error_t *
793 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
795 ip4_main_t *im = &ip4_main;
797 /* Fill in lookup tables with default table (0). */
798 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
799 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
803 ip4_main_t *im4 = &ip4_main;
804 ip_lookup_main_t *lm4 = &im4->lookup_main;
805 ip_interface_address_t *ia = 0;
806 ip4_address_t *address;
807 vlib_main_t *vm = vlib_get_main ();
809 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
811 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
813 address = ip_interface_address_get_address (lm4, ia);
814 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
819 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
822 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
823 sw_if_index, is_add, 0, 0);
825 return /* no error */ 0;
828 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
830 /* Global IP4 main. */
834 ip4_lookup_init (vlib_main_t * vm)
836 ip4_main_t *im = &ip4_main;
840 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
842 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
844 if ((error = vlib_call_init_function (vm, fib_module_init)))
846 if ((error = vlib_call_init_function (vm, mfib_module_init)))
849 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
854 m = pow2_mask (i) << (32 - i);
857 im->fib_masks[i] = clib_host_to_net_u32 (m);
860 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
862 /* Create FIB with index 0 and table id of 0. */
863 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
864 FIB_SOURCE_DEFAULT_ROUTE);
865 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
866 MFIB_SOURCE_DEFAULT_ROUTE);
870 pn = pg_get_node (ip4_lookup_node.index);
871 pn->unformat_edit = unformat_pg_ip4_header;
875 ethernet_arp_header_t h;
877 memset (&h, 0, sizeof (h));
879 /* Set target ethernet address to all zeros. */
880 memset (h.ip4_over_ethernet[1].ethernet, 0,
881 sizeof (h.ip4_over_ethernet[1].ethernet));
883 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
884 #define _8(f,v) h.f = v;
885 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
886 _16 (l3_type, ETHERNET_TYPE_IP4);
887 _8 (n_l2_address_bytes, 6);
888 _8 (n_l3_address_bytes, 4);
889 _16 (opcode, ETHERNET_ARP_OPCODE_request);
893 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
896 /* alloc chunk size */ 8,
903 VLIB_INIT_FUNCTION (ip4_lookup_init);
907 /* Adjacency taken. */
912 /* Packet data, possibly *after* rewrite. */
913 u8 packet_data[64 - 1 * sizeof (u32)];
915 ip4_forward_next_trace_t;
918 format_ip4_forward_next_trace (u8 * s, va_list * args)
920 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
921 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
922 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
923 u32 indent = format_get_indent (s);
924 s = format (s, "%U%U",
925 format_white_space, indent,
926 format_ip4_header, t->packet_data, sizeof (t->packet_data));
931 format_ip4_lookup_trace (u8 * s, va_list * args)
933 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
934 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
935 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
936 u32 indent = format_get_indent (s);
938 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
939 t->fib_index, t->dpo_index, t->flow_hash);
940 s = format (s, "\n%U%U",
941 format_white_space, indent,
942 format_ip4_header, t->packet_data, sizeof (t->packet_data));
947 format_ip4_rewrite_trace (u8 * s, va_list * args)
949 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
950 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
951 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
952 u32 indent = format_get_indent (s);
954 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
955 t->fib_index, t->dpo_index, format_ip_adjacency,
956 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
957 s = format (s, "\n%U%U",
958 format_white_space, indent,
959 format_ip_adjacency_packet_data,
960 t->dpo_index, t->packet_data, sizeof (t->packet_data));
964 /* Common trace function for all ip4-forward next nodes. */
966 ip4_forward_next_trace (vlib_main_t * vm,
967 vlib_node_runtime_t * node,
968 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
971 ip4_main_t *im = &ip4_main;
973 n_left = frame->n_vectors;
974 from = vlib_frame_vector_args (frame);
979 vlib_buffer_t *b0, *b1;
980 ip4_forward_next_trace_t *t0, *t1;
982 /* Prefetch next iteration. */
983 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
984 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
989 b0 = vlib_get_buffer (vm, bi0);
990 b1 = vlib_get_buffer (vm, bi1);
992 if (b0->flags & VLIB_BUFFER_IS_TRACED)
994 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
995 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
996 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
998 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
999 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1000 vec_elt (im->fib_index_by_sw_if_index,
1001 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1003 clib_memcpy (t0->packet_data,
1004 vlib_buffer_get_current (b0),
1005 sizeof (t0->packet_data));
1007 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1009 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1010 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1011 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1013 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1014 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1015 vec_elt (im->fib_index_by_sw_if_index,
1016 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1017 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1018 sizeof (t1->packet_data));
1028 ip4_forward_next_trace_t *t0;
1032 b0 = vlib_get_buffer (vm, bi0);
1034 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1036 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1037 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1038 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1040 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1041 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1042 vec_elt (im->fib_index_by_sw_if_index,
1043 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1044 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1045 sizeof (t0->packet_data));
1052 /* Compute TCP/UDP/ICMP4 checksum in software. */
1054 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1058 u32 ip_header_length, payload_length_host_byte_order;
1059 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
1061 void *data_this_buffer;
1063 /* Initialize checksum with ip header. */
1064 ip_header_length = ip4_header_bytes (ip0);
1065 payload_length_host_byte_order =
1066 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1068 clib_host_to_net_u32 (payload_length_host_byte_order +
1069 (ip0->protocol << 16));
1071 if (BITS (uword) == 32)
1074 ip_csum_with_carry (sum0,
1075 clib_mem_unaligned (&ip0->src_address, u32));
1077 ip_csum_with_carry (sum0,
1078 clib_mem_unaligned (&ip0->dst_address, u32));
1082 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1084 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1085 data_this_buffer = (void *) ip0 + ip_header_length;
1086 n_ip_bytes_this_buffer =
1087 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1088 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1090 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
1091 n_ip_bytes_this_buffer - ip_header_length : 0;
1095 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1096 n_bytes_left -= n_this_buffer;
1097 if (n_bytes_left == 0)
1100 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1101 p0 = vlib_get_buffer (vm, p0->next_buffer);
1102 data_this_buffer = vlib_buffer_get_current (p0);
1103 n_this_buffer = p0->current_length;
1106 sum16 = ~ip_csum_fold (sum0);
1112 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1114 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1118 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1119 || ip0->protocol == IP_PROTOCOL_UDP);
1121 udp0 = (void *) (ip0 + 1);
1122 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1124 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1125 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1129 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1131 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1132 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1138 VNET_FEATURE_ARC_INIT (ip4_local) =
1140 .arc_name = "ip4-local",
1141 .start_nodes = VNET_FEATURES ("ip4-local"),
1146 ip4_local_validate_l4 (vlib_main_t * vm, vlib_buffer_t * p, ip4_header_t * ip,
1147 u8 is_udp, u8 * error, u8 * good_tcp_udp)
1150 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1151 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1155 u32 ip_len, udp_len;
1157 udp = ip4_next_header (ip);
1158 /* Verify UDP length. */
1159 ip_len = clib_net_to_host_u16 (ip->length);
1160 udp_len = clib_net_to_host_u16 (udp->length);
1162 len_diff = ip_len - udp_len;
1163 *good_tcp_udp &= len_diff >= 0;
1164 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1168 #define ip4_local_do_l4_check(is_tcp_udp, flags) \
1169 (is_tcp_udp && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1170 || flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1171 || flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
1174 ip4_local_inline (vlib_main_t * vm,
1175 vlib_node_runtime_t * node,
1176 vlib_frame_t * frame, int head_of_feature_arc)
1178 ip4_main_t *im = &ip4_main;
1179 ip_lookup_main_t *lm = &im->lookup_main;
1180 ip_local_next_t next_index;
1181 u32 *from, *to_next, n_left_from, n_left_to_next;
1182 vlib_node_runtime_t *error_node =
1183 vlib_node_get_runtime (vm, ip4_input_node.index);
1184 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1186 from = vlib_frame_vector_args (frame);
1187 n_left_from = frame->n_vectors;
1188 next_index = node->cached_next_index;
1190 if (node->flags & VLIB_NODE_FLAG_TRACE)
1191 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1193 while (n_left_from > 0)
1195 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1197 while (n_left_from >= 4 && n_left_to_next >= 2)
1199 vlib_buffer_t *p0, *p1;
1200 ip4_header_t *ip0, *ip1;
1201 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1202 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1203 const dpo_id_t *dpo0, *dpo1;
1204 const load_balance_t *lb0, *lb1;
1205 u32 pi0, next0, lbi0;
1206 u32 pi1, next1, lbi1;
1207 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1208 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1209 u32 sw_if_index0, sw_if_index1;
1211 pi0 = to_next[0] = from[0];
1212 pi1 = to_next[1] = from[1];
1216 n_left_to_next -= 2;
1218 next0 = next1 = IP_LOCAL_NEXT_DROP;
1219 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1221 p0 = vlib_get_buffer (vm, pi0);
1222 p1 = vlib_get_buffer (vm, pi1);
1224 ip0 = vlib_buffer_get_current (p0);
1225 ip1 = vlib_buffer_get_current (p1);
1227 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1228 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
1230 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1231 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1233 proto0 = ip0->protocol;
1234 proto1 = ip1->protocol;
1236 if (head_of_feature_arc == 0)
1239 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1240 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1241 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1242 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1245 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1246 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1247 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1248 good_tcp_udp1 = (p1->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1249 || (p1->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1251 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1253 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)
1254 || ip4_local_do_l4_check (is_tcp_udp1,
1258 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1261 ip4_local_validate_l4 (vm, p1, ip1, is_udp1, &error1,
1265 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1266 error0 = (is_tcp_udp0 && !good_tcp_udp0
1267 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1268 error1 = (is_tcp_udp1 && !good_tcp_udp1
1269 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
1271 vnet_buffer (p0)->ip.fib_index =
1272 vnet_buffer (p0)->sw_if_index[VLIB_TX] != ~0 ?
1273 vnet_buffer (p0)->sw_if_index[VLIB_TX] :
1274 vnet_buffer (p0)->ip.fib_index;
1276 vnet_buffer (p1)->ip.fib_index =
1277 vnet_buffer (p1)->sw_if_index[VLIB_TX] != ~0 ?
1278 vnet_buffer (p1)->sw_if_index[VLIB_TX] :
1279 vnet_buffer (p1)->ip.fib_index;
1282 mtrie0 = &ip4_fib_get (vnet_buffer (p0)->ip.fib_index)->mtrie;
1283 mtrie1 = &ip4_fib_get (vnet_buffer (p1)->ip.fib_index)->mtrie;
1285 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1286 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
1287 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1289 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1291 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1293 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1296 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1297 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1298 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1300 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1301 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1302 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
1304 lb0 = load_balance_get (lbi0);
1305 lb1 = load_balance_get (lbi1);
1306 dpo0 = load_balance_get_bucket_i (lb0, 0);
1307 dpo1 = load_balance_get_bucket_i (lb1, 0);
1310 * Must have a route to source otherwise we drop the packet.
1311 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1314 * - the source is a recieve => it's from us => bogus, do this
1315 * first since it sets a different error code.
1316 * - uRPF check for any route to source - accept if passes.
1317 * - allow packets destined to the broadcast address from unknown sources
1319 if (p0->flags & VNET_BUFFER_F_IS_NATED)
1322 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1323 dpo0->dpoi_type == DPO_RECEIVE) ?
1324 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1325 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1326 !fib_urpf_check_size (lb0->lb_urpf) &&
1327 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1328 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1331 if (p1->flags & VNET_BUFFER_F_IS_NATED)
1334 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1335 dpo1->dpoi_type == DPO_RECEIVE) ?
1336 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1337 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1338 !fib_urpf_check_size (lb1->lb_urpf) &&
1339 ip1->dst_address.as_u32 != 0xFFFFFFFF)
1340 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
1344 next0 = lm->local_next_by_ip_protocol[proto0];
1345 next1 = lm->local_next_by_ip_protocol[proto1];
1348 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1350 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1352 p0->error = error0 ? error_node->errors[error0] : 0;
1353 p1->error = error1 ? error_node->errors[error1] : 0;
1355 if (head_of_feature_arc)
1357 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1358 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1359 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1360 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
1363 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1364 n_left_to_next, pi0, pi1,
1368 while (n_left_from > 0 && n_left_to_next > 0)
1372 ip4_fib_mtrie_t *mtrie0;
1373 ip4_fib_mtrie_leaf_t leaf0;
1374 u32 pi0, next0, lbi0;
1375 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1376 load_balance_t *lb0;
1377 const dpo_id_t *dpo0;
1380 pi0 = to_next[0] = from[0];
1384 n_left_to_next -= 1;
1386 next0 = IP_LOCAL_NEXT_DROP;
1387 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1389 p0 = vlib_get_buffer (vm, pi0);
1390 ip0 = vlib_buffer_get_current (p0);
1391 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1392 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1394 proto0 = ip0->protocol;
1396 if (head_of_feature_arc == 0 || p0->flags & VNET_BUFFER_F_IS_NATED)
1399 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1400 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1403 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1404 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1405 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1407 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
1409 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1413 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1414 error0 = (is_tcp_udp0 && !good_tcp_udp0
1415 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1417 vnet_buffer (p0)->ip.fib_index =
1418 vnet_buffer (p0)->sw_if_index[VLIB_TX] != ~0 ?
1419 vnet_buffer (p0)->sw_if_index[VLIB_TX] :
1420 vnet_buffer (p0)->ip.fib_index;
1422 mtrie0 = &ip4_fib_get (vnet_buffer (p0)->ip.fib_index)->mtrie;
1423 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1424 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1426 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1428 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1429 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1430 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
1432 lb0 = load_balance_get (lbi0);
1433 dpo0 = load_balance_get_bucket_i (lb0, 0);
1435 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1436 dpo0->dpoi_type == DPO_RECEIVE) ?
1437 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1438 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1439 !fib_urpf_check_size (lb0->lb_urpf) &&
1440 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1441 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1444 next0 = lm->local_next_by_ip_protocol[proto0];
1446 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1448 p0->error = error0 ? error_node->errors[error0] : 0;
1450 if (head_of_feature_arc)
1452 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1453 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1456 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1457 n_left_to_next, pi0, next0);
1459 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1462 return frame->n_vectors;
1466 ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1468 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1472 VLIB_REGISTER_NODE (ip4_local_node) =
1474 .function = ip4_local,
1475 .name = "ip4-local",
1476 .vector_size = sizeof (u32),
1477 .format_trace = format_ip4_forward_next_trace,
1478 .n_next_nodes = IP_LOCAL_N_NEXT,
1481 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1482 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1483 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1484 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1489 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1492 ip4_local_end_of_arc (vlib_main_t * vm,
1493 vlib_node_runtime_t * node, vlib_frame_t * frame)
1495 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1499 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1500 .function = ip4_local_end_of_arc,
1501 .name = "ip4-local-end-of-arc",
1502 .vector_size = sizeof (u32),
1504 .format_trace = format_ip4_forward_next_trace,
1505 .sibling_of = "ip4-local",
1508 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1510 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1511 .arc_name = "ip4-local",
1512 .node_name = "ip4-local-end-of-arc",
1513 .runs_before = 0, /* not before any other features */
1518 ip4_register_protocol (u32 protocol, u32 node_index)
1520 vlib_main_t *vm = vlib_get_main ();
1521 ip4_main_t *im = &ip4_main;
1522 ip_lookup_main_t *lm = &im->lookup_main;
1524 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1525 lm->local_next_by_ip_protocol[protocol] =
1526 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1529 static clib_error_t *
1530 show_ip_local_command_fn (vlib_main_t * vm,
1531 unformat_input_t * input, vlib_cli_command_t * cmd)
1533 ip4_main_t *im = &ip4_main;
1534 ip_lookup_main_t *lm = &im->lookup_main;
1537 vlib_cli_output (vm, "Protocols handled by ip4_local");
1538 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1540 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1542 u32 node_index = vlib_get_node (vm,
1543 ip4_local_node.index)->
1544 next_nodes[lm->local_next_by_ip_protocol[i]];
1545 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1555 * Display the set of protocols handled by the local IPv4 stack.
1558 * Example of how to display local protocol table:
1559 * @cliexstart{show ip local}
1560 * Protocols handled by ip4_local
1567 VLIB_CLI_COMMAND (show_ip_local, static) =
1569 .path = "show ip local",
1570 .function = show_ip_local_command_fn,
1571 .short_help = "show ip local",
1576 ip4_arp_inline (vlib_main_t * vm,
1577 vlib_node_runtime_t * node,
1578 vlib_frame_t * frame, int is_glean)
1580 vnet_main_t *vnm = vnet_get_main ();
1581 ip4_main_t *im = &ip4_main;
1582 ip_lookup_main_t *lm = &im->lookup_main;
1583 u32 *from, *to_next_drop;
1584 uword n_left_from, n_left_to_next_drop, next_index;
1585 static f64 time_last_seed_change = -1e100;
1586 static u32 hash_seeds[3];
1587 static uword hash_bitmap[256 / BITS (uword)];
1590 if (node->flags & VLIB_NODE_FLAG_TRACE)
1591 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1593 time_now = vlib_time_now (vm);
1594 if (time_now - time_last_seed_change > 1e-3)
1597 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1598 sizeof (hash_seeds));
1599 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1600 hash_seeds[i] = r[i];
1602 /* Mark all hash keys as been no-seen before. */
1603 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1606 time_last_seed_change = time_now;
1609 from = vlib_frame_vector_args (frame);
1610 n_left_from = frame->n_vectors;
1611 next_index = node->cached_next_index;
1612 if (next_index == IP4_ARP_NEXT_DROP)
1613 next_index = IP4_ARP_N_NEXT; /* point to first interface */
1615 while (n_left_from > 0)
1617 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1618 to_next_drop, n_left_to_next_drop);
1620 while (n_left_from > 0 && n_left_to_next_drop > 0)
1622 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1623 ip_adjacency_t *adj0;
1630 p0 = vlib_get_buffer (vm, pi0);
1632 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1633 adj0 = adj_get (adj_index0);
1634 ip0 = vlib_buffer_get_current (p0);
1640 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1641 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1646 * this is the Glean case, so we are ARPing for the
1647 * packet's destination
1649 a0 ^= ip0->dst_address.data_u32;
1653 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1657 hash_v3_mix32 (a0, b0, c0);
1658 hash_v3_finalize32 (a0, b0, c0);
1660 c0 &= BITS (hash_bitmap) - 1;
1661 m0 = (uword) 1 << (c0 % BITS (uword));
1662 c0 = c0 / BITS (uword);
1664 bm0 = hash_bitmap[c0];
1665 drop0 = (bm0 & m0) != 0;
1667 /* Mark it as seen. */
1668 hash_bitmap[c0] = bm0 | m0;
1672 to_next_drop[0] = pi0;
1674 n_left_to_next_drop -= 1;
1677 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
1678 IP4_ARP_ERROR_REQUEST_SENT];
1681 * the adj has been updated to a rewrite but the node the DPO that got
1682 * us here hasn't - yet. no big deal. we'll drop while we wait.
1684 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1691 * Can happen if the control-plane is programming tables
1692 * with traffic flowing; at least that's today's lame excuse.
1694 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1695 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
1697 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
1700 /* Send ARP request. */
1704 ethernet_arp_header_t *h0;
1705 vnet_hw_interface_t *hw_if0;
1708 vlib_packet_template_get_packet (vm,
1709 &im->ip4_arp_request_packet_template,
1712 /* Seems we're out of buffers */
1713 if (PREDICT_FALSE (!h0))
1716 /* Add rewrite/encap string for ARP packet. */
1717 vnet_rewrite_one_header (adj0[0], h0,
1718 sizeof (ethernet_header_t));
1720 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1722 /* Src ethernet address in ARP header. */
1723 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
1725 sizeof (h0->ip4_over_ethernet[0].ethernet));
1729 /* The interface's source address is stashed in the Glean Adj */
1730 h0->ip4_over_ethernet[0].ip4 =
1731 adj0->sub_type.glean.receive_addr.ip4;
1733 /* Copy in destination address we are requesting. This is the
1734 * glean case, so it's the packet's destination.*/
1735 h0->ip4_over_ethernet[1].ip4.data_u32 =
1736 ip0->dst_address.data_u32;
1740 /* Src IP address in ARP header. */
1741 if (ip4_src_address_for_packet (lm, sw_if_index0,
1743 ip4_over_ethernet[0].ip4))
1745 /* No source address available */
1747 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1748 vlib_buffer_free (vm, &bi0, 1);
1752 /* Copy in destination address we are requesting from the
1754 h0->ip4_over_ethernet[1].ip4.data_u32 =
1755 adj0->sub_type.nbr.next_hop.ip4.as_u32;
1758 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1759 b0 = vlib_get_buffer (vm, bi0);
1760 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1761 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1763 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1765 vlib_set_next_frame_buffer (vm, node,
1766 adj0->rewrite_header.next_index,
1771 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1774 return frame->n_vectors;
1778 ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1780 return (ip4_arp_inline (vm, node, frame, 0));
1784 ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1786 return (ip4_arp_inline (vm, node, frame, 1));
1789 static char *ip4_arp_error_strings[] = {
1790 [IP4_ARP_ERROR_DROP] = "address overflow drops",
1791 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1792 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
1793 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
1794 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
1795 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
1799 VLIB_REGISTER_NODE (ip4_arp_node) =
1801 .function = ip4_arp,
1803 .vector_size = sizeof (u32),
1804 .format_trace = format_ip4_forward_next_trace,
1805 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1806 .error_strings = ip4_arp_error_strings,
1807 .n_next_nodes = IP4_ARP_N_NEXT,
1810 [IP4_ARP_NEXT_DROP] = "error-drop",
1814 VLIB_REGISTER_NODE (ip4_glean_node) =
1816 .function = ip4_glean,
1817 .name = "ip4-glean",
1818 .vector_size = sizeof (u32),
1819 .format_trace = format_ip4_forward_next_trace,
1820 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1821 .error_strings = ip4_arp_error_strings,
1822 .n_next_nodes = IP4_ARP_N_NEXT,
1824 [IP4_ARP_NEXT_DROP] = "error-drop",
1829 #define foreach_notrace_ip4_arp_error \
1836 arp_notrace_init (vlib_main_t * vm)
1838 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
1840 /* don't trace ARP request packets */
1842 vnet_pcap_drop_trace_filter_add_del \
1843 (rt->errors[IP4_ARP_ERROR_##a], \
1845 foreach_notrace_ip4_arp_error;
1850 VLIB_INIT_FUNCTION (arp_notrace_init);
1853 /* Send an ARP request to see if given destination is reachable on given interface. */
1855 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
1857 vnet_main_t *vnm = vnet_get_main ();
1858 ip4_main_t *im = &ip4_main;
1859 ethernet_arp_header_t *h;
1861 ip_interface_address_t *ia;
1862 ip_adjacency_t *adj;
1863 vnet_hw_interface_t *hi;
1864 vnet_sw_interface_t *si;
1869 si = vnet_get_sw_interface (vnm, sw_if_index);
1871 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1873 return clib_error_return (0, "%U: interface %U down",
1874 format_ip4_address, dst,
1875 format_vnet_sw_if_index_name, vnm,
1880 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1883 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1884 return clib_error_return
1886 "no matching interface address for destination %U (interface %U)",
1887 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
1891 h = vlib_packet_template_get_packet (vm,
1892 &im->ip4_arp_request_packet_template,
1895 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1896 if (PREDICT_FALSE (!hi->hw_address))
1898 return clib_error_return (0, "%U: interface %U do not support ip probe",
1899 format_ip4_address, dst,
1900 format_vnet_sw_if_index_name, vnm,
1904 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
1905 sizeof (h->ip4_over_ethernet[0].ethernet));
1907 h->ip4_over_ethernet[0].ip4 = src[0];
1908 h->ip4_over_ethernet[1].ip4 = dst[0];
1910 b = vlib_get_buffer (vm, bi);
1911 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1912 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1914 ip46_address_t nh = {
1918 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
1919 VNET_LINK_IP4, &nh, sw_if_index);
1922 /* Peer has been previously resolved, retrieve glean adj instead */
1923 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1926 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
1927 VNET_LINK_IP4, sw_if_index, &nh);
1931 /* Add encapsulation string for software interface (e.g. ethernet header). */
1932 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1933 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1936 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1937 u32 *to_next = vlib_frame_vector_args (f);
1940 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1944 return /* no error */ 0;
1949 IP4_REWRITE_NEXT_DROP,
1950 IP4_REWRITE_NEXT_ICMP_ERROR,
1951 } ip4_rewrite_next_t;
1954 * This bits of an IPv4 address to mask to construct a multicast
1957 #if CLIB_ARCH_IS_BIG_ENDIAN
1958 #define IP4_MCAST_ADDR_MASK 0x007fffff
1960 #define IP4_MCAST_ADDR_MASK 0xffff7f00
1964 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
1965 u16 adj_packet_bytes, bool df, u32 * next, u32 * error)
1967 if (packet_len > adj_packet_bytes)
1969 *error = IP4_ERROR_MTU_EXCEEDED;
1972 icmp4_error_set_vnet_buffer
1973 (b, ICMP4_destination_unreachable,
1974 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
1976 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
1980 /* Add support for fragmentation here */
1981 *next = IP4_REWRITE_NEXT_DROP;
1987 ip4_rewrite_inline (vlib_main_t * vm,
1988 vlib_node_runtime_t * node,
1989 vlib_frame_t * frame,
1990 int do_counters, int is_midchain, int is_mcast)
1992 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1993 u32 *from = vlib_frame_vector_args (frame);
1994 u32 n_left_from, n_left_to_next, *to_next, next_index;
1995 vlib_node_runtime_t *error_node =
1996 vlib_node_get_runtime (vm, ip4_input_node.index);
1998 n_left_from = frame->n_vectors;
1999 next_index = node->cached_next_index;
2000 u32 thread_index = vlib_get_thread_index ();
2002 while (n_left_from > 0)
2004 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2006 while (n_left_from >= 4 && n_left_to_next >= 2)
2008 ip_adjacency_t *adj0, *adj1;
2009 vlib_buffer_t *p0, *p1;
2010 ip4_header_t *ip0, *ip1;
2011 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2012 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2013 u32 tx_sw_if_index0, tx_sw_if_index1;
2015 /* Prefetch next iteration. */
2017 vlib_buffer_t *p2, *p3;
2019 p2 = vlib_get_buffer (vm, from[2]);
2020 p3 = vlib_get_buffer (vm, from[3]);
2022 vlib_prefetch_buffer_header (p2, STORE);
2023 vlib_prefetch_buffer_header (p3, STORE);
2025 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2026 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2029 pi0 = to_next[0] = from[0];
2030 pi1 = to_next[1] = from[1];
2035 n_left_to_next -= 2;
2037 p0 = vlib_get_buffer (vm, pi0);
2038 p1 = vlib_get_buffer (vm, pi1);
2040 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2041 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2044 * pre-fetch the per-adjacency counters
2048 vlib_prefetch_combined_counter (&adjacency_counters,
2049 thread_index, adj_index0);
2050 vlib_prefetch_combined_counter (&adjacency_counters,
2051 thread_index, adj_index1);
2054 ip0 = vlib_buffer_get_current (p0);
2055 ip1 = vlib_buffer_get_current (p1);
2057 error0 = error1 = IP4_ERROR_NONE;
2058 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2060 /* Decrement TTL & update checksum.
2061 Works either endian, so no need for byte swap. */
2062 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2064 i32 ttl0 = ip0->ttl;
2066 /* Input node should have reject packets with ttl 0. */
2067 ASSERT (ip0->ttl > 0);
2069 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2070 checksum0 += checksum0 >= 0xffff;
2072 ip0->checksum = checksum0;
2077 * If the ttl drops below 1 when forwarding, generate
2080 if (PREDICT_FALSE (ttl0 <= 0))
2082 error0 = IP4_ERROR_TIME_EXPIRED;
2083 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2084 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2085 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2087 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2090 /* Verify checksum. */
2091 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2092 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2096 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2098 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2100 i32 ttl1 = ip1->ttl;
2102 /* Input node should have reject packets with ttl 0. */
2103 ASSERT (ip1->ttl > 0);
2105 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2106 checksum1 += checksum1 >= 0xffff;
2108 ip1->checksum = checksum1;
2113 * If the ttl drops below 1 when forwarding, generate
2116 if (PREDICT_FALSE (ttl1 <= 0))
2118 error1 = IP4_ERROR_TIME_EXPIRED;
2119 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2120 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2121 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2123 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2126 /* Verify checksum. */
2127 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
2128 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2132 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2135 /* Rewrite packet header and updates lengths. */
2136 adj0 = adj_get (adj_index0);
2137 adj1 = adj_get (adj_index1);
2139 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2140 rw_len0 = adj0[0].rewrite_header.data_bytes;
2141 rw_len1 = adj1[0].rewrite_header.data_bytes;
2142 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2143 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2145 /* Check MTU of outgoing interface. */
2146 ip4_mtu_check (p0, clib_net_to_host_u16 (ip0->length),
2147 adj0[0].rewrite_header.max_l3_packet_bytes,
2148 ip0->flags_and_fragment_offset &
2149 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2151 ip4_mtu_check (p1, clib_net_to_host_u16 (ip1->length),
2152 adj1[0].rewrite_header.max_l3_packet_bytes,
2153 ip1->flags_and_fragment_offset &
2154 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2159 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2160 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2161 IP4_ERROR_SAME_INTERFACE : error0);
2162 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2163 vnet_buffer (p1)->sw_if_index[VLIB_RX]) ?
2164 IP4_ERROR_SAME_INTERFACE : error1);
2167 p0->error = error_node->errors[error0];
2168 p1->error = error_node->errors[error1];
2169 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2170 * to see the IP headerr */
2171 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2173 next0 = adj0[0].rewrite_header.next_index;
2174 p0->current_data -= rw_len0;
2175 p0->current_length += rw_len0;
2176 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2177 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2180 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2181 vnet_feature_arc_start (lm->output_feature_arc_index,
2182 tx_sw_if_index0, &next0, p0);
2184 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2186 next1 = adj1[0].rewrite_header.next_index;
2187 p1->current_data -= rw_len1;
2188 p1->current_length += rw_len1;
2190 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2191 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2194 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2195 vnet_feature_arc_start (lm->output_feature_arc_index,
2196 tx_sw_if_index1, &next1, p1);
2199 /* Guess we are only writing on simple Ethernet header. */
2200 vnet_rewrite_two_headers (adj0[0], adj1[0],
2201 ip0, ip1, sizeof (ethernet_header_t));
2204 * Bump the per-adjacency counters
2208 vlib_increment_combined_counter
2209 (&adjacency_counters,
2212 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2214 vlib_increment_combined_counter
2215 (&adjacency_counters,
2218 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2223 adj0->sub_type.midchain.fixup_func
2224 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2225 adj1->sub_type.midchain.fixup_func
2226 (vm, adj1, p1, adj0->sub_type.midchain.fixup_data);
2231 * copy bytes from the IP address into the MAC rewrite
2233 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2235 rewrite_header.dst_mcast_offset,
2236 &ip0->dst_address.as_u32,
2238 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2240 rewrite_header.dst_mcast_offset,
2241 &ip1->dst_address.as_u32,
2245 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2246 to_next, n_left_to_next,
2247 pi0, pi1, next0, next1);
2250 while (n_left_from > 0 && n_left_to_next > 0)
2252 ip_adjacency_t *adj0;
2255 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2256 u32 tx_sw_if_index0;
2258 pi0 = to_next[0] = from[0];
2260 p0 = vlib_get_buffer (vm, pi0);
2262 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2264 adj0 = adj_get (adj_index0);
2266 ip0 = vlib_buffer_get_current (p0);
2268 error0 = IP4_ERROR_NONE;
2269 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2271 /* Decrement TTL & update checksum. */
2272 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2274 i32 ttl0 = ip0->ttl;
2276 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2278 checksum0 += checksum0 >= 0xffff;
2280 ip0->checksum = checksum0;
2282 ASSERT (ip0->ttl > 0);
2288 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2289 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2291 if (PREDICT_FALSE (ttl0 <= 0))
2294 * If the ttl drops below 1 when forwarding, generate
2297 error0 = IP4_ERROR_TIME_EXPIRED;
2298 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2299 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2300 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2301 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2307 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2311 vlib_prefetch_combined_counter (&adjacency_counters,
2312 thread_index, adj_index0);
2314 /* Guess we are only writing on simple Ethernet header. */
2315 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2319 * copy bytes from the IP address into the MAC rewrite
2321 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2323 rewrite_header.dst_mcast_offset,
2324 &ip0->dst_address.as_u32,
2328 /* Update packet buffer attributes/set output interface. */
2329 rw_len0 = adj0[0].rewrite_header.data_bytes;
2330 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2333 vlib_increment_combined_counter
2334 (&adjacency_counters,
2335 thread_index, adj_index0, 1,
2336 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2338 /* Check MTU of outgoing interface. */
2339 ip4_mtu_check (p0, clib_net_to_host_u16 (ip0->length),
2340 adj0[0].rewrite_header.max_l3_packet_bytes,
2341 ip0->flags_and_fragment_offset &
2342 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2347 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2348 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2349 IP4_ERROR_SAME_INTERFACE : error0);
2351 p0->error = error_node->errors[error0];
2353 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2354 * to see the IP headerr */
2355 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2357 p0->current_data -= rw_len0;
2358 p0->current_length += rw_len0;
2359 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2361 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2362 next0 = adj0[0].rewrite_header.next_index;
2366 adj0->sub_type.midchain.fixup_func
2367 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2371 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2372 vnet_feature_arc_start (lm->output_feature_arc_index,
2373 tx_sw_if_index0, &next0, p0);
2380 n_left_to_next -= 1;
2382 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2383 to_next, n_left_to_next,
2387 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2390 /* Need to do trace after rewrites to pick up new packet data. */
2391 if (node->flags & VLIB_NODE_FLAG_TRACE)
2392 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2394 return frame->n_vectors;
2398 /** @brief IPv4 rewrite node.
2401 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2402 header checksum, fetch the ip adjacency, check the outbound mtu,
2403 apply the adjacency rewrite, and send pkts to the adjacency
2404 rewrite header's rewrite_next_index.
2406 @param vm vlib_main_t corresponding to the current thread
2407 @param node vlib_node_runtime_t
2408 @param frame vlib_frame_t whose contents should be dispatched
2410 @par Graph mechanics: buffer metadata, next index usage
2413 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2414 - the rewrite adjacency index
2415 - <code>adj->lookup_next_index</code>
2416 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2417 the packet will be dropped.
2418 - <code>adj->rewrite_header</code>
2419 - Rewrite string length, rewrite string, next_index
2422 - <code>b->current_data, b->current_length</code>
2423 - Updated net of applying the rewrite string
2425 <em>Next Indices:</em>
2426 - <code> adj->rewrite_header.next_index </code>
2430 ip4_rewrite (vlib_main_t * vm,
2431 vlib_node_runtime_t * node, vlib_frame_t * frame)
2433 if (adj_are_counters_enabled ())
2434 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2436 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2440 ip4_midchain (vlib_main_t * vm,
2441 vlib_node_runtime_t * node, vlib_frame_t * frame)
2443 if (adj_are_counters_enabled ())
2444 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2446 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2450 ip4_rewrite_mcast (vlib_main_t * vm,
2451 vlib_node_runtime_t * node, vlib_frame_t * frame)
2453 if (adj_are_counters_enabled ())
2454 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2456 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2460 ip4_mcast_midchain (vlib_main_t * vm,
2461 vlib_node_runtime_t * node, vlib_frame_t * frame)
2463 if (adj_are_counters_enabled ())
2464 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2466 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2470 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2471 .function = ip4_rewrite,
2472 .name = "ip4-rewrite",
2473 .vector_size = sizeof (u32),
2475 .format_trace = format_ip4_rewrite_trace,
2479 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2480 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2483 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2485 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2486 .function = ip4_rewrite_mcast,
2487 .name = "ip4-rewrite-mcast",
2488 .vector_size = sizeof (u32),
2490 .format_trace = format_ip4_rewrite_trace,
2491 .sibling_of = "ip4-rewrite",
2493 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2495 VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2496 .function = ip4_mcast_midchain,
2497 .name = "ip4-mcast-midchain",
2498 .vector_size = sizeof (u32),
2500 .format_trace = format_ip4_rewrite_trace,
2501 .sibling_of = "ip4-rewrite",
2503 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2505 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2506 .function = ip4_midchain,
2507 .name = "ip4-midchain",
2508 .vector_size = sizeof (u32),
2509 .format_trace = format_ip4_forward_next_trace,
2510 .sibling_of = "ip4-rewrite",
2512 VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
2516 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2518 ip4_fib_mtrie_t *mtrie0;
2519 ip4_fib_mtrie_leaf_t leaf0;
2522 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2524 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
2525 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2526 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2528 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2530 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2533 static clib_error_t *
2534 test_lookup_command_fn (vlib_main_t * vm,
2535 unformat_input_t * input, vlib_cli_command_t * cmd)
2542 ip4_address_t ip4_base_address;
2545 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2547 if (unformat (input, "table %d", &table_id))
2549 /* Make sure the entry exists. */
2550 fib = ip4_fib_get (table_id);
2551 if ((fib) && (fib->index != table_id))
2552 return clib_error_return (0, "<fib-index> %d does not exist",
2555 else if (unformat (input, "count %f", &count))
2558 else if (unformat (input, "%U",
2559 unformat_ip4_address, &ip4_base_address))
2562 return clib_error_return (0, "unknown input `%U'",
2563 format_unformat_error, input);
2568 for (i = 0; i < n; i++)
2570 if (!ip4_lookup_validate (&ip4_base_address, table_id))
2573 ip4_base_address.as_u32 =
2574 clib_host_to_net_u32 (1 +
2575 clib_net_to_host_u32 (ip4_base_address.as_u32));
2579 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2581 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2587 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2588 * given FIB table to determine if there is a conflict with the
2589 * adjacency table. The fib-id can be determined by using the
2590 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2593 * @todo This command uses fib-id, other commands use table-id (not
2594 * just a name, they are different indexes). Would like to change this
2595 * to table-id for consistency.
2598 * Example of how to run the test lookup command:
2599 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2600 * No errors in 2 lookups
2604 VLIB_CLI_COMMAND (lookup_test_command, static) =
2606 .path = "test lookup",
2607 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2608 .function = test_lookup_command_fn,
2613 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
2617 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2619 if (~0 == fib_index)
2620 return VNET_API_ERROR_NO_SUCH_FIB;
2622 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2628 static clib_error_t *
2629 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2630 unformat_input_t * input,
2631 vlib_cli_command_t * cmd)
2635 u32 flow_hash_config = 0;
2638 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2640 if (unformat (input, "table %d", &table_id))
2643 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2644 foreach_flow_hash_bit
2651 return clib_error_return (0, "unknown input `%U'",
2652 format_unformat_error, input);
2654 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2660 case VNET_API_ERROR_NO_SUCH_FIB:
2661 return clib_error_return (0, "no such FIB table %d", table_id);
2664 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2672 * Configure the set of IPv4 fields used by the flow hash.
2675 * Example of how to set the flow hash on a given table:
2676 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2677 * Example of display the configured flow hash:
2678 * @cliexstart{show ip fib}
2679 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2682 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2683 * [0] [@0]: dpo-drop ip6
2686 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2687 * [0] [@0]: dpo-drop ip6
2690 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2691 * [0] [@0]: dpo-drop ip6
2694 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2695 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2698 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2699 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2700 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2701 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2702 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2705 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2706 * [0] [@0]: dpo-drop ip6
2707 * 255.255.255.255/32
2709 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2710 * [0] [@0]: dpo-drop ip6
2711 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2714 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2715 * [0] [@0]: dpo-drop ip6
2718 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2719 * [0] [@0]: dpo-drop ip6
2722 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2723 * [0] [@4]: ipv4-glean: af_packet0
2726 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2727 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2730 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2731 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2734 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2735 * [0] [@4]: ipv4-glean: af_packet1
2738 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2739 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2742 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2743 * [0] [@0]: dpo-drop ip6
2746 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2747 * [0] [@0]: dpo-drop ip6
2748 * 255.255.255.255/32
2750 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2751 * [0] [@0]: dpo-drop ip6
2755 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2757 .path = "set ip flow-hash",
2759 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2760 .function = set_ip_flow_hash_command_fn,
2765 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2768 vnet_main_t *vnm = vnet_get_main ();
2769 vnet_interface_main_t *im = &vnm->interface_main;
2770 ip4_main_t *ipm = &ip4_main;
2771 ip_lookup_main_t *lm = &ipm->lookup_main;
2772 vnet_classify_main_t *cm = &vnet_classify_main;
2773 ip4_address_t *if_addr;
2775 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2776 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2778 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2779 return VNET_API_ERROR_NO_SUCH_ENTRY;
2781 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2782 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2784 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2786 if (NULL != if_addr)
2788 fib_prefix_t pfx = {
2790 .fp_proto = FIB_PROTOCOL_IP4,
2791 .fp_addr.ip4 = *if_addr,
2795 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2799 if (table_index != (u32) ~ 0)
2801 dpo_id_t dpo = DPO_INVALID;
2806 classify_dpo_create (DPO_PROTO_IP4, table_index));
2808 fib_table_entry_special_dpo_add (fib_index,
2810 FIB_SOURCE_CLASSIFY,
2811 FIB_ENTRY_FLAG_NONE, &dpo);
2816 fib_table_entry_special_remove (fib_index,
2817 &pfx, FIB_SOURCE_CLASSIFY);
2824 static clib_error_t *
2825 set_ip_classify_command_fn (vlib_main_t * vm,
2826 unformat_input_t * input,
2827 vlib_cli_command_t * cmd)
2829 u32 table_index = ~0;
2830 int table_index_set = 0;
2831 u32 sw_if_index = ~0;
2834 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2836 if (unformat (input, "table-index %d", &table_index))
2837 table_index_set = 1;
2838 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2839 vnet_get_main (), &sw_if_index))
2845 if (table_index_set == 0)
2846 return clib_error_return (0, "classify table-index must be specified");
2848 if (sw_if_index == ~0)
2849 return clib_error_return (0, "interface / subif must be specified");
2851 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2858 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2859 return clib_error_return (0, "No such interface");
2861 case VNET_API_ERROR_NO_SUCH_ENTRY:
2862 return clib_error_return (0, "No such classifier table");
2868 * Assign a classification table to an interface. The classification
2869 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2870 * commands. Once the table is create, use this command to filter packets
2874 * Example of how to assign a classification table to an interface:
2875 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2878 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2880 .path = "set ip classify",
2882 "set ip classify intfc <interface> table-index <classify-idx>",
2883 .function = set_ip_classify_command_fn,
2887 static clib_error_t *
2888 ip4_config (vlib_main_t * vm, unformat_input_t * input)
2890 ip4_main_t *im = &ip4_main;
2893 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2895 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
2898 return clib_error_return (0,
2899 "invalid heap-size parameter `%U'",
2900 format_unformat_error, input);
2903 im->mtrie_heap_size = heapsize;
2908 VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
2911 * fd.io coding-style-patch-verification: ON
2914 * eval: (c-set-style "gnu")