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);
106 VLIB_REGISTER_NODE (ip4_lookup_node) =
108 .name = "ip4-lookup",
109 .vector_size = sizeof (u32),
110 .format_trace = format_ip4_lookup_trace,
111 .n_next_nodes = IP_LOOKUP_N_NEXT,
112 .next_nodes = IP4_LOOKUP_NEXT_NODES,
115 VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
116 vlib_node_runtime_t * node,
117 vlib_frame_t * frame)
119 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
121 u32 thread_index = vm->thread_index;
122 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
123 u16 nexts[VLIB_FRAME_SIZE], *next;
125 from = vlib_frame_vector_args (frame);
126 n_left = frame->n_vectors;
129 vlib_get_buffers (vm, from, bufs, n_left);
133 const load_balance_t *lb0, *lb1;
134 const ip4_header_t *ip0, *ip1;
135 u32 lbi0, hc0, lbi1, hc1;
136 const dpo_id_t *dpo0, *dpo1;
138 /* Prefetch next iteration. */
140 vlib_prefetch_buffer_header (b[2], LOAD);
141 vlib_prefetch_buffer_header (b[3], LOAD);
143 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
144 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
147 ip0 = vlib_buffer_get_current (b[0]);
148 ip1 = vlib_buffer_get_current (b[1]);
149 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
150 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
152 lb0 = load_balance_get (lbi0);
153 lb1 = load_balance_get (lbi1);
156 * this node is for via FIBs we can re-use the hash value from the
157 * to node if present.
158 * We don't want to use the same hash value at each level in the recursion
159 * graph as that would lead to polarisation
163 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
165 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
167 hc0 = vnet_buffer (b[0])->ip.flow_hash =
168 vnet_buffer (b[0])->ip.flow_hash >> 1;
172 hc0 = vnet_buffer (b[0])->ip.flow_hash =
173 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
175 dpo0 = load_balance_get_fwd_bucket
176 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
180 dpo0 = load_balance_get_bucket_i (lb0, 0);
182 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
184 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
186 hc1 = vnet_buffer (b[1])->ip.flow_hash =
187 vnet_buffer (b[1])->ip.flow_hash >> 1;
191 hc1 = vnet_buffer (b[1])->ip.flow_hash =
192 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
194 dpo1 = load_balance_get_fwd_bucket
195 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
199 dpo1 = load_balance_get_bucket_i (lb1, 0);
202 next[0] = dpo0->dpoi_next_node;
203 next[1] = dpo1->dpoi_next_node;
205 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
206 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
208 vlib_increment_combined_counter
209 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
210 vlib_increment_combined_counter
211 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
220 const load_balance_t *lb0;
221 const ip4_header_t *ip0;
222 const dpo_id_t *dpo0;
225 ip0 = vlib_buffer_get_current (b[0]);
226 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
228 lb0 = load_balance_get (lbi0);
231 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
233 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
235 hc0 = vnet_buffer (b[0])->ip.flow_hash =
236 vnet_buffer (b[0])->ip.flow_hash >> 1;
240 hc0 = vnet_buffer (b[0])->ip.flow_hash =
241 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
243 dpo0 = load_balance_get_fwd_bucket
244 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
248 dpo0 = load_balance_get_bucket_i (lb0, 0);
251 next[0] = dpo0->dpoi_next_node;
252 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
254 vlib_increment_combined_counter
255 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
262 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
263 if (node->flags & VLIB_NODE_FLAG_TRACE)
264 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
266 return frame->n_vectors;
269 VLIB_REGISTER_NODE (ip4_load_balance_node) =
271 .name = "ip4-load-balance",
272 .vector_size = sizeof (u32),
273 .sibling_of = "ip4-lookup",
274 .format_trace = format_ip4_lookup_trace,
277 #ifndef CLIB_MARCH_VARIANT
278 /* get first interface address */
280 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
281 ip_interface_address_t ** result_ia)
283 ip_lookup_main_t *lm = &im->lookup_main;
284 ip_interface_address_t *ia = 0;
285 ip4_address_t *result = 0;
287 foreach_ip_interface_address
288 (lm, ia, sw_if_index,
289 1 /* honor unnumbered */ ,
292 ip_interface_address_get_address (lm, ia);
297 *result_ia = result ? ia : 0;
303 ip4_add_subnet_bcast_route (u32 fib_index,
307 vnet_sw_interface_flags_t iflags;
309 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
311 fib_table_entry_special_remove(fib_index,
313 FIB_SOURCE_INTERFACE);
315 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
317 fib_table_entry_update_one_path (fib_index, pfx,
318 FIB_SOURCE_INTERFACE,
321 /* No next-hop address */
327 // no out-label stack
329 FIB_ROUTE_PATH_FLAG_NONE);
333 fib_table_entry_special_add(fib_index,
335 FIB_SOURCE_INTERFACE,
336 (FIB_ENTRY_FLAG_DROP |
337 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
342 ip4_add_interface_prefix_routes (ip4_main_t *im,
345 ip_interface_address_t * a)
347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip_interface_prefix_t *if_prefix;
349 ip4_address_t *address = ip_interface_address_get_address (lm, a);
351 ip_interface_prefix_key_t key = {
353 .fp_len = a->address_length,
354 .fp_proto = FIB_PROTOCOL_IP4,
355 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
357 .sw_if_index = sw_if_index,
360 fib_prefix_t pfx_special = {
361 .fp_proto = FIB_PROTOCOL_IP4,
364 /* If prefix already set on interface, just increment ref count & return */
365 if_prefix = ip_get_interface_prefix (lm, &key);
368 if_prefix->ref_count += 1;
372 /* New prefix - allocate a pool entry, initialize it, add to the hash */
373 pool_get (lm->if_prefix_pool, if_prefix);
374 if_prefix->ref_count = 1;
375 if_prefix->src_ia_index = a - lm->if_address_pool;
376 clib_memcpy (&if_prefix->key, &key, sizeof (key));
377 mhash_set (&lm->prefix_to_if_prefix_index, &key,
378 if_prefix - lm->if_prefix_pool, 0 /* old value */);
380 pfx_special.fp_len = a->address_length;
381 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
383 /* set the glean route for the prefix */
384 fib_table_entry_update_one_path (fib_index, &pfx_special,
385 FIB_SOURCE_INTERFACE,
386 (FIB_ENTRY_FLAG_CONNECTED |
387 FIB_ENTRY_FLAG_ATTACHED),
389 /* No next-hop address */
392 /* invalid FIB index */
395 /* no out-label stack */
397 FIB_ROUTE_PATH_FLAG_NONE);
399 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
400 if (a->address_length <= 30)
402 /* set a drop route for the base address of the prefix */
403 pfx_special.fp_len = 32;
404 pfx_special.fp_addr.ip4.as_u32 =
405 address->as_u32 & im->fib_masks[a->address_length];
407 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
408 fib_table_entry_special_add (fib_index, &pfx_special,
409 FIB_SOURCE_INTERFACE,
410 (FIB_ENTRY_FLAG_DROP |
411 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
413 /* set a route for the broadcast address of the prefix */
414 pfx_special.fp_len = 32;
415 pfx_special.fp_addr.ip4.as_u32 =
416 address->as_u32 | ~im->fib_masks[a->address_length];
417 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
418 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
422 /* length == 31 - add an attached route for the other address */
423 else if (a->address_length == 31)
425 pfx_special.fp_len = 32;
426 pfx_special.fp_addr.ip4.as_u32 =
427 address->as_u32 ^ clib_host_to_net_u32(1);
429 fib_table_entry_update_one_path (fib_index, &pfx_special,
430 FIB_SOURCE_INTERFACE,
431 (FIB_ENTRY_FLAG_ATTACHED),
433 &pfx_special.fp_addr,
435 /* invalid FIB index */
439 FIB_ROUTE_PATH_FLAG_NONE);
444 ip4_add_interface_routes (u32 sw_if_index,
445 ip4_main_t * im, u32 fib_index,
446 ip_interface_address_t * a)
448 ip_lookup_main_t *lm = &im->lookup_main;
449 ip4_address_t *address = ip_interface_address_get_address (lm, a);
452 .fp_proto = FIB_PROTOCOL_IP4,
453 .fp_addr.ip4 = *address,
456 /* set special routes for the prefix if needed */
457 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
459 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
461 u32 classify_table_index =
462 lm->classify_table_index_by_sw_if_index[sw_if_index];
463 if (classify_table_index != (u32) ~ 0)
465 dpo_id_t dpo = DPO_INVALID;
470 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
472 fib_table_entry_special_dpo_add (fib_index,
475 FIB_ENTRY_FLAG_NONE, &dpo);
480 fib_table_entry_update_one_path (fib_index, &pfx,
481 FIB_SOURCE_INTERFACE,
482 (FIB_ENTRY_FLAG_CONNECTED |
483 FIB_ENTRY_FLAG_LOCAL),
490 FIB_ROUTE_PATH_FLAG_NONE);
494 ip4_del_interface_prefix_routes (ip4_main_t * im,
497 ip4_address_t * address,
500 ip_lookup_main_t *lm = &im->lookup_main;
501 ip_interface_prefix_t *if_prefix;
503 ip_interface_prefix_key_t key = {
505 .fp_len = address_length,
506 .fp_proto = FIB_PROTOCOL_IP4,
507 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
509 .sw_if_index = sw_if_index,
512 fib_prefix_t pfx_special = {
514 .fp_proto = FIB_PROTOCOL_IP4,
517 if_prefix = ip_get_interface_prefix (lm, &key);
520 clib_warning ("Prefix not found while deleting %U",
521 format_ip4_address_and_length, address, address_length);
525 if_prefix->ref_count -= 1;
528 * Routes need to be adjusted if deleting last intf addr in prefix
530 * We're done now otherwise
532 if (if_prefix->ref_count > 0)
535 /* length <= 30, delete glean route, first address, last address */
536 if (address_length <= 30)
538 /* Less work to do in FIB if we remove the covered /32s first */
540 /* first address in prefix */
541 pfx_special.fp_addr.ip4.as_u32 =
542 address->as_u32 & im->fib_masks[address_length];
543 pfx_special.fp_len = 32;
545 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
546 fib_table_entry_special_remove (fib_index,
548 FIB_SOURCE_INTERFACE);
550 /* prefix broadcast address */
551 pfx_special.fp_addr.ip4.as_u32 =
552 address->as_u32 | ~im->fib_masks[address_length];
553 pfx_special.fp_len = 32;
555 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
556 fib_table_entry_special_remove (fib_index,
558 FIB_SOURCE_INTERFACE);
560 else if (address_length == 31)
562 /* length == 31, delete attached route for the other address */
563 pfx_special.fp_addr.ip4.as_u32 =
564 address->as_u32 ^ clib_host_to_net_u32(1);
566 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
569 /* remove glean route for prefix */
570 pfx_special.fp_addr.ip4 = *address;
571 pfx_special.fp_len = address_length;
572 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
574 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
575 pool_put (lm->if_prefix_pool, if_prefix);
579 ip4_del_interface_routes (u32 sw_if_index,
582 ip4_address_t * address, u32 address_length)
586 .fp_proto = FIB_PROTOCOL_IP4,
587 .fp_addr.ip4 = *address,
590 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
592 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
593 address, address_length);
596 #ifndef CLIB_MARCH_VARIANT
598 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
600 ip4_main_t *im = &ip4_main;
601 vnet_main_t *vnm = vnet_get_main ();
602 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
604 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
607 * enable/disable only on the 1<->0 transition
611 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
616 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
617 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
620 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
624 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
625 sw_if_index, !is_enable, 0, 0);
629 else if (hi->l3_if_count)
633 ip4_enable_disable_interface_callback_t *cb;
634 vec_foreach (cb, im->enable_disable_interface_callbacks)
635 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
639 static clib_error_t *
640 ip4_add_del_interface_address_internal (vlib_main_t * vm,
642 ip4_address_t * address,
643 u32 address_length, u32 is_del)
645 vnet_main_t *vnm = vnet_get_main ();
646 ip4_main_t *im = &ip4_main;
647 ip_lookup_main_t *lm = &im->lookup_main;
648 clib_error_t *error = 0;
649 u32 if_address_index;
650 ip4_address_fib_t ip4_af, *addr_fib = 0;
652 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
655 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
659 ip4_addr_fib_init (&ip4_af, address,
660 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
661 vec_add1 (addr_fib, ip4_af);
664 * there is no support for adj-fib handling in the presence of overlapping
665 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
670 /* When adding an address check that it does not conflict
671 with an existing address on any interface in this table. */
672 ip_interface_address_t *ia;
673 vnet_sw_interface_t *sif;
675 pool_foreach (sif, vnm->interface_main.sw_interfaces)
677 if (im->fib_index_by_sw_if_index[sw_if_index] ==
678 im->fib_index_by_sw_if_index[sif->sw_if_index])
680 foreach_ip_interface_address
681 (&im->lookup_main, ia, sif->sw_if_index,
682 0 /* honor unnumbered */ ,
685 ip_interface_address_get_address
686 (&im->lookup_main, ia);
688 if (ip4_destination_matches_route
689 (im, address, x, ia->address_length) ||
690 ip4_destination_matches_route (im,
695 /* an intf may have >1 addr from the same prefix */
696 if ((sw_if_index == sif->sw_if_index) &&
697 (ia->address_length == address_length) &&
698 (x->as_u32 != address->as_u32))
701 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
702 /* if the address we're comparing against is stale
703 * then the CP has not added this one back yet, maybe
704 * it never will, so we have to assume it won't and
705 * ignore it. if it does add it back, then it will fail
706 * because this one is now present */
709 /* error if the length or intf was different */
710 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
712 error = clib_error_create
713 ("failed to add %U on %U which conflicts with %U for interface %U",
714 format_ip4_address_and_length, address,
716 format_vnet_sw_if_index_name, vnm,
718 format_ip4_address_and_length, x,
720 format_vnet_sw_if_index_name, vnm,
729 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
733 if (~0 == if_address_index)
735 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
736 error = clib_error_create ("%U not found for interface %U",
737 lm->format_address_and_length,
738 addr_fib, address_length,
739 format_vnet_sw_if_index_name, vnm,
744 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
745 address_length, sw_if_index);
751 if (~0 != if_address_index)
753 ip_interface_address_t *ia;
755 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
757 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
759 if (ia->sw_if_index == sw_if_index)
761 /* re-adding an address during the replace action.
762 * consdier this the update. clear the flag and
764 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
769 /* The prefix is moving from one interface to another.
770 * delete the stale and add the new */
771 ip4_add_del_interface_address_internal (vm,
776 error = ip_interface_address_add (lm, sw_if_index,
777 addr_fib, address_length,
783 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
784 error = clib_error_create
785 ("Prefix %U already found on interface %U",
786 lm->format_address_and_length, addr_fib, address_length,
787 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
791 error = ip_interface_address_add (lm, sw_if_index,
792 addr_fib, address_length,
799 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
800 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
802 /* intf addr routes are added/deleted on admin up/down */
803 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
806 ip4_del_interface_routes (sw_if_index,
807 im, ip4_af.fib_index, address,
810 ip4_add_interface_routes (sw_if_index,
811 im, ip4_af.fib_index,
813 (lm->if_address_pool, if_address_index));
816 ip4_add_del_interface_address_callback_t *cb;
817 vec_foreach (cb, im->add_del_interface_address_callbacks)
818 cb->function (im, cb->function_opaque, sw_if_index,
819 address, address_length, if_address_index, is_del);
827 ip4_add_del_interface_address (vlib_main_t * vm,
829 ip4_address_t * address,
830 u32 address_length, u32 is_del)
832 return ip4_add_del_interface_address_internal
833 (vm, sw_if_index, address, address_length, is_del);
837 ip4_directed_broadcast (u32 sw_if_index, u8 enable)
839 ip_interface_address_t *ia;
845 * when directed broadcast is enabled, the subnet braodcast route will forward
846 * packets using an adjacency with a broadcast MAC. otherwise it drops
848 foreach_ip_interface_address(&im->lookup_main, ia,
851 if (ia->address_length <= 30)
855 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
859 .fp_proto = FIB_PROTOCOL_IP4,
861 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
865 ip4_add_subnet_bcast_route
866 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
874 static clib_error_t *
875 ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
877 ip4_main_t *im = &ip4_main;
878 ip_interface_address_t *ia;
880 u32 is_admin_up, fib_index;
882 vec_validate_init_empty (im->
883 lookup_main.if_address_pool_index_by_sw_if_index,
886 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
888 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
890 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
891 0 /* honor unnumbered */,
893 a = ip_interface_address_get_address (&im->lookup_main, ia);
895 ip4_add_interface_routes (sw_if_index,
899 ip4_del_interface_routes (sw_if_index,
901 a, ia->address_length);
907 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
909 /* Built-in ip4 unicast rx feature path definition */
910 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
912 .arc_name = "ip4-unicast",
913 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
914 .last_in_arc = "ip4-lookup",
915 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
918 VNET_FEATURE_INIT (ip4_flow_classify, static) =
920 .arc_name = "ip4-unicast",
921 .node_name = "ip4-flow-classify",
922 .runs_before = VNET_FEATURES ("ip4-inacl"),
925 VNET_FEATURE_INIT (ip4_inacl, static) =
927 .arc_name = "ip4-unicast",
928 .node_name = "ip4-inacl",
929 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
932 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
934 .arc_name = "ip4-unicast",
935 .node_name = "ip4-source-and-port-range-check-rx",
936 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
939 VNET_FEATURE_INIT (ip4_policer_classify, static) =
941 .arc_name = "ip4-unicast",
942 .node_name = "ip4-policer-classify",
943 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
946 VNET_FEATURE_INIT (ip4_ipsec, static) =
948 .arc_name = "ip4-unicast",
949 .node_name = "ipsec4-input-feature",
950 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
953 VNET_FEATURE_INIT (ip4_vpath, static) =
955 .arc_name = "ip4-unicast",
956 .node_name = "vpath-input-ip4",
957 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
960 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
962 .arc_name = "ip4-unicast",
963 .node_name = "ip4-vxlan-bypass",
964 .runs_before = VNET_FEATURES ("ip4-lookup"),
967 VNET_FEATURE_INIT (ip4_not_enabled, static) =
969 .arc_name = "ip4-unicast",
970 .node_name = "ip4-not-enabled",
971 .runs_before = VNET_FEATURES ("ip4-lookup"),
974 VNET_FEATURE_INIT (ip4_lookup, static) =
976 .arc_name = "ip4-unicast",
977 .node_name = "ip4-lookup",
978 .runs_before = 0, /* not before any other features */
981 /* Built-in ip4 multicast rx feature path definition */
982 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
984 .arc_name = "ip4-multicast",
985 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
986 .last_in_arc = "ip4-mfib-forward-lookup",
987 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
990 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
992 .arc_name = "ip4-multicast",
993 .node_name = "vpath-input-ip4",
994 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
997 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
999 .arc_name = "ip4-multicast",
1000 .node_name = "ip4-not-enabled",
1001 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1004 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1006 .arc_name = "ip4-multicast",
1007 .node_name = "ip4-mfib-forward-lookup",
1008 .runs_before = 0, /* last feature */
1011 /* Source and port-range check ip4 tx feature path definition */
1012 VNET_FEATURE_ARC_INIT (ip4_output, static) =
1014 .arc_name = "ip4-output",
1015 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
1016 .last_in_arc = "interface-output",
1017 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1020 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1022 .arc_name = "ip4-output",
1023 .node_name = "ip4-source-and-port-range-check-tx",
1024 .runs_before = VNET_FEATURES ("ip4-outacl"),
1027 VNET_FEATURE_INIT (ip4_outacl, static) =
1029 .arc_name = "ip4-output",
1030 .node_name = "ip4-outacl",
1031 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
1034 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1036 .arc_name = "ip4-output",
1037 .node_name = "ipsec4-output-feature",
1038 .runs_before = VNET_FEATURES ("interface-output"),
1041 /* Built-in ip4 tx feature path definition */
1042 VNET_FEATURE_INIT (ip4_interface_output, static) =
1044 .arc_name = "ip4-output",
1045 .node_name = "interface-output",
1046 .runs_before = 0, /* not before any other features */
1049 static clib_error_t *
1050 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1052 ip4_main_t *im = &ip4_main;
1054 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1055 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
1059 /* Fill in lookup tables with default table (0). */
1060 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1061 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1065 ip4_main_t *im4 = &ip4_main;
1066 ip_lookup_main_t *lm4 = &im4->lookup_main;
1067 ip_interface_address_t *ia = 0;
1068 ip4_address_t *address;
1069 vlib_main_t *vm = vlib_get_main ();
1071 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
1072 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1074 address = ip_interface_address_get_address (lm4, ia);
1075 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1077 ip4_mfib_interface_enable_disable (sw_if_index, 0);
1079 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1080 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1081 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1082 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1084 /* Erase the lookup tables just in case */
1085 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1086 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
1089 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
1092 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1093 sw_if_index, is_add, 0, 0);
1095 return /* no error */ 0;
1098 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1100 /* Global IP4 main. */
1101 #ifndef CLIB_MARCH_VARIANT
1102 ip4_main_t ip4_main;
1103 #endif /* CLIB_MARCH_VARIANT */
1105 static clib_error_t *
1106 ip4_lookup_init (vlib_main_t * vm)
1108 ip4_main_t *im = &ip4_main;
1109 clib_error_t *error;
1112 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1114 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1116 if ((error = vlib_call_init_function (vm, fib_module_init)))
1118 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1121 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1126 m = pow2_mask (i) << (32 - i);
1129 im->fib_masks[i] = clib_host_to_net_u32 (m);
1132 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1134 /* Create FIB with index 0 and table id of 0. */
1135 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1136 FIB_SOURCE_DEFAULT_ROUTE);
1137 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1138 MFIB_SOURCE_DEFAULT_ROUTE);
1142 pn = pg_get_node (ip4_lookup_node.index);
1143 pn->unformat_edit = unformat_pg_ip4_header;
1147 ethernet_arp_header_t h;
1149 clib_memset (&h, 0, sizeof (h));
1151 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1152 #define _8(f,v) h.f = v;
1153 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1154 _16 (l3_type, ETHERNET_TYPE_IP4);
1155 _8 (n_l2_address_bytes, 6);
1156 _8 (n_l3_address_bytes, 4);
1157 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1161 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1164 /* alloc chunk size */ 8,
1171 VLIB_INIT_FUNCTION (ip4_lookup_init);
1175 /* Adjacency taken. */
1180 /* Packet data, possibly *after* rewrite. */
1181 u8 packet_data[64 - 1 * sizeof (u32)];
1183 ip4_forward_next_trace_t;
1185 #ifndef CLIB_MARCH_VARIANT
1187 format_ip4_forward_next_trace (u8 * s, va_list * args)
1189 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1190 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1191 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1192 u32 indent = format_get_indent (s);
1194 s = format (s, "%Ufib:%d adj:%d flow:0x%08x", format_white_space, indent,
1195 t->fib_index, t->dpo_index, t->flow_hash);
1196 s = format (s, "\n%U%U", format_white_space, indent, format_ip4_header,
1197 t->packet_data, sizeof (t->packet_data));
1203 format_ip4_lookup_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);
1210 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1211 t->fib_index, t->dpo_index, t->flow_hash);
1212 s = format (s, "\n%U%U",
1213 format_white_space, indent,
1214 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1219 format_ip4_rewrite_trace (u8 * s, va_list * args)
1221 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1222 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1223 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1224 u32 indent = format_get_indent (s);
1226 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1227 t->fib_index, t->dpo_index, format_ip_adjacency,
1228 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1229 s = format (s, "\n%U%U",
1230 format_white_space, indent,
1231 format_ip_adjacency_packet_data,
1232 t->packet_data, sizeof (t->packet_data));
1236 #ifndef CLIB_MARCH_VARIANT
1237 /* Common trace function for all ip4-forward next nodes. */
1239 ip4_forward_next_trace (vlib_main_t * vm,
1240 vlib_node_runtime_t * node,
1241 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1244 ip4_main_t *im = &ip4_main;
1246 n_left = frame->n_vectors;
1247 from = vlib_frame_vector_args (frame);
1252 vlib_buffer_t *b0, *b1;
1253 ip4_forward_next_trace_t *t0, *t1;
1255 /* Prefetch next iteration. */
1256 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1257 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1262 b0 = vlib_get_buffer (vm, bi0);
1263 b1 = vlib_get_buffer (vm, bi1);
1265 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1267 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1268 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1269 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1271 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1272 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1273 vec_elt (im->fib_index_by_sw_if_index,
1274 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1276 clib_memcpy_fast (t0->packet_data,
1277 vlib_buffer_get_current (b0),
1278 sizeof (t0->packet_data));
1280 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1282 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1283 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1284 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1286 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1287 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1288 vec_elt (im->fib_index_by_sw_if_index,
1289 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1290 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1291 sizeof (t1->packet_data));
1301 ip4_forward_next_trace_t *t0;
1305 b0 = vlib_get_buffer (vm, bi0);
1307 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1309 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1310 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1311 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1313 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1314 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1315 vec_elt (im->fib_index_by_sw_if_index,
1316 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1317 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1318 sizeof (t0->packet_data));
1325 /* Compute TCP/UDP/ICMP4 checksum in software. */
1327 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1331 u32 ip_header_length, payload_length_host_byte_order;
1333 /* Initialize checksum with ip header. */
1334 ip_header_length = ip4_header_bytes (ip0);
1335 payload_length_host_byte_order =
1336 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1338 clib_host_to_net_u32 (payload_length_host_byte_order +
1339 (ip0->protocol << 16));
1341 if (BITS (uword) == 32)
1344 ip_csum_with_carry (sum0,
1345 clib_mem_unaligned (&ip0->src_address, u32));
1347 ip_csum_with_carry (sum0,
1348 clib_mem_unaligned (&ip0->dst_address, u32));
1352 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1354 return ip_calculate_l4_checksum (vm, p0, sum0,
1355 payload_length_host_byte_order, (u8 *) ip0,
1356 ip_header_length, NULL);
1360 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1362 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1366 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1367 || ip0->protocol == IP_PROTOCOL_UDP);
1369 udp0 = (void *) (ip0 + 1);
1370 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1372 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1373 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1377 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1379 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1380 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1386 VNET_FEATURE_ARC_INIT (ip4_local) = {
1387 .arc_name = "ip4-local",
1388 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
1389 .last_in_arc = "ip4-local-end-of-arc",
1393 ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1394 ip4_header_t * ip, u8 is_udp, u8 * error,
1398 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1399 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1403 u32 ip_len, udp_len;
1405 udp = ip4_next_header (ip);
1406 /* Verify UDP length. */
1407 ip_len = clib_net_to_host_u16 (ip->length);
1408 udp_len = clib_net_to_host_u16 (udp->length);
1410 len_diff = ip_len - udp_len;
1411 *good_tcp_udp &= len_diff >= 0;
1412 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1416 #define ip4_local_csum_is_offloaded(_b) \
1417 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
1418 (vnet_buffer (_b)->oflags & \
1419 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
1421 #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1422 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1423 || ip4_local_csum_is_offloaded (_b)))
1425 #define ip4_local_csum_is_valid(_b) \
1426 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1427 || (ip4_local_csum_is_offloaded (_b))) != 0
1430 ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1431 ip4_header_t * ih, u8 * error)
1433 u8 is_udp, is_tcp_udp, good_tcp_udp;
1435 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1436 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1438 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1439 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1441 good_tcp_udp = ip4_local_csum_is_valid (b);
1443 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1444 *error = (is_tcp_udp && !good_tcp_udp
1445 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1449 ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1450 ip4_header_t ** ih, u8 * error)
1452 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1454 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1455 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1457 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1458 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1460 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1461 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1463 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1464 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1466 if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
1467 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1469 if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
1470 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1474 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1475 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1476 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1477 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1481 ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1482 vlib_buffer_t * b, u16 * next, u8 error,
1483 u8 head_of_feature_arc)
1485 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1488 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1489 b->error = error ? error_node->errors[error] : 0;
1490 if (head_of_feature_arc)
1493 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1495 vnet_feature_arc_start (
1496 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
1504 /* The src and fib-index together determine if packet n is the same as n-1 */
1510 } ip4_local_last_check_t;
1513 ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1514 ip4_local_last_check_t *last_check, u8 *error0,
1517 const dpo_id_t *dpo0;
1518 load_balance_t *lb0;
1521 vnet_buffer (b)->ip.fib_index =
1522 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1523 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1525 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1529 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1530 if (rd->rd_sw_if_index != ~0)
1531 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1535 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1536 * adjacency for the destination address (the local interface address).
1537 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1538 * adjacency for the source address (the remote sender's address)
1540 if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1541 (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
1544 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1547 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1548 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1549 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1551 lb0 = load_balance_get (lbi0);
1552 dpo0 = load_balance_get_bucket_i (lb0, 0);
1555 * Must have a route to source otherwise we drop the packet.
1556 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1559 * - the source is a recieve => it's from us => bogus, do this
1560 * first since it sets a different error code.
1561 * - uRPF check for any route to source - accept if passes.
1562 * - allow packets destined to the broadcast address from unknown sources
1565 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1566 && dpo0->dpoi_type == DPO_RECEIVE) ?
1567 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1568 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1569 && !fib_urpf_check_size (lb0->lb_urpf)
1570 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1571 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1573 last_check->src.as_u32 = ip0->src_address.as_u32;
1574 last_check->lbi = lbi0;
1575 last_check->error = *error0;
1576 last_check->first = 0;
1577 last_check->fib_index = vnet_buffer (b)->ip.fib_index;
1581 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1582 vnet_buffer (b)->ip.adj_index[VLIB_TX];
1583 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1584 *error0 = last_check->error;
1589 ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1590 ip4_local_last_check_t *last_check, u8 *error,
1593 const dpo_id_t *dpo[2];
1594 load_balance_t *lb[2];
1598 not_last_hit = last_check->first;
1599 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1600 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1602 vnet_buffer (b[0])->ip.fib_index =
1603 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1604 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1605 vnet_buffer (b[0])->ip.fib_index;
1607 vnet_buffer (b[1])->ip.fib_index =
1608 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1609 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1610 vnet_buffer (b[1])->ip.fib_index;
1612 not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1613 not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1615 vnet_buffer (b[0])->ip.rx_sw_if_index =
1616 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1617 vnet_buffer (b[1])->ip.rx_sw_if_index =
1618 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1621 const receive_dpo_t *rd0, *rd1;
1622 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1623 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1624 if (rd0->rd_sw_if_index != ~0)
1625 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1626 if (rd1->rd_sw_if_index != ~0)
1627 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1631 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1632 * adjacency for the destination address (the local interface address).
1633 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1634 * adjacency for the source address (the remote sender's address)
1636 if (PREDICT_TRUE (not_last_hit))
1638 ip4_fib_forwarding_lookup_x2 (
1639 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1640 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
1642 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1643 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1644 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1646 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1647 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1648 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1650 lb[0] = load_balance_get (lbi[0]);
1651 lb[1] = load_balance_get (lbi[1]);
1653 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1654 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1656 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1657 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1658 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1659 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1660 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1661 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1662 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1664 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1665 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1666 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1667 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1668 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1669 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1670 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1672 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1673 last_check->lbi = lbi[1];
1674 last_check->error = error[1];
1675 last_check->first = 0;
1676 last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
1680 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1681 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1682 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1684 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1685 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1686 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1688 error[0] = last_check->error;
1689 error[1] = last_check->error;
1693 enum ip_local_packet_type_e
1695 IP_LOCAL_PACKET_TYPE_L4,
1696 IP_LOCAL_PACKET_TYPE_NAT,
1697 IP_LOCAL_PACKET_TYPE_FRAG,
1701 * Determine packet type and next node.
1703 * The expectation is that all packets that are not L4 will skip
1704 * checksums and source checks.
1707 ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1709 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1711 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1713 *next = IP_LOCAL_NEXT_REASSEMBLY;
1714 return IP_LOCAL_PACKET_TYPE_FRAG;
1716 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1718 *next = lm->local_next_by_ip_protocol[ip->protocol];
1719 return IP_LOCAL_PACKET_TYPE_NAT;
1722 *next = lm->local_next_by_ip_protocol[ip->protocol];
1723 return IP_LOCAL_PACKET_TYPE_L4;
1727 ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1728 vlib_frame_t *frame, int head_of_feature_arc,
1731 u32 *from, n_left_from;
1732 vlib_node_runtime_t *error_node =
1733 vlib_node_get_runtime (vm, ip4_local_node.index);
1734 u16 nexts[VLIB_FRAME_SIZE], *next;
1735 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1736 ip4_header_t *ip[2];
1739 ip4_local_last_check_t last_check = {
1741 * 0.0.0.0 can appear as the source address of an IP packet,
1742 * as can any other address, hence the need to use the 'first'
1743 * member to make sure the .lbi is initialised for the first
1746 .src = { .as_u32 = 0 },
1748 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1753 from = vlib_frame_vector_args (frame);
1754 n_left_from = frame->n_vectors;
1756 if (node->flags & VLIB_NODE_FLAG_TRACE)
1757 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1759 vlib_get_buffers (vm, from, bufs, n_left_from);
1763 while (n_left_from >= 6)
1767 /* Prefetch next iteration. */
1769 vlib_prefetch_buffer_header (b[4], LOAD);
1770 vlib_prefetch_buffer_header (b[5], LOAD);
1772 clib_prefetch_load (b[4]->data);
1773 clib_prefetch_load (b[5]->data);
1776 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1778 ip[0] = vlib_buffer_get_current (b[0]);
1779 ip[1] = vlib_buffer_get_current (b[1]);
1781 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1782 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1784 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1785 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1787 not_batch = pt[0] ^ pt[1];
1789 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1792 if (PREDICT_TRUE (not_batch == 0))
1794 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1795 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
1801 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1802 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1807 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1808 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1815 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1816 head_of_feature_arc);
1817 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1818 head_of_feature_arc);
1825 while (n_left_from > 0)
1827 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1829 ip[0] = vlib_buffer_get_current (b[0]);
1830 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1831 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1833 if (head_of_feature_arc == 0 || pt[0])
1836 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1837 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1842 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1843 head_of_feature_arc);
1850 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1851 return frame->n_vectors;
1854 VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1855 vlib_frame_t * frame)
1857 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1858 0 /* is_receive_dpo */);
1861 VLIB_REGISTER_NODE (ip4_local_node) =
1863 .name = "ip4-local",
1864 .vector_size = sizeof (u32),
1865 .format_trace = format_ip4_forward_next_trace,
1866 .n_errors = IP4_N_ERROR,
1867 .error_counters = ip4_error_counters,
1868 .n_next_nodes = IP_LOCAL_N_NEXT,
1871 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1872 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1873 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1874 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1875 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
1879 VLIB_NODE_FN (ip4_receive_local_node)
1880 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1882 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1883 1 /* is_receive_dpo */);
1886 VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1887 .name = "ip4-receive",
1888 .vector_size = sizeof (u32),
1889 .format_trace = format_ip4_forward_next_trace,
1890 .sibling_of = "ip4-local"
1893 VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1894 vlib_node_runtime_t * node,
1895 vlib_frame_t * frame)
1897 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1898 0 /* is_receive_dpo */);
1901 VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1902 .name = "ip4-local-end-of-arc",
1903 .vector_size = sizeof (u32),
1905 .format_trace = format_ip4_forward_next_trace,
1906 .sibling_of = "ip4-local",
1909 VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1910 .arc_name = "ip4-local",
1911 .node_name = "ip4-local-end-of-arc",
1912 .runs_before = 0, /* not before any other features */
1915 #ifndef CLIB_MARCH_VARIANT
1917 ip4_register_protocol (u32 protocol, u32 node_index)
1919 vlib_main_t *vm = vlib_get_main ();
1920 ip4_main_t *im = &ip4_main;
1921 ip_lookup_main_t *lm = &im->lookup_main;
1923 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1924 lm->local_next_by_ip_protocol[protocol] =
1925 vlib_node_add_next (vm, ip4_local_node.index, node_index);
1929 ip4_unregister_protocol (u32 protocol)
1931 ip4_main_t *im = &ip4_main;
1932 ip_lookup_main_t *lm = &im->lookup_main;
1934 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1935 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1939 static clib_error_t *
1940 show_ip_local_command_fn (vlib_main_t * vm,
1941 unformat_input_t * input, vlib_cli_command_t * cmd)
1943 ip4_main_t *im = &ip4_main;
1944 ip_lookup_main_t *lm = &im->lookup_main;
1947 vlib_cli_output (vm, "Protocols handled by ip4_local");
1948 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1950 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1952 u32 node_index = vlib_get_node (vm,
1953 ip4_local_node.index)->
1954 next_nodes[lm->local_next_by_ip_protocol[i]];
1955 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1956 format_vlib_node_name, vm, node_index);
1965 * Display the set of protocols handled by the local IPv4 stack.
1968 * Example of how to display local protocol table:
1969 * @cliexstart{show ip local}
1970 * Protocols handled by ip4_local
1976 VLIB_CLI_COMMAND (show_ip_local, static) =
1978 .path = "show ip local",
1979 .function = show_ip_local_command_fn,
1980 .short_help = "show ip local",
1985 IP4_REWRITE_NEXT_DROP,
1986 IP4_REWRITE_NEXT_ICMP_ERROR,
1987 IP4_REWRITE_NEXT_FRAGMENT,
1988 IP4_REWRITE_N_NEXT /* Last */
1989 } ip4_rewrite_next_t;
1992 * This bits of an IPv4 address to mask to construct a multicast
1995 #if CLIB_ARCH_IS_BIG_ENDIAN
1996 #define IP4_MCAST_ADDR_MASK 0x007fffff
1998 #define IP4_MCAST_ADDR_MASK 0xffff7f00
2002 ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2003 u16 adj_packet_bytes, bool df, u16 * next,
2004 u8 is_midchain, u32 * error)
2006 if (packet_len > adj_packet_bytes)
2008 *error = IP4_ERROR_MTU_EXCEEDED;
2011 icmp4_error_set_vnet_buffer
2012 (b, ICMP4_destination_unreachable,
2013 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2015 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2019 /* IP fragmentation */
2020 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2022 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2023 IP_FRAG_NEXT_IP_REWRITE), 0);
2024 *next = IP4_REWRITE_NEXT_FRAGMENT;
2029 /* increment TTL & update checksum.
2030 Works either endian, so no need for byte swap. */
2031 static_always_inline void
2032 ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2036 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2041 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2042 checksum += checksum >= 0xffff;
2044 ip->checksum = checksum;
2048 ASSERT (ip4_header_checksum_is_valid (ip) ||
2049 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2050 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2053 /* Decrement TTL & update checksum.
2054 Works either endian, so no need for byte swap. */
2055 static_always_inline void
2056 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2061 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2066 /* Input node should have reject packets with ttl 0. */
2067 ASSERT (ip->ttl > 0);
2069 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2070 checksum += checksum >= 0xffff;
2072 ip->checksum = checksum;
2077 * If the ttl drops below 1 when forwarding, generate
2080 if (PREDICT_FALSE (ttl <= 0))
2082 *error = IP4_ERROR_TIME_EXPIRED;
2083 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2084 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2085 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2087 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2090 /* Verify checksum. */
2091 ASSERT (ip4_header_checksum_is_valid (ip) ||
2092 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2093 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2097 ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2098 vlib_frame_t *frame, int do_counters, int is_midchain,
2101 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2102 u32 *from = vlib_frame_vector_args (frame);
2103 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2104 u16 nexts[VLIB_FRAME_SIZE], *next;
2106 vlib_node_runtime_t *error_node =
2107 vlib_node_get_runtime (vm, ip4_input_node.index);
2109 n_left_from = frame->n_vectors;
2110 u32 thread_index = vm->thread_index;
2112 vlib_get_buffers (vm, from, bufs, n_left_from);
2113 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2115 #if (CLIB_N_PREFETCHES >= 8)
2116 if (n_left_from >= 6)
2119 for (i = 2; i < 6; i++)
2120 vlib_prefetch_buffer_header (bufs[i], LOAD);
2125 while (n_left_from >= 8)
2127 const ip_adjacency_t *adj0, *adj1;
2128 ip4_header_t *ip0, *ip1;
2129 u32 rw_len0, error0, adj_index0;
2130 u32 rw_len1, error1, adj_index1;
2131 u32 tx_sw_if_index0, tx_sw_if_index1;
2136 vlib_prefetch_buffer_header (b[6], LOAD);
2137 vlib_prefetch_buffer_header (b[7], LOAD);
2140 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2141 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2144 * pre-fetch the per-adjacency counters
2148 vlib_prefetch_combined_counter (&adjacency_counters,
2149 thread_index, adj_index0);
2150 vlib_prefetch_combined_counter (&adjacency_counters,
2151 thread_index, adj_index1);
2154 ip0 = vlib_buffer_get_current (b[0]);
2155 ip1 = vlib_buffer_get_current (b[1]);
2157 error0 = error1 = IP4_ERROR_NONE;
2159 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2160 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2162 /* Rewrite packet header and updates lengths. */
2163 adj0 = adj_get (adj_index0);
2164 adj1 = adj_get (adj_index1);
2166 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2167 rw_len0 = adj0[0].rewrite_header.data_bytes;
2168 rw_len1 = adj1[0].rewrite_header.data_bytes;
2169 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2170 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2172 p = vlib_buffer_get_current (b[2]);
2173 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2174 clib_prefetch_load (p);
2176 p = vlib_buffer_get_current (b[3]);
2177 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2178 clib_prefetch_load (p);
2180 /* Check MTU of outgoing interface. */
2181 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2182 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2184 if (b[0]->flags & VNET_BUFFER_F_GSO)
2185 ip0_len = gso_mtu_sz (b[0]);
2186 if (b[1]->flags & VNET_BUFFER_F_GSO)
2187 ip1_len = gso_mtu_sz (b[1]);
2189 ip4_mtu_check (b[0], ip0_len,
2190 adj0[0].rewrite_header.max_l3_packet_bytes,
2191 ip0->flags_and_fragment_offset &
2192 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2193 next + 0, is_midchain, &error0);
2194 ip4_mtu_check (b[1], ip1_len,
2195 adj1[0].rewrite_header.max_l3_packet_bytes,
2196 ip1->flags_and_fragment_offset &
2197 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2198 next + 1, is_midchain, &error1);
2202 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2203 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2204 IP4_ERROR_SAME_INTERFACE : error0);
2205 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2206 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2207 IP4_ERROR_SAME_INTERFACE : error1);
2210 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2211 * to see the IP header */
2212 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2214 u32 next_index = adj0[0].rewrite_header.next_index;
2215 vlib_buffer_advance (b[0], -(word) rw_len0);
2217 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2218 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2221 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2222 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2225 adj0->ia_cfg_index);
2227 next[0] = next_index;
2231 b[0]->error = error_node->errors[error0];
2232 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2233 ip4_ttl_inc (b[0], ip0);
2235 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2237 u32 next_index = adj1[0].rewrite_header.next_index;
2238 vlib_buffer_advance (b[1], -(word) rw_len1);
2240 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2241 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2244 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2245 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2248 adj1->ia_cfg_index);
2249 next[1] = next_index;
2253 b[1]->error = error_node->errors[error1];
2254 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2255 ip4_ttl_inc (b[1], ip1);
2259 /* Guess we are only writing on ipv4 header. */
2260 vnet_rewrite_two_headers (adj0[0], adj1[0],
2261 ip0, ip1, sizeof (ip4_header_t));
2263 /* Guess we are only writing on simple Ethernet header. */
2264 vnet_rewrite_two_headers (adj0[0], adj1[0],
2265 ip0, ip1, sizeof (ethernet_header_t));
2269 if (error0 == IP4_ERROR_NONE)
2270 vlib_increment_combined_counter
2271 (&adjacency_counters,
2274 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2276 if (error1 == IP4_ERROR_NONE)
2277 vlib_increment_combined_counter
2278 (&adjacency_counters,
2281 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2286 if (error0 == IP4_ERROR_NONE)
2287 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2288 if (error1 == IP4_ERROR_NONE)
2289 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2294 /* copy bytes from the IP address into the MAC rewrite */
2295 if (error0 == IP4_ERROR_NONE)
2296 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2297 adj0->rewrite_header.dst_mcast_offset,
2298 &ip0->dst_address.as_u32, (u8 *) ip0);
2299 if (error1 == IP4_ERROR_NONE)
2300 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2301 adj1->rewrite_header.dst_mcast_offset,
2302 &ip1->dst_address.as_u32, (u8 *) ip1);
2309 #elif (CLIB_N_PREFETCHES >= 4)
2312 while (n_left_from >= 1)
2314 ip_adjacency_t *adj0;
2316 u32 rw_len0, error0, adj_index0;
2317 u32 tx_sw_if_index0;
2320 /* Prefetch next iteration */
2321 if (PREDICT_TRUE (n_left_from >= 4))
2323 ip_adjacency_t *adj2;
2326 vlib_prefetch_buffer_header (b[3], LOAD);
2327 vlib_prefetch_buffer_data (b[2], LOAD);
2329 /* Prefetch adj->rewrite_header */
2330 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2331 adj2 = adj_get (adj_index2);
2333 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2337 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2340 * Prefetch the per-adjacency counters
2344 vlib_prefetch_combined_counter (&adjacency_counters,
2345 thread_index, adj_index0);
2348 ip0 = vlib_buffer_get_current (b[0]);
2350 error0 = IP4_ERROR_NONE;
2352 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2354 /* Rewrite packet header and updates lengths. */
2355 adj0 = adj_get (adj_index0);
2357 /* Rewrite header was prefetched. */
2358 rw_len0 = adj0[0].rewrite_header.data_bytes;
2359 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2361 /* Check MTU of outgoing interface. */
2362 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2364 if (b[0]->flags & VNET_BUFFER_F_GSO)
2365 ip0_len = gso_mtu_sz (b[0]);
2367 ip4_mtu_check (b[0], ip0_len,
2368 adj0[0].rewrite_header.max_l3_packet_bytes,
2369 ip0->flags_and_fragment_offset &
2370 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2371 next + 0, is_midchain, &error0);
2375 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2376 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2377 IP4_ERROR_SAME_INTERFACE : error0);
2380 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2381 * to see the IP header */
2382 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2384 u32 next_index = adj0[0].rewrite_header.next_index;
2385 vlib_buffer_advance (b[0], -(word) rw_len0);
2386 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2387 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2390 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2391 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2394 adj0->ia_cfg_index);
2395 next[0] = next_index;
2399 /* Guess we are only writing on ipv4 header. */
2400 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2403 /* Guess we are only writing on simple Ethernet header. */
2404 vnet_rewrite_one_header (adj0[0], ip0,
2405 sizeof (ethernet_header_t));
2408 * Bump the per-adjacency counters
2411 vlib_increment_combined_counter
2412 (&adjacency_counters,
2414 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2418 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2421 /* copy bytes from the IP address into the MAC rewrite */
2422 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2423 adj0->rewrite_header.dst_mcast_offset,
2424 &ip0->dst_address.as_u32, (u8 *) ip0);
2428 b[0]->error = error_node->errors[error0];
2429 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2430 ip4_ttl_inc (b[0], ip0);
2439 while (n_left_from > 0)
2441 ip_adjacency_t *adj0;
2443 u32 rw_len0, adj_index0, error0;
2444 u32 tx_sw_if_index0;
2446 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2448 adj0 = adj_get (adj_index0);
2451 vlib_prefetch_combined_counter (&adjacency_counters,
2452 thread_index, adj_index0);
2454 ip0 = vlib_buffer_get_current (b[0]);
2456 error0 = IP4_ERROR_NONE;
2458 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2461 /* Update packet buffer attributes/set output interface. */
2462 rw_len0 = adj0[0].rewrite_header.data_bytes;
2463 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2465 /* Check MTU of outgoing interface. */
2466 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2467 if (b[0]->flags & VNET_BUFFER_F_GSO)
2468 ip0_len = gso_mtu_sz (b[0]);
2470 ip4_mtu_check (b[0], ip0_len,
2471 adj0[0].rewrite_header.max_l3_packet_bytes,
2472 ip0->flags_and_fragment_offset &
2473 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2474 next + 0, is_midchain, &error0);
2478 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2479 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2480 IP4_ERROR_SAME_INTERFACE : error0);
2483 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2484 * to see the IP header */
2485 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2487 u32 next_index = adj0[0].rewrite_header.next_index;
2488 vlib_buffer_advance (b[0], -(word) rw_len0);
2489 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2490 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2493 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2494 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2497 adj0->ia_cfg_index);
2498 next[0] = next_index;
2502 /* Guess we are only writing on ipv4 header. */
2503 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2506 /* Guess we are only writing on simple Ethernet header. */
2507 vnet_rewrite_one_header (adj0[0], ip0,
2508 sizeof (ethernet_header_t));
2511 vlib_increment_combined_counter
2512 (&adjacency_counters,
2513 thread_index, adj_index0, 1,
2514 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2517 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2520 /* copy bytes from the IP address into the MAC rewrite */
2521 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2522 adj0->rewrite_header.dst_mcast_offset,
2523 &ip0->dst_address.as_u32, (u8 *) ip0);
2527 b[0]->error = error_node->errors[error0];
2528 /* undo the TTL decrement - we'll be back to do it again */
2529 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2530 ip4_ttl_inc (b[0], ip0);
2539 /* Need to do trace after rewrites to pick up new packet data. */
2540 if (node->flags & VLIB_NODE_FLAG_TRACE)
2541 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2543 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2544 return frame->n_vectors;
2547 /** @brief IPv4 rewrite node.
2550 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2551 header checksum, fetch the ip adjacency, check the outbound mtu,
2552 apply the adjacency rewrite, and send pkts to the adjacency
2553 rewrite header's rewrite_next_index.
2555 @param vm vlib_main_t corresponding to the current thread
2556 @param node vlib_node_runtime_t
2557 @param frame vlib_frame_t whose contents should be dispatched
2559 @par Graph mechanics: buffer metadata, next index usage
2562 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2563 - the rewrite adjacency index
2564 - <code>adj->lookup_next_index</code>
2565 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2566 the packet will be dropped.
2567 - <code>adj->rewrite_header</code>
2568 - Rewrite string length, rewrite string, next_index
2571 - <code>b->current_data, b->current_length</code>
2572 - Updated net of applying the rewrite string
2574 <em>Next Indices:</em>
2575 - <code> adj->rewrite_header.next_index </code>
2579 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2580 vlib_frame_t * frame)
2582 if (adj_are_counters_enabled ())
2583 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2585 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2588 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2589 vlib_node_runtime_t * node,
2590 vlib_frame_t * frame)
2592 if (adj_are_counters_enabled ())
2593 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2595 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2598 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2599 vlib_node_runtime_t * node,
2600 vlib_frame_t * frame)
2602 if (adj_are_counters_enabled ())
2603 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2605 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2608 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2609 vlib_node_runtime_t * node,
2610 vlib_frame_t * frame)
2612 if (adj_are_counters_enabled ())
2613 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2615 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2618 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2619 vlib_node_runtime_t * node,
2620 vlib_frame_t * frame)
2622 if (adj_are_counters_enabled ())
2623 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2625 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2628 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2629 .name = "ip4-rewrite",
2630 .vector_size = sizeof (u32),
2632 .format_trace = format_ip4_rewrite_trace,
2634 .n_next_nodes = IP4_REWRITE_N_NEXT,
2636 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2637 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2638 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2642 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2643 .name = "ip4-rewrite-bcast",
2644 .vector_size = sizeof (u32),
2646 .format_trace = format_ip4_rewrite_trace,
2647 .sibling_of = "ip4-rewrite",
2650 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2651 .name = "ip4-rewrite-mcast",
2652 .vector_size = sizeof (u32),
2654 .format_trace = format_ip4_rewrite_trace,
2655 .sibling_of = "ip4-rewrite",
2658 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2659 .name = "ip4-mcast-midchain",
2660 .vector_size = sizeof (u32),
2662 .format_trace = format_ip4_rewrite_trace,
2663 .sibling_of = "ip4-rewrite",
2666 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2667 .name = "ip4-midchain",
2668 .vector_size = sizeof (u32),
2669 .format_trace = format_ip4_rewrite_trace,
2670 .sibling_of = "ip4-rewrite",
2673 static clib_error_t *
2674 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2675 unformat_input_t * input,
2676 vlib_cli_command_t * cmd)
2680 u32 flow_hash_config = 0;
2683 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2685 if (unformat (input, "table %d", &table_id))
2687 #define _(a, b, v) \
2688 else if (unformat (input, #a)) \
2690 flow_hash_config |= v; \
2693 foreach_flow_hash_bit
2700 return clib_error_return (0, "unknown input `%U'",
2701 format_unformat_error, input);
2703 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2709 case VNET_API_ERROR_NO_SUCH_FIB:
2710 return clib_error_return (0, "no such FIB table %d", table_id);
2713 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2721 * Configure the set of IPv4 fields used by the flow hash.
2724 * Example of how to set the flow hash on a given table:
2725 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2726 * Example of display the configured flow hash:
2727 * @cliexstart{show ip fib}
2728 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2731 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2732 * [0] [@0]: dpo-drop ip6
2735 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2736 * [0] [@0]: dpo-drop ip6
2739 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2740 * [0] [@0]: dpo-drop ip6
2743 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2744 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2747 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2748 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2749 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2750 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2751 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2754 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2755 * [0] [@0]: dpo-drop ip6
2756 * 255.255.255.255/32
2758 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2759 * [0] [@0]: dpo-drop ip6
2760 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2763 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2764 * [0] [@0]: dpo-drop ip6
2767 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2768 * [0] [@0]: dpo-drop ip6
2771 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2772 * [0] [@4]: ipv4-glean: af_packet0
2775 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2776 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2779 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2780 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2783 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2784 * [0] [@4]: ipv4-glean: af_packet1
2787 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2788 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2791 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2792 * [0] [@0]: dpo-drop ip6
2795 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2796 * [0] [@0]: dpo-drop ip6
2797 * 255.255.255.255/32
2799 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2800 * [0] [@0]: dpo-drop ip6
2803 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
2804 .path = "set ip flow-hash",
2805 .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
2806 "[dport] [proto] [reverse] [gtpv1teid]",
2807 .function = set_ip_flow_hash_command_fn,
2810 #ifndef CLIB_MARCH_VARIANT
2812 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2815 vnet_main_t *vnm = vnet_get_main ();
2816 vnet_interface_main_t *im = &vnm->interface_main;
2817 ip4_main_t *ipm = &ip4_main;
2818 ip_lookup_main_t *lm = &ipm->lookup_main;
2819 vnet_classify_main_t *cm = &vnet_classify_main;
2820 ip4_address_t *if_addr;
2822 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2823 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2825 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2826 return VNET_API_ERROR_NO_SUCH_ENTRY;
2828 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2829 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2831 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2833 if (NULL != if_addr)
2835 fib_prefix_t pfx = {
2837 .fp_proto = FIB_PROTOCOL_IP4,
2838 .fp_addr.ip4 = *if_addr,
2842 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2846 if (table_index != (u32) ~ 0)
2848 dpo_id_t dpo = DPO_INVALID;
2853 classify_dpo_create (DPO_PROTO_IP4, table_index));
2855 fib_table_entry_special_dpo_add (fib_index,
2857 FIB_SOURCE_CLASSIFY,
2858 FIB_ENTRY_FLAG_NONE, &dpo);
2863 fib_table_entry_special_remove (fib_index,
2864 &pfx, FIB_SOURCE_CLASSIFY);
2872 static clib_error_t *
2873 set_ip_classify_command_fn (vlib_main_t * vm,
2874 unformat_input_t * input,
2875 vlib_cli_command_t * cmd)
2877 u32 table_index = ~0;
2878 int table_index_set = 0;
2879 u32 sw_if_index = ~0;
2882 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2884 if (unformat (input, "table-index %d", &table_index))
2885 table_index_set = 1;
2886 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2887 vnet_get_main (), &sw_if_index))
2893 if (table_index_set == 0)
2894 return clib_error_return (0, "classify table-index must be specified");
2896 if (sw_if_index == ~0)
2897 return clib_error_return (0, "interface / subif must be specified");
2899 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2906 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2907 return clib_error_return (0, "No such interface");
2909 case VNET_API_ERROR_NO_SUCH_ENTRY:
2910 return clib_error_return (0, "No such classifier table");
2916 * Assign a classification table to an interface. The classification
2917 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2918 * commands. Once the table is create, use this command to filter packets
2922 * Example of how to assign a classification table to an interface:
2923 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2925 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2927 .path = "set ip classify",
2929 "set ip classify intfc <interface> table-index <classify-idx>",
2930 .function = set_ip_classify_command_fn,
2934 * fd.io coding-style-patch-verification: ON
2937 * eval: (c-set-style "gnu")