2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 * ip/ip4_forward.c: IP v4 forwarding
18 * Copyright (c) 2008 Eliot Dresselhaus
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #include <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/ip/ip_frag.h>
43 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44 #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
45 #include <vnet/ppp/ppp.h>
46 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
47 #include <vnet/api_errno.h> /* for API error numbers */
48 #include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
49 #include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
50 #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
51 #include <vnet/fib/ip4_fib.h>
52 #include <vnet/mfib/ip4_mfib.h>
53 #include <vnet/dpo/load_balance.h>
54 #include <vnet/dpo/load_balance_map.h>
55 #include <vnet/dpo/receive_dpo.h>
56 #include <vnet/dpo/classify_dpo.h>
57 #include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
58 #include <vnet/adj/adj_dp.h>
59 #include <vnet/pg/pg.h>
61 #include <vnet/ip/ip4_forward.h>
62 #include <vnet/interface_output.h>
63 #include <vnet/classify/vnet_classify.h>
64 #include <vnet/ip/reass/ip4_full_reass.h>
66 /** @brief IPv4 lookup node.
69 This is the main IPv4 lookup dispatch node.
71 @param vm vlib_main_t corresponding to the current thread
72 @param node vlib_node_runtime_t
73 @param frame vlib_frame_t whose contents should be dispatched
75 @par Graph mechanics: buffer metadata, next index usage
78 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
79 - Indicates the @c sw_if_index value of the interface that the
80 packet was received on.
81 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
82 - When the value is @c ~0 then the node performs a longest prefix
83 match (LPM) for the packet destination address in the FIB attached
84 to the receive interface.
85 - Otherwise perform LPM for the packet destination address in the
86 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
87 value (0, 1, ...) and not a VRF id.
90 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
91 - The lookup result adjacency index.
94 - Dispatches the packet to the node index found in
95 ip_adjacency_t @c adj->lookup_next_index
96 (where @c adj is the lookup result adjacency).
98 VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
101 return ip4_lookup_inline (vm, node, frame);
104 static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
107 VLIB_REGISTER_NODE (ip4_lookup_node) =
109 .name = "ip4-lookup",
110 .vector_size = sizeof (u32),
111 .format_trace = format_ip4_lookup_trace,
112 .n_next_nodes = IP_LOOKUP_N_NEXT,
113 .next_nodes = IP4_LOOKUP_NEXT_NODES,
117 VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
118 vlib_node_runtime_t * node,
119 vlib_frame_t * frame)
121 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
123 u32 thread_index = vm->thread_index;
124 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
125 u16 nexts[VLIB_FRAME_SIZE], *next;
127 from = vlib_frame_vector_args (frame);
128 n_left = frame->n_vectors;
131 vlib_get_buffers (vm, from, bufs, n_left);
135 const load_balance_t *lb0, *lb1;
136 const ip4_header_t *ip0, *ip1;
137 u32 lbi0, hc0, lbi1, hc1;
138 const dpo_id_t *dpo0, *dpo1;
140 /* Prefetch next iteration. */
142 vlib_prefetch_buffer_header (b[2], LOAD);
143 vlib_prefetch_buffer_header (b[3], LOAD);
145 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
146 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
149 ip0 = vlib_buffer_get_current (b[0]);
150 ip1 = vlib_buffer_get_current (b[1]);
151 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
152 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
154 lb0 = load_balance_get (lbi0);
155 lb1 = load_balance_get (lbi1);
158 * this node is for via FIBs we can re-use the hash value from the
159 * to node if present.
160 * We don't want to use the same hash value at each level in the recursion
161 * graph as that would lead to polarisation
165 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
167 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
169 hc0 = vnet_buffer (b[0])->ip.flow_hash =
170 vnet_buffer (b[0])->ip.flow_hash >> 1;
174 hc0 = vnet_buffer (b[0])->ip.flow_hash =
175 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
177 dpo0 = load_balance_get_fwd_bucket
178 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
182 dpo0 = load_balance_get_bucket_i (lb0, 0);
184 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
186 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
188 hc1 = vnet_buffer (b[1])->ip.flow_hash =
189 vnet_buffer (b[1])->ip.flow_hash >> 1;
193 hc1 = vnet_buffer (b[1])->ip.flow_hash =
194 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
196 dpo1 = load_balance_get_fwd_bucket
197 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
201 dpo1 = load_balance_get_bucket_i (lb1, 0);
204 next[0] = dpo0->dpoi_next_node;
205 next[1] = dpo1->dpoi_next_node;
207 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
208 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
210 vlib_increment_combined_counter
211 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
212 vlib_increment_combined_counter
213 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
222 const load_balance_t *lb0;
223 const ip4_header_t *ip0;
224 const dpo_id_t *dpo0;
227 ip0 = vlib_buffer_get_current (b[0]);
228 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
230 lb0 = load_balance_get (lbi0);
233 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
235 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
237 hc0 = vnet_buffer (b[0])->ip.flow_hash =
238 vnet_buffer (b[0])->ip.flow_hash >> 1;
242 hc0 = vnet_buffer (b[0])->ip.flow_hash =
243 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
245 dpo0 = load_balance_get_fwd_bucket
246 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
250 dpo0 = load_balance_get_bucket_i (lb0, 0);
253 next[0] = dpo0->dpoi_next_node;
254 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
256 vlib_increment_combined_counter
257 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
264 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
265 if (node->flags & VLIB_NODE_FLAG_TRACE)
266 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
268 return frame->n_vectors;
272 VLIB_REGISTER_NODE (ip4_load_balance_node) =
274 .name = "ip4-load-balance",
275 .vector_size = sizeof (u32),
276 .sibling_of = "ip4-lookup",
277 .format_trace = format_ip4_lookup_trace,
281 #ifndef CLIB_MARCH_VARIANT
282 /* get first interface address */
284 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
285 ip_interface_address_t ** result_ia)
287 ip_lookup_main_t *lm = &im->lookup_main;
288 ip_interface_address_t *ia = 0;
289 ip4_address_t *result = 0;
292 foreach_ip_interface_address
293 (lm, ia, sw_if_index,
294 1 /* honor unnumbered */ ,
297 ip_interface_address_get_address (lm, ia);
303 *result_ia = result ? ia : 0;
309 ip4_add_subnet_bcast_route (u32 fib_index,
313 vnet_sw_interface_flags_t iflags;
315 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
317 fib_table_entry_special_remove(fib_index,
319 FIB_SOURCE_INTERFACE);
321 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
323 fib_table_entry_update_one_path (fib_index, pfx,
324 FIB_SOURCE_INTERFACE,
327 /* No next-hop address */
333 // no out-label stack
335 FIB_ROUTE_PATH_FLAG_NONE);
339 fib_table_entry_special_add(fib_index,
341 FIB_SOURCE_INTERFACE,
342 (FIB_ENTRY_FLAG_DROP |
343 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
348 ip4_add_interface_prefix_routes (ip4_main_t *im,
351 ip_interface_address_t * a)
353 ip_lookup_main_t *lm = &im->lookup_main;
354 ip_interface_prefix_t *if_prefix;
355 ip4_address_t *address = ip_interface_address_get_address (lm, a);
357 ip_interface_prefix_key_t key = {
359 .fp_len = a->address_length,
360 .fp_proto = FIB_PROTOCOL_IP4,
361 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
363 .sw_if_index = sw_if_index,
366 fib_prefix_t pfx_special = {
367 .fp_proto = FIB_PROTOCOL_IP4,
370 /* If prefix already set on interface, just increment ref count & return */
371 if_prefix = ip_get_interface_prefix (lm, &key);
374 if_prefix->ref_count += 1;
378 /* New prefix - allocate a pool entry, initialize it, add to the hash */
379 pool_get (lm->if_prefix_pool, if_prefix);
380 if_prefix->ref_count = 1;
381 if_prefix->src_ia_index = a - lm->if_address_pool;
382 clib_memcpy (&if_prefix->key, &key, sizeof (key));
383 mhash_set (&lm->prefix_to_if_prefix_index, &key,
384 if_prefix - lm->if_prefix_pool, 0 /* old value */);
386 pfx_special.fp_len = a->address_length;
387 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
389 /* set the glean route for the prefix */
390 fib_table_entry_update_one_path (fib_index, &pfx_special,
391 FIB_SOURCE_INTERFACE,
392 (FIB_ENTRY_FLAG_CONNECTED |
393 FIB_ENTRY_FLAG_ATTACHED),
395 /* No next-hop address */
398 /* invalid FIB index */
401 /* no out-label stack */
403 FIB_ROUTE_PATH_FLAG_NONE);
405 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
406 if (a->address_length <= 30)
408 /* set a drop route for the base address of the prefix */
409 pfx_special.fp_len = 32;
410 pfx_special.fp_addr.ip4.as_u32 =
411 address->as_u32 & im->fib_masks[a->address_length];
413 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
414 fib_table_entry_special_add (fib_index, &pfx_special,
415 FIB_SOURCE_INTERFACE,
416 (FIB_ENTRY_FLAG_DROP |
417 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
419 /* set a route for the broadcast address of the prefix */
420 pfx_special.fp_len = 32;
421 pfx_special.fp_addr.ip4.as_u32 =
422 address->as_u32 | ~im->fib_masks[a->address_length];
423 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
424 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
428 /* length == 31 - add an attached route for the other address */
429 else if (a->address_length == 31)
431 pfx_special.fp_len = 32;
432 pfx_special.fp_addr.ip4.as_u32 =
433 address->as_u32 ^ clib_host_to_net_u32(1);
435 fib_table_entry_update_one_path (fib_index, &pfx_special,
436 FIB_SOURCE_INTERFACE,
437 (FIB_ENTRY_FLAG_ATTACHED),
439 &pfx_special.fp_addr,
441 /* invalid FIB index */
445 FIB_ROUTE_PATH_FLAG_NONE);
450 ip4_add_interface_routes (u32 sw_if_index,
451 ip4_main_t * im, u32 fib_index,
452 ip_interface_address_t * a)
454 ip_lookup_main_t *lm = &im->lookup_main;
455 ip4_address_t *address = ip_interface_address_get_address (lm, a);
458 .fp_proto = FIB_PROTOCOL_IP4,
459 .fp_addr.ip4 = *address,
462 /* set special routes for the prefix if needed */
463 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
465 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
467 u32 classify_table_index =
468 lm->classify_table_index_by_sw_if_index[sw_if_index];
469 if (classify_table_index != (u32) ~ 0)
471 dpo_id_t dpo = DPO_INVALID;
476 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
478 fib_table_entry_special_dpo_add (fib_index,
481 FIB_ENTRY_FLAG_NONE, &dpo);
486 fib_table_entry_update_one_path (fib_index, &pfx,
487 FIB_SOURCE_INTERFACE,
488 (FIB_ENTRY_FLAG_CONNECTED |
489 FIB_ENTRY_FLAG_LOCAL),
496 FIB_ROUTE_PATH_FLAG_NONE);
500 ip4_del_interface_prefix_routes (ip4_main_t * im,
503 ip4_address_t * address,
506 ip_lookup_main_t *lm = &im->lookup_main;
507 ip_interface_prefix_t *if_prefix;
509 ip_interface_prefix_key_t key = {
511 .fp_len = address_length,
512 .fp_proto = FIB_PROTOCOL_IP4,
513 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
515 .sw_if_index = sw_if_index,
518 fib_prefix_t pfx_special = {
520 .fp_proto = FIB_PROTOCOL_IP4,
523 if_prefix = ip_get_interface_prefix (lm, &key);
526 clib_warning ("Prefix not found while deleting %U",
527 format_ip4_address_and_length, address, address_length);
531 if_prefix->ref_count -= 1;
534 * Routes need to be adjusted if deleting last intf addr in prefix
536 * We're done now otherwise
538 if (if_prefix->ref_count > 0)
541 /* length <= 30, delete glean route, first address, last address */
542 if (address_length <= 30)
544 /* Less work to do in FIB if we remove the covered /32s first */
546 /* first address in prefix */
547 pfx_special.fp_addr.ip4.as_u32 =
548 address->as_u32 & im->fib_masks[address_length];
549 pfx_special.fp_len = 32;
551 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
552 fib_table_entry_special_remove (fib_index,
554 FIB_SOURCE_INTERFACE);
556 /* prefix broadcast address */
557 pfx_special.fp_addr.ip4.as_u32 =
558 address->as_u32 | ~im->fib_masks[address_length];
559 pfx_special.fp_len = 32;
561 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
562 fib_table_entry_special_remove (fib_index,
564 FIB_SOURCE_INTERFACE);
566 else if (address_length == 31)
568 /* length == 31, delete attached route for the other address */
569 pfx_special.fp_addr.ip4.as_u32 =
570 address->as_u32 ^ clib_host_to_net_u32(1);
572 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
575 /* remove glean route for prefix */
576 pfx_special.fp_addr.ip4 = *address;
577 pfx_special.fp_len = address_length;
578 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
580 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
581 pool_put (lm->if_prefix_pool, if_prefix);
585 ip4_del_interface_routes (u32 sw_if_index,
588 ip4_address_t * address, u32 address_length)
592 .fp_proto = FIB_PROTOCOL_IP4,
593 .fp_addr.ip4 = *address,
596 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
598 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
599 address, address_length);
602 #ifndef CLIB_MARCH_VARIANT
604 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
606 ip4_main_t *im = &ip4_main;
607 vnet_main_t *vnm = vnet_get_main ();
608 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
610 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
613 * enable/disable only on the 1<->0 transition
617 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
622 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
623 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
626 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
630 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
631 sw_if_index, !is_enable, 0, 0);
635 else if (hi->l3_if_count)
639 ip4_enable_disable_interface_callback_t *cb;
640 vec_foreach (cb, im->enable_disable_interface_callbacks)
641 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
645 static clib_error_t *
646 ip4_add_del_interface_address_internal (vlib_main_t * vm,
648 ip4_address_t * address,
649 u32 address_length, u32 is_del)
651 vnet_main_t *vnm = vnet_get_main ();
652 ip4_main_t *im = &ip4_main;
653 ip_lookup_main_t *lm = &im->lookup_main;
654 clib_error_t *error = 0;
655 u32 if_address_index;
656 ip4_address_fib_t ip4_af, *addr_fib = 0;
658 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
661 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
665 ip4_addr_fib_init (&ip4_af, address,
666 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
667 vec_add1 (addr_fib, ip4_af);
670 * there is no support for adj-fib handling in the presence of overlapping
671 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
677 /* When adding an address check that it does not conflict
678 with an existing address on any interface in this table. */
679 ip_interface_address_t *ia;
680 vnet_sw_interface_t *sif;
682 pool_foreach (sif, vnm->interface_main.sw_interfaces)
684 if (im->fib_index_by_sw_if_index[sw_if_index] ==
685 im->fib_index_by_sw_if_index[sif->sw_if_index])
687 foreach_ip_interface_address
688 (&im->lookup_main, ia, sif->sw_if_index,
689 0 /* honor unnumbered */ ,
692 ip_interface_address_get_address
693 (&im->lookup_main, ia);
695 if (ip4_destination_matches_route
696 (im, address, x, ia->address_length) ||
697 ip4_destination_matches_route (im,
702 /* an intf may have >1 addr from the same prefix */
703 if ((sw_if_index == sif->sw_if_index) &&
704 (ia->address_length == address_length) &&
705 (x->as_u32 != address->as_u32))
708 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
709 /* if the address we're comparing against is stale
710 * then the CP has not added this one back yet, maybe
711 * it never will, so we have to assume it won't and
712 * ignore it. if it does add it back, then it will fail
713 * because this one is now present */
716 /* error if the length or intf was different */
717 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
719 error = clib_error_create
720 ("failed to add %U on %U which conflicts with %U for interface %U",
721 format_ip4_address_and_length, address,
723 format_vnet_sw_if_index_name, vnm,
725 format_ip4_address_and_length, x,
727 format_vnet_sw_if_index_name, vnm,
737 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
741 if (~0 == if_address_index)
743 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
744 error = clib_error_create ("%U not found for interface %U",
745 lm->format_address_and_length,
746 addr_fib, address_length,
747 format_vnet_sw_if_index_name, vnm,
752 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
753 address_length, sw_if_index);
759 if (~0 != if_address_index)
761 ip_interface_address_t *ia;
763 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
765 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
767 if (ia->sw_if_index == sw_if_index)
769 /* re-adding an address during the replace action.
770 * consdier this the update. clear the flag and
772 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
777 /* The prefix is moving from one interface to another.
778 * delete the stale and add the new */
779 ip4_add_del_interface_address_internal (vm,
784 error = ip_interface_address_add (lm, sw_if_index,
785 addr_fib, address_length,
791 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
792 error = clib_error_create
793 ("Prefix %U already found on interface %U",
794 lm->format_address_and_length, addr_fib, address_length,
795 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
799 error = ip_interface_address_add (lm, sw_if_index,
800 addr_fib, address_length,
807 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
808 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
810 /* intf addr routes are added/deleted on admin up/down */
811 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
814 ip4_del_interface_routes (sw_if_index,
815 im, ip4_af.fib_index, address,
818 ip4_add_interface_routes (sw_if_index,
819 im, ip4_af.fib_index,
821 (lm->if_address_pool, if_address_index));
824 ip4_add_del_interface_address_callback_t *cb;
825 vec_foreach (cb, im->add_del_interface_address_callbacks)
826 cb->function (im, cb->function_opaque, sw_if_index,
827 address, address_length, if_address_index, is_del);
835 ip4_add_del_interface_address (vlib_main_t * vm,
837 ip4_address_t * address,
838 u32 address_length, u32 is_del)
840 return ip4_add_del_interface_address_internal
841 (vm, sw_if_index, address, address_length, is_del);
845 ip4_directed_broadcast (u32 sw_if_index, u8 enable)
847 ip_interface_address_t *ia;
853 * when directed broadcast is enabled, the subnet braodcast route will forward
854 * packets using an adjacency with a broadcast MAC. otherwise it drops
857 foreach_ip_interface_address(&im->lookup_main, ia,
860 if (ia->address_length <= 30)
864 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
868 .fp_proto = FIB_PROTOCOL_IP4,
870 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
874 ip4_add_subnet_bcast_route
875 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
884 static clib_error_t *
885 ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
887 ip4_main_t *im = &ip4_main;
888 ip_interface_address_t *ia;
890 u32 is_admin_up, fib_index;
892 vec_validate_init_empty (im->
893 lookup_main.if_address_pool_index_by_sw_if_index,
896 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
898 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
901 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
902 0 /* honor unnumbered */,
904 a = ip_interface_address_get_address (&im->lookup_main, ia);
906 ip4_add_interface_routes (sw_if_index,
910 ip4_del_interface_routes (sw_if_index,
912 a, ia->address_length);
919 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
921 /* Built-in ip4 unicast rx feature path definition */
923 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
925 .arc_name = "ip4-unicast",
926 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
927 .last_in_arc = "ip4-lookup",
928 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
931 VNET_FEATURE_INIT (ip4_flow_classify, static) =
933 .arc_name = "ip4-unicast",
934 .node_name = "ip4-flow-classify",
935 .runs_before = VNET_FEATURES ("ip4-inacl"),
938 VNET_FEATURE_INIT (ip4_inacl, static) =
940 .arc_name = "ip4-unicast",
941 .node_name = "ip4-inacl",
942 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
945 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
947 .arc_name = "ip4-unicast",
948 .node_name = "ip4-source-and-port-range-check-rx",
949 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
952 VNET_FEATURE_INIT (ip4_policer_classify, static) =
954 .arc_name = "ip4-unicast",
955 .node_name = "ip4-policer-classify",
956 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
959 VNET_FEATURE_INIT (ip4_ipsec, static) =
961 .arc_name = "ip4-unicast",
962 .node_name = "ipsec4-input-feature",
963 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
966 VNET_FEATURE_INIT (ip4_vpath, static) =
968 .arc_name = "ip4-unicast",
969 .node_name = "vpath-input-ip4",
970 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
973 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
975 .arc_name = "ip4-unicast",
976 .node_name = "ip4-vxlan-bypass",
977 .runs_before = VNET_FEATURES ("ip4-lookup"),
980 VNET_FEATURE_INIT (ip4_not_enabled, static) =
982 .arc_name = "ip4-unicast",
983 .node_name = "ip4-not-enabled",
984 .runs_before = VNET_FEATURES ("ip4-lookup"),
987 VNET_FEATURE_INIT (ip4_lookup, static) =
989 .arc_name = "ip4-unicast",
990 .node_name = "ip4-lookup",
991 .runs_before = 0, /* not before any other features */
994 /* Built-in ip4 multicast rx feature path definition */
995 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
997 .arc_name = "ip4-multicast",
998 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
999 .last_in_arc = "ip4-mfib-forward-lookup",
1000 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1003 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1005 .arc_name = "ip4-multicast",
1006 .node_name = "vpath-input-ip4",
1007 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1010 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
1012 .arc_name = "ip4-multicast",
1013 .node_name = "ip4-not-enabled",
1014 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1017 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1019 .arc_name = "ip4-multicast",
1020 .node_name = "ip4-mfib-forward-lookup",
1021 .runs_before = 0, /* last feature */
1024 /* Source and port-range check ip4 tx feature path definition */
1025 VNET_FEATURE_ARC_INIT (ip4_output, static) =
1027 .arc_name = "ip4-output",
1028 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
1029 .last_in_arc = "interface-output",
1030 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1033 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1035 .arc_name = "ip4-output",
1036 .node_name = "ip4-source-and-port-range-check-tx",
1037 .runs_before = VNET_FEATURES ("ip4-outacl"),
1040 VNET_FEATURE_INIT (ip4_outacl, static) =
1042 .arc_name = "ip4-output",
1043 .node_name = "ip4-outacl",
1044 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
1047 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1049 .arc_name = "ip4-output",
1050 .node_name = "ipsec4-output-feature",
1051 .runs_before = VNET_FEATURES ("interface-output"),
1054 /* Built-in ip4 tx feature path definition */
1055 VNET_FEATURE_INIT (ip4_interface_output, static) =
1057 .arc_name = "ip4-output",
1058 .node_name = "interface-output",
1059 .runs_before = 0, /* not before any other features */
1063 static clib_error_t *
1064 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1066 ip4_main_t *im = &ip4_main;
1068 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1069 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
1073 /* Fill in lookup tables with default table (0). */
1074 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1075 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1079 ip4_main_t *im4 = &ip4_main;
1080 ip_lookup_main_t *lm4 = &im4->lookup_main;
1081 ip_interface_address_t *ia = 0;
1082 ip4_address_t *address;
1083 vlib_main_t *vm = vlib_get_main ();
1085 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
1087 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1089 address = ip_interface_address_get_address (lm4, ia);
1090 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1093 ip4_mfib_interface_enable_disable (sw_if_index, 0);
1095 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1096 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1097 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1098 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1100 /* Erase the lookup tables just in case */
1101 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1102 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
1105 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
1108 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1109 sw_if_index, is_add, 0, 0);
1111 return /* no error */ 0;
1114 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1116 /* Global IP4 main. */
1117 #ifndef CLIB_MARCH_VARIANT
1118 ip4_main_t ip4_main;
1119 #endif /* CLIB_MARCH_VARIANT */
1121 static clib_error_t *
1122 ip4_lookup_init (vlib_main_t * vm)
1124 ip4_main_t *im = &ip4_main;
1125 clib_error_t *error;
1128 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1130 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1132 if ((error = vlib_call_init_function (vm, fib_module_init)))
1134 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1137 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1142 m = pow2_mask (i) << (32 - i);
1145 im->fib_masks[i] = clib_host_to_net_u32 (m);
1148 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1150 /* Create FIB with index 0 and table id of 0. */
1151 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1152 FIB_SOURCE_DEFAULT_ROUTE);
1153 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1154 MFIB_SOURCE_DEFAULT_ROUTE);
1158 pn = pg_get_node (ip4_lookup_node.index);
1159 pn->unformat_edit = unformat_pg_ip4_header;
1163 ethernet_arp_header_t h;
1165 clib_memset (&h, 0, sizeof (h));
1167 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1168 #define _8(f,v) h.f = v;
1169 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1170 _16 (l3_type, ETHERNET_TYPE_IP4);
1171 _8 (n_l2_address_bytes, 6);
1172 _8 (n_l3_address_bytes, 4);
1173 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1177 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1180 /* alloc chunk size */ 8,
1187 VLIB_INIT_FUNCTION (ip4_lookup_init);
1191 /* Adjacency taken. */
1196 /* Packet data, possibly *after* rewrite. */
1197 u8 packet_data[64 - 1 * sizeof (u32)];
1199 ip4_forward_next_trace_t;
1201 #ifndef CLIB_MARCH_VARIANT
1203 format_ip4_forward_next_trace (u8 * s, va_list * args)
1205 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1206 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1207 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1208 u32 indent = format_get_indent (s);
1209 s = format (s, "%U%U",
1210 format_white_space, indent,
1211 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1217 format_ip4_lookup_trace (u8 * s, va_list * args)
1219 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1220 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1221 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1222 u32 indent = format_get_indent (s);
1224 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1225 t->fib_index, t->dpo_index, t->flow_hash);
1226 s = format (s, "\n%U%U",
1227 format_white_space, indent,
1228 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1233 format_ip4_rewrite_trace (u8 * s, va_list * args)
1235 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1236 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1237 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1238 u32 indent = format_get_indent (s);
1240 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1241 t->fib_index, t->dpo_index, format_ip_adjacency,
1242 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1243 s = format (s, "\n%U%U",
1244 format_white_space, indent,
1245 format_ip_adjacency_packet_data,
1246 t->packet_data, sizeof (t->packet_data));
1250 #ifndef CLIB_MARCH_VARIANT
1251 /* Common trace function for all ip4-forward next nodes. */
1253 ip4_forward_next_trace (vlib_main_t * vm,
1254 vlib_node_runtime_t * node,
1255 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1258 ip4_main_t *im = &ip4_main;
1260 n_left = frame->n_vectors;
1261 from = vlib_frame_vector_args (frame);
1266 vlib_buffer_t *b0, *b1;
1267 ip4_forward_next_trace_t *t0, *t1;
1269 /* Prefetch next iteration. */
1270 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1271 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1276 b0 = vlib_get_buffer (vm, bi0);
1277 b1 = vlib_get_buffer (vm, bi1);
1279 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1281 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1282 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1283 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1285 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1286 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1287 vec_elt (im->fib_index_by_sw_if_index,
1288 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1290 clib_memcpy_fast (t0->packet_data,
1291 vlib_buffer_get_current (b0),
1292 sizeof (t0->packet_data));
1294 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1296 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1297 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1298 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1300 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1301 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1302 vec_elt (im->fib_index_by_sw_if_index,
1303 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1304 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1305 sizeof (t1->packet_data));
1315 ip4_forward_next_trace_t *t0;
1319 b0 = vlib_get_buffer (vm, bi0);
1321 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1323 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1324 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1325 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1327 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1328 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1329 vec_elt (im->fib_index_by_sw_if_index,
1330 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1331 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1332 sizeof (t0->packet_data));
1339 /* Compute TCP/UDP/ICMP4 checksum in software. */
1341 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1345 u32 ip_header_length, payload_length_host_byte_order;
1347 /* Initialize checksum with ip header. */
1348 ip_header_length = ip4_header_bytes (ip0);
1349 payload_length_host_byte_order =
1350 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1352 clib_host_to_net_u32 (payload_length_host_byte_order +
1353 (ip0->protocol << 16));
1355 if (BITS (uword) == 32)
1358 ip_csum_with_carry (sum0,
1359 clib_mem_unaligned (&ip0->src_address, u32));
1361 ip_csum_with_carry (sum0,
1362 clib_mem_unaligned (&ip0->dst_address, u32));
1366 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1368 return ip_calculate_l4_checksum (vm, p0, sum0,
1369 payload_length_host_byte_order, (u8 *) ip0,
1370 ip_header_length, NULL);
1374 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1376 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1380 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1381 || ip0->protocol == IP_PROTOCOL_UDP);
1383 udp0 = (void *) (ip0 + 1);
1384 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1386 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1387 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1391 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1393 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1394 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1401 VNET_FEATURE_ARC_INIT (ip4_local) = {
1402 .arc_name = "ip4-local",
1403 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
1404 .last_in_arc = "ip4-local-end-of-arc",
1409 ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1410 ip4_header_t * ip, u8 is_udp, u8 * error,
1414 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1415 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1419 u32 ip_len, udp_len;
1421 udp = ip4_next_header (ip);
1422 /* Verify UDP length. */
1423 ip_len = clib_net_to_host_u16 (ip->length);
1424 udp_len = clib_net_to_host_u16 (udp->length);
1426 len_diff = ip_len - udp_len;
1427 *good_tcp_udp &= len_diff >= 0;
1428 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1432 #define ip4_local_csum_is_offloaded(_b) \
1433 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
1434 (vnet_buffer (_b)->oflags & \
1435 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
1437 #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1438 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1439 || ip4_local_csum_is_offloaded (_b)))
1441 #define ip4_local_csum_is_valid(_b) \
1442 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1443 || (ip4_local_csum_is_offloaded (_b))) != 0
1446 ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1447 ip4_header_t * ih, u8 * error)
1449 u8 is_udp, is_tcp_udp, good_tcp_udp;
1451 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1452 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1454 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1455 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1457 good_tcp_udp = ip4_local_csum_is_valid (b);
1459 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1460 *error = (is_tcp_udp && !good_tcp_udp
1461 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1465 ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1466 ip4_header_t ** ih, u8 * error)
1468 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1470 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1471 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1473 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1474 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1476 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1477 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1479 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1480 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1483 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1486 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1490 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1491 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1492 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1493 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1497 ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1498 vlib_buffer_t * b, u16 * next, u8 error,
1499 u8 head_of_feature_arc)
1501 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1504 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1505 b->error = error ? error_node->errors[error] : 0;
1506 if (head_of_feature_arc)
1509 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1511 vnet_feature_arc_start (arc_index,
1512 vnet_buffer (b)->sw_if_index[VLIB_RX],
1525 } ip4_local_last_check_t;
1528 ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1529 ip4_local_last_check_t *last_check, u8 *error0,
1532 const dpo_id_t *dpo0;
1533 load_balance_t *lb0;
1536 vnet_buffer (b)->ip.fib_index =
1537 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1538 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1543 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1544 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1547 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1550 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1551 * adjacency for the destination address (the local interface address).
1552 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1553 * adjacency for the source address (the remote sender's address)
1555 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1558 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1561 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1562 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1563 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1565 lb0 = load_balance_get (lbi0);
1566 dpo0 = load_balance_get_bucket_i (lb0, 0);
1569 * Must have a route to source otherwise we drop the packet.
1570 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1573 * - the source is a recieve => it's from us => bogus, do this
1574 * first since it sets a different error code.
1575 * - uRPF check for any route to source - accept if passes.
1576 * - allow packets destined to the broadcast address from unknown sources
1579 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1580 && dpo0->dpoi_type == DPO_RECEIVE) ?
1581 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1582 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1583 && !fib_urpf_check_size (lb0->lb_urpf)
1584 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1585 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1587 last_check->src.as_u32 = ip0->src_address.as_u32;
1588 last_check->lbi = lbi0;
1589 last_check->error = *error0;
1590 last_check->first = 0;
1594 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1595 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1596 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1597 *error0 = last_check->error;
1602 ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1603 ip4_local_last_check_t *last_check, u8 *error,
1606 const dpo_id_t *dpo[2];
1607 load_balance_t *lb[2];
1611 not_last_hit = last_check->first;
1612 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1613 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1615 vnet_buffer (b[0])->ip.fib_index =
1616 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1617 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1618 vnet_buffer (b[0])->ip.fib_index;
1620 vnet_buffer (b[1])->ip.fib_index =
1621 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1622 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1623 vnet_buffer (b[1])->ip.fib_index;
1627 const receive_dpo_t *rd0, *rd1;
1628 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1629 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1630 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1631 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1635 vnet_buffer (b[0])->ip.rx_sw_if_index =
1636 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1637 vnet_buffer (b[1])->ip.rx_sw_if_index =
1638 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1642 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1643 * adjacency for the destination address (the local interface address).
1644 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1645 * adjacency for the source address (the remote sender's address)
1647 if (PREDICT_TRUE (not_last_hit))
1649 ip4_fib_forwarding_lookup_x2 (
1650 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1651 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
1653 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1654 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1655 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1657 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1658 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1659 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1661 lb[0] = load_balance_get (lbi[0]);
1662 lb[1] = load_balance_get (lbi[1]);
1664 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1665 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1667 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1668 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1669 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1670 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1671 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1672 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1673 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1675 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1676 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1677 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1678 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1679 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1680 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1681 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1683 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1684 last_check->lbi = lbi[1];
1685 last_check->error = error[1];
1686 last_check->first = 0;
1690 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1691 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1692 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1694 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1695 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1696 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1698 error[0] = last_check->error;
1699 error[1] = last_check->error;
1703 enum ip_local_packet_type_e
1705 IP_LOCAL_PACKET_TYPE_L4,
1706 IP_LOCAL_PACKET_TYPE_NAT,
1707 IP_LOCAL_PACKET_TYPE_FRAG,
1711 * Determine packet type and next node.
1713 * The expectation is that all packets that are not L4 will skip
1714 * checksums and source checks.
1717 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1719 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1721 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1723 *next = IP_LOCAL_NEXT_REASSEMBLY;
1724 return IP_LOCAL_PACKET_TYPE_FRAG;
1726 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1728 *next = lm->local_next_by_ip_protocol[ip->protocol];
1729 return IP_LOCAL_PACKET_TYPE_NAT;
1732 *next = lm->local_next_by_ip_protocol[ip->protocol];
1733 return IP_LOCAL_PACKET_TYPE_L4;
1737 ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1738 vlib_frame_t *frame, int head_of_feature_arc,
1741 u32 *from, n_left_from;
1742 vlib_node_runtime_t *error_node =
1743 vlib_node_get_runtime (vm, ip4_local_node.index);
1744 u16 nexts[VLIB_FRAME_SIZE], *next;
1745 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1746 ip4_header_t *ip[2];
1749 ip4_local_last_check_t last_check = {
1751 * 0.0.0.0 can appear as the source address of an IP packet,
1752 * as can any other address, hence the need to use the 'first'
1753 * member to make sure the .lbi is initialised for the first
1756 .src = {.as_u32 = 0},
1758 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1762 from = vlib_frame_vector_args (frame);
1763 n_left_from = frame->n_vectors;
1765 if (node->flags & VLIB_NODE_FLAG_TRACE)
1766 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1768 vlib_get_buffers (vm, from, bufs, n_left_from);
1772 while (n_left_from >= 6)
1776 /* Prefetch next iteration. */
1778 vlib_prefetch_buffer_header (b[4], LOAD);
1779 vlib_prefetch_buffer_header (b[5], LOAD);
1781 clib_prefetch_load (b[4]->data);
1782 clib_prefetch_load (b[5]->data);
1785 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1787 ip[0] = vlib_buffer_get_current (b[0]);
1788 ip[1] = vlib_buffer_get_current (b[1]);
1790 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1791 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1793 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1794 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1796 not_batch = pt[0] ^ pt[1];
1798 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1801 if (PREDICT_TRUE (not_batch == 0))
1803 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1804 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
1810 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1811 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1816 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1817 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1824 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1825 head_of_feature_arc);
1826 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1827 head_of_feature_arc);
1834 while (n_left_from > 0)
1836 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1838 ip[0] = vlib_buffer_get_current (b[0]);
1839 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1840 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1842 if (head_of_feature_arc == 0 || pt[0])
1845 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1846 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1851 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1852 head_of_feature_arc);
1859 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1860 return frame->n_vectors;
1863 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1864 vlib_frame_t * frame)
1866 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1867 0 /* is_receive_dpo */);
1870 VLIB_REGISTER_NODE (ip4_local_node) =
1872 .name = "ip4-local",
1873 .vector_size = sizeof (u32),
1874 .format_trace = format_ip4_forward_next_trace,
1875 .n_errors = IP4_N_ERROR,
1876 .error_strings = ip4_error_strings,
1877 .n_next_nodes = IP_LOCAL_N_NEXT,
1880 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1881 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1882 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1883 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1884 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
1888 VLIB_NODE_FN (ip4_receive_local_node)
1889 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1891 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1892 1 /* is_receive_dpo */);
1895 VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1896 .name = "ip4-receive",
1897 .vector_size = sizeof (u32),
1898 .format_trace = format_ip4_forward_next_trace,
1899 .sibling_of = "ip4-local"
1902 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1903 vlib_node_runtime_t * node,
1904 vlib_frame_t * frame)
1906 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1907 0 /* is_receive_dpo */);
1910 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1911 .name = "ip4-local-end-of-arc",
1912 .vector_size = sizeof (u32),
1914 .format_trace = format_ip4_forward_next_trace,
1915 .sibling_of = "ip4-local",
1918 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1919 .arc_name = "ip4-local",
1920 .node_name = "ip4-local-end-of-arc",
1921 .runs_before = 0, /* not before any other features */
1924 #ifndef CLIB_MARCH_VARIANT
1926 ip4_register_protocol (u32 protocol, u32 node_index)
1928 vlib_main_t *vm = vlib_get_main ();
1929 ip4_main_t *im = &ip4_main;
1930 ip_lookup_main_t *lm = &im->lookup_main;
1932 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1933 lm->local_next_by_ip_protocol[protocol] =
1934 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1938 ip4_unregister_protocol (u32 protocol)
1940 ip4_main_t *im = &ip4_main;
1941 ip_lookup_main_t *lm = &im->lookup_main;
1943 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1944 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1948 static clib_error_t *
1949 show_ip_local_command_fn (vlib_main_t * vm,
1950 unformat_input_t * input, vlib_cli_command_t * cmd)
1952 ip4_main_t *im = &ip4_main;
1953 ip_lookup_main_t *lm = &im->lookup_main;
1956 vlib_cli_output (vm, "Protocols handled by ip4_local");
1957 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1959 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1961 u32 node_index = vlib_get_node (vm,
1962 ip4_local_node.index)->
1963 next_nodes[lm->local_next_by_ip_protocol[i]];
1964 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1965 format_vlib_node_name, vm, node_index);
1974 * Display the set of protocols handled by the local IPv4 stack.
1977 * Example of how to display local protocol table:
1978 * @cliexstart{show ip local}
1979 * Protocols handled by ip4_local
1986 VLIB_CLI_COMMAND (show_ip_local, static) =
1988 .path = "show ip local",
1989 .function = show_ip_local_command_fn,
1990 .short_help = "show ip local",
1996 IP4_REWRITE_NEXT_DROP,
1997 IP4_REWRITE_NEXT_ICMP_ERROR,
1998 IP4_REWRITE_NEXT_FRAGMENT,
1999 IP4_REWRITE_N_NEXT /* Last */
2000 } ip4_rewrite_next_t;
2003 * This bits of an IPv4 address to mask to construct a multicast
2006 #if CLIB_ARCH_IS_BIG_ENDIAN
2007 #define IP4_MCAST_ADDR_MASK 0x007fffff
2009 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2013 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2014 u16 adj_packet_bytes, bool df, u16 * next,
2015 u8 is_midchain, u32 * error)
2017 if (packet_len > adj_packet_bytes)
2019 *error = IP4_ERROR_MTU_EXCEEDED;
2022 icmp4_error_set_vnet_buffer
2023 (b, ICMP4_destination_unreachable,
2024 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2026 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2030 /* IP fragmentation */
2031 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2033 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2034 IP_FRAG_NEXT_IP_REWRITE), 0);
2035 *next = IP4_REWRITE_NEXT_FRAGMENT;
2040 /* increment TTL & update checksum.
2041 Works either endian, so no need for byte swap. */
2042 static_always_inline void
2043 ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2047 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2052 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2053 checksum += checksum >= 0xffff;
2055 ip->checksum = checksum;
2059 ASSERT (ip4_header_checksum_is_valid (ip));
2062 /* Decrement TTL & update checksum.
2063 Works either endian, so no need for byte swap. */
2064 static_always_inline void
2065 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2070 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2075 /* Input node should have reject packets with ttl 0. */
2076 ASSERT (ip->ttl > 0);
2078 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2079 checksum += checksum >= 0xffff;
2081 ip->checksum = checksum;
2086 * If the ttl drops below 1 when forwarding, generate
2089 if (PREDICT_FALSE (ttl <= 0))
2091 *error = IP4_ERROR_TIME_EXPIRED;
2092 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2093 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2094 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2096 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2099 /* Verify checksum. */
2100 ASSERT (ip4_header_checksum_is_valid (ip) ||
2101 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2102 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2106 ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2107 vlib_frame_t *frame, int do_counters, int is_midchain,
2110 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2111 u32 *from = vlib_frame_vector_args (frame);
2112 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2113 u16 nexts[VLIB_FRAME_SIZE], *next;
2115 vlib_node_runtime_t *error_node =
2116 vlib_node_get_runtime (vm, ip4_input_node.index);
2118 n_left_from = frame->n_vectors;
2119 u32 thread_index = vm->thread_index;
2121 vlib_get_buffers (vm, from, bufs, n_left_from);
2122 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2124 #if (CLIB_N_PREFETCHES >= 8)
2125 if (n_left_from >= 6)
2128 for (i = 2; i < 6; i++)
2129 vlib_prefetch_buffer_header (bufs[i], LOAD);
2134 while (n_left_from >= 8)
2136 const ip_adjacency_t *adj0, *adj1;
2137 ip4_header_t *ip0, *ip1;
2138 u32 rw_len0, error0, adj_index0;
2139 u32 rw_len1, error1, adj_index1;
2140 u32 tx_sw_if_index0, tx_sw_if_index1;
2145 vlib_prefetch_buffer_header (b[6], LOAD);
2146 vlib_prefetch_buffer_header (b[7], LOAD);
2149 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2150 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2153 * pre-fetch the per-adjacency counters
2157 vlib_prefetch_combined_counter (&adjacency_counters,
2158 thread_index, adj_index0);
2159 vlib_prefetch_combined_counter (&adjacency_counters,
2160 thread_index, adj_index1);
2163 ip0 = vlib_buffer_get_current (b[0]);
2164 ip1 = vlib_buffer_get_current (b[1]);
2166 error0 = error1 = IP4_ERROR_NONE;
2168 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2169 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2171 /* Rewrite packet header and updates lengths. */
2172 adj0 = adj_get (adj_index0);
2173 adj1 = adj_get (adj_index1);
2175 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2176 rw_len0 = adj0[0].rewrite_header.data_bytes;
2177 rw_len1 = adj1[0].rewrite_header.data_bytes;
2178 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2179 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2181 p = vlib_buffer_get_current (b[2]);
2182 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2183 clib_prefetch_load (p);
2185 p = vlib_buffer_get_current (b[3]);
2186 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2187 clib_prefetch_load (p);
2189 /* Check MTU of outgoing interface. */
2190 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2191 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2193 if (b[0]->flags & VNET_BUFFER_F_GSO)
2194 ip0_len = gso_mtu_sz (b[0]);
2195 if (b[1]->flags & VNET_BUFFER_F_GSO)
2196 ip1_len = gso_mtu_sz (b[1]);
2198 ip4_mtu_check (b[0], ip0_len,
2199 adj0[0].rewrite_header.max_l3_packet_bytes,
2200 ip0->flags_and_fragment_offset &
2201 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2202 next + 0, is_midchain, &error0);
2203 ip4_mtu_check (b[1], ip1_len,
2204 adj1[0].rewrite_header.max_l3_packet_bytes,
2205 ip1->flags_and_fragment_offset &
2206 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2207 next + 1, is_midchain, &error1);
2211 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2212 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2213 IP4_ERROR_SAME_INTERFACE : error0);
2214 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2215 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2216 IP4_ERROR_SAME_INTERFACE : error1);
2219 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2220 * to see the IP header */
2221 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2223 u32 next_index = adj0[0].rewrite_header.next_index;
2224 vlib_buffer_advance (b[0], -(word) rw_len0);
2226 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2227 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2230 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2231 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2234 adj0->ia_cfg_index);
2236 next[0] = next_index;
2238 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2243 b[0]->error = error_node->errors[error0];
2244 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2245 ip4_ttl_inc (b[0], ip0);
2247 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2249 u32 next_index = adj1[0].rewrite_header.next_index;
2250 vlib_buffer_advance (b[1], -(word) rw_len1);
2252 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2253 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2256 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2257 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2260 adj1->ia_cfg_index);
2261 next[1] = next_index;
2263 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
2268 b[1]->error = error_node->errors[error1];
2269 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2270 ip4_ttl_inc (b[1], ip1);
2274 /* Guess we are only writing on ipv4 header. */
2275 vnet_rewrite_two_headers (adj0[0], adj1[0],
2276 ip0, ip1, sizeof (ip4_header_t));
2278 /* Guess we are only writing on simple Ethernet header. */
2279 vnet_rewrite_two_headers (adj0[0], adj1[0],
2280 ip0, ip1, sizeof (ethernet_header_t));
2284 if (error0 == IP4_ERROR_NONE)
2285 vlib_increment_combined_counter
2286 (&adjacency_counters,
2289 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2291 if (error1 == IP4_ERROR_NONE)
2292 vlib_increment_combined_counter
2293 (&adjacency_counters,
2296 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2301 if (error0 == IP4_ERROR_NONE)
2302 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2303 if (error1 == IP4_ERROR_NONE)
2304 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2309 /* copy bytes from the IP address into the MAC rewrite */
2310 if (error0 == IP4_ERROR_NONE)
2311 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2312 adj0->rewrite_header.dst_mcast_offset,
2313 &ip0->dst_address.as_u32, (u8 *) ip0);
2314 if (error1 == IP4_ERROR_NONE)
2315 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2316 adj1->rewrite_header.dst_mcast_offset,
2317 &ip1->dst_address.as_u32, (u8 *) ip1);
2324 #elif (CLIB_N_PREFETCHES >= 4)
2327 while (n_left_from >= 1)
2329 ip_adjacency_t *adj0;
2331 u32 rw_len0, error0, adj_index0;
2332 u32 tx_sw_if_index0;
2335 /* Prefetch next iteration */
2336 if (PREDICT_TRUE (n_left_from >= 4))
2338 ip_adjacency_t *adj2;
2341 vlib_prefetch_buffer_header (b[3], LOAD);
2342 vlib_prefetch_buffer_data (b[2], LOAD);
2344 /* Prefetch adj->rewrite_header */
2345 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2346 adj2 = adj_get (adj_index2);
2348 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2352 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2355 * Prefetch the per-adjacency counters
2359 vlib_prefetch_combined_counter (&adjacency_counters,
2360 thread_index, adj_index0);
2363 ip0 = vlib_buffer_get_current (b[0]);
2365 error0 = IP4_ERROR_NONE;
2367 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2369 /* Rewrite packet header and updates lengths. */
2370 adj0 = adj_get (adj_index0);
2372 /* Rewrite header was prefetched. */
2373 rw_len0 = adj0[0].rewrite_header.data_bytes;
2374 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2376 /* Check MTU of outgoing interface. */
2377 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2379 if (b[0]->flags & VNET_BUFFER_F_GSO)
2380 ip0_len = gso_mtu_sz (b[0]);
2382 ip4_mtu_check (b[0], ip0_len,
2383 adj0[0].rewrite_header.max_l3_packet_bytes,
2384 ip0->flags_and_fragment_offset &
2385 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2386 next + 0, is_midchain, &error0);
2390 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2391 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2392 IP4_ERROR_SAME_INTERFACE : error0);
2395 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2396 * to see the IP header */
2397 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2399 u32 next_index = adj0[0].rewrite_header.next_index;
2400 vlib_buffer_advance (b[0], -(word) rw_len0);
2401 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2402 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2405 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2406 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2409 adj0->ia_cfg_index);
2410 next[0] = next_index;
2414 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2417 /* Guess we are only writing on ipv4 header. */
2418 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2421 /* Guess we are only writing on simple Ethernet header. */
2422 vnet_rewrite_one_header (adj0[0], ip0,
2423 sizeof (ethernet_header_t));
2426 * Bump the per-adjacency counters
2429 vlib_increment_combined_counter
2430 (&adjacency_counters,
2432 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2436 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2439 /* copy bytes from the IP address into the MAC rewrite */
2440 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2441 adj0->rewrite_header.dst_mcast_offset,
2442 &ip0->dst_address.as_u32, (u8 *) ip0);
2446 b[0]->error = error_node->errors[error0];
2447 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2448 ip4_ttl_inc (b[0], ip0);
2457 while (n_left_from > 0)
2459 ip_adjacency_t *adj0;
2461 u32 rw_len0, adj_index0, error0;
2462 u32 tx_sw_if_index0;
2464 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2466 adj0 = adj_get (adj_index0);
2469 vlib_prefetch_combined_counter (&adjacency_counters,
2470 thread_index, adj_index0);
2472 ip0 = vlib_buffer_get_current (b[0]);
2474 error0 = IP4_ERROR_NONE;
2476 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2479 /* Update packet buffer attributes/set output interface. */
2480 rw_len0 = adj0[0].rewrite_header.data_bytes;
2481 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2483 /* Check MTU of outgoing interface. */
2484 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2485 if (b[0]->flags & VNET_BUFFER_F_GSO)
2486 ip0_len = gso_mtu_sz (b[0]);
2488 ip4_mtu_check (b[0], ip0_len,
2489 adj0[0].rewrite_header.max_l3_packet_bytes,
2490 ip0->flags_and_fragment_offset &
2491 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2492 next + 0, is_midchain, &error0);
2496 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2497 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2498 IP4_ERROR_SAME_INTERFACE : error0);
2501 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2502 * to see the IP header */
2503 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2505 u32 next_index = adj0[0].rewrite_header.next_index;
2506 vlib_buffer_advance (b[0], -(word) rw_len0);
2507 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2508 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2511 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2512 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2515 adj0->ia_cfg_index);
2516 next[0] = next_index;
2520 /* this acts on the packet that is about to be encapped */
2521 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2524 /* Guess we are only writing on ipv4 header. */
2525 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2528 /* Guess we are only writing on simple Ethernet header. */
2529 vnet_rewrite_one_header (adj0[0], ip0,
2530 sizeof (ethernet_header_t));
2533 vlib_increment_combined_counter
2534 (&adjacency_counters,
2535 thread_index, adj_index0, 1,
2536 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2539 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2542 /* copy bytes from the IP address into the MAC rewrite */
2543 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2544 adj0->rewrite_header.dst_mcast_offset,
2545 &ip0->dst_address.as_u32, (u8 *) ip0);
2549 b[0]->error = error_node->errors[error0];
2550 /* undo the TTL decrement - we'll be back to do it again */
2551 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2552 ip4_ttl_inc (b[0], ip0);
2561 /* Need to do trace after rewrites to pick up new packet data. */
2562 if (node->flags & VLIB_NODE_FLAG_TRACE)
2563 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2565 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2566 return frame->n_vectors;
2569 /** @brief IPv4 rewrite node.
2572 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2573 header checksum, fetch the ip adjacency, check the outbound mtu,
2574 apply the adjacency rewrite, and send pkts to the adjacency
2575 rewrite header's rewrite_next_index.
2577 @param vm vlib_main_t corresponding to the current thread
2578 @param node vlib_node_runtime_t
2579 @param frame vlib_frame_t whose contents should be dispatched
2581 @par Graph mechanics: buffer metadata, next index usage
2584 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2585 - the rewrite adjacency index
2586 - <code>adj->lookup_next_index</code>
2587 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2588 the packet will be dropped.
2589 - <code>adj->rewrite_header</code>
2590 - Rewrite string length, rewrite string, next_index
2593 - <code>b->current_data, b->current_length</code>
2594 - Updated net of applying the rewrite string
2596 <em>Next Indices:</em>
2597 - <code> adj->rewrite_header.next_index </code>
2601 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2602 vlib_frame_t * frame)
2604 if (adj_are_counters_enabled ())
2605 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2607 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2610 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2611 vlib_node_runtime_t * node,
2612 vlib_frame_t * frame)
2614 if (adj_are_counters_enabled ())
2615 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2617 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2620 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2621 vlib_node_runtime_t * node,
2622 vlib_frame_t * frame)
2624 if (adj_are_counters_enabled ())
2625 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2627 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2630 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2631 vlib_node_runtime_t * node,
2632 vlib_frame_t * frame)
2634 if (adj_are_counters_enabled ())
2635 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2637 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2640 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2641 vlib_node_runtime_t * node,
2642 vlib_frame_t * frame)
2644 if (adj_are_counters_enabled ())
2645 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2647 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2651 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2652 .name = "ip4-rewrite",
2653 .vector_size = sizeof (u32),
2655 .format_trace = format_ip4_rewrite_trace,
2657 .n_next_nodes = IP4_REWRITE_N_NEXT,
2659 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2660 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2661 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2665 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2666 .name = "ip4-rewrite-bcast",
2667 .vector_size = sizeof (u32),
2669 .format_trace = format_ip4_rewrite_trace,
2670 .sibling_of = "ip4-rewrite",
2673 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2674 .name = "ip4-rewrite-mcast",
2675 .vector_size = sizeof (u32),
2677 .format_trace = format_ip4_rewrite_trace,
2678 .sibling_of = "ip4-rewrite",
2681 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2682 .name = "ip4-mcast-midchain",
2683 .vector_size = sizeof (u32),
2685 .format_trace = format_ip4_rewrite_trace,
2686 .sibling_of = "ip4-rewrite",
2689 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2690 .name = "ip4-midchain",
2691 .vector_size = sizeof (u32),
2692 .format_trace = format_ip4_rewrite_trace,
2693 .sibling_of = "ip4-rewrite",
2697 static clib_error_t *
2698 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2699 unformat_input_t * input,
2700 vlib_cli_command_t * cmd)
2704 u32 flow_hash_config = 0;
2707 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2709 if (unformat (input, "table %d", &table_id))
2711 #define _(a, b, v) \
2712 else if (unformat (input, #a)) \
2714 flow_hash_config |= v; \
2717 foreach_flow_hash_bit
2724 return clib_error_return (0, "unknown input `%U'",
2725 format_unformat_error, input);
2727 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2733 case VNET_API_ERROR_NO_SUCH_FIB:
2734 return clib_error_return (0, "no such FIB table %d", table_id);
2737 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2745 * Configure the set of IPv4 fields used by the flow hash.
2748 * Example of how to set the flow hash on a given table:
2749 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2750 * Example of display the configured flow hash:
2751 * @cliexstart{show ip fib}
2752 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2755 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2756 * [0] [@0]: dpo-drop ip6
2759 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2760 * [0] [@0]: dpo-drop ip6
2763 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2764 * [0] [@0]: dpo-drop ip6
2767 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2768 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2771 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2772 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2773 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2774 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2775 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2778 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2779 * [0] [@0]: dpo-drop ip6
2780 * 255.255.255.255/32
2782 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2783 * [0] [@0]: dpo-drop ip6
2784 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2787 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2788 * [0] [@0]: dpo-drop ip6
2791 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2792 * [0] [@0]: dpo-drop ip6
2795 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2796 * [0] [@4]: ipv4-glean: af_packet0
2799 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2800 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2803 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2804 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2807 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2808 * [0] [@4]: ipv4-glean: af_packet1
2811 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2812 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2815 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2816 * [0] [@0]: dpo-drop ip6
2819 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2820 * [0] [@0]: dpo-drop ip6
2821 * 255.255.255.255/32
2823 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2824 * [0] [@0]: dpo-drop ip6
2828 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2830 .path = "set ip flow-hash",
2832 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2833 .function = set_ip_flow_hash_command_fn,
2837 #ifndef CLIB_MARCH_VARIANT
2839 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2842 vnet_main_t *vnm = vnet_get_main ();
2843 vnet_interface_main_t *im = &vnm->interface_main;
2844 ip4_main_t *ipm = &ip4_main;
2845 ip_lookup_main_t *lm = &ipm->lookup_main;
2846 vnet_classify_main_t *cm = &vnet_classify_main;
2847 ip4_address_t *if_addr;
2849 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2850 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2852 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2853 return VNET_API_ERROR_NO_SUCH_ENTRY;
2855 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2856 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2858 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2860 if (NULL != if_addr)
2862 fib_prefix_t pfx = {
2864 .fp_proto = FIB_PROTOCOL_IP4,
2865 .fp_addr.ip4 = *if_addr,
2869 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2873 if (table_index != (u32) ~ 0)
2875 dpo_id_t dpo = DPO_INVALID;
2880 classify_dpo_create (DPO_PROTO_IP4, table_index));
2882 fib_table_entry_special_dpo_add (fib_index,
2884 FIB_SOURCE_CLASSIFY,
2885 FIB_ENTRY_FLAG_NONE, &dpo);
2890 fib_table_entry_special_remove (fib_index,
2891 &pfx, FIB_SOURCE_CLASSIFY);
2899 static clib_error_t *
2900 set_ip_classify_command_fn (vlib_main_t * vm,
2901 unformat_input_t * input,
2902 vlib_cli_command_t * cmd)
2904 u32 table_index = ~0;
2905 int table_index_set = 0;
2906 u32 sw_if_index = ~0;
2909 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2911 if (unformat (input, "table-index %d", &table_index))
2912 table_index_set = 1;
2913 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2914 vnet_get_main (), &sw_if_index))
2920 if (table_index_set == 0)
2921 return clib_error_return (0, "classify table-index must be specified");
2923 if (sw_if_index == ~0)
2924 return clib_error_return (0, "interface / subif must be specified");
2926 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2933 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2934 return clib_error_return (0, "No such interface");
2936 case VNET_API_ERROR_NO_SUCH_ENTRY:
2937 return clib_error_return (0, "No such classifier table");
2943 * Assign a classification table to an interface. The classification
2944 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2945 * commands. Once the table is create, use this command to filter packets
2949 * Example of how to assign a classification table to an interface:
2950 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2953 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2955 .path = "set ip classify",
2957 "set ip classify intfc <interface> table-index <classify-idx>",
2958 .function = set_ip_classify_command_fn,
2963 * fd.io coding-style-patch-verification: ON
2966 * eval: (c-set-style "gnu")