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 (
1512 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
1520 /* The src and fib-index together determine if packet n is the same as n-1 */
1526 } ip4_local_last_check_t;
1529 ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1530 ip4_local_last_check_t *last_check, u8 *error0,
1533 const dpo_id_t *dpo0;
1534 load_balance_t *lb0;
1537 vnet_buffer (b)->ip.fib_index =
1538 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1539 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1544 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1545 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1548 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1551 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1552 * adjacency for the destination address (the local interface address).
1553 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1554 * adjacency for the source address (the remote sender's address)
1556 if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1557 (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
1560 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1563 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1564 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1565 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1567 lb0 = load_balance_get (lbi0);
1568 dpo0 = load_balance_get_bucket_i (lb0, 0);
1571 * Must have a route to source otherwise we drop the packet.
1572 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1575 * - the source is a recieve => it's from us => bogus, do this
1576 * first since it sets a different error code.
1577 * - uRPF check for any route to source - accept if passes.
1578 * - allow packets destined to the broadcast address from unknown sources
1581 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1582 && dpo0->dpoi_type == DPO_RECEIVE) ?
1583 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1584 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1585 && !fib_urpf_check_size (lb0->lb_urpf)
1586 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1587 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1589 last_check->src.as_u32 = ip0->src_address.as_u32;
1590 last_check->lbi = lbi0;
1591 last_check->error = *error0;
1592 last_check->first = 0;
1593 last_check->fib_index = vnet_buffer (b)->ip.fib_index;
1597 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1598 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1599 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1600 *error0 = last_check->error;
1605 ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1606 ip4_local_last_check_t *last_check, u8 *error,
1609 const dpo_id_t *dpo[2];
1610 load_balance_t *lb[2];
1614 not_last_hit = last_check->first;
1615 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1616 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1618 vnet_buffer (b[0])->ip.fib_index =
1619 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1620 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1621 vnet_buffer (b[0])->ip.fib_index;
1623 vnet_buffer (b[1])->ip.fib_index =
1624 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1625 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1626 vnet_buffer (b[1])->ip.fib_index;
1628 not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1629 not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1633 const receive_dpo_t *rd0, *rd1;
1634 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1635 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1636 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1637 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1641 vnet_buffer (b[0])->ip.rx_sw_if_index =
1642 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1643 vnet_buffer (b[1])->ip.rx_sw_if_index =
1644 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1648 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1649 * adjacency for the destination address (the local interface address).
1650 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1651 * adjacency for the source address (the remote sender's address)
1653 if (PREDICT_TRUE (not_last_hit))
1655 ip4_fib_forwarding_lookup_x2 (
1656 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1657 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
1659 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1660 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1661 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1663 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1664 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1665 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1667 lb[0] = load_balance_get (lbi[0]);
1668 lb[1] = load_balance_get (lbi[1]);
1670 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1671 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1673 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1674 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1675 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1676 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1677 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1678 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1679 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1681 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1682 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1683 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1684 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1685 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1686 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1687 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1689 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1690 last_check->lbi = lbi[1];
1691 last_check->error = error[1];
1692 last_check->first = 0;
1693 last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
1697 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1698 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1699 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1701 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1702 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1703 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1705 error[0] = last_check->error;
1706 error[1] = last_check->error;
1710 enum ip_local_packet_type_e
1712 IP_LOCAL_PACKET_TYPE_L4,
1713 IP_LOCAL_PACKET_TYPE_NAT,
1714 IP_LOCAL_PACKET_TYPE_FRAG,
1718 * Determine packet type and next node.
1720 * The expectation is that all packets that are not L4 will skip
1721 * checksums and source checks.
1724 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1726 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1728 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1730 *next = IP_LOCAL_NEXT_REASSEMBLY;
1731 return IP_LOCAL_PACKET_TYPE_FRAG;
1733 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1735 *next = lm->local_next_by_ip_protocol[ip->protocol];
1736 return IP_LOCAL_PACKET_TYPE_NAT;
1739 *next = lm->local_next_by_ip_protocol[ip->protocol];
1740 return IP_LOCAL_PACKET_TYPE_L4;
1744 ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1745 vlib_frame_t *frame, int head_of_feature_arc,
1748 u32 *from, n_left_from;
1749 vlib_node_runtime_t *error_node =
1750 vlib_node_get_runtime (vm, ip4_local_node.index);
1751 u16 nexts[VLIB_FRAME_SIZE], *next;
1752 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1753 ip4_header_t *ip[2];
1756 ip4_local_last_check_t last_check = {
1758 * 0.0.0.0 can appear as the source address of an IP packet,
1759 * as can any other address, hence the need to use the 'first'
1760 * member to make sure the .lbi is initialised for the first
1763 .src = { .as_u32 = 0 },
1765 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1770 from = vlib_frame_vector_args (frame);
1771 n_left_from = frame->n_vectors;
1773 if (node->flags & VLIB_NODE_FLAG_TRACE)
1774 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1776 vlib_get_buffers (vm, from, bufs, n_left_from);
1780 while (n_left_from >= 6)
1784 /* Prefetch next iteration. */
1786 vlib_prefetch_buffer_header (b[4], LOAD);
1787 vlib_prefetch_buffer_header (b[5], LOAD);
1789 clib_prefetch_load (b[4]->data);
1790 clib_prefetch_load (b[5]->data);
1793 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1795 ip[0] = vlib_buffer_get_current (b[0]);
1796 ip[1] = vlib_buffer_get_current (b[1]);
1798 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1799 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1801 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1802 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1804 not_batch = pt[0] ^ pt[1];
1806 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1809 if (PREDICT_TRUE (not_batch == 0))
1811 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1812 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
1818 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1819 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1824 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1825 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1832 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1833 head_of_feature_arc);
1834 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1835 head_of_feature_arc);
1842 while (n_left_from > 0)
1844 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1846 ip[0] = vlib_buffer_get_current (b[0]);
1847 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1848 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1850 if (head_of_feature_arc == 0 || pt[0])
1853 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1854 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1859 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1860 head_of_feature_arc);
1867 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1868 return frame->n_vectors;
1871 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1872 vlib_frame_t * frame)
1874 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1875 0 /* is_receive_dpo */);
1878 VLIB_REGISTER_NODE (ip4_local_node) =
1880 .name = "ip4-local",
1881 .vector_size = sizeof (u32),
1882 .format_trace = format_ip4_forward_next_trace,
1883 .n_errors = IP4_N_ERROR,
1884 .error_strings = ip4_error_strings,
1885 .n_next_nodes = IP_LOCAL_N_NEXT,
1888 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1889 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1890 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1891 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1892 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
1896 VLIB_NODE_FN (ip4_receive_local_node)
1897 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1899 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1900 1 /* is_receive_dpo */);
1903 VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1904 .name = "ip4-receive",
1905 .vector_size = sizeof (u32),
1906 .format_trace = format_ip4_forward_next_trace,
1907 .sibling_of = "ip4-local"
1910 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1911 vlib_node_runtime_t * node,
1912 vlib_frame_t * frame)
1914 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1915 0 /* is_receive_dpo */);
1918 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1919 .name = "ip4-local-end-of-arc",
1920 .vector_size = sizeof (u32),
1922 .format_trace = format_ip4_forward_next_trace,
1923 .sibling_of = "ip4-local",
1926 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1927 .arc_name = "ip4-local",
1928 .node_name = "ip4-local-end-of-arc",
1929 .runs_before = 0, /* not before any other features */
1932 #ifndef CLIB_MARCH_VARIANT
1934 ip4_register_protocol (u32 protocol, u32 node_index)
1936 vlib_main_t *vm = vlib_get_main ();
1937 ip4_main_t *im = &ip4_main;
1938 ip_lookup_main_t *lm = &im->lookup_main;
1940 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1941 lm->local_next_by_ip_protocol[protocol] =
1942 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1946 ip4_unregister_protocol (u32 protocol)
1948 ip4_main_t *im = &ip4_main;
1949 ip_lookup_main_t *lm = &im->lookup_main;
1951 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1952 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1956 static clib_error_t *
1957 show_ip_local_command_fn (vlib_main_t * vm,
1958 unformat_input_t * input, vlib_cli_command_t * cmd)
1960 ip4_main_t *im = &ip4_main;
1961 ip_lookup_main_t *lm = &im->lookup_main;
1964 vlib_cli_output (vm, "Protocols handled by ip4_local");
1965 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1967 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1969 u32 node_index = vlib_get_node (vm,
1970 ip4_local_node.index)->
1971 next_nodes[lm->local_next_by_ip_protocol[i]];
1972 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1973 format_vlib_node_name, vm, node_index);
1982 * Display the set of protocols handled by the local IPv4 stack.
1985 * Example of how to display local protocol table:
1986 * @cliexstart{show ip local}
1987 * Protocols handled by ip4_local
1994 VLIB_CLI_COMMAND (show_ip_local, static) =
1996 .path = "show ip local",
1997 .function = show_ip_local_command_fn,
1998 .short_help = "show ip local",
2004 IP4_REWRITE_NEXT_DROP,
2005 IP4_REWRITE_NEXT_ICMP_ERROR,
2006 IP4_REWRITE_NEXT_FRAGMENT,
2007 IP4_REWRITE_N_NEXT /* Last */
2008 } ip4_rewrite_next_t;
2011 * This bits of an IPv4 address to mask to construct a multicast
2014 #if CLIB_ARCH_IS_BIG_ENDIAN
2015 #define IP4_MCAST_ADDR_MASK 0x007fffff
2017 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2021 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2022 u16 adj_packet_bytes, bool df, u16 * next,
2023 u8 is_midchain, u32 * error)
2025 if (packet_len > adj_packet_bytes)
2027 *error = IP4_ERROR_MTU_EXCEEDED;
2030 icmp4_error_set_vnet_buffer
2031 (b, ICMP4_destination_unreachable,
2032 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2034 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2038 /* IP fragmentation */
2039 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2041 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2042 IP_FRAG_NEXT_IP_REWRITE), 0);
2043 *next = IP4_REWRITE_NEXT_FRAGMENT;
2048 /* increment TTL & update checksum.
2049 Works either endian, so no need for byte swap. */
2050 static_always_inline void
2051 ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2055 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2060 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2061 checksum += checksum >= 0xffff;
2063 ip->checksum = checksum;
2067 ASSERT (ip4_header_checksum_is_valid (ip) ||
2068 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2069 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2072 /* Decrement TTL & update checksum.
2073 Works either endian, so no need for byte swap. */
2074 static_always_inline void
2075 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2080 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2085 /* Input node should have reject packets with ttl 0. */
2086 ASSERT (ip->ttl > 0);
2088 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2089 checksum += checksum >= 0xffff;
2091 ip->checksum = checksum;
2096 * If the ttl drops below 1 when forwarding, generate
2099 if (PREDICT_FALSE (ttl <= 0))
2101 *error = IP4_ERROR_TIME_EXPIRED;
2102 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2103 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2104 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2106 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2109 /* Verify checksum. */
2110 ASSERT (ip4_header_checksum_is_valid (ip) ||
2111 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2112 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2116 ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2117 vlib_frame_t *frame, int do_counters, int is_midchain,
2120 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2121 u32 *from = vlib_frame_vector_args (frame);
2122 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2123 u16 nexts[VLIB_FRAME_SIZE], *next;
2125 vlib_node_runtime_t *error_node =
2126 vlib_node_get_runtime (vm, ip4_input_node.index);
2128 n_left_from = frame->n_vectors;
2129 u32 thread_index = vm->thread_index;
2131 vlib_get_buffers (vm, from, bufs, n_left_from);
2132 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2134 #if (CLIB_N_PREFETCHES >= 8)
2135 if (n_left_from >= 6)
2138 for (i = 2; i < 6; i++)
2139 vlib_prefetch_buffer_header (bufs[i], LOAD);
2144 while (n_left_from >= 8)
2146 const ip_adjacency_t *adj0, *adj1;
2147 ip4_header_t *ip0, *ip1;
2148 u32 rw_len0, error0, adj_index0;
2149 u32 rw_len1, error1, adj_index1;
2150 u32 tx_sw_if_index0, tx_sw_if_index1;
2155 vlib_prefetch_buffer_header (b[6], LOAD);
2156 vlib_prefetch_buffer_header (b[7], LOAD);
2159 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2160 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2163 * pre-fetch the per-adjacency counters
2167 vlib_prefetch_combined_counter (&adjacency_counters,
2168 thread_index, adj_index0);
2169 vlib_prefetch_combined_counter (&adjacency_counters,
2170 thread_index, adj_index1);
2173 ip0 = vlib_buffer_get_current (b[0]);
2174 ip1 = vlib_buffer_get_current (b[1]);
2176 error0 = error1 = IP4_ERROR_NONE;
2178 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2179 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2181 /* Rewrite packet header and updates lengths. */
2182 adj0 = adj_get (adj_index0);
2183 adj1 = adj_get (adj_index1);
2185 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2186 rw_len0 = adj0[0].rewrite_header.data_bytes;
2187 rw_len1 = adj1[0].rewrite_header.data_bytes;
2188 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2189 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2191 p = vlib_buffer_get_current (b[2]);
2192 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2193 clib_prefetch_load (p);
2195 p = vlib_buffer_get_current (b[3]);
2196 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2197 clib_prefetch_load (p);
2199 /* Check MTU of outgoing interface. */
2200 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2201 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2203 if (b[0]->flags & VNET_BUFFER_F_GSO)
2204 ip0_len = gso_mtu_sz (b[0]);
2205 if (b[1]->flags & VNET_BUFFER_F_GSO)
2206 ip1_len = gso_mtu_sz (b[1]);
2208 ip4_mtu_check (b[0], ip0_len,
2209 adj0[0].rewrite_header.max_l3_packet_bytes,
2210 ip0->flags_and_fragment_offset &
2211 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2212 next + 0, is_midchain, &error0);
2213 ip4_mtu_check (b[1], ip1_len,
2214 adj1[0].rewrite_header.max_l3_packet_bytes,
2215 ip1->flags_and_fragment_offset &
2216 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2217 next + 1, is_midchain, &error1);
2221 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2222 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2223 IP4_ERROR_SAME_INTERFACE : error0);
2224 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2225 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2226 IP4_ERROR_SAME_INTERFACE : error1);
2229 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2230 * to see the IP header */
2231 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2233 u32 next_index = adj0[0].rewrite_header.next_index;
2234 vlib_buffer_advance (b[0], -(word) rw_len0);
2236 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2237 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2240 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2241 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2244 adj0->ia_cfg_index);
2246 next[0] = next_index;
2248 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2253 b[0]->error = error_node->errors[error0];
2254 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2255 ip4_ttl_inc (b[0], ip0);
2257 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2259 u32 next_index = adj1[0].rewrite_header.next_index;
2260 vlib_buffer_advance (b[1], -(word) rw_len1);
2262 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2263 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2266 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2267 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2270 adj1->ia_cfg_index);
2271 next[1] = next_index;
2273 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
2278 b[1]->error = error_node->errors[error1];
2279 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2280 ip4_ttl_inc (b[1], ip1);
2284 /* Guess we are only writing on ipv4 header. */
2285 vnet_rewrite_two_headers (adj0[0], adj1[0],
2286 ip0, ip1, sizeof (ip4_header_t));
2288 /* Guess we are only writing on simple Ethernet header. */
2289 vnet_rewrite_two_headers (adj0[0], adj1[0],
2290 ip0, ip1, sizeof (ethernet_header_t));
2294 if (error0 == IP4_ERROR_NONE)
2295 vlib_increment_combined_counter
2296 (&adjacency_counters,
2299 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2301 if (error1 == IP4_ERROR_NONE)
2302 vlib_increment_combined_counter
2303 (&adjacency_counters,
2306 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2311 if (error0 == IP4_ERROR_NONE)
2312 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2313 if (error1 == IP4_ERROR_NONE)
2314 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2319 /* copy bytes from the IP address into the MAC rewrite */
2320 if (error0 == IP4_ERROR_NONE)
2321 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2322 adj0->rewrite_header.dst_mcast_offset,
2323 &ip0->dst_address.as_u32, (u8 *) ip0);
2324 if (error1 == IP4_ERROR_NONE)
2325 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2326 adj1->rewrite_header.dst_mcast_offset,
2327 &ip1->dst_address.as_u32, (u8 *) ip1);
2334 #elif (CLIB_N_PREFETCHES >= 4)
2337 while (n_left_from >= 1)
2339 ip_adjacency_t *adj0;
2341 u32 rw_len0, error0, adj_index0;
2342 u32 tx_sw_if_index0;
2345 /* Prefetch next iteration */
2346 if (PREDICT_TRUE (n_left_from >= 4))
2348 ip_adjacency_t *adj2;
2351 vlib_prefetch_buffer_header (b[3], LOAD);
2352 vlib_prefetch_buffer_data (b[2], LOAD);
2354 /* Prefetch adj->rewrite_header */
2355 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2356 adj2 = adj_get (adj_index2);
2358 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2362 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2365 * Prefetch the per-adjacency counters
2369 vlib_prefetch_combined_counter (&adjacency_counters,
2370 thread_index, adj_index0);
2373 ip0 = vlib_buffer_get_current (b[0]);
2375 error0 = IP4_ERROR_NONE;
2377 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2379 /* Rewrite packet header and updates lengths. */
2380 adj0 = adj_get (adj_index0);
2382 /* Rewrite header was prefetched. */
2383 rw_len0 = adj0[0].rewrite_header.data_bytes;
2384 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2386 /* Check MTU of outgoing interface. */
2387 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2389 if (b[0]->flags & VNET_BUFFER_F_GSO)
2390 ip0_len = gso_mtu_sz (b[0]);
2392 ip4_mtu_check (b[0], ip0_len,
2393 adj0[0].rewrite_header.max_l3_packet_bytes,
2394 ip0->flags_and_fragment_offset &
2395 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2396 next + 0, is_midchain, &error0);
2400 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2401 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2402 IP4_ERROR_SAME_INTERFACE : error0);
2405 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2406 * to see the IP header */
2407 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2409 u32 next_index = adj0[0].rewrite_header.next_index;
2410 vlib_buffer_advance (b[0], -(word) rw_len0);
2411 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2412 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2415 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2416 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2419 adj0->ia_cfg_index);
2420 next[0] = next_index;
2424 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2427 /* Guess we are only writing on ipv4 header. */
2428 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2431 /* Guess we are only writing on simple Ethernet header. */
2432 vnet_rewrite_one_header (adj0[0], ip0,
2433 sizeof (ethernet_header_t));
2436 * Bump the per-adjacency counters
2439 vlib_increment_combined_counter
2440 (&adjacency_counters,
2442 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2446 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2449 /* copy bytes from the IP address into the MAC rewrite */
2450 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2451 adj0->rewrite_header.dst_mcast_offset,
2452 &ip0->dst_address.as_u32, (u8 *) ip0);
2456 b[0]->error = error_node->errors[error0];
2457 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2458 ip4_ttl_inc (b[0], ip0);
2467 while (n_left_from > 0)
2469 ip_adjacency_t *adj0;
2471 u32 rw_len0, adj_index0, error0;
2472 u32 tx_sw_if_index0;
2474 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2476 adj0 = adj_get (adj_index0);
2479 vlib_prefetch_combined_counter (&adjacency_counters,
2480 thread_index, adj_index0);
2482 ip0 = vlib_buffer_get_current (b[0]);
2484 error0 = IP4_ERROR_NONE;
2486 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2489 /* Update packet buffer attributes/set output interface. */
2490 rw_len0 = adj0[0].rewrite_header.data_bytes;
2491 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2493 /* Check MTU of outgoing interface. */
2494 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2495 if (b[0]->flags & VNET_BUFFER_F_GSO)
2496 ip0_len = gso_mtu_sz (b[0]);
2498 ip4_mtu_check (b[0], ip0_len,
2499 adj0[0].rewrite_header.max_l3_packet_bytes,
2500 ip0->flags_and_fragment_offset &
2501 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2502 next + 0, is_midchain, &error0);
2506 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2507 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2508 IP4_ERROR_SAME_INTERFACE : error0);
2511 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2512 * to see the IP header */
2513 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2515 u32 next_index = adj0[0].rewrite_header.next_index;
2516 vlib_buffer_advance (b[0], -(word) rw_len0);
2517 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2518 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2521 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2522 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2525 adj0->ia_cfg_index);
2526 next[0] = next_index;
2530 /* this acts on the packet that is about to be encapped */
2531 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2534 /* Guess we are only writing on ipv4 header. */
2535 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2538 /* Guess we are only writing on simple Ethernet header. */
2539 vnet_rewrite_one_header (adj0[0], ip0,
2540 sizeof (ethernet_header_t));
2543 vlib_increment_combined_counter
2544 (&adjacency_counters,
2545 thread_index, adj_index0, 1,
2546 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2549 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2552 /* copy bytes from the IP address into the MAC rewrite */
2553 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2554 adj0->rewrite_header.dst_mcast_offset,
2555 &ip0->dst_address.as_u32, (u8 *) ip0);
2559 b[0]->error = error_node->errors[error0];
2560 /* undo the TTL decrement - we'll be back to do it again */
2561 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2562 ip4_ttl_inc (b[0], ip0);
2571 /* Need to do trace after rewrites to pick up new packet data. */
2572 if (node->flags & VLIB_NODE_FLAG_TRACE)
2573 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2575 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2576 return frame->n_vectors;
2579 /** @brief IPv4 rewrite node.
2582 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2583 header checksum, fetch the ip adjacency, check the outbound mtu,
2584 apply the adjacency rewrite, and send pkts to the adjacency
2585 rewrite header's rewrite_next_index.
2587 @param vm vlib_main_t corresponding to the current thread
2588 @param node vlib_node_runtime_t
2589 @param frame vlib_frame_t whose contents should be dispatched
2591 @par Graph mechanics: buffer metadata, next index usage
2594 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2595 - the rewrite adjacency index
2596 - <code>adj->lookup_next_index</code>
2597 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2598 the packet will be dropped.
2599 - <code>adj->rewrite_header</code>
2600 - Rewrite string length, rewrite string, next_index
2603 - <code>b->current_data, b->current_length</code>
2604 - Updated net of applying the rewrite string
2606 <em>Next Indices:</em>
2607 - <code> adj->rewrite_header.next_index </code>
2611 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, 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_rewrite_bcast_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, 0, 0);
2627 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2630 VLIB_NODE_FN (ip4_midchain_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, 1, 0);
2637 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2640 VLIB_NODE_FN (ip4_rewrite_mcast_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, 0, 1);
2647 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2650 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2651 vlib_node_runtime_t * node,
2652 vlib_frame_t * frame)
2654 if (adj_are_counters_enabled ())
2655 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2657 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2661 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2662 .name = "ip4-rewrite",
2663 .vector_size = sizeof (u32),
2665 .format_trace = format_ip4_rewrite_trace,
2667 .n_next_nodes = IP4_REWRITE_N_NEXT,
2669 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2670 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2671 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2675 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2676 .name = "ip4-rewrite-bcast",
2677 .vector_size = sizeof (u32),
2679 .format_trace = format_ip4_rewrite_trace,
2680 .sibling_of = "ip4-rewrite",
2683 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2684 .name = "ip4-rewrite-mcast",
2685 .vector_size = sizeof (u32),
2687 .format_trace = format_ip4_rewrite_trace,
2688 .sibling_of = "ip4-rewrite",
2691 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2692 .name = "ip4-mcast-midchain",
2693 .vector_size = sizeof (u32),
2695 .format_trace = format_ip4_rewrite_trace,
2696 .sibling_of = "ip4-rewrite",
2699 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2700 .name = "ip4-midchain",
2701 .vector_size = sizeof (u32),
2702 .format_trace = format_ip4_rewrite_trace,
2703 .sibling_of = "ip4-rewrite",
2707 static clib_error_t *
2708 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2709 unformat_input_t * input,
2710 vlib_cli_command_t * cmd)
2714 u32 flow_hash_config = 0;
2717 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2719 if (unformat (input, "table %d", &table_id))
2721 #define _(a, b, v) \
2722 else if (unformat (input, #a)) \
2724 flow_hash_config |= v; \
2727 foreach_flow_hash_bit
2734 return clib_error_return (0, "unknown input `%U'",
2735 format_unformat_error, input);
2737 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2743 case VNET_API_ERROR_NO_SUCH_FIB:
2744 return clib_error_return (0, "no such FIB table %d", table_id);
2747 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2755 * Configure the set of IPv4 fields used by the flow hash.
2758 * Example of how to set the flow hash on a given table:
2759 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2760 * Example of display the configured flow hash:
2761 * @cliexstart{show ip fib}
2762 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2765 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2766 * [0] [@0]: dpo-drop ip6
2769 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2770 * [0] [@0]: dpo-drop ip6
2773 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2774 * [0] [@0]: dpo-drop ip6
2777 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2778 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2781 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2782 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2783 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2784 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2785 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2788 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2789 * [0] [@0]: dpo-drop ip6
2790 * 255.255.255.255/32
2792 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2793 * [0] [@0]: dpo-drop ip6
2794 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2797 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2798 * [0] [@0]: dpo-drop ip6
2801 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2802 * [0] [@0]: dpo-drop ip6
2805 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2806 * [0] [@4]: ipv4-glean: af_packet0
2809 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2810 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2813 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2814 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2817 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2818 * [0] [@4]: ipv4-glean: af_packet1
2821 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2822 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2825 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2826 * [0] [@0]: dpo-drop ip6
2829 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2830 * [0] [@0]: dpo-drop ip6
2831 * 255.255.255.255/32
2833 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2834 * [0] [@0]: dpo-drop ip6
2838 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2840 .path = "set ip flow-hash",
2842 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2843 .function = set_ip_flow_hash_command_fn,
2847 #ifndef CLIB_MARCH_VARIANT
2849 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2852 vnet_main_t *vnm = vnet_get_main ();
2853 vnet_interface_main_t *im = &vnm->interface_main;
2854 ip4_main_t *ipm = &ip4_main;
2855 ip_lookup_main_t *lm = &ipm->lookup_main;
2856 vnet_classify_main_t *cm = &vnet_classify_main;
2857 ip4_address_t *if_addr;
2859 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2860 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2862 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2863 return VNET_API_ERROR_NO_SUCH_ENTRY;
2865 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2866 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2868 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2870 if (NULL != if_addr)
2872 fib_prefix_t pfx = {
2874 .fp_proto = FIB_PROTOCOL_IP4,
2875 .fp_addr.ip4 = *if_addr,
2879 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2883 if (table_index != (u32) ~ 0)
2885 dpo_id_t dpo = DPO_INVALID;
2890 classify_dpo_create (DPO_PROTO_IP4, table_index));
2892 fib_table_entry_special_dpo_add (fib_index,
2894 FIB_SOURCE_CLASSIFY,
2895 FIB_ENTRY_FLAG_NONE, &dpo);
2900 fib_table_entry_special_remove (fib_index,
2901 &pfx, FIB_SOURCE_CLASSIFY);
2909 static clib_error_t *
2910 set_ip_classify_command_fn (vlib_main_t * vm,
2911 unformat_input_t * input,
2912 vlib_cli_command_t * cmd)
2914 u32 table_index = ~0;
2915 int table_index_set = 0;
2916 u32 sw_if_index = ~0;
2919 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2921 if (unformat (input, "table-index %d", &table_index))
2922 table_index_set = 1;
2923 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2924 vnet_get_main (), &sw_if_index))
2930 if (table_index_set == 0)
2931 return clib_error_return (0, "classify table-index must be specified");
2933 if (sw_if_index == ~0)
2934 return clib_error_return (0, "interface / subif must be specified");
2936 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2943 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2944 return clib_error_return (0, "No such interface");
2946 case VNET_API_ERROR_NO_SUCH_ENTRY:
2947 return clib_error_return (0, "No such classifier table");
2953 * Assign a classification table to an interface. The classification
2954 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2955 * commands. Once the table is create, use this command to filter packets
2959 * Example of how to assign a classification table to an interface:
2960 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2963 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2965 .path = "set ip classify",
2967 "set ip classify intfc <interface> table-index <classify-idx>",
2968 .function = set_ip_classify_command_fn,
2973 * fd.io coding-style-patch-verification: ON
2976 * eval: (c-set-style "gnu")