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>
65 /** @brief IPv4 lookup node.
68 This is the main IPv4 lookup dispatch node.
70 @param vm vlib_main_t corresponding to the current thread
71 @param node vlib_node_runtime_t
72 @param frame vlib_frame_t whose contents should be dispatched
74 @par Graph mechanics: buffer metadata, next index usage
77 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
78 - Indicates the @c sw_if_index value of the interface that the
79 packet was received on.
80 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
81 - When the value is @c ~0 then the node performs a longest prefix
82 match (LPM) for the packet destination address in the FIB attached
83 to the receive interface.
84 - Otherwise perform LPM for the packet destination address in the
85 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
86 value (0, 1, ...) and not a VRF id.
89 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
90 - The lookup result adjacency index.
93 - Dispatches the packet to the node index found in
94 ip_adjacency_t @c adj->lookup_next_index
95 (where @c adj is the lookup result adjacency).
97 VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
100 return ip4_lookup_inline (vm, node, frame);
103 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,
116 VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
117 vlib_node_runtime_t * node,
118 vlib_frame_t * frame)
120 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
122 u32 thread_index = vm->thread_index;
123 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
124 u16 nexts[VLIB_FRAME_SIZE], *next;
126 from = vlib_frame_vector_args (frame);
127 n_left = frame->n_vectors;
130 vlib_get_buffers (vm, from, bufs, n_left);
134 const load_balance_t *lb0, *lb1;
135 const ip4_header_t *ip0, *ip1;
136 u32 lbi0, hc0, lbi1, hc1;
137 const dpo_id_t *dpo0, *dpo1;
139 /* Prefetch next iteration. */
141 vlib_prefetch_buffer_header (b[2], LOAD);
142 vlib_prefetch_buffer_header (b[3], LOAD);
144 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
145 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
148 ip0 = vlib_buffer_get_current (b[0]);
149 ip1 = vlib_buffer_get_current (b[1]);
150 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
151 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
153 lb0 = load_balance_get (lbi0);
154 lb1 = load_balance_get (lbi1);
157 * this node is for via FIBs we can re-use the hash value from the
158 * to node if present.
159 * We don't want to use the same hash value at each level in the recursion
160 * graph as that would lead to polarisation
164 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
166 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
168 hc0 = vnet_buffer (b[0])->ip.flow_hash =
169 vnet_buffer (b[0])->ip.flow_hash >> 1;
173 hc0 = vnet_buffer (b[0])->ip.flow_hash =
174 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
176 dpo0 = load_balance_get_fwd_bucket
177 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
181 dpo0 = load_balance_get_bucket_i (lb0, 0);
183 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
185 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
187 hc1 = vnet_buffer (b[1])->ip.flow_hash =
188 vnet_buffer (b[1])->ip.flow_hash >> 1;
192 hc1 = vnet_buffer (b[1])->ip.flow_hash =
193 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
195 dpo1 = load_balance_get_fwd_bucket
196 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
200 dpo1 = load_balance_get_bucket_i (lb1, 0);
203 next[0] = dpo0->dpoi_next_node;
204 next[1] = dpo1->dpoi_next_node;
206 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
207 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
209 vlib_increment_combined_counter
210 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
211 vlib_increment_combined_counter
212 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
221 const load_balance_t *lb0;
222 const ip4_header_t *ip0;
223 const dpo_id_t *dpo0;
226 ip0 = vlib_buffer_get_current (b[0]);
227 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
229 lb0 = load_balance_get (lbi0);
232 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
234 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
236 hc0 = vnet_buffer (b[0])->ip.flow_hash =
237 vnet_buffer (b[0])->ip.flow_hash >> 1;
241 hc0 = vnet_buffer (b[0])->ip.flow_hash =
242 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
244 dpo0 = load_balance_get_fwd_bucket
245 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
249 dpo0 = load_balance_get_bucket_i (lb0, 0);
252 next[0] = dpo0->dpoi_next_node;
253 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
255 vlib_increment_combined_counter
256 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
263 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
264 if (node->flags & VLIB_NODE_FLAG_TRACE)
265 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
267 return frame->n_vectors;
271 VLIB_REGISTER_NODE (ip4_load_balance_node) =
273 .name = "ip4-load-balance",
274 .vector_size = sizeof (u32),
275 .sibling_of = "ip4-lookup",
276 .format_trace = format_ip4_lookup_trace,
280 #ifndef CLIB_MARCH_VARIANT
281 /* get first interface address */
283 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
284 ip_interface_address_t ** result_ia)
286 ip_lookup_main_t *lm = &im->lookup_main;
287 ip_interface_address_t *ia = 0;
288 ip4_address_t *result = 0;
291 foreach_ip_interface_address
292 (lm, ia, sw_if_index,
293 1 /* honor unnumbered */ ,
296 ip_interface_address_get_address (lm, ia);
302 *result_ia = result ? ia : 0;
308 ip4_add_subnet_bcast_route (u32 fib_index,
312 vnet_sw_interface_flags_t iflags;
314 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
316 fib_table_entry_special_remove(fib_index,
318 FIB_SOURCE_INTERFACE);
320 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
322 fib_table_entry_update_one_path (fib_index, pfx,
323 FIB_SOURCE_INTERFACE,
326 /* No next-hop address */
332 // no out-label stack
334 FIB_ROUTE_PATH_FLAG_NONE);
338 fib_table_entry_special_add(fib_index,
340 FIB_SOURCE_INTERFACE,
341 (FIB_ENTRY_FLAG_DROP |
342 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
347 ip4_add_interface_prefix_routes (ip4_main_t *im,
350 ip_interface_address_t * a)
352 ip_lookup_main_t *lm = &im->lookup_main;
353 ip_interface_prefix_t *if_prefix;
354 ip4_address_t *address = ip_interface_address_get_address (lm, a);
356 ip_interface_prefix_key_t key = {
358 .fp_len = a->address_length,
359 .fp_proto = FIB_PROTOCOL_IP4,
360 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
362 .sw_if_index = sw_if_index,
365 fib_prefix_t pfx_special = {
366 .fp_proto = FIB_PROTOCOL_IP4,
369 /* If prefix already set on interface, just increment ref count & return */
370 if_prefix = ip_get_interface_prefix (lm, &key);
373 if_prefix->ref_count += 1;
377 /* New prefix - allocate a pool entry, initialize it, add to the hash */
378 pool_get (lm->if_prefix_pool, if_prefix);
379 if_prefix->ref_count = 1;
380 if_prefix->src_ia_index = a - lm->if_address_pool;
381 clib_memcpy (&if_prefix->key, &key, sizeof (key));
382 mhash_set (&lm->prefix_to_if_prefix_index, &key,
383 if_prefix - lm->if_prefix_pool, 0 /* old value */);
385 pfx_special.fp_len = a->address_length;
386 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
388 /* set the glean route for the prefix */
389 fib_table_entry_update_one_path (fib_index, &pfx_special,
390 FIB_SOURCE_INTERFACE,
391 (FIB_ENTRY_FLAG_CONNECTED |
392 FIB_ENTRY_FLAG_ATTACHED),
394 /* No next-hop address */
397 /* invalid FIB index */
400 /* no out-label stack */
402 FIB_ROUTE_PATH_FLAG_NONE);
404 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
405 if (a->address_length <= 30)
407 /* set a drop route for the base address of the prefix */
408 pfx_special.fp_len = 32;
409 pfx_special.fp_addr.ip4.as_u32 =
410 address->as_u32 & im->fib_masks[a->address_length];
412 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
413 fib_table_entry_special_add (fib_index, &pfx_special,
414 FIB_SOURCE_INTERFACE,
415 (FIB_ENTRY_FLAG_DROP |
416 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
418 /* set a route for the broadcast address of the prefix */
419 pfx_special.fp_len = 32;
420 pfx_special.fp_addr.ip4.as_u32 =
421 address->as_u32 | ~im->fib_masks[a->address_length];
422 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
423 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
427 /* length == 31 - add an attached route for the other address */
428 else if (a->address_length == 31)
430 pfx_special.fp_len = 32;
431 pfx_special.fp_addr.ip4.as_u32 =
432 address->as_u32 ^ clib_host_to_net_u32(1);
434 fib_table_entry_update_one_path (fib_index, &pfx_special,
435 FIB_SOURCE_INTERFACE,
436 (FIB_ENTRY_FLAG_ATTACHED),
438 &pfx_special.fp_addr,
440 /* invalid FIB index */
444 FIB_ROUTE_PATH_FLAG_NONE);
449 ip4_add_interface_routes (u32 sw_if_index,
450 ip4_main_t * im, u32 fib_index,
451 ip_interface_address_t * a)
453 ip_lookup_main_t *lm = &im->lookup_main;
454 ip4_address_t *address = ip_interface_address_get_address (lm, a);
457 .fp_proto = FIB_PROTOCOL_IP4,
458 .fp_addr.ip4 = *address,
461 /* set special routes for the prefix if needed */
462 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
464 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
466 u32 classify_table_index =
467 lm->classify_table_index_by_sw_if_index[sw_if_index];
468 if (classify_table_index != (u32) ~ 0)
470 dpo_id_t dpo = DPO_INVALID;
475 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
477 fib_table_entry_special_dpo_add (fib_index,
480 FIB_ENTRY_FLAG_NONE, &dpo);
485 fib_table_entry_update_one_path (fib_index, &pfx,
486 FIB_SOURCE_INTERFACE,
487 (FIB_ENTRY_FLAG_CONNECTED |
488 FIB_ENTRY_FLAG_LOCAL),
495 FIB_ROUTE_PATH_FLAG_NONE);
499 ip4_del_interface_prefix_routes (ip4_main_t * im,
502 ip4_address_t * address,
505 ip_lookup_main_t *lm = &im->lookup_main;
506 ip_interface_prefix_t *if_prefix;
508 ip_interface_prefix_key_t key = {
510 .fp_len = address_length,
511 .fp_proto = FIB_PROTOCOL_IP4,
512 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
514 .sw_if_index = sw_if_index,
517 fib_prefix_t pfx_special = {
519 .fp_proto = FIB_PROTOCOL_IP4,
522 if_prefix = ip_get_interface_prefix (lm, &key);
525 clib_warning ("Prefix not found while deleting %U",
526 format_ip4_address_and_length, address, address_length);
530 if_prefix->ref_count -= 1;
533 * Routes need to be adjusted if deleting last intf addr in prefix
535 * We're done now otherwise
537 if (if_prefix->ref_count > 0)
540 /* length <= 30, delete glean route, first address, last address */
541 if (address_length <= 30)
543 /* Less work to do in FIB if we remove the covered /32s first */
545 /* first address in prefix */
546 pfx_special.fp_addr.ip4.as_u32 =
547 address->as_u32 & im->fib_masks[address_length];
548 pfx_special.fp_len = 32;
550 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
551 fib_table_entry_special_remove (fib_index,
553 FIB_SOURCE_INTERFACE);
555 /* prefix broadcast address */
556 pfx_special.fp_addr.ip4.as_u32 =
557 address->as_u32 | ~im->fib_masks[address_length];
558 pfx_special.fp_len = 32;
560 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
561 fib_table_entry_special_remove (fib_index,
563 FIB_SOURCE_INTERFACE);
565 else if (address_length == 31)
567 /* length == 31, delete attached route for the other address */
568 pfx_special.fp_addr.ip4.as_u32 =
569 address->as_u32 ^ clib_host_to_net_u32(1);
571 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
574 /* remove glean route for prefix */
575 pfx_special.fp_addr.ip4 = *address;
576 pfx_special.fp_len = address_length;
577 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
579 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
580 pool_put (lm->if_prefix_pool, if_prefix);
584 ip4_del_interface_routes (u32 sw_if_index,
587 ip4_address_t * address, u32 address_length)
591 .fp_proto = FIB_PROTOCOL_IP4,
592 .fp_addr.ip4 = *address,
595 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
597 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
598 address, address_length);
601 #ifndef CLIB_MARCH_VARIANT
603 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
605 ip4_main_t *im = &ip4_main;
606 vnet_main_t *vnm = vnet_get_main ();
607 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
609 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
612 * enable/disable only on the 1<->0 transition
616 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
621 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
622 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
625 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
629 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
630 sw_if_index, !is_enable, 0, 0);
634 else if (hi->l3_if_count)
638 ip4_enable_disable_interface_callback_t *cb;
639 vec_foreach (cb, im->enable_disable_interface_callbacks)
640 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
644 static clib_error_t *
645 ip4_add_del_interface_address_internal (vlib_main_t * vm,
647 ip4_address_t * address,
648 u32 address_length, u32 is_del)
650 vnet_main_t *vnm = vnet_get_main ();
651 ip4_main_t *im = &ip4_main;
652 ip_lookup_main_t *lm = &im->lookup_main;
653 clib_error_t *error = 0;
654 u32 if_address_index;
655 ip4_address_fib_t ip4_af, *addr_fib = 0;
657 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
660 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
664 ip4_addr_fib_init (&ip4_af, address,
665 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
666 vec_add1 (addr_fib, ip4_af);
669 * there is no support for adj-fib handling in the presence of overlapping
670 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
676 /* When adding an address check that it does not conflict
677 with an existing address on any interface in this table. */
678 ip_interface_address_t *ia;
679 vnet_sw_interface_t *sif;
681 pool_foreach (sif, vnm->interface_main.sw_interfaces)
683 if (im->fib_index_by_sw_if_index[sw_if_index] ==
684 im->fib_index_by_sw_if_index[sif->sw_if_index])
686 foreach_ip_interface_address
687 (&im->lookup_main, ia, sif->sw_if_index,
688 0 /* honor unnumbered */ ,
691 ip_interface_address_get_address
692 (&im->lookup_main, ia);
694 if (ip4_destination_matches_route
695 (im, address, x, ia->address_length) ||
696 ip4_destination_matches_route (im,
701 /* an intf may have >1 addr from the same prefix */
702 if ((sw_if_index == sif->sw_if_index) &&
703 (ia->address_length == address_length) &&
704 (x->as_u32 != address->as_u32))
707 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
708 /* if the address we're comparing against is stale
709 * then the CP has not added this one back yet, maybe
710 * it never will, so we have to assume it won't and
711 * ignore it. if it does add it back, then it will fail
712 * because this one is now present */
715 /* error if the length or intf was different */
716 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
718 error = clib_error_create
719 ("failed to add %U on %U which conflicts with %U for interface %U",
720 format_ip4_address_and_length, address,
722 format_vnet_sw_if_index_name, vnm,
724 format_ip4_address_and_length, x,
726 format_vnet_sw_if_index_name, vnm,
736 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
740 if (~0 == if_address_index)
742 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
743 error = clib_error_create ("%U not found for interface %U",
744 lm->format_address_and_length,
745 addr_fib, address_length,
746 format_vnet_sw_if_index_name, vnm,
751 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
752 address_length, sw_if_index);
758 if (~0 != if_address_index)
760 ip_interface_address_t *ia;
762 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
764 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
766 if (ia->sw_if_index == sw_if_index)
768 /* re-adding an address during the replace action.
769 * consdier this the update. clear the flag and
771 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
776 /* The prefix is moving from one interface to another.
777 * delete the stale and add the new */
778 ip4_add_del_interface_address_internal (vm,
783 error = ip_interface_address_add (lm, sw_if_index,
784 addr_fib, address_length,
790 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
791 error = clib_error_create
792 ("Prefix %U already found on interface %U",
793 lm->format_address_and_length, addr_fib, address_length,
794 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
798 error = ip_interface_address_add (lm, sw_if_index,
799 addr_fib, address_length,
806 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
807 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
809 /* intf addr routes are added/deleted on admin up/down */
810 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
813 ip4_del_interface_routes (sw_if_index,
814 im, ip4_af.fib_index, address,
817 ip4_add_interface_routes (sw_if_index,
818 im, ip4_af.fib_index,
820 (lm->if_address_pool, if_address_index));
823 ip4_add_del_interface_address_callback_t *cb;
824 vec_foreach (cb, im->add_del_interface_address_callbacks)
825 cb->function (im, cb->function_opaque, sw_if_index,
826 address, address_length, if_address_index, is_del);
834 ip4_add_del_interface_address (vlib_main_t * vm,
836 ip4_address_t * address,
837 u32 address_length, u32 is_del)
839 return ip4_add_del_interface_address_internal
840 (vm, sw_if_index, address, address_length, is_del);
844 ip4_directed_broadcast (u32 sw_if_index, u8 enable)
846 ip_interface_address_t *ia;
852 * when directed broadcast is enabled, the subnet braodcast route will forward
853 * packets using an adjacency with a broadcast MAC. otherwise it drops
856 foreach_ip_interface_address(&im->lookup_main, ia,
859 if (ia->address_length <= 30)
863 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
867 .fp_proto = FIB_PROTOCOL_IP4,
869 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
873 ip4_add_subnet_bcast_route
874 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
883 static clib_error_t *
884 ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
886 ip4_main_t *im = &ip4_main;
887 ip_interface_address_t *ia;
889 u32 is_admin_up, fib_index;
891 vec_validate_init_empty (im->
892 lookup_main.if_address_pool_index_by_sw_if_index,
895 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
897 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
900 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
901 0 /* honor unnumbered */,
903 a = ip_interface_address_get_address (&im->lookup_main, ia);
905 ip4_add_interface_routes (sw_if_index,
909 ip4_del_interface_routes (sw_if_index,
911 a, ia->address_length);
918 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
920 /* Built-in ip4 unicast rx feature path definition */
922 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
924 .arc_name = "ip4-unicast",
925 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
926 .last_in_arc = "ip4-lookup",
927 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
930 VNET_FEATURE_INIT (ip4_flow_classify, static) =
932 .arc_name = "ip4-unicast",
933 .node_name = "ip4-flow-classify",
934 .runs_before = VNET_FEATURES ("ip4-inacl"),
937 VNET_FEATURE_INIT (ip4_inacl, static) =
939 .arc_name = "ip4-unicast",
940 .node_name = "ip4-inacl",
941 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
944 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
946 .arc_name = "ip4-unicast",
947 .node_name = "ip4-source-and-port-range-check-rx",
948 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
951 VNET_FEATURE_INIT (ip4_policer_classify, static) =
953 .arc_name = "ip4-unicast",
954 .node_name = "ip4-policer-classify",
955 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
958 VNET_FEATURE_INIT (ip4_ipsec, static) =
960 .arc_name = "ip4-unicast",
961 .node_name = "ipsec4-input-feature",
962 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
965 VNET_FEATURE_INIT (ip4_vpath, static) =
967 .arc_name = "ip4-unicast",
968 .node_name = "vpath-input-ip4",
969 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
972 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
974 .arc_name = "ip4-unicast",
975 .node_name = "ip4-vxlan-bypass",
976 .runs_before = VNET_FEATURES ("ip4-lookup"),
979 VNET_FEATURE_INIT (ip4_not_enabled, static) =
981 .arc_name = "ip4-unicast",
982 .node_name = "ip4-not-enabled",
983 .runs_before = VNET_FEATURES ("ip4-lookup"),
986 VNET_FEATURE_INIT (ip4_lookup, static) =
988 .arc_name = "ip4-unicast",
989 .node_name = "ip4-lookup",
990 .runs_before = 0, /* not before any other features */
993 /* Built-in ip4 multicast rx feature path definition */
994 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
996 .arc_name = "ip4-multicast",
997 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
998 .last_in_arc = "ip4-mfib-forward-lookup",
999 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1002 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1004 .arc_name = "ip4-multicast",
1005 .node_name = "vpath-input-ip4",
1006 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1009 VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
1011 .arc_name = "ip4-multicast",
1012 .node_name = "ip4-not-enabled",
1013 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1016 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1018 .arc_name = "ip4-multicast",
1019 .node_name = "ip4-mfib-forward-lookup",
1020 .runs_before = 0, /* last feature */
1023 /* Source and port-range check ip4 tx feature path definition */
1024 VNET_FEATURE_ARC_INIT (ip4_output, static) =
1026 .arc_name = "ip4-output",
1027 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
1028 .last_in_arc = "interface-output",
1029 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1032 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1034 .arc_name = "ip4-output",
1035 .node_name = "ip4-source-and-port-range-check-tx",
1036 .runs_before = VNET_FEATURES ("ip4-outacl"),
1039 VNET_FEATURE_INIT (ip4_outacl, static) =
1041 .arc_name = "ip4-output",
1042 .node_name = "ip4-outacl",
1043 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
1046 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1048 .arc_name = "ip4-output",
1049 .node_name = "ipsec4-output-feature",
1050 .runs_before = VNET_FEATURES ("interface-output"),
1053 /* Built-in ip4 tx feature path definition */
1054 VNET_FEATURE_INIT (ip4_interface_output, static) =
1056 .arc_name = "ip4-output",
1057 .node_name = "interface-output",
1058 .runs_before = 0, /* not before any other features */
1062 static clib_error_t *
1063 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1065 ip4_main_t *im = &ip4_main;
1067 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1068 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
1072 /* Fill in lookup tables with default table (0). */
1073 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1074 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1078 ip4_main_t *im4 = &ip4_main;
1079 ip_lookup_main_t *lm4 = &im4->lookup_main;
1080 ip_interface_address_t *ia = 0;
1081 ip4_address_t *address;
1082 vlib_main_t *vm = vlib_get_main ();
1084 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
1086 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1088 address = ip_interface_address_get_address (lm4, ia);
1089 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1092 ip4_mfib_interface_enable_disable (sw_if_index, 0);
1094 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1095 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1096 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1097 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1099 /* Erase the lookup tables just in case */
1100 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1101 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
1104 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
1107 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1108 sw_if_index, is_add, 0, 0);
1110 return /* no error */ 0;
1113 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1115 /* Global IP4 main. */
1116 #ifndef CLIB_MARCH_VARIANT
1117 ip4_main_t ip4_main;
1118 #endif /* CLIB_MARCH_VARIANT */
1120 static clib_error_t *
1121 ip4_lookup_init (vlib_main_t * vm)
1123 ip4_main_t *im = &ip4_main;
1124 clib_error_t *error;
1127 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1129 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1131 if ((error = vlib_call_init_function (vm, fib_module_init)))
1133 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1136 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1141 m = pow2_mask (i) << (32 - i);
1144 im->fib_masks[i] = clib_host_to_net_u32 (m);
1147 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1149 /* Create FIB with index 0 and table id of 0. */
1150 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1151 FIB_SOURCE_DEFAULT_ROUTE);
1152 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1153 MFIB_SOURCE_DEFAULT_ROUTE);
1157 pn = pg_get_node (ip4_lookup_node.index);
1158 pn->unformat_edit = unformat_pg_ip4_header;
1162 ethernet_arp_header_t h;
1164 clib_memset (&h, 0, sizeof (h));
1166 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1167 #define _8(f,v) h.f = v;
1168 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1169 _16 (l3_type, ETHERNET_TYPE_IP4);
1170 _8 (n_l2_address_bytes, 6);
1171 _8 (n_l3_address_bytes, 4);
1172 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1176 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1179 /* alloc chunk size */ 8,
1186 VLIB_INIT_FUNCTION (ip4_lookup_init);
1190 /* Adjacency taken. */
1195 /* Packet data, possibly *after* rewrite. */
1196 u8 packet_data[64 - 1 * sizeof (u32)];
1198 ip4_forward_next_trace_t;
1200 #ifndef CLIB_MARCH_VARIANT
1202 format_ip4_forward_next_trace (u8 * s, va_list * args)
1204 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1205 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1206 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1207 u32 indent = format_get_indent (s);
1208 s = format (s, "%U%U",
1209 format_white_space, indent,
1210 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1216 format_ip4_lookup_trace (u8 * s, va_list * args)
1218 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1219 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1220 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1221 u32 indent = format_get_indent (s);
1223 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1224 t->fib_index, t->dpo_index, t->flow_hash);
1225 s = format (s, "\n%U%U",
1226 format_white_space, indent,
1227 format_ip4_header, t->packet_data, sizeof (t->packet_data));
1232 format_ip4_rewrite_trace (u8 * s, va_list * args)
1234 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1235 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1236 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1237 u32 indent = format_get_indent (s);
1239 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1240 t->fib_index, t->dpo_index, format_ip_adjacency,
1241 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1242 s = format (s, "\n%U%U",
1243 format_white_space, indent,
1244 format_ip_adjacency_packet_data,
1245 t->packet_data, sizeof (t->packet_data));
1249 #ifndef CLIB_MARCH_VARIANT
1250 /* Common trace function for all ip4-forward next nodes. */
1252 ip4_forward_next_trace (vlib_main_t * vm,
1253 vlib_node_runtime_t * node,
1254 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1257 ip4_main_t *im = &ip4_main;
1259 n_left = frame->n_vectors;
1260 from = vlib_frame_vector_args (frame);
1265 vlib_buffer_t *b0, *b1;
1266 ip4_forward_next_trace_t *t0, *t1;
1268 /* Prefetch next iteration. */
1269 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1270 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1275 b0 = vlib_get_buffer (vm, bi0);
1276 b1 = vlib_get_buffer (vm, bi1);
1278 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1280 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1281 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1282 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1284 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1285 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1286 vec_elt (im->fib_index_by_sw_if_index,
1287 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1289 clib_memcpy_fast (t0->packet_data,
1290 vlib_buffer_get_current (b0),
1291 sizeof (t0->packet_data));
1293 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1295 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1296 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1297 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1299 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1300 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1301 vec_elt (im->fib_index_by_sw_if_index,
1302 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1303 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1304 sizeof (t1->packet_data));
1314 ip4_forward_next_trace_t *t0;
1318 b0 = vlib_get_buffer (vm, bi0);
1320 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1322 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1323 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1324 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1326 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1327 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1328 vec_elt (im->fib_index_by_sw_if_index,
1329 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1330 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1331 sizeof (t0->packet_data));
1338 /* Compute TCP/UDP/ICMP4 checksum in software. */
1340 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1344 u32 ip_header_length, payload_length_host_byte_order;
1346 /* Initialize checksum with ip header. */
1347 ip_header_length = ip4_header_bytes (ip0);
1348 payload_length_host_byte_order =
1349 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1351 clib_host_to_net_u32 (payload_length_host_byte_order +
1352 (ip0->protocol << 16));
1354 if (BITS (uword) == 32)
1357 ip_csum_with_carry (sum0,
1358 clib_mem_unaligned (&ip0->src_address, u32));
1360 ip_csum_with_carry (sum0,
1361 clib_mem_unaligned (&ip0->dst_address, u32));
1365 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1367 return ip_calculate_l4_checksum (vm, p0, sum0,
1368 payload_length_host_byte_order, (u8 *) ip0,
1369 ip_header_length, NULL);
1373 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1375 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1379 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1380 || ip0->protocol == IP_PROTOCOL_UDP);
1382 udp0 = (void *) (ip0 + 1);
1383 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1385 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1386 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1390 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1392 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1393 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1400 VNET_FEATURE_ARC_INIT (ip4_local) = {
1401 .arc_name = "ip4-local",
1402 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
1403 .last_in_arc = "ip4-local-end-of-arc",
1408 ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1409 ip4_header_t * ip, u8 is_udp, u8 * error,
1413 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1414 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1418 u32 ip_len, udp_len;
1420 udp = ip4_next_header (ip);
1421 /* Verify UDP length. */
1422 ip_len = clib_net_to_host_u16 (ip->length);
1423 udp_len = clib_net_to_host_u16 (udp->length);
1425 len_diff = ip_len - udp_len;
1426 *good_tcp_udp &= len_diff >= 0;
1427 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1431 #define ip4_local_csum_is_offloaded(_b) \
1432 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
1433 (vnet_buffer (_b)->oflags & \
1434 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
1436 #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1437 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1438 || ip4_local_csum_is_offloaded (_b)))
1440 #define ip4_local_csum_is_valid(_b) \
1441 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1442 || (ip4_local_csum_is_offloaded (_b))) != 0
1445 ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1446 ip4_header_t * ih, u8 * error)
1448 u8 is_udp, is_tcp_udp, good_tcp_udp;
1450 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1451 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1453 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1454 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1456 good_tcp_udp = ip4_local_csum_is_valid (b);
1458 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1459 *error = (is_tcp_udp && !good_tcp_udp
1460 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1464 ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1465 ip4_header_t ** ih, u8 * error)
1467 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1469 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1470 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1472 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1473 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1475 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1476 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1478 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1479 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1482 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1485 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1489 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1490 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1491 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1492 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1496 ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1497 vlib_buffer_t * b, u16 * next, u8 error,
1498 u8 head_of_feature_arc)
1500 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1503 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1504 b->error = error ? error_node->errors[error] : 0;
1505 if (head_of_feature_arc)
1508 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1510 vnet_feature_arc_start (arc_index,
1511 vnet_buffer (b)->sw_if_index[VLIB_RX],
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-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));
2061 /* Decrement TTL & update checksum.
2062 Works either endian, so no need for byte swap. */
2063 static_always_inline void
2064 ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2069 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2074 /* Input node should have reject packets with ttl 0. */
2075 ASSERT (ip->ttl > 0);
2077 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2078 checksum += checksum >= 0xffff;
2080 ip->checksum = checksum;
2085 * If the ttl drops below 1 when forwarding, generate
2088 if (PREDICT_FALSE (ttl <= 0))
2090 *error = IP4_ERROR_TIME_EXPIRED;
2091 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2092 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2093 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2095 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2098 /* Verify checksum. */
2099 ASSERT (ip4_header_checksum_is_valid (ip) ||
2100 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2101 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2105 ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2106 vlib_frame_t *frame, int do_counters, int is_midchain,
2109 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2110 u32 *from = vlib_frame_vector_args (frame);
2111 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2112 u16 nexts[VLIB_FRAME_SIZE], *next;
2114 vlib_node_runtime_t *error_node =
2115 vlib_node_get_runtime (vm, ip4_input_node.index);
2117 n_left_from = frame->n_vectors;
2118 u32 thread_index = vm->thread_index;
2120 vlib_get_buffers (vm, from, bufs, n_left_from);
2121 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2123 #if (CLIB_N_PREFETCHES >= 8)
2124 if (n_left_from >= 6)
2127 for (i = 2; i < 6; i++)
2128 vlib_prefetch_buffer_header (bufs[i], LOAD);
2133 while (n_left_from >= 8)
2135 const ip_adjacency_t *adj0, *adj1;
2136 ip4_header_t *ip0, *ip1;
2137 u32 rw_len0, error0, adj_index0;
2138 u32 rw_len1, error1, adj_index1;
2139 u32 tx_sw_if_index0, tx_sw_if_index1;
2144 vlib_prefetch_buffer_header (b[6], LOAD);
2145 vlib_prefetch_buffer_header (b[7], LOAD);
2148 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2149 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2152 * pre-fetch the per-adjacency counters
2156 vlib_prefetch_combined_counter (&adjacency_counters,
2157 thread_index, adj_index0);
2158 vlib_prefetch_combined_counter (&adjacency_counters,
2159 thread_index, adj_index1);
2162 ip0 = vlib_buffer_get_current (b[0]);
2163 ip1 = vlib_buffer_get_current (b[1]);
2165 error0 = error1 = IP4_ERROR_NONE;
2167 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2168 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2170 /* Rewrite packet header and updates lengths. */
2171 adj0 = adj_get (adj_index0);
2172 adj1 = adj_get (adj_index1);
2174 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2175 rw_len0 = adj0[0].rewrite_header.data_bytes;
2176 rw_len1 = adj1[0].rewrite_header.data_bytes;
2177 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2178 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2180 p = vlib_buffer_get_current (b[2]);
2181 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2182 clib_prefetch_load (p);
2184 p = vlib_buffer_get_current (b[3]);
2185 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2186 clib_prefetch_load (p);
2188 /* Check MTU of outgoing interface. */
2189 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2190 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2192 if (b[0]->flags & VNET_BUFFER_F_GSO)
2193 ip0_len = gso_mtu_sz (b[0]);
2194 if (b[1]->flags & VNET_BUFFER_F_GSO)
2195 ip1_len = gso_mtu_sz (b[1]);
2197 ip4_mtu_check (b[0], ip0_len,
2198 adj0[0].rewrite_header.max_l3_packet_bytes,
2199 ip0->flags_and_fragment_offset &
2200 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2201 next + 0, is_midchain, &error0);
2202 ip4_mtu_check (b[1], ip1_len,
2203 adj1[0].rewrite_header.max_l3_packet_bytes,
2204 ip1->flags_and_fragment_offset &
2205 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2206 next + 1, is_midchain, &error1);
2210 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2211 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2212 IP4_ERROR_SAME_INTERFACE : error0);
2213 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2214 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2215 IP4_ERROR_SAME_INTERFACE : error1);
2218 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2219 * to see the IP header */
2220 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2222 u32 next_index = adj0[0].rewrite_header.next_index;
2223 vlib_buffer_advance (b[0], -(word) rw_len0);
2225 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2226 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2229 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2230 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2233 adj0->ia_cfg_index);
2235 next[0] = next_index;
2237 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2242 b[0]->error = error_node->errors[error0];
2243 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2244 ip4_ttl_inc (b[0], ip0);
2246 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2248 u32 next_index = adj1[0].rewrite_header.next_index;
2249 vlib_buffer_advance (b[1], -(word) rw_len1);
2251 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2252 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2255 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2256 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2259 adj1->ia_cfg_index);
2260 next[1] = next_index;
2262 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
2267 b[1]->error = error_node->errors[error1];
2268 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2269 ip4_ttl_inc (b[1], ip1);
2273 /* Guess we are only writing on ipv4 header. */
2274 vnet_rewrite_two_headers (adj0[0], adj1[0],
2275 ip0, ip1, sizeof (ip4_header_t));
2277 /* Guess we are only writing on simple Ethernet header. */
2278 vnet_rewrite_two_headers (adj0[0], adj1[0],
2279 ip0, ip1, sizeof (ethernet_header_t));
2283 if (error0 == IP4_ERROR_NONE)
2284 vlib_increment_combined_counter
2285 (&adjacency_counters,
2288 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2290 if (error1 == IP4_ERROR_NONE)
2291 vlib_increment_combined_counter
2292 (&adjacency_counters,
2295 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2300 if (error0 == IP4_ERROR_NONE)
2301 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2302 if (error1 == IP4_ERROR_NONE)
2303 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2308 /* copy bytes from the IP address into the MAC rewrite */
2309 if (error0 == IP4_ERROR_NONE)
2310 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2311 adj0->rewrite_header.dst_mcast_offset,
2312 &ip0->dst_address.as_u32, (u8 *) ip0);
2313 if (error1 == IP4_ERROR_NONE)
2314 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2315 adj1->rewrite_header.dst_mcast_offset,
2316 &ip1->dst_address.as_u32, (u8 *) ip1);
2323 #elif (CLIB_N_PREFETCHES >= 4)
2326 while (n_left_from >= 1)
2328 ip_adjacency_t *adj0;
2330 u32 rw_len0, error0, adj_index0;
2331 u32 tx_sw_if_index0;
2334 /* Prefetch next iteration */
2335 if (PREDICT_TRUE (n_left_from >= 4))
2337 ip_adjacency_t *adj2;
2340 vlib_prefetch_buffer_header (b[3], LOAD);
2341 vlib_prefetch_buffer_data (b[2], LOAD);
2343 /* Prefetch adj->rewrite_header */
2344 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2345 adj2 = adj_get (adj_index2);
2347 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2351 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2354 * Prefetch the per-adjacency counters
2358 vlib_prefetch_combined_counter (&adjacency_counters,
2359 thread_index, adj_index0);
2362 ip0 = vlib_buffer_get_current (b[0]);
2364 error0 = IP4_ERROR_NONE;
2366 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2368 /* Rewrite packet header and updates lengths. */
2369 adj0 = adj_get (adj_index0);
2371 /* Rewrite header was prefetched. */
2372 rw_len0 = adj0[0].rewrite_header.data_bytes;
2373 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2375 /* Check MTU of outgoing interface. */
2376 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2378 if (b[0]->flags & VNET_BUFFER_F_GSO)
2379 ip0_len = gso_mtu_sz (b[0]);
2381 ip4_mtu_check (b[0], ip0_len,
2382 adj0[0].rewrite_header.max_l3_packet_bytes,
2383 ip0->flags_and_fragment_offset &
2384 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2385 next + 0, is_midchain, &error0);
2389 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2390 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2391 IP4_ERROR_SAME_INTERFACE : error0);
2394 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2395 * to see the IP header */
2396 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2398 u32 next_index = adj0[0].rewrite_header.next_index;
2399 vlib_buffer_advance (b[0], -(word) rw_len0);
2400 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2401 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2404 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2405 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2408 adj0->ia_cfg_index);
2409 next[0] = next_index;
2413 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2416 /* Guess we are only writing on ipv4 header. */
2417 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2420 /* Guess we are only writing on simple Ethernet header. */
2421 vnet_rewrite_one_header (adj0[0], ip0,
2422 sizeof (ethernet_header_t));
2425 * Bump the per-adjacency counters
2428 vlib_increment_combined_counter
2429 (&adjacency_counters,
2431 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2435 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2438 /* copy bytes from the IP address into the MAC rewrite */
2439 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2440 adj0->rewrite_header.dst_mcast_offset,
2441 &ip0->dst_address.as_u32, (u8 *) ip0);
2445 b[0]->error = error_node->errors[error0];
2446 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2447 ip4_ttl_inc (b[0], ip0);
2456 while (n_left_from > 0)
2458 ip_adjacency_t *adj0;
2460 u32 rw_len0, adj_index0, error0;
2461 u32 tx_sw_if_index0;
2463 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2465 adj0 = adj_get (adj_index0);
2468 vlib_prefetch_combined_counter (&adjacency_counters,
2469 thread_index, adj_index0);
2471 ip0 = vlib_buffer_get_current (b[0]);
2473 error0 = IP4_ERROR_NONE;
2475 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2478 /* Update packet buffer attributes/set output interface. */
2479 rw_len0 = adj0[0].rewrite_header.data_bytes;
2480 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2482 /* Check MTU of outgoing interface. */
2483 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2484 if (b[0]->flags & VNET_BUFFER_F_GSO)
2485 ip0_len = gso_mtu_sz (b[0]);
2487 ip4_mtu_check (b[0], ip0_len,
2488 adj0[0].rewrite_header.max_l3_packet_bytes,
2489 ip0->flags_and_fragment_offset &
2490 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2491 next + 0, is_midchain, &error0);
2495 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2496 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2497 IP4_ERROR_SAME_INTERFACE : error0);
2500 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2501 * to see the IP header */
2502 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2504 u32 next_index = adj0[0].rewrite_header.next_index;
2505 vlib_buffer_advance (b[0], -(word) rw_len0);
2506 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2507 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2510 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2511 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2514 adj0->ia_cfg_index);
2515 next[0] = next_index;
2519 /* this acts on the packet that is about to be encapped */
2520 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2523 /* Guess we are only writing on ipv4 header. */
2524 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2527 /* Guess we are only writing on simple Ethernet header. */
2528 vnet_rewrite_one_header (adj0[0], ip0,
2529 sizeof (ethernet_header_t));
2532 vlib_increment_combined_counter
2533 (&adjacency_counters,
2534 thread_index, adj_index0, 1,
2535 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2538 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2541 /* copy bytes from the IP address into the MAC rewrite */
2542 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2543 adj0->rewrite_header.dst_mcast_offset,
2544 &ip0->dst_address.as_u32, (u8 *) ip0);
2548 b[0]->error = error_node->errors[error0];
2549 /* undo the TTL decrement - we'll be back to do it again */
2550 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2551 ip4_ttl_inc (b[0], ip0);
2560 /* Need to do trace after rewrites to pick up new packet data. */
2561 if (node->flags & VLIB_NODE_FLAG_TRACE)
2562 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2564 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2565 return frame->n_vectors;
2568 /** @brief IPv4 rewrite node.
2571 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2572 header checksum, fetch the ip adjacency, check the outbound mtu,
2573 apply the adjacency rewrite, and send pkts to the adjacency
2574 rewrite header's rewrite_next_index.
2576 @param vm vlib_main_t corresponding to the current thread
2577 @param node vlib_node_runtime_t
2578 @param frame vlib_frame_t whose contents should be dispatched
2580 @par Graph mechanics: buffer metadata, next index usage
2583 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2584 - the rewrite adjacency index
2585 - <code>adj->lookup_next_index</code>
2586 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2587 the packet will be dropped.
2588 - <code>adj->rewrite_header</code>
2589 - Rewrite string length, rewrite string, next_index
2592 - <code>b->current_data, b->current_length</code>
2593 - Updated net of applying the rewrite string
2595 <em>Next Indices:</em>
2596 - <code> adj->rewrite_header.next_index </code>
2600 VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2601 vlib_frame_t * frame)
2603 if (adj_are_counters_enabled ())
2604 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2606 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2609 VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2610 vlib_node_runtime_t * node,
2611 vlib_frame_t * frame)
2613 if (adj_are_counters_enabled ())
2614 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2616 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2619 VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2620 vlib_node_runtime_t * node,
2621 vlib_frame_t * frame)
2623 if (adj_are_counters_enabled ())
2624 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2626 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2629 VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2630 vlib_node_runtime_t * node,
2631 vlib_frame_t * frame)
2633 if (adj_are_counters_enabled ())
2634 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2636 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2639 VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2640 vlib_node_runtime_t * node,
2641 vlib_frame_t * frame)
2643 if (adj_are_counters_enabled ())
2644 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2646 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2650 VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2651 .name = "ip4-rewrite",
2652 .vector_size = sizeof (u32),
2654 .format_trace = format_ip4_rewrite_trace,
2656 .n_next_nodes = IP4_REWRITE_N_NEXT,
2658 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2659 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2660 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2664 VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2665 .name = "ip4-rewrite-bcast",
2666 .vector_size = sizeof (u32),
2668 .format_trace = format_ip4_rewrite_trace,
2669 .sibling_of = "ip4-rewrite",
2672 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2673 .name = "ip4-rewrite-mcast",
2674 .vector_size = sizeof (u32),
2676 .format_trace = format_ip4_rewrite_trace,
2677 .sibling_of = "ip4-rewrite",
2680 VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2681 .name = "ip4-mcast-midchain",
2682 .vector_size = sizeof (u32),
2684 .format_trace = format_ip4_rewrite_trace,
2685 .sibling_of = "ip4-rewrite",
2688 VLIB_REGISTER_NODE (ip4_midchain_node) = {
2689 .name = "ip4-midchain",
2690 .vector_size = sizeof (u32),
2691 .format_trace = format_ip4_rewrite_trace,
2692 .sibling_of = "ip4-rewrite",
2696 static clib_error_t *
2697 set_ip_flow_hash_command_fn (vlib_main_t * vm,
2698 unformat_input_t * input,
2699 vlib_cli_command_t * cmd)
2703 u32 flow_hash_config = 0;
2706 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2708 if (unformat (input, "table %d", &table_id))
2710 #define _(a, b, v) \
2711 else if (unformat (input, #a)) \
2713 flow_hash_config |= v; \
2716 foreach_flow_hash_bit
2723 return clib_error_return (0, "unknown input `%U'",
2724 format_unformat_error, input);
2726 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2732 case VNET_API_ERROR_NO_SUCH_FIB:
2733 return clib_error_return (0, "no such FIB table %d", table_id);
2736 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2744 * Configure the set of IPv4 fields used by the flow hash.
2747 * Example of how to set the flow hash on a given table:
2748 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2749 * Example of display the configured flow hash:
2750 * @cliexstart{show ip fib}
2751 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2754 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2755 * [0] [@0]: dpo-drop ip6
2758 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2759 * [0] [@0]: dpo-drop ip6
2762 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2763 * [0] [@0]: dpo-drop ip6
2766 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2767 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2770 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2771 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2772 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2773 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2774 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2777 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2778 * [0] [@0]: dpo-drop ip6
2779 * 255.255.255.255/32
2781 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2782 * [0] [@0]: dpo-drop ip6
2783 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2786 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2787 * [0] [@0]: dpo-drop ip6
2790 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2791 * [0] [@0]: dpo-drop ip6
2794 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2795 * [0] [@4]: ipv4-glean: af_packet0
2798 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2799 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2802 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2803 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2806 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2807 * [0] [@4]: ipv4-glean: af_packet1
2810 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2811 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2814 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2815 * [0] [@0]: dpo-drop ip6
2818 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2819 * [0] [@0]: dpo-drop ip6
2820 * 255.255.255.255/32
2822 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2823 * [0] [@0]: dpo-drop ip6
2827 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2829 .path = "set ip flow-hash",
2831 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2832 .function = set_ip_flow_hash_command_fn,
2836 #ifndef CLIB_MARCH_VARIANT
2838 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2841 vnet_main_t *vnm = vnet_get_main ();
2842 vnet_interface_main_t *im = &vnm->interface_main;
2843 ip4_main_t *ipm = &ip4_main;
2844 ip_lookup_main_t *lm = &ipm->lookup_main;
2845 vnet_classify_main_t *cm = &vnet_classify_main;
2846 ip4_address_t *if_addr;
2848 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2849 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2851 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2852 return VNET_API_ERROR_NO_SUCH_ENTRY;
2854 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2855 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2857 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2859 if (NULL != if_addr)
2861 fib_prefix_t pfx = {
2863 .fp_proto = FIB_PROTOCOL_IP4,
2864 .fp_addr.ip4 = *if_addr,
2868 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2872 if (table_index != (u32) ~ 0)
2874 dpo_id_t dpo = DPO_INVALID;
2879 classify_dpo_create (DPO_PROTO_IP4, table_index));
2881 fib_table_entry_special_dpo_add (fib_index,
2883 FIB_SOURCE_CLASSIFY,
2884 FIB_ENTRY_FLAG_NONE, &dpo);
2889 fib_table_entry_special_remove (fib_index,
2890 &pfx, FIB_SOURCE_CLASSIFY);
2898 static clib_error_t *
2899 set_ip_classify_command_fn (vlib_main_t * vm,
2900 unformat_input_t * input,
2901 vlib_cli_command_t * cmd)
2903 u32 table_index = ~0;
2904 int table_index_set = 0;
2905 u32 sw_if_index = ~0;
2908 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2910 if (unformat (input, "table-index %d", &table_index))
2911 table_index_set = 1;
2912 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2913 vnet_get_main (), &sw_if_index))
2919 if (table_index_set == 0)
2920 return clib_error_return (0, "classify table-index must be specified");
2922 if (sw_if_index == ~0)
2923 return clib_error_return (0, "interface / subif must be specified");
2925 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2932 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2933 return clib_error_return (0, "No such interface");
2935 case VNET_API_ERROR_NO_SUCH_ENTRY:
2936 return clib_error_return (0, "No such classifier table");
2942 * Assign a classification table to an interface. The classification
2943 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2944 * commands. Once the table is create, use this command to filter packets
2948 * Example of how to assign a classification table to an interface:
2949 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2952 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2954 .path = "set ip classify",
2956 "set ip classify intfc <interface> table-index <classify-idx>",
2957 .function = set_ip_classify_command_fn,
2962 * fd.io coding-style-patch-verification: ON
2965 * eval: (c-set-style "gnu")