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);
1524 } ip4_local_last_check_t;
1527 ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1528 ip4_local_last_check_t *last_check, u8 *error0,
1531 const dpo_id_t *dpo0;
1532 load_balance_t *lb0;
1535 vnet_buffer (b)->ip.fib_index =
1536 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1537 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1542 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1543 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1546 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1549 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1550 * adjacency for the destination address (the local interface address).
1551 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1552 * adjacency for the source address (the remote sender's address)
1554 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1557 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1560 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1561 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1562 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1564 lb0 = load_balance_get (lbi0);
1565 dpo0 = load_balance_get_bucket_i (lb0, 0);
1568 * Must have a route to source otherwise we drop the packet.
1569 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1572 * - the source is a recieve => it's from us => bogus, do this
1573 * first since it sets a different error code.
1574 * - uRPF check for any route to source - accept if passes.
1575 * - allow packets destined to the broadcast address from unknown sources
1578 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1579 && dpo0->dpoi_type == DPO_RECEIVE) ?
1580 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1581 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1582 && !fib_urpf_check_size (lb0->lb_urpf)
1583 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1584 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1586 last_check->src.as_u32 = ip0->src_address.as_u32;
1587 last_check->lbi = lbi0;
1588 last_check->error = *error0;
1589 last_check->first = 0;
1593 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1594 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1595 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1596 *error0 = last_check->error;
1601 ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1602 ip4_local_last_check_t *last_check, u8 *error,
1605 const dpo_id_t *dpo[2];
1606 load_balance_t *lb[2];
1610 not_last_hit = last_check->first;
1611 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1612 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1614 vnet_buffer (b[0])->ip.fib_index =
1615 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1616 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1617 vnet_buffer (b[0])->ip.fib_index;
1619 vnet_buffer (b[1])->ip.fib_index =
1620 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1621 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1622 vnet_buffer (b[1])->ip.fib_index;
1626 const receive_dpo_t *rd0, *rd1;
1627 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1628 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1629 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1630 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1634 vnet_buffer (b[0])->ip.rx_sw_if_index =
1635 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1636 vnet_buffer (b[1])->ip.rx_sw_if_index =
1637 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1641 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1642 * adjacency for the destination address (the local interface address).
1643 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1644 * adjacency for the source address (the remote sender's address)
1646 if (PREDICT_TRUE (not_last_hit))
1648 ip4_fib_forwarding_lookup_x2 (
1649 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1650 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
1652 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1653 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1654 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1656 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1657 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1658 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1660 lb[0] = load_balance_get (lbi[0]);
1661 lb[1] = load_balance_get (lbi[1]);
1663 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1664 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1666 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1667 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1668 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1669 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1670 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1671 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1672 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1674 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1675 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1676 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1677 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1678 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1679 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1680 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1682 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1683 last_check->lbi = lbi[1];
1684 last_check->error = error[1];
1685 last_check->first = 0;
1689 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1690 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1691 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1693 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1694 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1695 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1697 error[0] = last_check->error;
1698 error[1] = last_check->error;
1702 enum ip_local_packet_type_e
1704 IP_LOCAL_PACKET_TYPE_L4,
1705 IP_LOCAL_PACKET_TYPE_NAT,
1706 IP_LOCAL_PACKET_TYPE_FRAG,
1710 * Determine packet type and next node.
1712 * The expectation is that all packets that are not L4 will skip
1713 * checksums and source checks.
1716 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1718 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1720 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1722 *next = IP_LOCAL_NEXT_REASSEMBLY;
1723 return IP_LOCAL_PACKET_TYPE_FRAG;
1725 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1727 *next = lm->local_next_by_ip_protocol[ip->protocol];
1728 return IP_LOCAL_PACKET_TYPE_NAT;
1731 *next = lm->local_next_by_ip_protocol[ip->protocol];
1732 return IP_LOCAL_PACKET_TYPE_L4;
1736 ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1737 vlib_frame_t *frame, int head_of_feature_arc,
1740 u32 *from, n_left_from;
1741 vlib_node_runtime_t *error_node =
1742 vlib_node_get_runtime (vm, ip4_local_node.index);
1743 u16 nexts[VLIB_FRAME_SIZE], *next;
1744 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1745 ip4_header_t *ip[2];
1748 ip4_local_last_check_t last_check = {
1750 * 0.0.0.0 can appear as the source address of an IP packet,
1751 * as can any other address, hence the need to use the 'first'
1752 * member to make sure the .lbi is initialised for the first
1755 .src = {.as_u32 = 0},
1757 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1761 from = vlib_frame_vector_args (frame);
1762 n_left_from = frame->n_vectors;
1764 if (node->flags & VLIB_NODE_FLAG_TRACE)
1765 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1767 vlib_get_buffers (vm, from, bufs, n_left_from);
1771 while (n_left_from >= 6)
1775 /* Prefetch next iteration. */
1777 vlib_prefetch_buffer_header (b[4], LOAD);
1778 vlib_prefetch_buffer_header (b[5], LOAD);
1780 clib_prefetch_load (b[4]->data);
1781 clib_prefetch_load (b[5]->data);
1784 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1786 ip[0] = vlib_buffer_get_current (b[0]);
1787 ip[1] = vlib_buffer_get_current (b[1]);
1789 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1790 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1792 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1793 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1795 not_batch = pt[0] ^ pt[1];
1797 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1800 if (PREDICT_TRUE (not_batch == 0))
1802 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1803 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
1809 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1810 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1815 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1816 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1823 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1824 head_of_feature_arc);
1825 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1826 head_of_feature_arc);
1833 while (n_left_from > 0)
1835 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1837 ip[0] = vlib_buffer_get_current (b[0]);
1838 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1839 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1841 if (head_of_feature_arc == 0 || pt[0])
1844 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1845 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1850 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1851 head_of_feature_arc);
1858 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1859 return frame->n_vectors;
1862 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1863 vlib_frame_t * frame)
1865 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1866 0 /* is_receive_dpo */);
1869 VLIB_REGISTER_NODE (ip4_local_node) =
1871 .name = "ip4-local",
1872 .vector_size = sizeof (u32),
1873 .format_trace = format_ip4_forward_next_trace,
1874 .n_errors = IP4_N_ERROR,
1875 .error_strings = ip4_error_strings,
1876 .n_next_nodes = IP_LOCAL_N_NEXT,
1879 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1880 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1881 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1882 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1883 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
1887 VLIB_NODE_FN (ip4_receive_local_node)
1888 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1890 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1891 1 /* is_receive_dpo */);
1894 VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1895 .name = "ip4-receive",
1896 .vector_size = sizeof (u32),
1897 .format_trace = format_ip4_forward_next_trace,
1898 .sibling_of = "ip4-local"
1901 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1902 vlib_node_runtime_t * node,
1903 vlib_frame_t * frame)
1905 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1906 0 /* is_receive_dpo */);
1909 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1910 .name = "ip4-local-end-of-arc",
1911 .vector_size = sizeof (u32),
1913 .format_trace = format_ip4_forward_next_trace,
1914 .sibling_of = "ip4-local",
1917 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1918 .arc_name = "ip4-local",
1919 .node_name = "ip4-local-end-of-arc",
1920 .runs_before = 0, /* not before any other features */
1923 #ifndef CLIB_MARCH_VARIANT
1925 ip4_register_protocol (u32 protocol, u32 node_index)
1927 vlib_main_t *vm = vlib_get_main ();
1928 ip4_main_t *im = &ip4_main;
1929 ip_lookup_main_t *lm = &im->lookup_main;
1931 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1932 lm->local_next_by_ip_protocol[protocol] =
1933 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1937 ip4_unregister_protocol (u32 protocol)
1939 ip4_main_t *im = &ip4_main;
1940 ip_lookup_main_t *lm = &im->lookup_main;
1942 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1943 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1947 static clib_error_t *
1948 show_ip_local_command_fn (vlib_main_t * vm,
1949 unformat_input_t * input, vlib_cli_command_t * cmd)
1951 ip4_main_t *im = &ip4_main;
1952 ip_lookup_main_t *lm = &im->lookup_main;
1955 vlib_cli_output (vm, "Protocols handled by ip4_local");
1956 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1958 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1960 u32 node_index = vlib_get_node (vm,
1961 ip4_local_node.index)->
1962 next_nodes[lm->local_next_by_ip_protocol[i]];
1963 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1964 format_vlib_node_name, vm, node_index);
1973 * Display the set of protocols handled by the local IPv4 stack.
1976 * Example of how to display local protocol table:
1977 * @cliexstart{show ip local}
1978 * Protocols handled by ip4_local
1985 VLIB_CLI_COMMAND (show_ip_local, static) =
1987 .path = "show ip local",
1988 .function = show_ip_local_command_fn,
1989 .short_help = "show ip local",
1995 IP4_REWRITE_NEXT_DROP,
1996 IP4_REWRITE_NEXT_ICMP_ERROR,
1997 IP4_REWRITE_NEXT_FRAGMENT,
1998 IP4_REWRITE_N_NEXT /* Last */
1999 } ip4_rewrite_next_t;
2002 * This bits of an IPv4 address to mask to construct a multicast
2005 #if CLIB_ARCH_IS_BIG_ENDIAN
2006 #define IP4_MCAST_ADDR_MASK 0x007fffff
2008 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2012 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2013 u16 adj_packet_bytes, bool df, u16 * next,
2014 u8 is_midchain, u32 * error)
2016 if (packet_len > adj_packet_bytes)
2018 *error = IP4_ERROR_MTU_EXCEEDED;
2021 icmp4_error_set_vnet_buffer
2022 (b, ICMP4_destination_unreachable,
2023 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2025 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2029 /* IP fragmentation */
2030 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2032 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2033 IP_FRAG_NEXT_IP_REWRITE), 0);
2034 *next = IP4_REWRITE_NEXT_FRAGMENT;
2039 /* increment TTL & update checksum.
2040 Works either endian, so no need for byte swap. */
2041 static_always_inline void
2042 ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2046 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2051 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2052 checksum += checksum >= 0xffff;
2054 ip->checksum = checksum;
2058 ASSERT (ip4_header_checksum_is_valid (ip) ||
2059 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2060 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2063 /* Decrement TTL & update checksum.
2064 Works either endian, so no need for byte swap. */
2065 static_always_inline void
2066 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2071 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2076 /* Input node should have reject packets with ttl 0. */
2077 ASSERT (ip->ttl > 0);
2079 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2080 checksum += checksum >= 0xffff;
2082 ip->checksum = checksum;
2087 * If the ttl drops below 1 when forwarding, generate
2090 if (PREDICT_FALSE (ttl <= 0))
2092 *error = IP4_ERROR_TIME_EXPIRED;
2093 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2094 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2095 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2097 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2100 /* Verify checksum. */
2101 ASSERT (ip4_header_checksum_is_valid (ip) ||
2102 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2103 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2107 ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2108 vlib_frame_t *frame, int do_counters, int is_midchain,
2111 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2112 u32 *from = vlib_frame_vector_args (frame);
2113 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2114 u16 nexts[VLIB_FRAME_SIZE], *next;
2116 vlib_node_runtime_t *error_node =
2117 vlib_node_get_runtime (vm, ip4_input_node.index);
2119 n_left_from = frame->n_vectors;
2120 u32 thread_index = vm->thread_index;
2122 vlib_get_buffers (vm, from, bufs, n_left_from);
2123 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2125 #if (CLIB_N_PREFETCHES >= 8)
2126 if (n_left_from >= 6)
2129 for (i = 2; i < 6; i++)
2130 vlib_prefetch_buffer_header (bufs[i], LOAD);
2135 while (n_left_from >= 8)
2137 const ip_adjacency_t *adj0, *adj1;
2138 ip4_header_t *ip0, *ip1;
2139 u32 rw_len0, error0, adj_index0;
2140 u32 rw_len1, error1, adj_index1;
2141 u32 tx_sw_if_index0, tx_sw_if_index1;
2146 vlib_prefetch_buffer_header (b[6], LOAD);
2147 vlib_prefetch_buffer_header (b[7], LOAD);
2150 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2151 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2154 * pre-fetch the per-adjacency counters
2158 vlib_prefetch_combined_counter (&adjacency_counters,
2159 thread_index, adj_index0);
2160 vlib_prefetch_combined_counter (&adjacency_counters,
2161 thread_index, adj_index1);
2164 ip0 = vlib_buffer_get_current (b[0]);
2165 ip1 = vlib_buffer_get_current (b[1]);
2167 error0 = error1 = IP4_ERROR_NONE;
2169 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2170 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2172 /* Rewrite packet header and updates lengths. */
2173 adj0 = adj_get (adj_index0);
2174 adj1 = adj_get (adj_index1);
2176 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2177 rw_len0 = adj0[0].rewrite_header.data_bytes;
2178 rw_len1 = adj1[0].rewrite_header.data_bytes;
2179 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2180 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2182 p = vlib_buffer_get_current (b[2]);
2183 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2184 clib_prefetch_load (p);
2186 p = vlib_buffer_get_current (b[3]);
2187 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2188 clib_prefetch_load (p);
2190 /* Check MTU of outgoing interface. */
2191 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2192 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2194 if (b[0]->flags & VNET_BUFFER_F_GSO)
2195 ip0_len = gso_mtu_sz (b[0]);
2196 if (b[1]->flags & VNET_BUFFER_F_GSO)
2197 ip1_len = gso_mtu_sz (b[1]);
2199 ip4_mtu_check (b[0], ip0_len,
2200 adj0[0].rewrite_header.max_l3_packet_bytes,
2201 ip0->flags_and_fragment_offset &
2202 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2203 next + 0, is_midchain, &error0);
2204 ip4_mtu_check (b[1], ip1_len,
2205 adj1[0].rewrite_header.max_l3_packet_bytes,
2206 ip1->flags_and_fragment_offset &
2207 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2208 next + 1, is_midchain, &error1);
2212 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2213 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2214 IP4_ERROR_SAME_INTERFACE : error0);
2215 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2216 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2217 IP4_ERROR_SAME_INTERFACE : error1);
2220 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2221 * to see the IP header */
2222 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2224 u32 next_index = adj0[0].rewrite_header.next_index;
2225 vlib_buffer_advance (b[0], -(word) rw_len0);
2227 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2228 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2231 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2232 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2235 adj0->ia_cfg_index);
2237 next[0] = next_index;
2239 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2244 b[0]->error = error_node->errors[error0];
2245 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2246 ip4_ttl_inc (b[0], ip0);
2248 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2250 u32 next_index = adj1[0].rewrite_header.next_index;
2251 vlib_buffer_advance (b[1], -(word) rw_len1);
2253 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2254 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2257 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2258 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2261 adj1->ia_cfg_index);
2262 next[1] = next_index;
2264 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
2269 b[1]->error = error_node->errors[error1];
2270 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2271 ip4_ttl_inc (b[1], ip1);
2275 /* Guess we are only writing on ipv4 header. */
2276 vnet_rewrite_two_headers (adj0[0], adj1[0],
2277 ip0, ip1, sizeof (ip4_header_t));
2279 /* Guess we are only writing on simple Ethernet header. */
2280 vnet_rewrite_two_headers (adj0[0], adj1[0],
2281 ip0, ip1, sizeof (ethernet_header_t));
2285 if (error0 == IP4_ERROR_NONE)
2286 vlib_increment_combined_counter
2287 (&adjacency_counters,
2290 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2292 if (error1 == IP4_ERROR_NONE)
2293 vlib_increment_combined_counter
2294 (&adjacency_counters,
2297 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2302 if (error0 == IP4_ERROR_NONE)
2303 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2304 if (error1 == IP4_ERROR_NONE)
2305 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2310 /* copy bytes from the IP address into the MAC rewrite */
2311 if (error0 == IP4_ERROR_NONE)
2312 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2313 adj0->rewrite_header.dst_mcast_offset,
2314 &ip0->dst_address.as_u32, (u8 *) ip0);
2315 if (error1 == IP4_ERROR_NONE)
2316 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2317 adj1->rewrite_header.dst_mcast_offset,
2318 &ip1->dst_address.as_u32, (u8 *) ip1);
2325 #elif (CLIB_N_PREFETCHES >= 4)
2328 while (n_left_from >= 1)
2330 ip_adjacency_t *adj0;
2332 u32 rw_len0, error0, adj_index0;
2333 u32 tx_sw_if_index0;
2336 /* Prefetch next iteration */
2337 if (PREDICT_TRUE (n_left_from >= 4))
2339 ip_adjacency_t *adj2;
2342 vlib_prefetch_buffer_header (b[3], LOAD);
2343 vlib_prefetch_buffer_data (b[2], LOAD);
2345 /* Prefetch adj->rewrite_header */
2346 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2347 adj2 = adj_get (adj_index2);
2349 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2353 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2356 * Prefetch the per-adjacency counters
2360 vlib_prefetch_combined_counter (&adjacency_counters,
2361 thread_index, adj_index0);
2364 ip0 = vlib_buffer_get_current (b[0]);
2366 error0 = IP4_ERROR_NONE;
2368 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2370 /* Rewrite packet header and updates lengths. */
2371 adj0 = adj_get (adj_index0);
2373 /* Rewrite header was prefetched. */
2374 rw_len0 = adj0[0].rewrite_header.data_bytes;
2375 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2377 /* Check MTU of outgoing interface. */
2378 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2380 if (b[0]->flags & VNET_BUFFER_F_GSO)
2381 ip0_len = gso_mtu_sz (b[0]);
2383 ip4_mtu_check (b[0], ip0_len,
2384 adj0[0].rewrite_header.max_l3_packet_bytes,
2385 ip0->flags_and_fragment_offset &
2386 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2387 next + 0, is_midchain, &error0);
2391 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2392 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2393 IP4_ERROR_SAME_INTERFACE : error0);
2396 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2397 * to see the IP header */
2398 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2400 u32 next_index = adj0[0].rewrite_header.next_index;
2401 vlib_buffer_advance (b[0], -(word) rw_len0);
2402 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2403 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2406 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2407 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2410 adj0->ia_cfg_index);
2411 next[0] = next_index;
2415 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2418 /* Guess we are only writing on ipv4 header. */
2419 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2422 /* Guess we are only writing on simple Ethernet header. */
2423 vnet_rewrite_one_header (adj0[0], ip0,
2424 sizeof (ethernet_header_t));
2427 * Bump the per-adjacency counters
2430 vlib_increment_combined_counter
2431 (&adjacency_counters,
2433 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2437 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2440 /* copy bytes from the IP address into the MAC rewrite */
2441 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2442 adj0->rewrite_header.dst_mcast_offset,
2443 &ip0->dst_address.as_u32, (u8 *) ip0);
2447 b[0]->error = error_node->errors[error0];
2448 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2449 ip4_ttl_inc (b[0], ip0);
2458 while (n_left_from > 0)
2460 ip_adjacency_t *adj0;
2462 u32 rw_len0, adj_index0, error0;
2463 u32 tx_sw_if_index0;
2465 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2467 adj0 = adj_get (adj_index0);
2470 vlib_prefetch_combined_counter (&adjacency_counters,
2471 thread_index, adj_index0);
2473 ip0 = vlib_buffer_get_current (b[0]);
2475 error0 = IP4_ERROR_NONE;
2477 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2480 /* Update packet buffer attributes/set output interface. */
2481 rw_len0 = adj0[0].rewrite_header.data_bytes;
2482 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2484 /* Check MTU of outgoing interface. */
2485 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2486 if (b[0]->flags & VNET_BUFFER_F_GSO)
2487 ip0_len = gso_mtu_sz (b[0]);
2489 ip4_mtu_check (b[0], ip0_len,
2490 adj0[0].rewrite_header.max_l3_packet_bytes,
2491 ip0->flags_and_fragment_offset &
2492 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2493 next + 0, is_midchain, &error0);
2497 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2498 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2499 IP4_ERROR_SAME_INTERFACE : error0);
2502 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2503 * to see the IP header */
2504 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2506 u32 next_index = adj0[0].rewrite_header.next_index;
2507 vlib_buffer_advance (b[0], -(word) rw_len0);
2508 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2509 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2512 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2513 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2516 adj0->ia_cfg_index);
2517 next[0] = next_index;
2521 /* this acts on the packet that is about to be encapped */
2522 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2525 /* Guess we are only writing on ipv4 header. */
2526 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2529 /* Guess we are only writing on simple Ethernet header. */
2530 vnet_rewrite_one_header (adj0[0], ip0,
2531 sizeof (ethernet_header_t));
2534 vlib_increment_combined_counter
2535 (&adjacency_counters,
2536 thread_index, adj_index0, 1,
2537 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2540 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2543 /* copy bytes from the IP address into the MAC rewrite */
2544 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2545 adj0->rewrite_header.dst_mcast_offset,
2546 &ip0->dst_address.as_u32, (u8 *) ip0);
2550 b[0]->error = error_node->errors[error0];
2551 /* undo the TTL decrement - we'll be back to do it again */
2552 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2553 ip4_ttl_inc (b[0], ip0);
2562 /* Need to do trace after rewrites to pick up new packet data. */
2563 if (node->flags & VLIB_NODE_FLAG_TRACE)
2564 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2566 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2567 return frame->n_vectors;
2570 /** @brief IPv4 rewrite node.
2573 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2574 header checksum, fetch the ip adjacency, check the outbound mtu,
2575 apply the adjacency rewrite, and send pkts to the adjacency
2576 rewrite header's rewrite_next_index.
2578 @param vm vlib_main_t corresponding to the current thread
2579 @param node vlib_node_runtime_t
2580 @param frame vlib_frame_t whose contents should be dispatched
2582 @par Graph mechanics: buffer metadata, next index usage
2585 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2586 - the rewrite adjacency index
2587 - <code>adj->lookup_next_index</code>
2588 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2589 the packet will be dropped.
2590 - <code>adj->rewrite_header</code>
2591 - Rewrite string length, rewrite string, next_index
2594 - <code>b->current_data, b->current_length</code>
2595 - Updated net of applying the rewrite string
2597 <em>Next Indices:</em>
2598 - <code> adj->rewrite_header.next_index </code>
2602 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2603 vlib_frame_t * frame)
2605 if (adj_are_counters_enabled ())
2606 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2608 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2611 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2612 vlib_node_runtime_t * node,
2613 vlib_frame_t * frame)
2615 if (adj_are_counters_enabled ())
2616 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2618 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2621 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2622 vlib_node_runtime_t * node,
2623 vlib_frame_t * frame)
2625 if (adj_are_counters_enabled ())
2626 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2628 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2631 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2632 vlib_node_runtime_t * node,
2633 vlib_frame_t * frame)
2635 if (adj_are_counters_enabled ())
2636 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2638 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2641 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2642 vlib_node_runtime_t * node,
2643 vlib_frame_t * frame)
2645 if (adj_are_counters_enabled ())
2646 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2648 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2652 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2653 .name = "ip4-rewrite",
2654 .vector_size = sizeof (u32),
2656 .format_trace = format_ip4_rewrite_trace,
2658 .n_next_nodes = IP4_REWRITE_N_NEXT,
2660 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2661 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2662 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2666 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2667 .name = "ip4-rewrite-bcast",
2668 .vector_size = sizeof (u32),
2670 .format_trace = format_ip4_rewrite_trace,
2671 .sibling_of = "ip4-rewrite",
2674 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2675 .name = "ip4-rewrite-mcast",
2676 .vector_size = sizeof (u32),
2678 .format_trace = format_ip4_rewrite_trace,
2679 .sibling_of = "ip4-rewrite",
2682 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2683 .name = "ip4-mcast-midchain",
2684 .vector_size = sizeof (u32),
2686 .format_trace = format_ip4_rewrite_trace,
2687 .sibling_of = "ip4-rewrite",
2690 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2691 .name = "ip4-midchain",
2692 .vector_size = sizeof (u32),
2693 .format_trace = format_ip4_rewrite_trace,
2694 .sibling_of = "ip4-rewrite",
2698 static clib_error_t *
2699 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2700 unformat_input_t * input,
2701 vlib_cli_command_t * cmd)
2705 u32 flow_hash_config = 0;
2708 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2710 if (unformat (input, "table %d", &table_id))
2712 #define _(a, b, v) \
2713 else if (unformat (input, #a)) \
2715 flow_hash_config |= v; \
2718 foreach_flow_hash_bit
2725 return clib_error_return (0, "unknown input `%U'",
2726 format_unformat_error, input);
2728 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2734 case VNET_API_ERROR_NO_SUCH_FIB:
2735 return clib_error_return (0, "no such FIB table %d", table_id);
2738 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2746 * Configure the set of IPv4 fields used by the flow hash.
2749 * Example of how to set the flow hash on a given table:
2750 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2751 * Example of display the configured flow hash:
2752 * @cliexstart{show ip fib}
2753 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2756 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2757 * [0] [@0]: dpo-drop ip6
2760 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2761 * [0] [@0]: dpo-drop ip6
2764 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2765 * [0] [@0]: dpo-drop ip6
2768 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2769 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2772 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2773 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2774 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2775 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2776 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2779 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2780 * [0] [@0]: dpo-drop ip6
2781 * 255.255.255.255/32
2783 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2784 * [0] [@0]: dpo-drop ip6
2785 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2788 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2789 * [0] [@0]: dpo-drop ip6
2792 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2793 * [0] [@0]: dpo-drop ip6
2796 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2797 * [0] [@4]: ipv4-glean: af_packet0
2800 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2801 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2804 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2805 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2808 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2809 * [0] [@4]: ipv4-glean: af_packet1
2812 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2813 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2816 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2817 * [0] [@0]: dpo-drop ip6
2820 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2821 * [0] [@0]: dpo-drop ip6
2822 * 255.255.255.255/32
2824 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2825 * [0] [@0]: dpo-drop ip6
2829 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2831 .path = "set ip flow-hash",
2833 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2834 .function = set_ip_flow_hash_command_fn,
2838 #ifndef CLIB_MARCH_VARIANT
2840 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2843 vnet_main_t *vnm = vnet_get_main ();
2844 vnet_interface_main_t *im = &vnm->interface_main;
2845 ip4_main_t *ipm = &ip4_main;
2846 ip_lookup_main_t *lm = &ipm->lookup_main;
2847 vnet_classify_main_t *cm = &vnet_classify_main;
2848 ip4_address_t *if_addr;
2850 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2851 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2853 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2854 return VNET_API_ERROR_NO_SUCH_ENTRY;
2856 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2857 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2859 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2861 if (NULL != if_addr)
2863 fib_prefix_t pfx = {
2865 .fp_proto = FIB_PROTOCOL_IP4,
2866 .fp_addr.ip4 = *if_addr,
2870 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2874 if (table_index != (u32) ~ 0)
2876 dpo_id_t dpo = DPO_INVALID;
2881 classify_dpo_create (DPO_PROTO_IP4, table_index));
2883 fib_table_entry_special_dpo_add (fib_index,
2885 FIB_SOURCE_CLASSIFY,
2886 FIB_ENTRY_FLAG_NONE, &dpo);
2891 fib_table_entry_special_remove (fib_index,
2892 &pfx, FIB_SOURCE_CLASSIFY);
2900 static clib_error_t *
2901 set_ip_classify_command_fn (vlib_main_t * vm,
2902 unformat_input_t * input,
2903 vlib_cli_command_t * cmd)
2905 u32 table_index = ~0;
2906 int table_index_set = 0;
2907 u32 sw_if_index = ~0;
2910 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2912 if (unformat (input, "table-index %d", &table_index))
2913 table_index_set = 1;
2914 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2915 vnet_get_main (), &sw_if_index))
2921 if (table_index_set == 0)
2922 return clib_error_return (0, "classify table-index must be specified");
2924 if (sw_if_index == ~0)
2925 return clib_error_return (0, "interface / subif must be specified");
2927 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2934 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2935 return clib_error_return (0, "No such interface");
2937 case VNET_API_ERROR_NO_SUCH_ENTRY:
2938 return clib_error_return (0, "No such classifier table");
2944 * Assign a classification table to an interface. The classification
2945 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2946 * commands. Once the table is create, use this command to filter packets
2950 * Example of how to assign a classification table to an interface:
2951 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2954 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2956 .path = "set ip classify",
2958 "set ip classify intfc <interface> table-index <classify-idx>",
2959 .function = set_ip_classify_command_fn,
2964 * fd.io coding-style-patch-verification: ON
2967 * eval: (c-set-style "gnu")