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, fib_index0, lbi0;
1206 u32 pi1, next1, fib_index1, 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 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1273 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1274 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1276 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1278 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1279 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1281 /* TODO maybe move to lookup? */
1282 vnet_buffer (p0)->ip.fib_index = fib_index0;
1283 vnet_buffer (p1)->ip.fib_index = fib_index1;
1285 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1286 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
1288 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1289 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
1290 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1292 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1294 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1296 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1299 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1300 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1301 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1303 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1304 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1305 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
1307 lb0 = load_balance_get (lbi0);
1308 lb1 = load_balance_get (lbi1);
1309 dpo0 = load_balance_get_bucket_i (lb0, 0);
1310 dpo1 = load_balance_get_bucket_i (lb1, 0);
1313 * Must have a route to source otherwise we drop the packet.
1314 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1317 * - the source is a recieve => it's from us => bogus, do this
1318 * first since it sets a different error code.
1319 * - uRPF check for any route to source - accept if passes.
1320 * - allow packets destined to the broadcast address from unknown sources
1322 if (p0->flags & VNET_BUFFER_F_IS_NATED)
1325 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1326 dpo0->dpoi_type == DPO_RECEIVE) ?
1327 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1328 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1329 !fib_urpf_check_size (lb0->lb_urpf) &&
1330 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1331 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1334 if (p1->flags & VNET_BUFFER_F_IS_NATED)
1337 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1338 dpo1->dpoi_type == DPO_RECEIVE) ?
1339 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1340 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1341 !fib_urpf_check_size (lb1->lb_urpf) &&
1342 ip1->dst_address.as_u32 != 0xFFFFFFFF)
1343 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
1347 next0 = lm->local_next_by_ip_protocol[proto0];
1348 next1 = lm->local_next_by_ip_protocol[proto1];
1351 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1353 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1355 p0->error = error0 ? error_node->errors[error0] : 0;
1356 p1->error = error1 ? error_node->errors[error1] : 0;
1358 if (head_of_feature_arc)
1360 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1361 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1362 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1363 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
1366 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1367 n_left_to_next, pi0, pi1,
1371 while (n_left_from > 0 && n_left_to_next > 0)
1375 ip4_fib_mtrie_t *mtrie0;
1376 ip4_fib_mtrie_leaf_t leaf0;
1377 u32 pi0, next0, fib_index0, lbi0;
1378 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1379 load_balance_t *lb0;
1380 const dpo_id_t *dpo0;
1383 pi0 = to_next[0] = from[0];
1387 n_left_to_next -= 1;
1389 next0 = IP_LOCAL_NEXT_DROP;
1390 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1392 p0 = vlib_get_buffer (vm, pi0);
1393 ip0 = vlib_buffer_get_current (p0);
1394 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1395 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1397 proto0 = ip0->protocol;
1399 if (head_of_feature_arc == 0 || p0->flags & VNET_BUFFER_F_IS_NATED)
1402 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1403 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1406 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1407 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1408 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1410 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
1412 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1416 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1417 error0 = (is_tcp_udp0 && !good_tcp_udp0
1418 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1420 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1422 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1423 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1424 vnet_buffer (p0)->ip.fib_index = fib_index0;
1425 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1426 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1427 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1429 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1431 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1432 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1433 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
1435 lb0 = load_balance_get (lbi0);
1436 dpo0 = load_balance_get_bucket_i (lb0, 0);
1438 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1439 dpo0->dpoi_type == DPO_RECEIVE) ?
1440 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1441 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1442 !fib_urpf_check_size (lb0->lb_urpf) &&
1443 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1444 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1447 next0 = lm->local_next_by_ip_protocol[proto0];
1449 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1451 p0->error = error0 ? error_node->errors[error0] : 0;
1453 if (head_of_feature_arc)
1455 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1456 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1459 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1460 n_left_to_next, pi0, next0);
1462 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1465 return frame->n_vectors;
1469 ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1471 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1475 VLIB_REGISTER_NODE (ip4_local_node) =
1477 .function = ip4_local,
1478 .name = "ip4-local",
1479 .vector_size = sizeof (u32),
1480 .format_trace = format_ip4_forward_next_trace,
1481 .n_next_nodes = IP_LOCAL_N_NEXT,
1484 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1485 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1486 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1487 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1492 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1495 ip4_local_end_of_arc (vlib_main_t * vm,
1496 vlib_node_runtime_t * node, vlib_frame_t * frame)
1498 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1502 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1503 .function = ip4_local_end_of_arc,
1504 .name = "ip4-local-end-of-arc",
1505 .vector_size = sizeof (u32),
1507 .format_trace = format_ip4_forward_next_trace,
1508 .sibling_of = "ip4-local",
1511 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1513 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1514 .arc_name = "ip4-local",
1515 .node_name = "ip4-local-end-of-arc",
1516 .runs_before = 0, /* not before any other features */
1521 ip4_register_protocol (u32 protocol, u32 node_index)
1523 vlib_main_t *vm = vlib_get_main ();
1524 ip4_main_t *im = &ip4_main;
1525 ip_lookup_main_t *lm = &im->lookup_main;
1527 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1528 lm->local_next_by_ip_protocol[protocol] =
1529 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1532 static clib_error_t *
1533 show_ip_local_command_fn (vlib_main_t * vm,
1534 unformat_input_t * input, vlib_cli_command_t * cmd)
1536 ip4_main_t *im = &ip4_main;
1537 ip_lookup_main_t *lm = &im->lookup_main;
1540 vlib_cli_output (vm, "Protocols handled by ip4_local");
1541 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1543 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1545 u32 node_index = vlib_get_node (vm,
1546 ip4_local_node.index)->
1547 next_nodes[lm->local_next_by_ip_protocol[i]];
1548 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1558 * Display the set of protocols handled by the local IPv4 stack.
1561 * Example of how to display local protocol table:
1562 * @cliexstart{show ip local}
1563 * Protocols handled by ip4_local
1570 VLIB_CLI_COMMAND (show_ip_local, static) =
1572 .path = "show ip local",
1573 .function = show_ip_local_command_fn,
1574 .short_help = "show ip local",
1579 ip4_arp_inline (vlib_main_t * vm,
1580 vlib_node_runtime_t * node,
1581 vlib_frame_t * frame, int is_glean)
1583 vnet_main_t *vnm = vnet_get_main ();
1584 ip4_main_t *im = &ip4_main;
1585 ip_lookup_main_t *lm = &im->lookup_main;
1586 u32 *from, *to_next_drop;
1587 uword n_left_from, n_left_to_next_drop, next_index;
1588 static f64 time_last_seed_change = -1e100;
1589 static u32 hash_seeds[3];
1590 static uword hash_bitmap[256 / BITS (uword)];
1593 if (node->flags & VLIB_NODE_FLAG_TRACE)
1594 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1596 time_now = vlib_time_now (vm);
1597 if (time_now - time_last_seed_change > 1e-3)
1600 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1601 sizeof (hash_seeds));
1602 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1603 hash_seeds[i] = r[i];
1605 /* Mark all hash keys as been no-seen before. */
1606 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1609 time_last_seed_change = time_now;
1612 from = vlib_frame_vector_args (frame);
1613 n_left_from = frame->n_vectors;
1614 next_index = node->cached_next_index;
1615 if (next_index == IP4_ARP_NEXT_DROP)
1616 next_index = IP4_ARP_N_NEXT; /* point to first interface */
1618 while (n_left_from > 0)
1620 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1621 to_next_drop, n_left_to_next_drop);
1623 while (n_left_from > 0 && n_left_to_next_drop > 0)
1625 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1626 ip_adjacency_t *adj0;
1633 p0 = vlib_get_buffer (vm, pi0);
1635 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1636 adj0 = adj_get (adj_index0);
1637 ip0 = vlib_buffer_get_current (p0);
1643 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1644 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1649 * this is the Glean case, so we are ARPing for the
1650 * packet's destination
1652 a0 ^= ip0->dst_address.data_u32;
1656 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1660 hash_v3_mix32 (a0, b0, c0);
1661 hash_v3_finalize32 (a0, b0, c0);
1663 c0 &= BITS (hash_bitmap) - 1;
1664 m0 = (uword) 1 << (c0 % BITS (uword));
1665 c0 = c0 / BITS (uword);
1667 bm0 = hash_bitmap[c0];
1668 drop0 = (bm0 & m0) != 0;
1670 /* Mark it as seen. */
1671 hash_bitmap[c0] = bm0 | m0;
1675 to_next_drop[0] = pi0;
1677 n_left_to_next_drop -= 1;
1680 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
1681 IP4_ARP_ERROR_REQUEST_SENT];
1684 * the adj has been updated to a rewrite but the node the DPO that got
1685 * us here hasn't - yet. no big deal. we'll drop while we wait.
1687 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1694 * Can happen if the control-plane is programming tables
1695 * with traffic flowing; at least that's today's lame excuse.
1697 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1698 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
1700 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
1703 /* Send ARP request. */
1707 ethernet_arp_header_t *h0;
1708 vnet_hw_interface_t *hw_if0;
1711 vlib_packet_template_get_packet (vm,
1712 &im->ip4_arp_request_packet_template,
1715 /* Seems we're out of buffers */
1716 if (PREDICT_FALSE (!h0))
1719 /* Add rewrite/encap string for ARP packet. */
1720 vnet_rewrite_one_header (adj0[0], h0,
1721 sizeof (ethernet_header_t));
1723 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1725 /* Src ethernet address in ARP header. */
1726 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
1728 sizeof (h0->ip4_over_ethernet[0].ethernet));
1732 /* The interface's source address is stashed in the Glean Adj */
1733 h0->ip4_over_ethernet[0].ip4 =
1734 adj0->sub_type.glean.receive_addr.ip4;
1736 /* Copy in destination address we are requesting. This is the
1737 * glean case, so it's the packet's destination.*/
1738 h0->ip4_over_ethernet[1].ip4.data_u32 =
1739 ip0->dst_address.data_u32;
1743 /* Src IP address in ARP header. */
1744 if (ip4_src_address_for_packet (lm, sw_if_index0,
1746 ip4_over_ethernet[0].ip4))
1748 /* No source address available */
1750 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1751 vlib_buffer_free (vm, &bi0, 1);
1755 /* Copy in destination address we are requesting from the
1757 h0->ip4_over_ethernet[1].ip4.data_u32 =
1758 adj0->sub_type.nbr.next_hop.ip4.as_u32;
1761 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1762 b0 = vlib_get_buffer (vm, bi0);
1763 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1764 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1766 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1768 vlib_set_next_frame_buffer (vm, node,
1769 adj0->rewrite_header.next_index,
1774 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1777 return frame->n_vectors;
1781 ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1783 return (ip4_arp_inline (vm, node, frame, 0));
1787 ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1789 return (ip4_arp_inline (vm, node, frame, 1));
1792 static char *ip4_arp_error_strings[] = {
1793 [IP4_ARP_ERROR_DROP] = "address overflow drops",
1794 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1795 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
1796 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
1797 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
1798 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
1802 VLIB_REGISTER_NODE (ip4_arp_node) =
1804 .function = ip4_arp,
1806 .vector_size = sizeof (u32),
1807 .format_trace = format_ip4_forward_next_trace,
1808 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1809 .error_strings = ip4_arp_error_strings,
1810 .n_next_nodes = IP4_ARP_N_NEXT,
1813 [IP4_ARP_NEXT_DROP] = "error-drop",
1817 VLIB_REGISTER_NODE (ip4_glean_node) =
1819 .function = ip4_glean,
1820 .name = "ip4-glean",
1821 .vector_size = sizeof (u32),
1822 .format_trace = format_ip4_forward_next_trace,
1823 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1824 .error_strings = ip4_arp_error_strings,
1825 .n_next_nodes = IP4_ARP_N_NEXT,
1827 [IP4_ARP_NEXT_DROP] = "error-drop",
1832 #define foreach_notrace_ip4_arp_error \
1839 arp_notrace_init (vlib_main_t * vm)
1841 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
1843 /* don't trace ARP request packets */
1845 vnet_pcap_drop_trace_filter_add_del \
1846 (rt->errors[IP4_ARP_ERROR_##a], \
1848 foreach_notrace_ip4_arp_error;
1853 VLIB_INIT_FUNCTION (arp_notrace_init);
1856 /* Send an ARP request to see if given destination is reachable on given interface. */
1858 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
1860 vnet_main_t *vnm = vnet_get_main ();
1861 ip4_main_t *im = &ip4_main;
1862 ethernet_arp_header_t *h;
1864 ip_interface_address_t *ia;
1865 ip_adjacency_t *adj;
1866 vnet_hw_interface_t *hi;
1867 vnet_sw_interface_t *si;
1872 si = vnet_get_sw_interface (vnm, sw_if_index);
1874 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1876 return clib_error_return (0, "%U: interface %U down",
1877 format_ip4_address, dst,
1878 format_vnet_sw_if_index_name, vnm,
1883 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1886 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1887 return clib_error_return
1889 "no matching interface address for destination %U (interface %U)",
1890 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
1894 h = vlib_packet_template_get_packet (vm,
1895 &im->ip4_arp_request_packet_template,
1898 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1899 if (PREDICT_FALSE (!hi->hw_address))
1901 return clib_error_return (0, "%U: interface %U do not support ip probe",
1902 format_ip4_address, dst,
1903 format_vnet_sw_if_index_name, vnm,
1907 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
1908 sizeof (h->ip4_over_ethernet[0].ethernet));
1910 h->ip4_over_ethernet[0].ip4 = src[0];
1911 h->ip4_over_ethernet[1].ip4 = dst[0];
1913 b = vlib_get_buffer (vm, bi);
1914 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1915 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1917 ip46_address_t nh = {
1921 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
1922 VNET_LINK_IP4, &nh, sw_if_index);
1925 /* Peer has been previously resolved, retrieve glean adj instead */
1926 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1929 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
1930 VNET_LINK_IP4, sw_if_index, &nh);
1934 /* Add encapsulation string for software interface (e.g. ethernet header). */
1935 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1936 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1939 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1940 u32 *to_next = vlib_frame_vector_args (f);
1943 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1947 return /* no error */ 0;
1952 IP4_REWRITE_NEXT_DROP,
1953 IP4_REWRITE_NEXT_ICMP_ERROR,
1954 } ip4_rewrite_next_t;
1957 * This bits of an IPv4 address to mask to construct a multicast
1960 #if CLIB_ARCH_IS_BIG_ENDIAN
1961 #define IP4_MCAST_ADDR_MASK 0x007fffff
1963 #define IP4_MCAST_ADDR_MASK 0xffff7f00
1967 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
1968 u16 adj_packet_bytes, bool df, u32 * next, u32 * error)
1970 if (packet_len > adj_packet_bytes)
1972 *error = IP4_ERROR_MTU_EXCEEDED;
1975 icmp4_error_set_vnet_buffer
1976 (b, ICMP4_destination_unreachable,
1977 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
1979 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
1983 /* Add support for fragmentation here */
1984 *next = IP4_REWRITE_NEXT_DROP;
1990 ip4_rewrite_inline (vlib_main_t * vm,
1991 vlib_node_runtime_t * node,
1992 vlib_frame_t * frame,
1993 int do_counters, int is_midchain, int is_mcast)
1995 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1996 u32 *from = vlib_frame_vector_args (frame);
1997 u32 n_left_from, n_left_to_next, *to_next, next_index;
1998 vlib_node_runtime_t *error_node =
1999 vlib_node_get_runtime (vm, ip4_input_node.index);
2001 n_left_from = frame->n_vectors;
2002 next_index = node->cached_next_index;
2003 u32 thread_index = vlib_get_thread_index ();
2005 while (n_left_from > 0)
2007 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2009 while (n_left_from >= 4 && n_left_to_next >= 2)
2011 ip_adjacency_t *adj0, *adj1;
2012 vlib_buffer_t *p0, *p1;
2013 ip4_header_t *ip0, *ip1;
2014 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2015 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2016 u32 tx_sw_if_index0, tx_sw_if_index1;
2018 /* Prefetch next iteration. */
2020 vlib_buffer_t *p2, *p3;
2022 p2 = vlib_get_buffer (vm, from[2]);
2023 p3 = vlib_get_buffer (vm, from[3]);
2025 vlib_prefetch_buffer_header (p2, STORE);
2026 vlib_prefetch_buffer_header (p3, STORE);
2028 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2029 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2032 pi0 = to_next[0] = from[0];
2033 pi1 = to_next[1] = from[1];
2038 n_left_to_next -= 2;
2040 p0 = vlib_get_buffer (vm, pi0);
2041 p1 = vlib_get_buffer (vm, pi1);
2043 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2044 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2047 * pre-fetch the per-adjacency counters
2051 vlib_prefetch_combined_counter (&adjacency_counters,
2052 thread_index, adj_index0);
2053 vlib_prefetch_combined_counter (&adjacency_counters,
2054 thread_index, adj_index1);
2057 ip0 = vlib_buffer_get_current (p0);
2058 ip1 = vlib_buffer_get_current (p1);
2060 error0 = error1 = IP4_ERROR_NONE;
2061 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2063 /* Decrement TTL & update checksum.
2064 Works either endian, so no need for byte swap. */
2065 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2067 i32 ttl0 = ip0->ttl;
2069 /* Input node should have reject packets with ttl 0. */
2070 ASSERT (ip0->ttl > 0);
2072 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2073 checksum0 += checksum0 >= 0xffff;
2075 ip0->checksum = checksum0;
2080 * If the ttl drops below 1 when forwarding, generate
2083 if (PREDICT_FALSE (ttl0 <= 0))
2085 error0 = IP4_ERROR_TIME_EXPIRED;
2086 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2087 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2088 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2090 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2093 /* Verify checksum. */
2094 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2095 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2099 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2101 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2103 i32 ttl1 = ip1->ttl;
2105 /* Input node should have reject packets with ttl 0. */
2106 ASSERT (ip1->ttl > 0);
2108 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2109 checksum1 += checksum1 >= 0xffff;
2111 ip1->checksum = checksum1;
2116 * If the ttl drops below 1 when forwarding, generate
2119 if (PREDICT_FALSE (ttl1 <= 0))
2121 error1 = IP4_ERROR_TIME_EXPIRED;
2122 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2123 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2124 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2126 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2129 /* Verify checksum. */
2130 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
2131 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2135 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2138 /* Rewrite packet header and updates lengths. */
2139 adj0 = adj_get (adj_index0);
2140 adj1 = adj_get (adj_index1);
2142 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2143 rw_len0 = adj0[0].rewrite_header.data_bytes;
2144 rw_len1 = adj1[0].rewrite_header.data_bytes;
2145 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2146 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2148 /* Check MTU of outgoing interface. */
2149 ip4_mtu_check (p0, clib_net_to_host_u16 (ip0->length),
2150 adj0[0].rewrite_header.max_l3_packet_bytes,
2151 ip0->flags_and_fragment_offset &
2152 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2154 ip4_mtu_check (p1, clib_net_to_host_u16 (ip1->length),
2155 adj1[0].rewrite_header.max_l3_packet_bytes,
2156 ip1->flags_and_fragment_offset &
2157 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2162 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2163 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2164 IP4_ERROR_SAME_INTERFACE : error0);
2165 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2166 vnet_buffer (p1)->sw_if_index[VLIB_RX]) ?
2167 IP4_ERROR_SAME_INTERFACE : error1);
2170 p0->error = error_node->errors[error0];
2171 p1->error = error_node->errors[error1];
2172 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2173 * to see the IP headerr */
2174 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2176 next0 = adj0[0].rewrite_header.next_index;
2177 p0->current_data -= rw_len0;
2178 p0->current_length += rw_len0;
2179 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2180 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2183 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2184 vnet_feature_arc_start (lm->output_feature_arc_index,
2185 tx_sw_if_index0, &next0, p0);
2187 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2189 next1 = adj1[0].rewrite_header.next_index;
2190 p1->current_data -= rw_len1;
2191 p1->current_length += rw_len1;
2193 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2194 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2197 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2198 vnet_feature_arc_start (lm->output_feature_arc_index,
2199 tx_sw_if_index1, &next1, p1);
2202 /* Guess we are only writing on simple Ethernet header. */
2203 vnet_rewrite_two_headers (adj0[0], adj1[0],
2204 ip0, ip1, sizeof (ethernet_header_t));
2207 * Bump the per-adjacency counters
2211 vlib_increment_combined_counter
2212 (&adjacency_counters,
2215 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2217 vlib_increment_combined_counter
2218 (&adjacency_counters,
2221 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2226 adj0->sub_type.midchain.fixup_func
2227 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2228 adj1->sub_type.midchain.fixup_func
2229 (vm, adj1, p1, adj0->sub_type.midchain.fixup_data);
2234 * copy bytes from the IP address into the MAC rewrite
2236 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2238 rewrite_header.dst_mcast_offset,
2239 &ip0->dst_address.as_u32,
2241 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2243 rewrite_header.dst_mcast_offset,
2244 &ip1->dst_address.as_u32,
2248 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2249 to_next, n_left_to_next,
2250 pi0, pi1, next0, next1);
2253 while (n_left_from > 0 && n_left_to_next > 0)
2255 ip_adjacency_t *adj0;
2258 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2259 u32 tx_sw_if_index0;
2261 pi0 = to_next[0] = from[0];
2263 p0 = vlib_get_buffer (vm, pi0);
2265 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2267 adj0 = adj_get (adj_index0);
2269 ip0 = vlib_buffer_get_current (p0);
2271 error0 = IP4_ERROR_NONE;
2272 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2274 /* Decrement TTL & update checksum. */
2275 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2277 i32 ttl0 = ip0->ttl;
2279 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2281 checksum0 += checksum0 >= 0xffff;
2283 ip0->checksum = checksum0;
2285 ASSERT (ip0->ttl > 0);
2291 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2292 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2294 if (PREDICT_FALSE (ttl0 <= 0))
2297 * If the ttl drops below 1 when forwarding, generate
2300 error0 = IP4_ERROR_TIME_EXPIRED;
2301 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2302 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2303 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2304 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2310 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2314 vlib_prefetch_combined_counter (&adjacency_counters,
2315 thread_index, adj_index0);
2317 /* Guess we are only writing on simple Ethernet header. */
2318 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2322 * copy bytes from the IP address into the MAC rewrite
2324 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2326 rewrite_header.dst_mcast_offset,
2327 &ip0->dst_address.as_u32,
2331 /* Update packet buffer attributes/set output interface. */
2332 rw_len0 = adj0[0].rewrite_header.data_bytes;
2333 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2336 vlib_increment_combined_counter
2337 (&adjacency_counters,
2338 thread_index, adj_index0, 1,
2339 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2341 /* Check MTU of outgoing interface. */
2342 ip4_mtu_check (p0, clib_net_to_host_u16 (ip0->length),
2343 adj0[0].rewrite_header.max_l3_packet_bytes,
2344 ip0->flags_and_fragment_offset &
2345 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2350 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2351 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2352 IP4_ERROR_SAME_INTERFACE : error0);
2354 p0->error = error_node->errors[error0];
2356 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2357 * to see the IP headerr */
2358 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2360 p0->current_data -= rw_len0;
2361 p0->current_length += rw_len0;
2362 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2364 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2365 next0 = adj0[0].rewrite_header.next_index;
2369 adj0->sub_type.midchain.fixup_func
2370 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2374 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2375 vnet_feature_arc_start (lm->output_feature_arc_index,
2376 tx_sw_if_index0, &next0, p0);
2383 n_left_to_next -= 1;
2385 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2386 to_next, n_left_to_next,
2390 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2393 /* Need to do trace after rewrites to pick up new packet data. */
2394 if (node->flags & VLIB_NODE_FLAG_TRACE)
2395 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2397 return frame->n_vectors;
2401 /** @brief IPv4 rewrite node.
2404 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2405 header checksum, fetch the ip adjacency, check the outbound mtu,
2406 apply the adjacency rewrite, and send pkts to the adjacency
2407 rewrite header's rewrite_next_index.
2409 @param vm vlib_main_t corresponding to the current thread
2410 @param node vlib_node_runtime_t
2411 @param frame vlib_frame_t whose contents should be dispatched
2413 @par Graph mechanics: buffer metadata, next index usage
2416 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2417 - the rewrite adjacency index
2418 - <code>adj->lookup_next_index</code>
2419 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2420 the packet will be dropped.
2421 - <code>adj->rewrite_header</code>
2422 - Rewrite string length, rewrite string, next_index
2425 - <code>b->current_data, b->current_length</code>
2426 - Updated net of applying the rewrite string
2428 <em>Next Indices:</em>
2429 - <code> adj->rewrite_header.next_index </code>
2433 ip4_rewrite (vlib_main_t * vm,
2434 vlib_node_runtime_t * node, vlib_frame_t * frame)
2436 if (adj_are_counters_enabled ())
2437 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2439 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2443 ip4_midchain (vlib_main_t * vm,
2444 vlib_node_runtime_t * node, vlib_frame_t * frame)
2446 if (adj_are_counters_enabled ())
2447 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2449 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2453 ip4_rewrite_mcast (vlib_main_t * vm,
2454 vlib_node_runtime_t * node, vlib_frame_t * frame)
2456 if (adj_are_counters_enabled ())
2457 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2459 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2463 ip4_mcast_midchain (vlib_main_t * vm,
2464 vlib_node_runtime_t * node, vlib_frame_t * frame)
2466 if (adj_are_counters_enabled ())
2467 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2469 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2473 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2474 .function = ip4_rewrite,
2475 .name = "ip4-rewrite",
2476 .vector_size = sizeof (u32),
2478 .format_trace = format_ip4_rewrite_trace,
2482 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2483 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2486 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2488 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2489 .function = ip4_rewrite_mcast,
2490 .name = "ip4-rewrite-mcast",
2491 .vector_size = sizeof (u32),
2493 .format_trace = format_ip4_rewrite_trace,
2494 .sibling_of = "ip4-rewrite",
2496 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2498 VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2499 .function = ip4_mcast_midchain,
2500 .name = "ip4-mcast-midchain",
2501 .vector_size = sizeof (u32),
2503 .format_trace = format_ip4_rewrite_trace,
2504 .sibling_of = "ip4-rewrite",
2506 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2508 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2509 .function = ip4_midchain,
2510 .name = "ip4-midchain",
2511 .vector_size = sizeof (u32),
2512 .format_trace = format_ip4_forward_next_trace,
2513 .sibling_of = "ip4-rewrite",
2515 VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
2519 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2521 ip4_fib_mtrie_t *mtrie0;
2522 ip4_fib_mtrie_leaf_t leaf0;
2525 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2527 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
2528 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2529 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2531 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2533 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2536 static clib_error_t *
2537 test_lookup_command_fn (vlib_main_t * vm,
2538 unformat_input_t * input, vlib_cli_command_t * cmd)
2545 ip4_address_t ip4_base_address;
2548 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2550 if (unformat (input, "table %d", &table_id))
2552 /* Make sure the entry exists. */
2553 fib = ip4_fib_get (table_id);
2554 if ((fib) && (fib->index != table_id))
2555 return clib_error_return (0, "<fib-index> %d does not exist",
2558 else if (unformat (input, "count %f", &count))
2561 else if (unformat (input, "%U",
2562 unformat_ip4_address, &ip4_base_address))
2565 return clib_error_return (0, "unknown input `%U'",
2566 format_unformat_error, input);
2571 for (i = 0; i < n; i++)
2573 if (!ip4_lookup_validate (&ip4_base_address, table_id))
2576 ip4_base_address.as_u32 =
2577 clib_host_to_net_u32 (1 +
2578 clib_net_to_host_u32 (ip4_base_address.as_u32));
2582 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2584 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2590 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2591 * given FIB table to determine if there is a conflict with the
2592 * adjacency table. The fib-id can be determined by using the
2593 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2596 * @todo This command uses fib-id, other commands use table-id (not
2597 * just a name, they are different indexes). Would like to change this
2598 * to table-id for consistency.
2601 * Example of how to run the test lookup command:
2602 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2603 * No errors in 2 lookups
2607 VLIB_CLI_COMMAND (lookup_test_command, static) =
2609 .path = "test lookup",
2610 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2611 .function = test_lookup_command_fn,
2616 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
2620 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2622 if (~0 == fib_index)
2623 return VNET_API_ERROR_NO_SUCH_FIB;
2625 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2631 static clib_error_t *
2632 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2633 unformat_input_t * input,
2634 vlib_cli_command_t * cmd)
2638 u32 flow_hash_config = 0;
2641 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2643 if (unformat (input, "table %d", &table_id))
2646 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2647 foreach_flow_hash_bit
2654 return clib_error_return (0, "unknown input `%U'",
2655 format_unformat_error, input);
2657 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2663 case VNET_API_ERROR_NO_SUCH_FIB:
2664 return clib_error_return (0, "no such FIB table %d", table_id);
2667 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2675 * Configure the set of IPv4 fields used by the flow hash.
2678 * Example of how to set the flow hash on a given table:
2679 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2680 * Example of display the configured flow hash:
2681 * @cliexstart{show ip fib}
2682 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2685 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2686 * [0] [@0]: dpo-drop ip6
2689 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2690 * [0] [@0]: dpo-drop ip6
2693 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2694 * [0] [@0]: dpo-drop ip6
2697 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2698 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2701 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2702 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2703 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2704 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2705 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2708 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2709 * [0] [@0]: dpo-drop ip6
2710 * 255.255.255.255/32
2712 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2713 * [0] [@0]: dpo-drop ip6
2714 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2717 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2718 * [0] [@0]: dpo-drop ip6
2721 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2722 * [0] [@0]: dpo-drop ip6
2725 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2726 * [0] [@4]: ipv4-glean: af_packet0
2729 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2730 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2733 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2734 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2737 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2738 * [0] [@4]: ipv4-glean: af_packet1
2741 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2742 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2745 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2746 * [0] [@0]: dpo-drop ip6
2749 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2750 * [0] [@0]: dpo-drop ip6
2751 * 255.255.255.255/32
2753 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2754 * [0] [@0]: dpo-drop ip6
2758 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2760 .path = "set ip flow-hash",
2762 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2763 .function = set_ip_flow_hash_command_fn,
2768 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2771 vnet_main_t *vnm = vnet_get_main ();
2772 vnet_interface_main_t *im = &vnm->interface_main;
2773 ip4_main_t *ipm = &ip4_main;
2774 ip_lookup_main_t *lm = &ipm->lookup_main;
2775 vnet_classify_main_t *cm = &vnet_classify_main;
2776 ip4_address_t *if_addr;
2778 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2779 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2781 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2782 return VNET_API_ERROR_NO_SUCH_ENTRY;
2784 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2785 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2787 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2789 if (NULL != if_addr)
2791 fib_prefix_t pfx = {
2793 .fp_proto = FIB_PROTOCOL_IP4,
2794 .fp_addr.ip4 = *if_addr,
2798 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2802 if (table_index != (u32) ~ 0)
2804 dpo_id_t dpo = DPO_INVALID;
2809 classify_dpo_create (DPO_PROTO_IP4, table_index));
2811 fib_table_entry_special_dpo_add (fib_index,
2813 FIB_SOURCE_CLASSIFY,
2814 FIB_ENTRY_FLAG_NONE, &dpo);
2819 fib_table_entry_special_remove (fib_index,
2820 &pfx, FIB_SOURCE_CLASSIFY);
2827 static clib_error_t *
2828 set_ip_classify_command_fn (vlib_main_t * vm,
2829 unformat_input_t * input,
2830 vlib_cli_command_t * cmd)
2832 u32 table_index = ~0;
2833 int table_index_set = 0;
2834 u32 sw_if_index = ~0;
2837 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2839 if (unformat (input, "table-index %d", &table_index))
2840 table_index_set = 1;
2841 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2842 vnet_get_main (), &sw_if_index))
2848 if (table_index_set == 0)
2849 return clib_error_return (0, "classify table-index must be specified");
2851 if (sw_if_index == ~0)
2852 return clib_error_return (0, "interface / subif must be specified");
2854 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2861 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2862 return clib_error_return (0, "No such interface");
2864 case VNET_API_ERROR_NO_SUCH_ENTRY:
2865 return clib_error_return (0, "No such classifier table");
2871 * Assign a classification table to an interface. The classification
2872 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2873 * commands. Once the table is create, use this command to filter packets
2877 * Example of how to assign a classification table to an interface:
2878 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2881 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2883 .path = "set ip classify",
2885 "set ip classify intfc <interface> table-index <classify-idx>",
2886 .function = set_ip_classify_command_fn,
2890 static clib_error_t *
2891 ip4_config (vlib_main_t * vm, unformat_input_t * input)
2893 ip4_main_t *im = &ip4_main;
2896 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2898 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
2901 return clib_error_return (0,
2902 "invalid heap-size parameter `%U'",
2903 format_unformat_error, input);
2906 im->mtrie_heap_size = heapsize;
2911 VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
2914 * fd.io coding-style-patch-verification: ON
2917 * eval: (c-set-style "gnu")