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. */
558 ip_interface_address_t *ia;
559 foreach_ip_interface_address
560 (&im->lookup_main, ia, sw_if_index,
561 0 /* honor unnumbered */ ,
564 ip_interface_address_get_address
565 (&im->lookup_main, ia);
566 if (ip4_destination_matches_route
567 (im, address, x, ia->address_length) ||
568 ip4_destination_matches_route (im,
574 ("failed to add %U which conflicts with %U for interface %U",
575 format_ip4_address_and_length, address,
577 format_ip4_address_and_length, x,
579 format_vnet_sw_if_index_name, vnm,
585 elts_before = pool_elts (lm->if_address_pool);
587 error = ip_interface_address_add_del
588 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
592 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
595 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
597 ip4_add_interface_routes (sw_if_index,
598 im, ip4_af.fib_index,
600 (lm->if_address_pool, if_address_index));
602 /* If pool did not grow/shrink: add duplicate address. */
603 if (elts_before != pool_elts (lm->if_address_pool))
605 ip4_add_del_interface_address_callback_t *cb;
606 vec_foreach (cb, im->add_del_interface_address_callbacks)
607 cb->function (im, cb->function_opaque, sw_if_index,
608 address, address_length, if_address_index, is_del);
617 ip4_add_del_interface_address (vlib_main_t * vm,
619 ip4_address_t * address,
620 u32 address_length, u32 is_del)
622 return ip4_add_del_interface_address_internal
623 (vm, sw_if_index, address, address_length, is_del);
626 /* Built-in ip4 unicast rx feature path definition */
628 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
630 .arc_name = "ip4-unicast",
631 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
632 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
635 VNET_FEATURE_INIT (ip4_flow_classify, static) =
637 .arc_name = "ip4-unicast",
638 .node_name = "ip4-flow-classify",
639 .runs_before = VNET_FEATURES ("ip4-inacl"),
642 VNET_FEATURE_INIT (ip4_inacl, static) =
644 .arc_name = "ip4-unicast",
645 .node_name = "ip4-inacl",
646 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
649 VNET_FEATURE_INIT (ip4_source_check_1, static) =
651 .arc_name = "ip4-unicast",
652 .node_name = "ip4-source-check-via-rx",
653 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
656 VNET_FEATURE_INIT (ip4_source_check_2, static) =
658 .arc_name = "ip4-unicast",
659 .node_name = "ip4-source-check-via-any",
660 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
663 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
665 .arc_name = "ip4-unicast",
666 .node_name = "ip4-source-and-port-range-check-rx",
667 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
670 VNET_FEATURE_INIT (ip4_policer_classify, static) =
672 .arc_name = "ip4-unicast",
673 .node_name = "ip4-policer-classify",
674 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
677 VNET_FEATURE_INIT (ip4_ipsec, static) =
679 .arc_name = "ip4-unicast",
680 .node_name = "ipsec-input-ip4",
681 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
684 VNET_FEATURE_INIT (ip4_vpath, static) =
686 .arc_name = "ip4-unicast",
687 .node_name = "vpath-input-ip4",
688 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
691 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
693 .arc_name = "ip4-unicast",
694 .node_name = "ip4-vxlan-bypass",
695 .runs_before = VNET_FEATURES ("ip4-lookup"),
698 VNET_FEATURE_INIT (ip4_not_enabled, static) =
700 .arc_name = "ip4-unicast",
701 .node_name = "ip4-not-enabled",
702 .runs_before = VNET_FEATURES ("ip4-lookup"),
705 VNET_FEATURE_INIT (ip4_lookup, static) =
707 .arc_name = "ip4-unicast",
708 .node_name = "ip4-lookup",
709 .runs_before = 0, /* not before any other features */
712 /* Built-in ip4 multicast rx feature path definition */
713 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
715 .arc_name = "ip4-multicast",
716 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
717 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
720 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
722 .arc_name = "ip4-multicast",
723 .node_name = "vpath-input-ip4",
724 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
727 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
729 .arc_name = "ip4-multicast",
730 .node_name = "ip4-not-enabled",
731 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
734 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
736 .arc_name = "ip4-multicast",
737 .node_name = "ip4-mfib-forward-lookup",
738 .runs_before = 0, /* last feature */
741 /* Source and port-range check ip4 tx feature path definition */
742 VNET_FEATURE_ARC_INIT (ip4_output, static) =
744 .arc_name = "ip4-output",
745 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
746 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
749 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
751 .arc_name = "ip4-output",
752 .node_name = "ip4-source-and-port-range-check-tx",
753 .runs_before = VNET_FEATURES ("ip4-outacl"),
756 VNET_FEATURE_INIT (ip4_outacl, static) =
758 .arc_name = "ip4-output",
759 .node_name = "ip4-outacl",
760 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
763 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
765 .arc_name = "ip4-output",
766 .node_name = "ipsec-output-ip4",
767 .runs_before = VNET_FEATURES ("interface-output"),
770 /* Built-in ip4 tx feature path definition */
771 VNET_FEATURE_INIT (ip4_interface_output, static) =
773 .arc_name = "ip4-output",
774 .node_name = "interface-output",
775 .runs_before = 0, /* not before any other features */
779 static clib_error_t *
780 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
782 ip4_main_t *im = &ip4_main;
784 /* Fill in lookup tables with default table (0). */
785 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
786 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
790 ip4_main_t *im4 = &ip4_main;
791 ip_lookup_main_t *lm4 = &im4->lookup_main;
792 ip_interface_address_t *ia = 0;
793 ip4_address_t *address;
794 vlib_main_t *vm = vlib_get_main ();
796 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
798 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
800 address = ip_interface_address_get_address (lm4, ia);
801 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
806 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
809 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
810 sw_if_index, is_add, 0, 0);
812 return /* no error */ 0;
815 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
817 /* Global IP4 main. */
821 ip4_lookup_init (vlib_main_t * vm)
823 ip4_main_t *im = &ip4_main;
827 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
829 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
831 if ((error = vlib_call_init_function (vm, fib_module_init)))
833 if ((error = vlib_call_init_function (vm, mfib_module_init)))
836 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
841 m = pow2_mask (i) << (32 - i);
844 im->fib_masks[i] = clib_host_to_net_u32 (m);
847 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
849 /* Create FIB with index 0 and table id of 0. */
850 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
851 FIB_SOURCE_DEFAULT_ROUTE);
852 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
853 MFIB_SOURCE_DEFAULT_ROUTE);
857 pn = pg_get_node (ip4_lookup_node.index);
858 pn->unformat_edit = unformat_pg_ip4_header;
862 ethernet_arp_header_t h;
864 memset (&h, 0, sizeof (h));
866 /* Set target ethernet address to all zeros. */
867 memset (h.ip4_over_ethernet[1].ethernet, 0,
868 sizeof (h.ip4_over_ethernet[1].ethernet));
870 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
871 #define _8(f,v) h.f = v;
872 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
873 _16 (l3_type, ETHERNET_TYPE_IP4);
874 _8 (n_l2_address_bytes, 6);
875 _8 (n_l3_address_bytes, 4);
876 _16 (opcode, ETHERNET_ARP_OPCODE_request);
880 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
883 /* alloc chunk size */ 8,
890 VLIB_INIT_FUNCTION (ip4_lookup_init);
894 /* Adjacency taken. */
899 /* Packet data, possibly *after* rewrite. */
900 u8 packet_data[64 - 1 * sizeof (u32)];
902 ip4_forward_next_trace_t;
905 format_ip4_forward_next_trace (u8 * s, va_list * args)
907 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
908 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
909 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
910 u32 indent = format_get_indent (s);
911 s = format (s, "%U%U",
912 format_white_space, indent,
913 format_ip4_header, t->packet_data, sizeof (t->packet_data));
918 format_ip4_lookup_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);
925 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
926 t->fib_index, t->dpo_index, t->flow_hash);
927 s = format (s, "\n%U%U",
928 format_white_space, indent,
929 format_ip4_header, t->packet_data, sizeof (t->packet_data));
934 format_ip4_rewrite_trace (u8 * s, va_list * args)
936 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
937 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
938 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
939 u32 indent = format_get_indent (s);
941 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
942 t->fib_index, t->dpo_index, format_ip_adjacency,
943 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
944 s = format (s, "\n%U%U",
945 format_white_space, indent,
946 format_ip_adjacency_packet_data,
947 t->dpo_index, t->packet_data, sizeof (t->packet_data));
951 /* Common trace function for all ip4-forward next nodes. */
953 ip4_forward_next_trace (vlib_main_t * vm,
954 vlib_node_runtime_t * node,
955 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
958 ip4_main_t *im = &ip4_main;
960 n_left = frame->n_vectors;
961 from = vlib_frame_vector_args (frame);
966 vlib_buffer_t *b0, *b1;
967 ip4_forward_next_trace_t *t0, *t1;
969 /* Prefetch next iteration. */
970 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
971 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
976 b0 = vlib_get_buffer (vm, bi0);
977 b1 = vlib_get_buffer (vm, bi1);
979 if (b0->flags & VLIB_BUFFER_IS_TRACED)
981 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
982 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
983 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
985 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
986 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
987 vec_elt (im->fib_index_by_sw_if_index,
988 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
990 clib_memcpy (t0->packet_data,
991 vlib_buffer_get_current (b0),
992 sizeof (t0->packet_data));
994 if (b1->flags & VLIB_BUFFER_IS_TRACED)
996 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
997 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
998 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1000 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1001 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1002 vec_elt (im->fib_index_by_sw_if_index,
1003 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1004 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1005 sizeof (t1->packet_data));
1015 ip4_forward_next_trace_t *t0;
1019 b0 = vlib_get_buffer (vm, bi0);
1021 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1023 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1024 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1025 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1027 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1028 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1029 vec_elt (im->fib_index_by_sw_if_index,
1030 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1031 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1032 sizeof (t0->packet_data));
1039 /* Compute TCP/UDP/ICMP4 checksum in software. */
1041 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1045 u32 ip_header_length, payload_length_host_byte_order;
1046 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
1048 void *data_this_buffer;
1050 /* Initialize checksum with ip header. */
1051 ip_header_length = ip4_header_bytes (ip0);
1052 payload_length_host_byte_order =
1053 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1055 clib_host_to_net_u32 (payload_length_host_byte_order +
1056 (ip0->protocol << 16));
1058 if (BITS (uword) == 32)
1061 ip_csum_with_carry (sum0,
1062 clib_mem_unaligned (&ip0->src_address, u32));
1064 ip_csum_with_carry (sum0,
1065 clib_mem_unaligned (&ip0->dst_address, u32));
1069 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1071 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1072 data_this_buffer = (void *) ip0 + ip_header_length;
1073 n_ip_bytes_this_buffer =
1074 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1075 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1077 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
1078 n_ip_bytes_this_buffer - ip_header_length : 0;
1082 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1083 n_bytes_left -= n_this_buffer;
1084 if (n_bytes_left == 0)
1087 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1088 p0 = vlib_get_buffer (vm, p0->next_buffer);
1089 data_this_buffer = vlib_buffer_get_current (p0);
1090 n_this_buffer = p0->current_length;
1093 sum16 = ~ip_csum_fold (sum0);
1099 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1101 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1105 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1106 || ip0->protocol == IP_PROTOCOL_UDP);
1108 udp0 = (void *) (ip0 + 1);
1109 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1111 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1112 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1116 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1118 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1119 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1125 VNET_FEATURE_ARC_INIT (ip4_local) =
1127 .arc_name = "ip4-local",
1128 .start_nodes = VNET_FEATURES ("ip4-local"),
1133 ip4_local_validate_l4 (vlib_main_t * vm, vlib_buffer_t * p, ip4_header_t * ip,
1134 u8 is_udp, u8 * error, u8 * good_tcp_udp)
1137 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1138 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1142 u32 ip_len, udp_len;
1144 udp = ip4_next_header (ip);
1145 /* Verify UDP length. */
1146 ip_len = clib_net_to_host_u16 (ip->length);
1147 udp_len = clib_net_to_host_u16 (udp->length);
1149 len_diff = ip_len - udp_len;
1150 *good_tcp_udp &= len_diff >= 0;
1151 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1155 #define ip4_local_do_l4_check(is_tcp_udp, flags) \
1156 (is_tcp_udp && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1157 || flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1158 || flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
1161 ip4_local_inline (vlib_main_t * vm,
1162 vlib_node_runtime_t * node,
1163 vlib_frame_t * frame, int head_of_feature_arc)
1165 ip4_main_t *im = &ip4_main;
1166 ip_lookup_main_t *lm = &im->lookup_main;
1167 ip_local_next_t next_index;
1168 u32 *from, *to_next, n_left_from, n_left_to_next;
1169 vlib_node_runtime_t *error_node =
1170 vlib_node_get_runtime (vm, ip4_input_node.index);
1171 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1173 from = vlib_frame_vector_args (frame);
1174 n_left_from = frame->n_vectors;
1175 next_index = node->cached_next_index;
1177 if (node->flags & VLIB_NODE_FLAG_TRACE)
1178 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1180 while (n_left_from > 0)
1182 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1184 while (n_left_from >= 4 && n_left_to_next >= 2)
1186 vlib_buffer_t *p0, *p1;
1187 ip4_header_t *ip0, *ip1;
1188 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1189 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1190 const dpo_id_t *dpo0, *dpo1;
1191 const load_balance_t *lb0, *lb1;
1192 u32 pi0, next0, fib_index0, lbi0;
1193 u32 pi1, next1, fib_index1, lbi1;
1194 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1195 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1196 u32 sw_if_index0, sw_if_index1;
1198 pi0 = to_next[0] = from[0];
1199 pi1 = to_next[1] = from[1];
1203 n_left_to_next -= 2;
1205 next0 = next1 = IP_LOCAL_NEXT_DROP;
1206 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1208 p0 = vlib_get_buffer (vm, pi0);
1209 p1 = vlib_get_buffer (vm, pi1);
1211 ip0 = vlib_buffer_get_current (p0);
1212 ip1 = vlib_buffer_get_current (p1);
1214 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1215 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
1217 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1218 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1220 proto0 = ip0->protocol;
1221 proto1 = ip1->protocol;
1223 if (head_of_feature_arc == 0)
1226 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1227 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1228 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1229 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1232 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1233 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1234 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1235 good_tcp_udp1 = (p1->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1236 || (p1->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1238 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1240 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)
1241 || ip4_local_do_l4_check (is_tcp_udp1,
1245 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1248 ip4_local_validate_l4 (vm, p1, ip1, is_udp1, &error1,
1252 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1253 error0 = (is_tcp_udp0 && !good_tcp_udp0
1254 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1255 error1 = (is_tcp_udp1 && !good_tcp_udp1
1256 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
1258 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1260 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1261 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1263 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1265 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1266 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1268 /* TODO maybe move to lookup? */
1269 vnet_buffer (p0)->ip.fib_index = fib_index0;
1270 vnet_buffer (p1)->ip.fib_index = fib_index1;
1272 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1273 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
1275 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1276 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
1277 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1279 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1281 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1283 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1286 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1287 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1288 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1290 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1291 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1292 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
1294 lb0 = load_balance_get (lbi0);
1295 lb1 = load_balance_get (lbi1);
1296 dpo0 = load_balance_get_bucket_i (lb0, 0);
1297 dpo1 = load_balance_get_bucket_i (lb1, 0);
1300 * Must have a route to source otherwise we drop the packet.
1301 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1304 * - the source is a recieve => it's from us => bogus, do this
1305 * first since it sets a different error code.
1306 * - uRPF check for any route to source - accept if passes.
1307 * - allow packets destined to the broadcast address from unknown sources
1309 if (p0->flags & VNET_BUFFER_F_IS_NATED)
1312 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1313 dpo0->dpoi_type == DPO_RECEIVE) ?
1314 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1315 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1316 !fib_urpf_check_size (lb0->lb_urpf) &&
1317 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1318 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1321 if (p1->flags & VNET_BUFFER_F_IS_NATED)
1324 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1325 dpo1->dpoi_type == DPO_RECEIVE) ?
1326 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1327 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1328 !fib_urpf_check_size (lb1->lb_urpf) &&
1329 ip1->dst_address.as_u32 != 0xFFFFFFFF)
1330 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
1334 next0 = lm->local_next_by_ip_protocol[proto0];
1335 next1 = lm->local_next_by_ip_protocol[proto1];
1338 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1340 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1342 p0->error = error0 ? error_node->errors[error0] : 0;
1343 p1->error = error1 ? error_node->errors[error1] : 0;
1345 if (head_of_feature_arc)
1347 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1348 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1349 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1350 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
1353 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1354 n_left_to_next, pi0, pi1,
1358 while (n_left_from > 0 && n_left_to_next > 0)
1362 ip4_fib_mtrie_t *mtrie0;
1363 ip4_fib_mtrie_leaf_t leaf0;
1364 u32 pi0, next0, fib_index0, lbi0;
1365 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1366 load_balance_t *lb0;
1367 const dpo_id_t *dpo0;
1370 pi0 = to_next[0] = from[0];
1374 n_left_to_next -= 1;
1376 next0 = IP_LOCAL_NEXT_DROP;
1377 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1379 p0 = vlib_get_buffer (vm, pi0);
1380 ip0 = vlib_buffer_get_current (p0);
1381 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1382 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1384 proto0 = ip0->protocol;
1386 if (head_of_feature_arc == 0 || p0->flags & VNET_BUFFER_F_IS_NATED)
1389 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1390 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1393 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1394 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1395 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
1397 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
1399 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1403 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1404 error0 = (is_tcp_udp0 && !good_tcp_udp0
1405 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1407 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1409 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1410 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1411 vnet_buffer (p0)->ip.fib_index = fib_index0;
1412 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1413 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1414 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1416 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1418 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1419 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1420 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
1422 lb0 = load_balance_get (lbi0);
1423 dpo0 = load_balance_get_bucket_i (lb0, 0);
1425 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1426 dpo0->dpoi_type == DPO_RECEIVE) ?
1427 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1428 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1429 !fib_urpf_check_size (lb0->lb_urpf) &&
1430 ip0->dst_address.as_u32 != 0xFFFFFFFF)
1431 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1434 next0 = lm->local_next_by_ip_protocol[proto0];
1436 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1438 p0->error = error0 ? error_node->errors[error0] : 0;
1440 if (head_of_feature_arc)
1442 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1443 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1446 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1447 n_left_to_next, pi0, next0);
1449 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1452 return frame->n_vectors;
1456 ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1458 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1462 VLIB_REGISTER_NODE (ip4_local_node) =
1464 .function = ip4_local,
1465 .name = "ip4-local",
1466 .vector_size = sizeof (u32),
1467 .format_trace = format_ip4_forward_next_trace,
1468 .n_next_nodes = IP_LOCAL_N_NEXT,
1471 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1472 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1473 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1474 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1479 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1482 ip4_local_end_of_arc (vlib_main_t * vm,
1483 vlib_node_runtime_t * node, vlib_frame_t * frame)
1485 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1489 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1490 .function = ip4_local_end_of_arc,
1491 .name = "ip4-local-end-of-arc",
1492 .vector_size = sizeof (u32),
1494 .format_trace = format_ip4_forward_next_trace,
1495 .sibling_of = "ip4-local",
1498 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1500 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1501 .arc_name = "ip4-local",
1502 .node_name = "ip4-local-end-of-arc",
1503 .runs_before = 0, /* not before any other features */
1508 ip4_register_protocol (u32 protocol, u32 node_index)
1510 vlib_main_t *vm = vlib_get_main ();
1511 ip4_main_t *im = &ip4_main;
1512 ip_lookup_main_t *lm = &im->lookup_main;
1514 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1515 lm->local_next_by_ip_protocol[protocol] =
1516 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1519 static clib_error_t *
1520 show_ip_local_command_fn (vlib_main_t * vm,
1521 unformat_input_t * input, vlib_cli_command_t * cmd)
1523 ip4_main_t *im = &ip4_main;
1524 ip_lookup_main_t *lm = &im->lookup_main;
1527 vlib_cli_output (vm, "Protocols handled by ip4_local");
1528 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1530 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1532 u32 node_index = vlib_get_node (vm,
1533 ip4_local_node.index)->
1534 next_nodes[lm->local_next_by_ip_protocol[i]];
1535 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1545 * Display the set of protocols handled by the local IPv4 stack.
1548 * Example of how to display local protocol table:
1549 * @cliexstart{show ip local}
1550 * Protocols handled by ip4_local
1557 VLIB_CLI_COMMAND (show_ip_local, static) =
1559 .path = "show ip local",
1560 .function = show_ip_local_command_fn,
1561 .short_help = "show ip local",
1566 ip4_arp_inline (vlib_main_t * vm,
1567 vlib_node_runtime_t * node,
1568 vlib_frame_t * frame, int is_glean)
1570 vnet_main_t *vnm = vnet_get_main ();
1571 ip4_main_t *im = &ip4_main;
1572 ip_lookup_main_t *lm = &im->lookup_main;
1573 u32 *from, *to_next_drop;
1574 uword n_left_from, n_left_to_next_drop, next_index;
1575 static f64 time_last_seed_change = -1e100;
1576 static u32 hash_seeds[3];
1577 static uword hash_bitmap[256 / BITS (uword)];
1580 if (node->flags & VLIB_NODE_FLAG_TRACE)
1581 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1583 time_now = vlib_time_now (vm);
1584 if (time_now - time_last_seed_change > 1e-3)
1587 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1588 sizeof (hash_seeds));
1589 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1590 hash_seeds[i] = r[i];
1592 /* Mark all hash keys as been no-seen before. */
1593 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1596 time_last_seed_change = time_now;
1599 from = vlib_frame_vector_args (frame);
1600 n_left_from = frame->n_vectors;
1601 next_index = node->cached_next_index;
1602 if (next_index == IP4_ARP_NEXT_DROP)
1603 next_index = IP4_ARP_N_NEXT; /* point to first interface */
1605 while (n_left_from > 0)
1607 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1608 to_next_drop, n_left_to_next_drop);
1610 while (n_left_from > 0 && n_left_to_next_drop > 0)
1612 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1613 ip_adjacency_t *adj0;
1620 p0 = vlib_get_buffer (vm, pi0);
1622 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1623 adj0 = adj_get (adj_index0);
1624 ip0 = vlib_buffer_get_current (p0);
1630 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1631 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1636 * this is the Glean case, so we are ARPing for the
1637 * packet's destination
1639 a0 ^= ip0->dst_address.data_u32;
1643 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1647 hash_v3_mix32 (a0, b0, c0);
1648 hash_v3_finalize32 (a0, b0, c0);
1650 c0 &= BITS (hash_bitmap) - 1;
1651 m0 = (uword) 1 << (c0 % BITS (uword));
1652 c0 = c0 / BITS (uword);
1654 bm0 = hash_bitmap[c0];
1655 drop0 = (bm0 & m0) != 0;
1657 /* Mark it as seen. */
1658 hash_bitmap[c0] = bm0 | m0;
1662 to_next_drop[0] = pi0;
1664 n_left_to_next_drop -= 1;
1667 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
1668 IP4_ARP_ERROR_REQUEST_SENT];
1671 * the adj has been updated to a rewrite but the node the DPO that got
1672 * us here hasn't - yet. no big deal. we'll drop while we wait.
1674 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1681 * Can happen if the control-plane is programming tables
1682 * with traffic flowing; at least that's today's lame excuse.
1684 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1685 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
1687 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
1690 /* Send ARP request. */
1694 ethernet_arp_header_t *h0;
1695 vnet_hw_interface_t *hw_if0;
1698 vlib_packet_template_get_packet (vm,
1699 &im->ip4_arp_request_packet_template,
1702 /* Seems we're out of buffers */
1703 if (PREDICT_FALSE (!h0))
1706 /* Add rewrite/encap string for ARP packet. */
1707 vnet_rewrite_one_header (adj0[0], h0,
1708 sizeof (ethernet_header_t));
1710 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1712 /* Src ethernet address in ARP header. */
1713 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
1715 sizeof (h0->ip4_over_ethernet[0].ethernet));
1719 /* The interface's source address is stashed in the Glean Adj */
1720 h0->ip4_over_ethernet[0].ip4 =
1721 adj0->sub_type.glean.receive_addr.ip4;
1723 /* Copy in destination address we are requesting. This is the
1724 * glean case, so it's the packet's destination.*/
1725 h0->ip4_over_ethernet[1].ip4.data_u32 =
1726 ip0->dst_address.data_u32;
1730 /* Src IP address in ARP header. */
1731 if (ip4_src_address_for_packet (lm, sw_if_index0,
1733 ip4_over_ethernet[0].ip4))
1735 /* No source address available */
1737 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1738 vlib_buffer_free (vm, &bi0, 1);
1742 /* Copy in destination address we are requesting from the
1744 h0->ip4_over_ethernet[1].ip4.data_u32 =
1745 adj0->sub_type.nbr.next_hop.ip4.as_u32;
1748 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1749 b0 = vlib_get_buffer (vm, bi0);
1750 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1751 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1753 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1755 vlib_set_next_frame_buffer (vm, node,
1756 adj0->rewrite_header.next_index,
1761 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1764 return frame->n_vectors;
1768 ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1770 return (ip4_arp_inline (vm, node, frame, 0));
1774 ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1776 return (ip4_arp_inline (vm, node, frame, 1));
1779 static char *ip4_arp_error_strings[] = {
1780 [IP4_ARP_ERROR_DROP] = "address overflow drops",
1781 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1782 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
1783 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
1784 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
1785 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
1789 VLIB_REGISTER_NODE (ip4_arp_node) =
1791 .function = ip4_arp,
1793 .vector_size = sizeof (u32),
1794 .format_trace = format_ip4_forward_next_trace,
1795 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1796 .error_strings = ip4_arp_error_strings,
1797 .n_next_nodes = IP4_ARP_N_NEXT,
1800 [IP4_ARP_NEXT_DROP] = "error-drop",
1804 VLIB_REGISTER_NODE (ip4_glean_node) =
1806 .function = ip4_glean,
1807 .name = "ip4-glean",
1808 .vector_size = sizeof (u32),
1809 .format_trace = format_ip4_forward_next_trace,
1810 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1811 .error_strings = ip4_arp_error_strings,
1812 .n_next_nodes = IP4_ARP_N_NEXT,
1814 [IP4_ARP_NEXT_DROP] = "error-drop",
1819 #define foreach_notrace_ip4_arp_error \
1826 arp_notrace_init (vlib_main_t * vm)
1828 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
1830 /* don't trace ARP request packets */
1832 vnet_pcap_drop_trace_filter_add_del \
1833 (rt->errors[IP4_ARP_ERROR_##a], \
1835 foreach_notrace_ip4_arp_error;
1840 VLIB_INIT_FUNCTION (arp_notrace_init);
1843 /* Send an ARP request to see if given destination is reachable on given interface. */
1845 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
1847 vnet_main_t *vnm = vnet_get_main ();
1848 ip4_main_t *im = &ip4_main;
1849 ethernet_arp_header_t *h;
1851 ip_interface_address_t *ia;
1852 ip_adjacency_t *adj;
1853 vnet_hw_interface_t *hi;
1854 vnet_sw_interface_t *si;
1859 si = vnet_get_sw_interface (vnm, sw_if_index);
1861 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1863 return clib_error_return (0, "%U: interface %U down",
1864 format_ip4_address, dst,
1865 format_vnet_sw_if_index_name, vnm,
1870 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1873 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1874 return clib_error_return
1876 "no matching interface address for destination %U (interface %U)",
1877 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
1881 h = vlib_packet_template_get_packet (vm,
1882 &im->ip4_arp_request_packet_template,
1885 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1886 if (PREDICT_FALSE (!hi->hw_address))
1888 return clib_error_return (0, "%U: interface %U do not support ip probe",
1889 format_ip4_address, dst,
1890 format_vnet_sw_if_index_name, vnm,
1894 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
1895 sizeof (h->ip4_over_ethernet[0].ethernet));
1897 h->ip4_over_ethernet[0].ip4 = src[0];
1898 h->ip4_over_ethernet[1].ip4 = dst[0];
1900 b = vlib_get_buffer (vm, bi);
1901 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1902 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1904 ip46_address_t nh = {
1908 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
1909 VNET_LINK_IP4, &nh, sw_if_index);
1912 /* Peer has been previously resolved, retrieve glean adj instead */
1913 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1916 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
1917 VNET_LINK_IP4, sw_if_index, &nh);
1921 /* Add encapsulation string for software interface (e.g. ethernet header). */
1922 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1923 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1926 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1927 u32 *to_next = vlib_frame_vector_args (f);
1930 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1934 return /* no error */ 0;
1939 IP4_REWRITE_NEXT_DROP,
1940 IP4_REWRITE_NEXT_ICMP_ERROR,
1941 } ip4_rewrite_next_t;
1944 ip4_rewrite_inline (vlib_main_t * vm,
1945 vlib_node_runtime_t * node,
1946 vlib_frame_t * frame,
1947 int do_counters, int is_midchain, int is_mcast)
1949 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1950 u32 *from = vlib_frame_vector_args (frame);
1951 u32 n_left_from, n_left_to_next, *to_next, next_index;
1952 vlib_node_runtime_t *error_node =
1953 vlib_node_get_runtime (vm, ip4_input_node.index);
1955 n_left_from = frame->n_vectors;
1956 next_index = node->cached_next_index;
1957 u32 thread_index = vlib_get_thread_index ();
1959 while (n_left_from > 0)
1961 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1963 while (n_left_from >= 4 && n_left_to_next >= 2)
1965 ip_adjacency_t *adj0, *adj1;
1966 vlib_buffer_t *p0, *p1;
1967 ip4_header_t *ip0, *ip1;
1968 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
1969 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
1970 u32 tx_sw_if_index0, tx_sw_if_index1;
1972 /* Prefetch next iteration. */
1974 vlib_buffer_t *p2, *p3;
1976 p2 = vlib_get_buffer (vm, from[2]);
1977 p3 = vlib_get_buffer (vm, from[3]);
1979 vlib_prefetch_buffer_header (p2, STORE);
1980 vlib_prefetch_buffer_header (p3, STORE);
1982 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1983 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1986 pi0 = to_next[0] = from[0];
1987 pi1 = to_next[1] = from[1];
1992 n_left_to_next -= 2;
1994 p0 = vlib_get_buffer (vm, pi0);
1995 p1 = vlib_get_buffer (vm, pi1);
1997 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1998 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2001 * pre-fetch the per-adjacency counters
2005 vlib_prefetch_combined_counter (&adjacency_counters,
2006 thread_index, adj_index0);
2007 vlib_prefetch_combined_counter (&adjacency_counters,
2008 thread_index, adj_index1);
2011 ip0 = vlib_buffer_get_current (p0);
2012 ip1 = vlib_buffer_get_current (p1);
2014 error0 = error1 = IP4_ERROR_NONE;
2015 next0 = next1 = IP4_REWRITE_NEXT_DROP;
2017 /* Decrement TTL & update checksum.
2018 Works either endian, so no need for byte swap. */
2019 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2021 i32 ttl0 = ip0->ttl;
2023 /* Input node should have reject packets with ttl 0. */
2024 ASSERT (ip0->ttl > 0);
2026 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2027 checksum0 += checksum0 >= 0xffff;
2029 ip0->checksum = checksum0;
2034 * If the ttl drops below 1 when forwarding, generate
2037 if (PREDICT_FALSE (ttl0 <= 0))
2039 error0 = IP4_ERROR_TIME_EXPIRED;
2040 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2041 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2042 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2044 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2047 /* Verify checksum. */
2048 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2049 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2053 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2055 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2057 i32 ttl1 = ip1->ttl;
2059 /* Input node should have reject packets with ttl 0. */
2060 ASSERT (ip1->ttl > 0);
2062 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2063 checksum1 += checksum1 >= 0xffff;
2065 ip1->checksum = checksum1;
2070 * If the ttl drops below 1 when forwarding, generate
2073 if (PREDICT_FALSE (ttl1 <= 0))
2075 error1 = IP4_ERROR_TIME_EXPIRED;
2076 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2077 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2078 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2080 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2083 /* Verify checksum. */
2084 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
2085 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2089 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2092 /* Rewrite packet header and updates lengths. */
2093 adj0 = adj_get (adj_index0);
2094 adj1 = adj_get (adj_index1);
2096 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2097 rw_len0 = adj0[0].rewrite_header.data_bytes;
2098 rw_len1 = adj1[0].rewrite_header.data_bytes;
2099 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2100 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2102 /* Check MTU of outgoing interface. */
2103 if (vlib_buffer_length_in_chain (vm, p0) >
2104 adj0[0].rewrite_header.max_l3_packet_bytes)
2106 error0 = IP4_ERROR_MTU_EXCEEDED;
2107 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2108 icmp4_error_set_vnet_buffer
2109 (p0, ICMP4_destination_unreachable,
2110 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2113 if (vlib_buffer_length_in_chain (vm, p1) >
2114 adj1[0].rewrite_header.max_l3_packet_bytes)
2116 error1 = IP4_ERROR_MTU_EXCEEDED;
2117 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2118 icmp4_error_set_vnet_buffer
2119 (p1, ICMP4_destination_unreachable,
2120 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2126 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2127 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2128 IP4_ERROR_SAME_INTERFACE : error0);
2129 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2130 vnet_buffer (p1)->sw_if_index[VLIB_RX]) ?
2131 IP4_ERROR_SAME_INTERFACE : error1);
2134 p0->error = error_node->errors[error0];
2135 p1->error = error_node->errors[error1];
2136 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2137 * to see the IP headerr */
2138 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2140 next0 = adj0[0].rewrite_header.next_index;
2141 p0->current_data -= rw_len0;
2142 p0->current_length += rw_len0;
2143 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2144 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2147 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2148 vnet_feature_arc_start (lm->output_feature_arc_index,
2149 tx_sw_if_index0, &next0, p0);
2151 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2153 next1 = adj1[0].rewrite_header.next_index;
2154 p1->current_data -= rw_len1;
2155 p1->current_length += rw_len1;
2157 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2158 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2161 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2162 vnet_feature_arc_start (lm->output_feature_arc_index,
2163 tx_sw_if_index1, &next1, p1);
2166 /* Guess we are only writing on simple Ethernet header. */
2167 vnet_rewrite_two_headers (adj0[0], adj1[0],
2168 ip0, ip1, sizeof (ethernet_header_t));
2171 * Bump the per-adjacency counters
2175 vlib_increment_combined_counter
2176 (&adjacency_counters,
2179 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2181 vlib_increment_combined_counter
2182 (&adjacency_counters,
2185 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2190 adj0->sub_type.midchain.fixup_func
2191 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2192 adj1->sub_type.midchain.fixup_func
2193 (vm, adj1, p1, adj0->sub_type.midchain.fixup_data);
2198 * copy bytes from the IP address into the MAC rewrite
2200 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2201 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
2204 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2205 to_next, n_left_to_next,
2206 pi0, pi1, next0, next1);
2209 while (n_left_from > 0 && n_left_to_next > 0)
2211 ip_adjacency_t *adj0;
2214 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2215 u32 tx_sw_if_index0;
2217 pi0 = to_next[0] = from[0];
2219 p0 = vlib_get_buffer (vm, pi0);
2221 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2223 adj0 = adj_get (adj_index0);
2225 ip0 = vlib_buffer_get_current (p0);
2227 error0 = IP4_ERROR_NONE;
2228 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
2230 /* Decrement TTL & update checksum. */
2231 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
2233 i32 ttl0 = ip0->ttl;
2235 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2237 checksum0 += checksum0 >= 0xffff;
2239 ip0->checksum = checksum0;
2241 ASSERT (ip0->ttl > 0);
2247 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
2248 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2250 if (PREDICT_FALSE (ttl0 <= 0))
2253 * If the ttl drops below 1 when forwarding, generate
2256 error0 = IP4_ERROR_TIME_EXPIRED;
2257 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2258 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2259 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2260 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2266 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2270 vlib_prefetch_combined_counter (&adjacency_counters,
2271 thread_index, adj_index0);
2273 /* Guess we are only writing on simple Ethernet header. */
2274 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2278 * copy bytes from the IP address into the MAC rewrite
2280 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2283 /* Update packet buffer attributes/set output interface. */
2284 rw_len0 = adj0[0].rewrite_header.data_bytes;
2285 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2288 vlib_increment_combined_counter
2289 (&adjacency_counters,
2290 thread_index, adj_index0, 1,
2291 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2293 /* Check MTU of outgoing interface. */
2294 if (vlib_buffer_length_in_chain (vm, p0) >
2295 adj0[0].rewrite_header.max_l3_packet_bytes)
2297 error0 = IP4_ERROR_MTU_EXCEEDED;
2298 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2299 icmp4_error_set_vnet_buffer
2300 (p0, ICMP4_destination_unreachable,
2301 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2306 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2307 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2308 IP4_ERROR_SAME_INTERFACE : error0);
2310 p0->error = error_node->errors[error0];
2312 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2313 * to see the IP headerr */
2314 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2316 p0->current_data -= rw_len0;
2317 p0->current_length += rw_len0;
2318 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2320 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2321 next0 = adj0[0].rewrite_header.next_index;
2325 adj0->sub_type.midchain.fixup_func
2326 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2330 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2331 vnet_feature_arc_start (lm->output_feature_arc_index,
2332 tx_sw_if_index0, &next0, p0);
2339 n_left_to_next -= 1;
2341 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2342 to_next, n_left_to_next,
2346 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2349 /* Need to do trace after rewrites to pick up new packet data. */
2350 if (node->flags & VLIB_NODE_FLAG_TRACE)
2351 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2353 return frame->n_vectors;
2357 /** @brief IPv4 rewrite node.
2360 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2361 header checksum, fetch the ip adjacency, check the outbound mtu,
2362 apply the adjacency rewrite, and send pkts to the adjacency
2363 rewrite header's rewrite_next_index.
2365 @param vm vlib_main_t corresponding to the current thread
2366 @param node vlib_node_runtime_t
2367 @param frame vlib_frame_t whose contents should be dispatched
2369 @par Graph mechanics: buffer metadata, next index usage
2372 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2373 - the rewrite adjacency index
2374 - <code>adj->lookup_next_index</code>
2375 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2376 the packet will be dropped.
2377 - <code>adj->rewrite_header</code>
2378 - Rewrite string length, rewrite string, next_index
2381 - <code>b->current_data, b->current_length</code>
2382 - Updated net of applying the rewrite string
2384 <em>Next Indices:</em>
2385 - <code> adj->rewrite_header.next_index </code>
2389 ip4_rewrite (vlib_main_t * vm,
2390 vlib_node_runtime_t * node, vlib_frame_t * frame)
2392 if (adj_are_counters_enabled ())
2393 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2395 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2399 ip4_midchain (vlib_main_t * vm,
2400 vlib_node_runtime_t * node, vlib_frame_t * frame)
2402 if (adj_are_counters_enabled ())
2403 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2405 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2409 ip4_rewrite_mcast (vlib_main_t * vm,
2410 vlib_node_runtime_t * node, vlib_frame_t * frame)
2412 if (adj_are_counters_enabled ())
2413 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2415 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2419 ip4_mcast_midchain (vlib_main_t * vm,
2420 vlib_node_runtime_t * node, vlib_frame_t * frame)
2422 if (adj_are_counters_enabled ())
2423 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2425 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2429 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2430 .function = ip4_rewrite,
2431 .name = "ip4-rewrite",
2432 .vector_size = sizeof (u32),
2434 .format_trace = format_ip4_rewrite_trace,
2438 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2439 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2442 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2444 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2445 .function = ip4_rewrite_mcast,
2446 .name = "ip4-rewrite-mcast",
2447 .vector_size = sizeof (u32),
2449 .format_trace = format_ip4_rewrite_trace,
2450 .sibling_of = "ip4-rewrite",
2452 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2454 VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2455 .function = ip4_mcast_midchain,
2456 .name = "ip4-mcast-midchain",
2457 .vector_size = sizeof (u32),
2459 .format_trace = format_ip4_rewrite_trace,
2460 .sibling_of = "ip4-rewrite",
2462 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2464 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2465 .function = ip4_midchain,
2466 .name = "ip4-midchain",
2467 .vector_size = sizeof (u32),
2468 .format_trace = format_ip4_forward_next_trace,
2469 .sibling_of = "ip4-rewrite",
2471 VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
2475 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2477 ip4_fib_mtrie_t *mtrie0;
2478 ip4_fib_mtrie_leaf_t leaf0;
2481 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2483 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
2484 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2485 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2487 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2489 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2492 static clib_error_t *
2493 test_lookup_command_fn (vlib_main_t * vm,
2494 unformat_input_t * input, vlib_cli_command_t * cmd)
2501 ip4_address_t ip4_base_address;
2504 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2506 if (unformat (input, "table %d", &table_id))
2508 /* Make sure the entry exists. */
2509 fib = ip4_fib_get (table_id);
2510 if ((fib) && (fib->index != table_id))
2511 return clib_error_return (0, "<fib-index> %d does not exist",
2514 else if (unformat (input, "count %f", &count))
2517 else if (unformat (input, "%U",
2518 unformat_ip4_address, &ip4_base_address))
2521 return clib_error_return (0, "unknown input `%U'",
2522 format_unformat_error, input);
2527 for (i = 0; i < n; i++)
2529 if (!ip4_lookup_validate (&ip4_base_address, table_id))
2532 ip4_base_address.as_u32 =
2533 clib_host_to_net_u32 (1 +
2534 clib_net_to_host_u32 (ip4_base_address.as_u32));
2538 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2540 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2546 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2547 * given FIB table to determine if there is a conflict with the
2548 * adjacency table. The fib-id can be determined by using the
2549 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2552 * @todo This command uses fib-id, other commands use table-id (not
2553 * just a name, they are different indexes). Would like to change this
2554 * to table-id for consistency.
2557 * Example of how to run the test lookup command:
2558 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2559 * No errors in 2 lookups
2563 VLIB_CLI_COMMAND (lookup_test_command, static) =
2565 .path = "test lookup",
2566 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2567 .function = test_lookup_command_fn,
2572 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
2576 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2578 if (~0 == fib_index)
2579 return VNET_API_ERROR_NO_SUCH_FIB;
2581 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2587 static clib_error_t *
2588 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2589 unformat_input_t * input,
2590 vlib_cli_command_t * cmd)
2594 u32 flow_hash_config = 0;
2597 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2599 if (unformat (input, "table %d", &table_id))
2602 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2603 foreach_flow_hash_bit
2610 return clib_error_return (0, "unknown input `%U'",
2611 format_unformat_error, input);
2613 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2619 case VNET_API_ERROR_NO_SUCH_FIB:
2620 return clib_error_return (0, "no such FIB table %d", table_id);
2623 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2631 * Configure the set of IPv4 fields used by the flow hash.
2634 * Example of how to set the flow hash on a given table:
2635 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2636 * Example of display the configured flow hash:
2637 * @cliexstart{show ip fib}
2638 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2641 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2642 * [0] [@0]: dpo-drop ip6
2645 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2646 * [0] [@0]: dpo-drop ip6
2649 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2650 * [0] [@0]: dpo-drop ip6
2653 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2654 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2657 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2658 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2659 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2660 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2661 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2664 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2665 * [0] [@0]: dpo-drop ip6
2666 * 255.255.255.255/32
2668 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2669 * [0] [@0]: dpo-drop ip6
2670 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2673 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2674 * [0] [@0]: dpo-drop ip6
2677 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2678 * [0] [@0]: dpo-drop ip6
2681 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2682 * [0] [@4]: ipv4-glean: af_packet0
2685 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2686 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2689 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2690 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2693 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2694 * [0] [@4]: ipv4-glean: af_packet1
2697 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2698 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2701 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2702 * [0] [@0]: dpo-drop ip6
2705 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2706 * [0] [@0]: dpo-drop ip6
2707 * 255.255.255.255/32
2709 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2710 * [0] [@0]: dpo-drop ip6
2714 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2716 .path = "set ip flow-hash",
2718 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2719 .function = set_ip_flow_hash_command_fn,
2724 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2727 vnet_main_t *vnm = vnet_get_main ();
2728 vnet_interface_main_t *im = &vnm->interface_main;
2729 ip4_main_t *ipm = &ip4_main;
2730 ip_lookup_main_t *lm = &ipm->lookup_main;
2731 vnet_classify_main_t *cm = &vnet_classify_main;
2732 ip4_address_t *if_addr;
2734 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2735 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2737 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2738 return VNET_API_ERROR_NO_SUCH_ENTRY;
2740 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2741 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2743 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2745 if (NULL != if_addr)
2747 fib_prefix_t pfx = {
2749 .fp_proto = FIB_PROTOCOL_IP4,
2750 .fp_addr.ip4 = *if_addr,
2754 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2758 if (table_index != (u32) ~ 0)
2760 dpo_id_t dpo = DPO_INVALID;
2765 classify_dpo_create (DPO_PROTO_IP4, table_index));
2767 fib_table_entry_special_dpo_add (fib_index,
2769 FIB_SOURCE_CLASSIFY,
2770 FIB_ENTRY_FLAG_NONE, &dpo);
2775 fib_table_entry_special_remove (fib_index,
2776 &pfx, FIB_SOURCE_CLASSIFY);
2783 static clib_error_t *
2784 set_ip_classify_command_fn (vlib_main_t * vm,
2785 unformat_input_t * input,
2786 vlib_cli_command_t * cmd)
2788 u32 table_index = ~0;
2789 int table_index_set = 0;
2790 u32 sw_if_index = ~0;
2793 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2795 if (unformat (input, "table-index %d", &table_index))
2796 table_index_set = 1;
2797 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2798 vnet_get_main (), &sw_if_index))
2804 if (table_index_set == 0)
2805 return clib_error_return (0, "classify table-index must be specified");
2807 if (sw_if_index == ~0)
2808 return clib_error_return (0, "interface / subif must be specified");
2810 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2817 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2818 return clib_error_return (0, "No such interface");
2820 case VNET_API_ERROR_NO_SUCH_ENTRY:
2821 return clib_error_return (0, "No such classifier table");
2827 * Assign a classification table to an interface. The classification
2828 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2829 * commands. Once the table is create, use this command to filter packets
2833 * Example of how to assign a classification table to an interface:
2834 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2837 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2839 .path = "set ip classify",
2841 "set ip classify intfc <interface> table-index <classify-idx>",
2842 .function = set_ip_classify_command_fn,
2846 static clib_error_t *
2847 ip4_config (vlib_main_t * vm, unformat_input_t * input)
2849 ip4_main_t *im = &ip4_main;
2852 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2854 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
2857 return clib_error_return (0,
2858 "invalid heap-size parameter `%U'",
2859 format_unformat_error, input);
2862 im->mtrie_heap_size = heapsize;
2867 VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
2870 * fd.io coding-style-patch-verification: ON
2873 * eval: (c-set-style "gnu")