LCOV - code coverage report
Current view: top level - vnet/ip - ip4_forward.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 853 969 88.0 %
Date: 2023-10-26 01:39:38 Functions: 155 191 81.2 %

          Line data    Source code
       1             : /*
       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:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       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.
      14             :  */
      15             : /*
      16             :  * ip/ip4_forward.c: IP v4 forwarding
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      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:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      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.
      38             :  */
      39             : 
      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>
      60             : 
      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>
      65             : 
      66             : /** @brief IPv4 lookup node.
      67             :     @node ip4-lookup
      68             : 
      69             :     This is the main IPv4 lookup dispatch node.
      70             : 
      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
      74             : 
      75             :     @par Graph mechanics: buffer metadata, next index usage
      76             : 
      77             :     @em Uses:
      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.
      88             : 
      89             :     @em Sets:
      90             :     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
      91             :         - The lookup result adjacency index.
      92             : 
      93             :     <em>Next Index:</em>
      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).
      97             : */
      98      343073 : VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
      99             :                                 vlib_frame_t * frame)
     100             : {
     101      340773 :   return ip4_lookup_inline (vm, node, frame);
     102             : }
     103             : 
     104             : static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
     105             : 
     106             : /* *INDENT-OFF* */
     107      183788 : VLIB_REGISTER_NODE (ip4_lookup_node) =
     108             : {
     109             :   .name = "ip4-lookup",
     110             :   .vector_size = sizeof (u32),
     111             :   .format_trace = format_ip4_lookup_trace,
     112             :   .n_next_nodes = IP_LOOKUP_N_NEXT,
     113             :   .next_nodes = IP4_LOOKUP_NEXT_NODES,
     114             : };
     115             : /* *INDENT-ON* */
     116             : 
     117        7939 : VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
     118             :                                       vlib_node_runtime_t * node,
     119             :                                       vlib_frame_t * frame)
     120             : {
     121        5639 :   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
     122             :   u32 n_left, *from;
     123        5639 :   u32 thread_index = vm->thread_index;
     124        5639 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     125             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     126             : 
     127        5639 :   from = vlib_frame_vector_args (frame);
     128        5639 :   n_left = frame->n_vectors;
     129        5639 :   next = nexts;
     130             : 
     131        5639 :   vlib_get_buffers (vm, from, bufs, n_left);
     132             : 
     133      108955 :   while (n_left >= 4)
     134             :     {
     135             :       const load_balance_t *lb0, *lb1;
     136             :       const ip4_header_t *ip0, *ip1;
     137             :       u32 lbi0, hc0, lbi1, hc1;
     138             :       const dpo_id_t *dpo0, *dpo1;
     139             : 
     140             :       /* Prefetch next iteration. */
     141             :       {
     142      103316 :         vlib_prefetch_buffer_header (b[2], LOAD);
     143      103316 :         vlib_prefetch_buffer_header (b[3], LOAD);
     144             : 
     145      103316 :         CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
     146      103316 :         CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
     147             :       }
     148             : 
     149      103316 :       ip0 = vlib_buffer_get_current (b[0]);
     150      103316 :       ip1 = vlib_buffer_get_current (b[1]);
     151      103316 :       lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
     152      103316 :       lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
     153             : 
     154      103316 :       lb0 = load_balance_get (lbi0);
     155      103316 :       lb1 = load_balance_get (lbi1);
     156             : 
     157             :       /*
     158             :        * this node is for via FIBs we can re-use the hash value from the
     159             :        * to node if present.
     160             :        * We don't want to use the same hash value at each level in the recursion
     161             :        * graph as that would lead to polarisation
     162             :        */
     163      103316 :       hc0 = hc1 = 0;
     164             : 
     165      103316 :       if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     166             :         {
     167         870 :           if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
     168             :             {
     169         584 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     170         584 :                 vnet_buffer (b[0])->ip.flow_hash >> 1;
     171             :             }
     172             :           else
     173             :             {
     174         286 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     175         286 :                 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
     176             :             }
     177         870 :           dpo0 = load_balance_get_fwd_bucket
     178         870 :             (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
     179             :         }
     180             :       else
     181             :         {
     182      102446 :           dpo0 = load_balance_get_bucket_i (lb0, 0);
     183             :         }
     184      103316 :       if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
     185             :         {
     186         855 :           if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
     187             :             {
     188         569 :               hc1 = vnet_buffer (b[1])->ip.flow_hash =
     189         569 :                 vnet_buffer (b[1])->ip.flow_hash >> 1;
     190             :             }
     191             :           else
     192             :             {
     193         286 :               hc1 = vnet_buffer (b[1])->ip.flow_hash =
     194         286 :                 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
     195             :             }
     196         855 :           dpo1 = load_balance_get_fwd_bucket
     197         855 :             (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
     198             :         }
     199             :       else
     200             :         {
     201      102461 :           dpo1 = load_balance_get_bucket_i (lb1, 0);
     202             :         }
     203             : 
     204      103316 :       next[0] = dpo0->dpoi_next_node;
     205      103316 :       next[1] = dpo1->dpoi_next_node;
     206             : 
     207      103316 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     208      103316 :       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     209             : 
     210      103316 :       vlib_increment_combined_counter
     211             :         (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
     212      103316 :       vlib_increment_combined_counter
     213      103316 :         (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
     214             : 
     215      103316 :       b += 2;
     216      103316 :       next += 2;
     217      103316 :       n_left -= 2;
     218             :     }
     219             : 
     220       18019 :   while (n_left > 0)
     221             :     {
     222             :       const load_balance_t *lb0;
     223             :       const ip4_header_t *ip0;
     224             :       const dpo_id_t *dpo0;
     225             :       u32 lbi0, hc0;
     226             : 
     227       12380 :       ip0 = vlib_buffer_get_current (b[0]);
     228       12380 :       lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
     229             : 
     230       12380 :       lb0 = load_balance_get (lbi0);
     231             : 
     232       12380 :       hc0 = 0;
     233       12380 :       if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     234             :         {
     235          22 :           if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
     236             :             {
     237          13 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     238          13 :                 vnet_buffer (b[0])->ip.flow_hash >> 1;
     239             :             }
     240             :           else
     241             :             {
     242           9 :               hc0 = vnet_buffer (b[0])->ip.flow_hash =
     243           9 :                 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
     244             :             }
     245          22 :           dpo0 = load_balance_get_fwd_bucket
     246          22 :             (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
     247             :         }
     248             :       else
     249             :         {
     250       12358 :           dpo0 = load_balance_get_bucket_i (lb0, 0);
     251             :         }
     252             : 
     253       12380 :       next[0] = dpo0->dpoi_next_node;
     254       12380 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     255             : 
     256       12380 :       vlib_increment_combined_counter
     257             :         (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
     258             : 
     259       12380 :       b += 1;
     260       12380 :       next += 1;
     261       12380 :       n_left -= 1;
     262             :     }
     263             : 
     264        5639 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     265        5639 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     266        4604 :     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
     267             : 
     268        5639 :   return frame->n_vectors;
     269             : }
     270             : 
     271             : /* *INDENT-OFF* */
     272      183788 : VLIB_REGISTER_NODE (ip4_load_balance_node) =
     273             : {
     274             :   .name = "ip4-load-balance",
     275             :   .vector_size = sizeof (u32),
     276             :   .sibling_of = "ip4-lookup",
     277             :   .format_trace = format_ip4_lookup_trace,
     278             : };
     279             : /* *INDENT-ON* */
     280             : 
     281             : #ifndef CLIB_MARCH_VARIANT
     282             : /* get first interface address */
     283             : ip4_address_t *
     284          52 : ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
     285             :                              ip_interface_address_t ** result_ia)
     286             : {
     287          52 :   ip_lookup_main_t *lm = &im->lookup_main;
     288          52 :   ip_interface_address_t *ia = 0;
     289          52 :   ip4_address_t *result = 0;
     290             : 
     291             :   /* *INDENT-OFF* */
     292          52 :   foreach_ip_interface_address
     293             :     (lm, ia, sw_if_index,
     294             :      1 /* honor unnumbered */ ,
     295             :      ({
     296             :        ip4_address_t * a =
     297             :          ip_interface_address_get_address (lm, ia);
     298             :        result = a;
     299             :        break;
     300             :      }));
     301             :   /* *INDENT-OFF* */
     302          52 :   if (result_ia)
     303           0 :     *result_ia = result ? ia : 0;
     304          52 :   return result;
     305             : }
     306             : #endif
     307             : 
     308             : static void
     309        2503 : ip4_add_subnet_bcast_route (u32 fib_index,
     310             :                             fib_prefix_t *pfx,
     311             :                             u32 sw_if_index)
     312             : {
     313             :   vnet_sw_interface_flags_t iflags;
     314             : 
     315        2503 :   iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
     316             : 
     317        2503 :   fib_table_entry_special_remove(fib_index,
     318             :                                  pfx,
     319             :                                  FIB_SOURCE_INTERFACE);
     320             : 
     321        2503 :   if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
     322             :     {
     323           2 :       fib_table_entry_update_one_path (fib_index, pfx,
     324             :                                        FIB_SOURCE_INTERFACE,
     325             :                                        FIB_ENTRY_FLAG_NONE,
     326             :                                        DPO_PROTO_IP4,
     327             :                                        /* No next-hop address */
     328             :                                        &ADJ_BCAST_ADDR,
     329             :                                        sw_if_index,
     330             :                                        // invalid FIB index
     331             :                                        ~0,
     332             :                                        1,
     333             :                                        // no out-label stack
     334             :                                        NULL,
     335             :                                        FIB_ROUTE_PATH_FLAG_NONE);
     336             :     }
     337             :   else
     338             :     {
     339        2501 :         fib_table_entry_special_add(fib_index,
     340             :                                     pfx,
     341             :                                     FIB_SOURCE_INTERFACE,
     342             :                                     (FIB_ENTRY_FLAG_DROP |
     343             :                                      FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
     344             :     }
     345        2503 : }
     346             : 
     347             : static void
     348        2568 : ip4_add_interface_prefix_routes (ip4_main_t *im,
     349             :                                  u32 sw_if_index,
     350             :                                  u32 fib_index,
     351             :                                  ip_interface_address_t * a)
     352             : {
     353        2568 :   ip_lookup_main_t *lm = &im->lookup_main;
     354             :   ip_interface_prefix_t *if_prefix;
     355        2568 :   ip4_address_t *address = ip_interface_address_get_address (lm, a);
     356             : 
     357        2568 :   ip_interface_prefix_key_t key = {
     358             :     .prefix = {
     359        2568 :       .fp_len = a->address_length,
     360             :       .fp_proto = FIB_PROTOCOL_IP4,
     361        2568 :       .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
     362             :     },
     363             :     .sw_if_index = sw_if_index,
     364             :   };
     365             : 
     366        2568 :   fib_prefix_t pfx_special = {
     367             :     .fp_proto = FIB_PROTOCOL_IP4,
     368             :   };
     369             : 
     370             :   /* If prefix already set on interface, just increment ref count & return */
     371        2568 :   if_prefix = ip_get_interface_prefix (lm, &key);
     372        2568 :   if (if_prefix)
     373             :     {
     374          13 :       if_prefix->ref_count += 1;
     375          13 :       return;
     376             :     }
     377             : 
     378             :   /* New prefix - allocate a pool entry, initialize it, add to the hash */
     379        2555 :   pool_get (lm->if_prefix_pool, if_prefix);
     380        2555 :   if_prefix->ref_count = 1;
     381        2555 :   if_prefix->src_ia_index = a - lm->if_address_pool;
     382        2555 :   clib_memcpy (&if_prefix->key, &key, sizeof (key));
     383        2555 :   mhash_set (&lm->prefix_to_if_prefix_index, &key,
     384        2555 :              if_prefix - lm->if_prefix_pool, 0 /* old value */);
     385             : 
     386        2555 :   pfx_special.fp_len = a->address_length;
     387        2555 :   pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
     388             : 
     389             :   /* set the glean route for the prefix */
     390        2555 :   fib_table_entry_update_one_path (fib_index, &pfx_special,
     391             :                                    FIB_SOURCE_INTERFACE,
     392             :                                    (FIB_ENTRY_FLAG_CONNECTED |
     393             :                                     FIB_ENTRY_FLAG_ATTACHED),
     394             :                                    DPO_PROTO_IP4,
     395             :                                    /* No next-hop address */
     396             :                                    NULL,
     397             :                                    sw_if_index,
     398             :                                    /* invalid FIB index */
     399             :                                    ~0,
     400             :                                    1,
     401             :                                    /* no out-label stack */
     402             :                                    NULL,
     403             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     404             : 
     405             :   /* length <= 30 - add glean, drop first address, maybe drop bcast address */
     406        2555 :   if (a->address_length <= 30)
     407             :     {
     408             :       /* set a drop route for the base address of the prefix */
     409        2501 :       pfx_special.fp_len = 32;
     410        2501 :       pfx_special.fp_addr.ip4.as_u32 =
     411        2501 :         address->as_u32 & im->fib_masks[a->address_length];
     412             : 
     413        2501 :       if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
     414        2499 :         fib_table_entry_special_add (fib_index, &pfx_special,
     415             :                                      FIB_SOURCE_INTERFACE,
     416             :                                      (FIB_ENTRY_FLAG_DROP |
     417             :                                       FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
     418             : 
     419             :       /* set a route for the broadcast address of the prefix */
     420        2501 :       pfx_special.fp_len = 32;
     421        2501 :       pfx_special.fp_addr.ip4.as_u32 =
     422        2501 :         address->as_u32 | ~im->fib_masks[a->address_length];
     423        2501 :       if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
     424        2501 :         ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
     425             : 
     426             : 
     427             :     }
     428             :   /* length == 31 - add an attached route for the other address */
     429          54 :   else if (a->address_length == 31)
     430             :     {
     431           1 :       pfx_special.fp_len = 32;
     432           1 :       pfx_special.fp_addr.ip4.as_u32 =
     433           1 :         address->as_u32 ^ clib_host_to_net_u32(1);
     434             : 
     435           1 :       fib_table_entry_update_one_path (fib_index, &pfx_special,
     436             :                                        FIB_SOURCE_INTERFACE,
     437             :                                        (FIB_ENTRY_FLAG_ATTACHED),
     438             :                                        DPO_PROTO_IP4,
     439             :                                        &pfx_special.fp_addr,
     440             :                                        sw_if_index,
     441             :                                        /* invalid FIB index */
     442             :                                        ~0,
     443             :                                        1,
     444             :                                        NULL,
     445             :                                        FIB_ROUTE_PATH_FLAG_NONE);
     446             :     }
     447             : }
     448             : 
     449             : static void
     450        2568 : ip4_add_interface_routes (u32 sw_if_index,
     451             :                           ip4_main_t * im, u32 fib_index,
     452             :                           ip_interface_address_t * a)
     453             : {
     454        2568 :   ip_lookup_main_t *lm = &im->lookup_main;
     455        2568 :   ip4_address_t *address = ip_interface_address_get_address (lm, a);
     456        2568 :   fib_prefix_t pfx = {
     457             :     .fp_len = 32,
     458             :     .fp_proto = FIB_PROTOCOL_IP4,
     459             :     .fp_addr.ip4 = *address,
     460             :   };
     461             : 
     462             :   /* set special routes for the prefix if needed */
     463        2568 :   ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
     464             : 
     465        2568 :   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
     466             :     {
     467           0 :       u32 classify_table_index =
     468           0 :         lm->classify_table_index_by_sw_if_index[sw_if_index];
     469           0 :       if (classify_table_index != (u32) ~ 0)
     470             :         {
     471           0 :           dpo_id_t dpo = DPO_INVALID;
     472             : 
     473           0 :           dpo_set (&dpo,
     474             :                    DPO_CLASSIFY,
     475             :                    DPO_PROTO_IP4,
     476             :                    classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
     477             : 
     478           0 :           fib_table_entry_special_dpo_add (fib_index,
     479             :                                            &pfx,
     480             :                                            FIB_SOURCE_CLASSIFY,
     481             :                                            FIB_ENTRY_FLAG_NONE, &dpo);
     482           0 :           dpo_reset (&dpo);
     483             :         }
     484             :     }
     485             : 
     486        2568 :   fib_table_entry_update_one_path (fib_index, &pfx,
     487             :                                    FIB_SOURCE_INTERFACE,
     488             :                                    (FIB_ENTRY_FLAG_CONNECTED |
     489             :                                     FIB_ENTRY_FLAG_LOCAL),
     490             :                                    DPO_PROTO_IP4,
     491             :                                    &pfx.fp_addr,
     492             :                                    sw_if_index,
     493             :                                    // invalid FIB index
     494             :                                    ~0,
     495             :                                    1, NULL,
     496             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     497        2568 : }
     498             : 
     499             : static void
     500        2330 : ip4_del_interface_prefix_routes (ip4_main_t * im,
     501             :                                  u32 sw_if_index,
     502             :                                  u32 fib_index,
     503             :                                  ip4_address_t * address,
     504             :                                  u32 address_length)
     505             : {
     506        2330 :   ip_lookup_main_t *lm = &im->lookup_main;
     507             :   ip_interface_prefix_t *if_prefix;
     508             : 
     509        2330 :   ip_interface_prefix_key_t key = {
     510             :     .prefix = {
     511             :       .fp_len = address_length,
     512             :       .fp_proto = FIB_PROTOCOL_IP4,
     513        2330 :       .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
     514             :     },
     515             :     .sw_if_index = sw_if_index,
     516             :   };
     517             : 
     518        2330 :   fib_prefix_t pfx_special = {
     519             :     .fp_len = 32,
     520             :     .fp_proto = FIB_PROTOCOL_IP4,
     521             :   };
     522             : 
     523        2330 :   if_prefix = ip_get_interface_prefix (lm, &key);
     524        2330 :   if (!if_prefix)
     525             :     {
     526           0 :       clib_warning ("Prefix not found while deleting %U",
     527             :                     format_ip4_address_and_length, address, address_length);
     528          13 :       return;
     529             :     }
     530             : 
     531        2330 :   if_prefix->ref_count -= 1;
     532             : 
     533             :   /*
     534             :    * Routes need to be adjusted if deleting last intf addr in prefix
     535             :    *
     536             :    * We're done now otherwise
     537             :    */
     538        2330 :   if (if_prefix->ref_count > 0)
     539          13 :     return;
     540             : 
     541             :   /* length <= 30, delete glean route, first address, last address */
     542        2317 :   if (address_length <= 30)
     543             :     {
     544             :       /* Less work to do in FIB if we remove the covered /32s first */
     545             : 
     546             :       /* first address in prefix */
     547        2264 :       pfx_special.fp_addr.ip4.as_u32 =
     548        2264 :         address->as_u32 & im->fib_masks[address_length];
     549        2264 :       pfx_special.fp_len = 32;
     550             : 
     551        2264 :       if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
     552        2262 :         fib_table_entry_special_remove (fib_index,
     553             :                                         &pfx_special,
     554             :                                         FIB_SOURCE_INTERFACE);
     555             : 
     556             :       /* prefix broadcast address */
     557        2264 :       pfx_special.fp_addr.ip4.as_u32 =
     558        2264 :         address->as_u32 | ~im->fib_masks[address_length];
     559        2264 :       pfx_special.fp_len = 32;
     560             : 
     561        2264 :       if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
     562        2264 :         fib_table_entry_special_remove (fib_index,
     563             :                                         &pfx_special,
     564             :                                         FIB_SOURCE_INTERFACE);
     565             :     }
     566          53 :   else if (address_length == 31)
     567             :     {
     568             :       /* length == 31, delete attached route for the other address */
     569           1 :       pfx_special.fp_addr.ip4.as_u32 =
     570           1 :         address->as_u32 ^ clib_host_to_net_u32(1);
     571             : 
     572           1 :       fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
     573             :     }
     574             : 
     575             :   /* remove glean route for prefix */
     576        2317 :   pfx_special.fp_addr.ip4 = *address;
     577        2317 :   pfx_special.fp_len = address_length;
     578        2317 :   fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
     579             : 
     580        2317 :   mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
     581        2317 :   pool_put (lm->if_prefix_pool, if_prefix);
     582             : }
     583             : 
     584             : static void
     585        2330 : ip4_del_interface_routes (u32 sw_if_index,
     586             :                           ip4_main_t * im,
     587             :                           u32 fib_index,
     588             :                           ip4_address_t * address, u32 address_length)
     589             : {
     590        2330 :   fib_prefix_t pfx = {
     591             :     .fp_len = 32,
     592             :     .fp_proto = FIB_PROTOCOL_IP4,
     593             :     .fp_addr.ip4 = *address,
     594             :   };
     595             : 
     596        2330 :   fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
     597             : 
     598        2330 :   ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
     599             :                                    address, address_length);
     600        2330 : }
     601             : 
     602             : #ifndef CLIB_MARCH_VARIANT
     603             : void
     604        4891 : ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
     605             : {
     606        4891 :   ip4_main_t *im = &ip4_main;
     607        4891 :   vnet_main_t *vnm = vnet_get_main ();
     608        4891 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     609             : 
     610        6817 :   vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
     611             : 
     612             :   /*
     613             :    * enable/disable only on the 1<->0 transition
     614             :    */
     615        4891 :   if (is_enable)
     616             :     {
     617        2572 :       if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
     618          44 :         return;
     619             :     }
     620             :   else
     621             :     {
     622        2319 :       ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
     623        2319 :       if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
     624          38 :         return;
     625             :     }
     626        4809 :   vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
     627             :                                !is_enable, 0, 0);
     628             : 
     629             : 
     630        4809 :   vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
     631             :                                sw_if_index, !is_enable, 0, 0);
     632             : 
     633        4809 :   if (is_enable)
     634        2528 :     hi->l3_if_count++;
     635        2281 :   else if (hi->l3_if_count)
     636        2281 :     hi->l3_if_count--;
     637             : 
     638             :   {
     639             :     ip4_enable_disable_interface_callback_t *cb;
     640        9618 :     vec_foreach (cb, im->enable_disable_interface_callbacks)
     641        4809 :       cb->function (im, cb->function_opaque, sw_if_index, is_enable);
     642             :   }
     643             : }
     644             : 
     645             : static clib_error_t *
     646        4845 : ip4_add_del_interface_address_internal (vlib_main_t * vm,
     647             :                                         u32 sw_if_index,
     648             :                                         ip4_address_t * address,
     649             :                                         u32 address_length, u32 is_del)
     650             : {
     651        4845 :   vnet_main_t *vnm = vnet_get_main ();
     652        4845 :   ip4_main_t *im = &ip4_main;
     653        4845 :   ip_lookup_main_t *lm = &im->lookup_main;
     654        4845 :   clib_error_t *error = 0;
     655             :   u32 if_address_index;
     656        4845 :   ip4_address_fib_t ip4_af, *addr_fib = 0;
     657             : 
     658        4845 :   error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
     659        4845 :   if (error)
     660             :     {
     661           0 :       vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
     662           0 :       return error;
     663             :     }
     664             : 
     665        4845 :   ip4_addr_fib_init (&ip4_af, address,
     666        4845 :                      vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
     667        4845 :   vec_add1 (addr_fib, ip4_af);
     668             : 
     669             :   /*
     670             :    * there is no support for adj-fib handling in the presence of overlapping
     671             :    * subnets on interfaces. Easy fix - disallow overlapping subnets, like
     672             :    * most routers do.
     673             :    */
     674             :   /* *INDENT-OFF* */
     675        4845 :   if (!is_del)
     676             :     {
     677             :       /* When adding an address check that it does not conflict
     678             :          with an existing address on any interface in this table. */
     679             :       ip_interface_address_t *ia;
     680             :       vnet_sw_interface_t *sif;
     681             : 
     682       15969 :       pool_foreach (sif, vnm->interface_main.sw_interfaces)
     683             :        {
     684       13422 :           if (im->fib_index_by_sw_if_index[sw_if_index] ==
     685       13422 :               im->fib_index_by_sw_if_index[sif->sw_if_index])
     686             :             {
     687       15375 :               foreach_ip_interface_address
     688             :                 (&im->lookup_main, ia, sif->sw_if_index,
     689             :                  0 /* honor unnumbered */ ,
     690             :                  ({
     691             :                    ip4_address_t * x =
     692             :                      ip_interface_address_get_address
     693             :                      (&im->lookup_main, ia);
     694             : 
     695             :                    if (ip4_destination_matches_route
     696             :                        (im, address, x, ia->address_length) ||
     697             :                        ip4_destination_matches_route (im,
     698             :                                                       x,
     699             :                                                       address,
     700             :                                                       address_length))
     701             :                      {
     702             :                        /* an intf may have >1 addr from the same prefix */
     703             :                        if ((sw_if_index == sif->sw_if_index) &&
     704             :                            (ia->address_length == address_length) &&
     705             :                            (x->as_u32 != address->as_u32))
     706             :                          continue;
     707             : 
     708             :                        if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     709             :                          /* if the address we're comparing against is stale
     710             :                           * then the CP has not added this one back yet, maybe
     711             :                           * it never will, so we have to assume it won't and
     712             :                           * ignore it. if it does add it back, then it will fail
     713             :                           * because this one is now present */
     714             :                          continue;
     715             : 
     716             :                        /* error if the length or intf was different */
     717             :                        vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
     718             : 
     719             :                        error = clib_error_create
     720             :                          ("failed to add %U on %U which conflicts with %U for interface %U",
     721             :                           format_ip4_address_and_length, address,
     722             :                           address_length,
     723             :                           format_vnet_sw_if_index_name, vnm,
     724             :                           sw_if_index,
     725             :                           format_ip4_address_and_length, x,
     726             :                           ia->address_length,
     727             :                           format_vnet_sw_if_index_name, vnm,
     728             :                           sif->sw_if_index);
     729             :                        goto done;
     730             :                      }
     731             :                  }));
     732             :             }
     733             :       }
     734             :     }
     735             :   /* *INDENT-ON* */
     736             : 
     737        4845 :   if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
     738             : 
     739        4845 :   if (is_del)
     740             :     {
     741        2298 :       if (~0 == if_address_index)
     742             :         {
     743           0 :           vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
     744           0 :           error = clib_error_create ("%U not found for interface %U",
     745             :                                      lm->format_address_and_length,
     746             :                                      addr_fib, address_length,
     747             :                                      format_vnet_sw_if_index_name, vnm,
     748             :                                      sw_if_index);
     749           0 :           goto done;
     750             :         }
     751             : 
     752        2298 :       error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
     753             :                                         address_length, sw_if_index);
     754        2298 :       if (error)
     755           1 :         goto done;
     756             :     }
     757             :   else
     758             :     {
     759        2547 :       if (~0 != if_address_index)
     760             :         {
     761             :           ip_interface_address_t *ia;
     762             : 
     763           9 :           ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
     764             : 
     765           9 :           if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     766             :             {
     767           9 :               if (ia->sw_if_index == sw_if_index)
     768             :                 {
     769             :                   /* re-adding an address during the replace action.
     770             :                    * consdier this the update. clear the flag and
     771             :                    * we're done */
     772           6 :                   ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
     773           6 :                   goto done;
     774             :                 }
     775             :               else
     776             :                 {
     777             :                   /* The prefix is moving from one interface to another.
     778             :                    * delete the stale and add the new */
     779           3 :                   ip4_add_del_interface_address_internal (vm,
     780             :                                                           ia->sw_if_index,
     781             :                                                           address,
     782             :                                                           address_length, 1);
     783           3 :                   ia = NULL;
     784           3 :                   error = ip_interface_address_add (lm, sw_if_index,
     785             :                                                     addr_fib, address_length,
     786             :                                                     &if_address_index);
     787             :                 }
     788             :             }
     789             :           else
     790             :             {
     791           0 :               vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
     792           0 :               error = clib_error_create
     793             :                 ("Prefix %U already found on interface %U",
     794             :                  lm->format_address_and_length, addr_fib, address_length,
     795             :                  format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
     796             :             }
     797             :         }
     798             :       else
     799        2538 :         error = ip_interface_address_add (lm, sw_if_index,
     800             :                                           addr_fib, address_length,
     801             :                                           &if_address_index);
     802             :     }
     803             : 
     804        4838 :   if (error)
     805           0 :     goto done;
     806             : 
     807        4838 :   ip4_sw_interface_enable_disable (sw_if_index, !is_del);
     808        4838 :   ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
     809             : 
     810             :   /* intf addr routes are added/deleted on admin up/down */
     811        4838 :   if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
     812             :     {
     813        3549 :       if (is_del)
     814        1123 :         ip4_del_interface_routes (sw_if_index,
     815             :                                   im, ip4_af.fib_index, address,
     816             :                                   address_length);
     817             :       else
     818        2426 :         ip4_add_interface_routes (sw_if_index,
     819             :                                   im, ip4_af.fib_index,
     820        2426 :                                   pool_elt_at_index
     821             :                                   (lm->if_address_pool, if_address_index));
     822             :     }
     823             : 
     824             :   ip4_add_del_interface_address_callback_t *cb;
     825       48396 :   vec_foreach (cb, im->add_del_interface_address_callbacks)
     826       43558 :     cb->function (im, cb->function_opaque, sw_if_index,
     827             :                   address, address_length, if_address_index, is_del);
     828             : 
     829        4838 : done:
     830        4845 :   vec_free (addr_fib);
     831        4845 :   return error;
     832             : }
     833             : 
     834             : clib_error_t *
     835        4842 : ip4_add_del_interface_address (vlib_main_t * vm,
     836             :                                u32 sw_if_index,
     837             :                                ip4_address_t * address,
     838             :                                u32 address_length, u32 is_del)
     839             : {
     840        4842 :   return ip4_add_del_interface_address_internal
     841             :     (vm, sw_if_index, address, address_length, is_del);
     842             : }
     843             : 
     844             : void
     845           3 : ip4_directed_broadcast (u32 sw_if_index, u8 enable)
     846             : {
     847             :   ip_interface_address_t *ia;
     848             :   ip4_main_t *im;
     849             : 
     850           3 :   im = &ip4_main;
     851             : 
     852             :   /*
     853             :    * when directed broadcast is enabled, the subnet braodcast route will forward
     854             :    * packets using an adjacency with a broadcast MAC. otherwise it drops
     855             :    */
     856             :   /* *INDENT-OFF* */
     857           5 :   foreach_ip_interface_address(&im->lookup_main, ia,
     858             :                                sw_if_index, 0,
     859             :      ({
     860             :        if (ia->address_length <= 30)
     861             :          {
     862             :            ip4_address_t *ipa;
     863             : 
     864             :            ipa = ip_interface_address_get_address (&im->lookup_main, ia);
     865             : 
     866             :            fib_prefix_t pfx = {
     867             :              .fp_len = 32,
     868             :              .fp_proto = FIB_PROTOCOL_IP4,
     869             :              .fp_addr = {
     870             :                .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
     871             :              },
     872             :            };
     873             : 
     874             :            ip4_add_subnet_bcast_route
     875             :              (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
     876             :                                                   sw_if_index),
     877             :               &pfx, sw_if_index);
     878             :          }
     879             :      }));
     880             :   /* *INDENT-ON* */
     881           3 : }
     882             : #endif
     883             : 
     884             : static clib_error_t *
     885       13514 : ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
     886             : {
     887       13514 :   ip4_main_t *im = &ip4_main;
     888             :   ip_interface_address_t *ia;
     889             :   ip4_address_t *a;
     890             :   u32 is_admin_up, fib_index;
     891             : 
     892       13514 :   vec_validate_init_empty (im->
     893             :                            lookup_main.if_address_pool_index_by_sw_if_index,
     894             :                            sw_if_index, ~0);
     895             : 
     896       13514 :   is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
     897             : 
     898       13514 :   fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
     899             : 
     900             :   /* *INDENT-OFF* */
     901       14863 :   foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
     902             :                                 0 /* honor unnumbered */,
     903             :   ({
     904             :     a = ip_interface_address_get_address (&im->lookup_main, ia);
     905             :     if (is_admin_up)
     906             :       ip4_add_interface_routes (sw_if_index,
     907             :                                 im, fib_index,
     908             :                                 ia);
     909             :     else
     910             :       ip4_del_interface_routes (sw_if_index,
     911             :                                 im, fib_index,
     912             :                                 a, ia->address_length);
     913             :   }));
     914             :   /* *INDENT-ON* */
     915             : 
     916       13514 :   return 0;
     917             : }
     918             : 
     919        2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
     920             : 
     921             : /* Built-in ip4 unicast rx feature path definition */
     922             : /* *INDENT-OFF* */
     923        1151 : VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
     924             : {
     925             :   .arc_name = "ip4-unicast",
     926             :   .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
     927             :   .last_in_arc = "ip4-lookup",
     928             :   .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
     929             : };
     930             : 
     931       76635 : VNET_FEATURE_INIT (ip4_flow_classify, static) =
     932             : {
     933             :   .arc_name = "ip4-unicast",
     934             :   .node_name = "ip4-flow-classify",
     935             :   .runs_before = VNET_FEATURES ("ip4-inacl"),
     936             : };
     937             : 
     938       76635 : VNET_FEATURE_INIT (ip4_inacl, static) =
     939             : {
     940             :   .arc_name = "ip4-unicast",
     941             :   .node_name = "ip4-inacl",
     942             :   .runs_before = VNET_FEATURES ("ip4-policer-classify"),
     943             : };
     944             : 
     945       76635 : VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
     946             : {
     947             :   .arc_name = "ip4-unicast",
     948             :   .node_name = "ip4-source-and-port-range-check-rx",
     949             :   .runs_before = VNET_FEATURES ("ip4-policer-classify"),
     950             : };
     951             : 
     952       76635 : VNET_FEATURE_INIT (ip4_policer_classify, static) =
     953             : {
     954             :   .arc_name = "ip4-unicast",
     955             :   .node_name = "ip4-policer-classify",
     956             :   .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
     957             : };
     958             : 
     959       76635 : VNET_FEATURE_INIT (ip4_ipsec, static) =
     960             : {
     961             :   .arc_name = "ip4-unicast",
     962             :   .node_name = "ipsec4-input-feature",
     963             :   .runs_before = VNET_FEATURES ("vpath-input-ip4"),
     964             : };
     965             : 
     966       76635 : VNET_FEATURE_INIT (ip4_vpath, static) =
     967             : {
     968             :   .arc_name = "ip4-unicast",
     969             :   .node_name = "vpath-input-ip4",
     970             :   .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
     971             : };
     972             : 
     973       76635 : VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
     974             : {
     975             :   .arc_name = "ip4-unicast",
     976             :   .node_name = "ip4-vxlan-bypass",
     977             :   .runs_before = VNET_FEATURES ("ip4-lookup"),
     978             : };
     979             : 
     980       76635 : VNET_FEATURE_INIT (ip4_not_enabled, static) =
     981             : {
     982             :   .arc_name = "ip4-unicast",
     983             :   .node_name = "ip4-not-enabled",
     984             :   .runs_before = VNET_FEATURES ("ip4-lookup"),
     985             : };
     986             : 
     987       76635 : VNET_FEATURE_INIT (ip4_lookup, static) =
     988             : {
     989             :   .arc_name = "ip4-unicast",
     990             :   .node_name = "ip4-lookup",
     991             :   .runs_before = 0,     /* not before any other features */
     992             : };
     993             : 
     994             : /* Built-in ip4 multicast rx feature path definition */
     995        1151 : VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
     996             : {
     997             :   .arc_name = "ip4-multicast",
     998             :   .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
     999             :   .last_in_arc = "ip4-mfib-forward-lookup",
    1000             :   .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
    1001             : };
    1002             : 
    1003       76635 : VNET_FEATURE_INIT (ip4_vpath_mc, static) =
    1004             : {
    1005             :   .arc_name = "ip4-multicast",
    1006             :   .node_name = "vpath-input-ip4",
    1007             :   .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
    1008             : };
    1009             : 
    1010       76635 : VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
    1011             : {
    1012             :   .arc_name = "ip4-multicast",
    1013             :   .node_name = "ip4-not-enabled",
    1014             :   .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
    1015             : };
    1016             : 
    1017       76635 : VNET_FEATURE_INIT (ip4_lookup_mc, static) =
    1018             : {
    1019             :   .arc_name = "ip4-multicast",
    1020             :   .node_name = "ip4-mfib-forward-lookup",
    1021             :   .runs_before = 0,     /* last feature */
    1022             : };
    1023             : 
    1024             : /* Source and port-range check ip4 tx feature path definition */
    1025        1151 : VNET_FEATURE_ARC_INIT (ip4_output, static) =
    1026             : {
    1027             :   .arc_name = "ip4-output",
    1028             :   .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
    1029             :   .last_in_arc = "interface-output",
    1030             :   .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
    1031             : };
    1032             : 
    1033       76635 : VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
    1034             : {
    1035             :   .arc_name = "ip4-output",
    1036             :   .node_name = "ip4-source-and-port-range-check-tx",
    1037             :   .runs_before = VNET_FEATURES ("ip4-outacl"),
    1038             : };
    1039             : 
    1040       76635 : VNET_FEATURE_INIT (ip4_outacl, static) =
    1041             : {
    1042             :   .arc_name = "ip4-output",
    1043             :   .node_name = "ip4-outacl",
    1044             :   .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
    1045             : };
    1046             : 
    1047       76635 : VNET_FEATURE_INIT (ip4_ipsec_output, static) =
    1048             : {
    1049             :   .arc_name = "ip4-output",
    1050             :   .node_name = "ipsec4-output-feature",
    1051             :   .runs_before = VNET_FEATURES ("interface-output"),
    1052             : };
    1053             : 
    1054             : /* Built-in ip4 tx feature path definition */
    1055       76635 : VNET_FEATURE_INIT (ip4_interface_output, static) =
    1056             : {
    1057             :   .arc_name = "ip4-output",
    1058             :   .node_name = "interface-output",
    1059             :   .runs_before = 0,     /* not before any other features */
    1060             : };
    1061             : /* *INDENT-ON* */
    1062             : 
    1063             : static clib_error_t *
    1064       11798 : ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
    1065             : {
    1066       11798 :   ip4_main_t *im = &ip4_main;
    1067             : 
    1068       15752 :   vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
    1069       15752 :   vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
    1070             : 
    1071       11798 :   if (is_add)
    1072             :     {
    1073             :       /* Fill in lookup tables with default table (0). */
    1074        7547 :       im->fib_index_by_sw_if_index[sw_if_index] = 0;
    1075        7547 :       im->mfib_index_by_sw_if_index[sw_if_index] = 0;
    1076             :     }
    1077             :   else
    1078             :     {
    1079        4251 :       ip4_main_t *im4 = &ip4_main;
    1080        4251 :       ip_lookup_main_t *lm4 = &im4->lookup_main;
    1081        4251 :       ip_interface_address_t *ia = 0;
    1082             :       ip4_address_t *address;
    1083        4251 :       vlib_main_t *vm = vlib_get_main ();
    1084             : 
    1085        4251 :       vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
    1086             :       /* *INDENT-OFF* */
    1087        4252 :       foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
    1088             :       ({
    1089             :         address = ip_interface_address_get_address (lm4, ia);
    1090             :         ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
    1091             :       }));
    1092             :       /* *INDENT-ON* */
    1093        4251 :       ip4_mfib_interface_enable_disable (sw_if_index, 0);
    1094             : 
    1095        4251 :       if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
    1096         108 :         fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
    1097        4251 :       if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
    1098         108 :         mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
    1099             : 
    1100             :       /* Erase the lookup tables just in case */
    1101        4251 :       im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
    1102        4251 :       im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
    1103             :     }
    1104             : 
    1105       11798 :   vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
    1106             :                                is_add, 0, 0);
    1107             : 
    1108       11798 :   vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
    1109             :                                sw_if_index, is_add, 0, 0);
    1110             : 
    1111       11798 :   return /* no error */ 0;
    1112             : }
    1113             : 
    1114        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
    1115             : 
    1116             : /* Global IP4 main. */
    1117             : #ifndef CLIB_MARCH_VARIANT
    1118             : ip4_main_t ip4_main;
    1119             : #endif /* CLIB_MARCH_VARIANT */
    1120             : 
    1121             : static clib_error_t *
    1122         575 : ip4_lookup_init (vlib_main_t * vm)
    1123             : {
    1124         575 :   ip4_main_t *im = &ip4_main;
    1125             :   clib_error_t *error;
    1126             :   uword i;
    1127             : 
    1128         575 :   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
    1129           0 :     return error;
    1130         575 :   if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
    1131           0 :     return (error);
    1132         575 :   if ((error = vlib_call_init_function (vm, fib_module_init)))
    1133           0 :     return error;
    1134         575 :   if ((error = vlib_call_init_function (vm, mfib_module_init)))
    1135           0 :     return error;
    1136             : 
    1137       19550 :   for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
    1138             :     {
    1139             :       u32 m;
    1140             : 
    1141       18975 :       if (i < 32)
    1142       18400 :         m = pow2_mask (i) << (32 - i);
    1143             :       else
    1144         575 :         m = ~0;
    1145       18975 :       im->fib_masks[i] = clib_host_to_net_u32 (m);
    1146             :     }
    1147             : 
    1148         575 :   ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
    1149             : 
    1150             :   /* Create FIB with index 0 and table id of 0. */
    1151         575 :   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
    1152             :                                      FIB_SOURCE_DEFAULT_ROUTE);
    1153         575 :   mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
    1154             :                                       MFIB_SOURCE_DEFAULT_ROUTE);
    1155             : 
    1156             :   {
    1157             :     pg_node_t *pn;
    1158         575 :     pn = pg_get_node (ip4_lookup_node.index);
    1159         575 :     pn->unformat_edit = unformat_pg_ip4_header;
    1160             :   }
    1161             : 
    1162             :   {
    1163             :     ethernet_arp_header_t h;
    1164             : 
    1165         575 :     clib_memset (&h, 0, sizeof (h));
    1166             : 
    1167             : #define _16(f,v) h.f = clib_host_to_net_u16 (v);
    1168             : #define _8(f,v) h.f = v;
    1169         575 :     _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
    1170         575 :     _16 (l3_type, ETHERNET_TYPE_IP4);
    1171         575 :     _8 (n_l2_address_bytes, 6);
    1172         575 :     _8 (n_l3_address_bytes, 4);
    1173         575 :     _16 (opcode, ETHERNET_ARP_OPCODE_request);
    1174             : #undef _16
    1175             : #undef _8
    1176             : 
    1177         575 :     vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
    1178             :                                /* data */ &h,
    1179             :                                sizeof (h),
    1180             :                                /* alloc chunk size */ 8,
    1181             :                                "ip4 arp");
    1182             :   }
    1183             : 
    1184         575 :   return error;
    1185             : }
    1186             : 
    1187       12671 : VLIB_INIT_FUNCTION (ip4_lookup_init);
    1188             : 
    1189             : typedef struct
    1190             : {
    1191             :   /* Adjacency taken. */
    1192             :   u32 dpo_index;
    1193             :   u32 flow_hash;
    1194             :   u32 fib_index;
    1195             : 
    1196             :   /* Packet data, possibly *after* rewrite. */
    1197             :   u8 packet_data[64 - 1 * sizeof (u32)];
    1198             : }
    1199             : ip4_forward_next_trace_t;
    1200             : 
    1201             : #ifndef CLIB_MARCH_VARIANT
    1202             : u8 *
    1203      121592 : format_ip4_forward_next_trace (u8 * s, va_list * args)
    1204             : {
    1205      121592 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1206      121592 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1207      121592 :   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
    1208      121592 :   u32 indent = format_get_indent (s);
    1209      121592 :   s = format (s, "%U%U",
    1210             :               format_white_space, indent,
    1211      121592 :               format_ip4_header, t->packet_data, sizeof (t->packet_data));
    1212      121592 :   return s;
    1213             : }
    1214             : #endif
    1215             : 
    1216             : static u8 *
    1217      348913 : format_ip4_lookup_trace (u8 * s, va_list * args)
    1218             : {
    1219      348913 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1220      348913 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1221      348913 :   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
    1222      348913 :   u32 indent = format_get_indent (s);
    1223             : 
    1224      348913 :   s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
    1225             :               t->fib_index, t->dpo_index, t->flow_hash);
    1226      348913 :   s = format (s, "\n%U%U",
    1227             :               format_white_space, indent,
    1228      348913 :               format_ip4_header, t->packet_data, sizeof (t->packet_data));
    1229      348913 :   return s;
    1230             : }
    1231             : 
    1232             : static u8 *
    1233      223055 : format_ip4_rewrite_trace (u8 * s, va_list * args)
    1234             : {
    1235      223055 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1236      223055 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1237      223055 :   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
    1238      223055 :   u32 indent = format_get_indent (s);
    1239             : 
    1240      223055 :   s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
    1241             :               t->fib_index, t->dpo_index, format_ip_adjacency,
    1242             :               t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
    1243      223055 :   s = format (s, "\n%U%U",
    1244             :               format_white_space, indent,
    1245             :               format_ip_adjacency_packet_data,
    1246      223055 :               t->packet_data, sizeof (t->packet_data));
    1247      223055 :   return s;
    1248             : }
    1249             : 
    1250             : #ifndef CLIB_MARCH_VARIANT
    1251             : /* Common trace function for all ip4-forward next nodes. */
    1252             : void
    1253       25258 : ip4_forward_next_trace (vlib_main_t * vm,
    1254             :                         vlib_node_runtime_t * node,
    1255             :                         vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
    1256             : {
    1257             :   u32 *from, n_left;
    1258       25258 :   ip4_main_t *im = &ip4_main;
    1259             : 
    1260       25258 :   n_left = frame->n_vectors;
    1261       25258 :   from = vlib_frame_vector_args (frame);
    1262             : 
    1263      497725 :   while (n_left >= 4)
    1264             :     {
    1265             :       u32 bi0, bi1;
    1266             :       vlib_buffer_t *b0, *b1;
    1267             :       ip4_forward_next_trace_t *t0, *t1;
    1268             : 
    1269             :       /* Prefetch next iteration. */
    1270      472469 :       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
    1271      472466 :       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
    1272             : 
    1273      472465 :       bi0 = from[0];
    1274      472465 :       bi1 = from[1];
    1275             : 
    1276      472465 :       b0 = vlib_get_buffer (vm, bi0);
    1277      472465 :       b1 = vlib_get_buffer (vm, bi1);
    1278             : 
    1279      472465 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1280             :         {
    1281      471459 :           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
    1282      471458 :           t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
    1283      471458 :           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
    1284      471458 :           t0->fib_index =
    1285      471458 :             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
    1286      471458 :              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
    1287      289347 :             vec_elt (im->fib_index_by_sw_if_index,
    1288             :                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
    1289             : 
    1290      471457 :           clib_memcpy_fast (t0->packet_data,
    1291      471458 :                             vlib_buffer_get_current (b0),
    1292             :                             sizeof (t0->packet_data));
    1293             :         }
    1294      472467 :       if (b1->flags & VLIB_BUFFER_IS_TRACED)
    1295             :         {
    1296      471461 :           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
    1297      471459 :           t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
    1298      471459 :           t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
    1299      471459 :           t1->fib_index =
    1300      471459 :             (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
    1301      471459 :              (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
    1302      289280 :             vec_elt (im->fib_index_by_sw_if_index,
    1303             :                      vnet_buffer (b1)->sw_if_index[VLIB_RX]);
    1304      471459 :           clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
    1305             :                             sizeof (t1->packet_data));
    1306             :         }
    1307      472467 :       from += 2;
    1308      472467 :       n_left -= 2;
    1309             :     }
    1310             : 
    1311       78700 :   while (n_left >= 1)
    1312             :     {
    1313             :       u32 bi0;
    1314             :       vlib_buffer_t *b0;
    1315             :       ip4_forward_next_trace_t *t0;
    1316             : 
    1317       53444 :       bi0 = from[0];
    1318             : 
    1319       53444 :       b0 = vlib_get_buffer (vm, bi0);
    1320             : 
    1321       53444 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1322             :         {
    1323       53299 :           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
    1324       53299 :           t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
    1325       53299 :           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
    1326       53299 :           t0->fib_index =
    1327       53299 :             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
    1328       53299 :              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
    1329       34525 :             vec_elt (im->fib_index_by_sw_if_index,
    1330             :                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
    1331       53299 :           clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
    1332             :                             sizeof (t0->packet_data));
    1333             :         }
    1334       53444 :       from += 1;
    1335       53444 :       n_left -= 1;
    1336             :     }
    1337       25256 : }
    1338             : 
    1339             : /* Compute TCP/UDP/ICMP4 checksum in software. */
    1340             : u16
    1341    14606200 : ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
    1342             :                               ip4_header_t * ip0)
    1343             : {
    1344             :   ip_csum_t sum0;
    1345             :   u32 ip_header_length, payload_length_host_byte_order;
    1346             : 
    1347             :   /* Initialize checksum with ip header. */
    1348    14606200 :   ip_header_length = ip4_header_bytes (ip0);
    1349    14606200 :   payload_length_host_byte_order =
    1350    14606200 :     clib_net_to_host_u16 (ip0->length) - ip_header_length;
    1351    14606200 :   sum0 =
    1352    14606200 :     clib_host_to_net_u32 (payload_length_host_byte_order +
    1353    14606200 :                           (ip0->protocol << 16));
    1354             : 
    1355             :   if (BITS (uword) == 32)
    1356             :     {
    1357             :       sum0 =
    1358             :         ip_csum_with_carry (sum0,
    1359             :                             clib_mem_unaligned (&ip0->src_address, u32));
    1360             :       sum0 =
    1361             :         ip_csum_with_carry (sum0,
    1362             :                             clib_mem_unaligned (&ip0->dst_address, u32));
    1363             :     }
    1364             :   else
    1365             :     sum0 =
    1366    14606200 :       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
    1367             : 
    1368    14606200 :   return ip_calculate_l4_checksum (vm, p0, sum0,
    1369             :                                    payload_length_host_byte_order, (u8 *) ip0,
    1370             :                                    ip_header_length, NULL);
    1371             : }
    1372             : 
    1373             : u32
    1374    14200500 : ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
    1375             : {
    1376    14200500 :   ip4_header_t *ip0 = vlib_buffer_get_current (p0);
    1377             :   udp_header_t *udp0;
    1378             :   u16 sum16;
    1379             : 
    1380    14200500 :   ASSERT (ip0->protocol == IP_PROTOCOL_TCP
    1381             :           || ip0->protocol == IP_PROTOCOL_UDP);
    1382             : 
    1383    14200500 :   udp0 = (void *) (ip0 + 1);
    1384    14200500 :   if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
    1385             :     {
    1386         755 :       p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
    1387             :                     | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
    1388         755 :       return p0->flags;
    1389             :     }
    1390             : 
    1391    14199700 :   sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
    1392             : 
    1393    28399400 :   p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
    1394    14199700 :                 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
    1395             : 
    1396    14199700 :   return p0->flags;
    1397             : }
    1398             : #endif
    1399             : 
    1400             : /* *INDENT-OFF* */
    1401        1151 : VNET_FEATURE_ARC_INIT (ip4_local) = {
    1402             :   .arc_name = "ip4-local",
    1403             :   .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
    1404             :   .last_in_arc = "ip4-local-end-of-arc",
    1405             : };
    1406             : /* *INDENT-ON* */
    1407             : 
    1408             : static inline void
    1409       10480 : ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
    1410             :                             ip4_header_t * ip, u8 is_udp, u8 * error,
    1411             :                             u8 * good_tcp_udp)
    1412             : {
    1413             :   u32 flags0;
    1414       10480 :   flags0 = ip4_tcp_udp_validate_checksum (vm, p);
    1415       10480 :   *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
    1416       10480 :   if (is_udp)
    1417             :     {
    1418             :       udp_header_t *udp;
    1419             :       u32 ip_len, udp_len;
    1420             :       i32 len_diff;
    1421       10389 :       udp = ip4_next_header (ip);
    1422             :       /* Verify UDP length. */
    1423       10389 :       ip_len = clib_net_to_host_u16 (ip->length);
    1424       10389 :       udp_len = clib_net_to_host_u16 (udp->length);
    1425             : 
    1426       10389 :       len_diff = ip_len - udp_len;
    1427       10389 :       *good_tcp_udp &= len_diff >= 0;
    1428       10389 :       *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
    1429             :     }
    1430       10480 : }
    1431             : 
    1432             : #define ip4_local_csum_is_offloaded(_b)                                       \
    1433             :   ((_b->flags & VNET_BUFFER_F_OFFLOAD) &&                                     \
    1434             :    (vnet_buffer (_b)->oflags &                                                \
    1435             :     (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
    1436             : 
    1437             : #define ip4_local_need_csum_check(is_tcp_udp, _b)                       \
    1438             :     (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED      \
    1439             :         || ip4_local_csum_is_offloaded (_b)))
    1440             : 
    1441             : #define ip4_local_csum_is_valid(_b)                                     \
    1442             :     (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT                       \
    1443             :         || (ip4_local_csum_is_offloaded (_b))) != 0
    1444             : 
    1445             : static inline void
    1446      148974 : ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
    1447             :                          ip4_header_t * ih, u8 * error)
    1448             : {
    1449             :   u8 is_udp, is_tcp_udp, good_tcp_udp;
    1450             : 
    1451      148974 :   is_udp = ih->protocol == IP_PROTOCOL_UDP;
    1452      148974 :   is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
    1453             : 
    1454      148974 :   if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
    1455         974 :     ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
    1456             :   else
    1457      148000 :     good_tcp_udp = ip4_local_csum_is_valid (b);
    1458             : 
    1459             :   ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
    1460      148974 :   *error = (is_tcp_udp && !good_tcp_udp
    1461             :             ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
    1462      148974 : }
    1463             : 
    1464             : static inline void
    1465      568673 : ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
    1466             :                             ip4_header_t ** ih, u8 * error)
    1467             : {
    1468             :   u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
    1469             : 
    1470      568673 :   is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
    1471      568673 :   is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
    1472             : 
    1473      568673 :   is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
    1474      568673 :   is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
    1475             : 
    1476      568673 :   good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
    1477      568673 :   good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
    1478             : 
    1479      568673 :   if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
    1480             :                      || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
    1481             :     {
    1482        4753 :       if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
    1483        4753 :         ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
    1484             :                                     &good_tcp_udp[0]);
    1485        4753 :       if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
    1486        4753 :         ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
    1487             :                                     &good_tcp_udp[1]);
    1488             :     }
    1489             : 
    1490      568673 :   error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
    1491           0 :               IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
    1492      568673 :   error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
    1493           0 :               IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
    1494      568673 : }
    1495             : 
    1496             : static inline void
    1497     1286780 : ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
    1498             :                               vlib_buffer_t * b, u16 * next, u8 error,
    1499             :                               u8 head_of_feature_arc)
    1500             : {
    1501     1286780 :   u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
    1502             :   u32 next_index;
    1503             : 
    1504     1286780 :   *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
    1505     1286780 :   b->error = error ? error_node->errors[error] : 0;
    1506     1286780 :   if (head_of_feature_arc)
    1507             :     {
    1508     1286780 :       next_index = *next;
    1509     1286780 :       if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
    1510             :         {
    1511     1285930 :           vnet_feature_arc_start (
    1512     1285930 :             arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
    1513     1285930 :           *next = next_index;
    1514             :         }
    1515             :     }
    1516     1286780 : }
    1517             : 
    1518             : typedef struct
    1519             : {
    1520             :   /* The src and fib-index together determine if packet n is the same as n-1 */
    1521             :   ip4_address_t src;
    1522             :   u32 fib_index;
    1523             :   u32 lbi;
    1524             :   u8 error;
    1525             :   u8 first;
    1526             : } ip4_local_last_check_t;
    1527             : 
    1528             : static inline void
    1529      148974 : ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
    1530             :                      ip4_local_last_check_t *last_check, u8 *error0,
    1531             :                      int is_receive_dpo)
    1532             : {
    1533             :   const dpo_id_t *dpo0;
    1534             :   load_balance_t *lb0;
    1535             :   u32 lbi0;
    1536             : 
    1537      148974 :   vnet_buffer (b)->ip.fib_index =
    1538      148974 :     vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
    1539      148974 :     vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
    1540             : 
    1541      148974 :   vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
    1542      148974 :   if (is_receive_dpo)
    1543             :     {
    1544             :       receive_dpo_t *rd;
    1545      148950 :       rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
    1546      148950 :       if (rd->rd_sw_if_index != ~0)
    1547      148928 :         vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
    1548             :     }
    1549             : 
    1550             :   /*
    1551             :    * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
    1552             :    *  adjacency for the destination address (the local interface address).
    1553             :    * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
    1554             :    *  adjacency for the source address (the remote sender's address)
    1555             :    */
    1556      148974 :   if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
    1557      120523 :       (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
    1558      120504 :       last_check->first)
    1559             :     {
    1560       28473 :       lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
    1561       28473 :                                         &ip0->src_address);
    1562             : 
    1563       28473 :       vnet_buffer (b)->ip.adj_index[VLIB_RX] =
    1564       28473 :         vnet_buffer (b)->ip.adj_index[VLIB_TX];
    1565       28473 :       vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
    1566             : 
    1567       28473 :       lb0 = load_balance_get (lbi0);
    1568       28473 :       dpo0 = load_balance_get_bucket_i (lb0, 0);
    1569             : 
    1570             :       /*
    1571             :        * Must have a route to source otherwise we drop the packet.
    1572             :        * ip4 broadcasts are accepted, e.g. to make dhcp client work
    1573             :        *
    1574             :        * The checks are:
    1575             :        *  - the source is a recieve => it's from us => bogus, do this
    1576             :        *    first since it sets a different error code.
    1577             :        *  - uRPF check for any route to source - accept if passes.
    1578             :        *  - allow packets destined to the broadcast address from unknown sources
    1579             :        */
    1580             : 
    1581       56946 :       *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
    1582       28473 :                   && dpo0->dpoi_type == DPO_RECEIVE) ?
    1583             :                  IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
    1584       56946 :       *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
    1585       28473 :                   && !fib_urpf_check_size (lb0->lb_urpf)
    1586          26 :                   && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
    1587             :                  IP4_ERROR_SRC_LOOKUP_MISS : *error0);
    1588             : 
    1589       28473 :       last_check->src.as_u32 = ip0->src_address.as_u32;
    1590       28473 :       last_check->lbi = lbi0;
    1591       28473 :       last_check->error = *error0;
    1592       28473 :       last_check->first = 0;
    1593       28473 :       last_check->fib_index = vnet_buffer (b)->ip.fib_index;
    1594             :     }
    1595             :   else
    1596             :     {
    1597      120501 :       vnet_buffer (b)->ip.adj_index[VLIB_RX] =
    1598      120501 :         vnet_buffer (b)->ip.adj_index[VLIB_TX];
    1599      120501 :       vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
    1600      120501 :       *error0 = last_check->error;
    1601             :     }
    1602      148974 : }
    1603             : 
    1604             : static inline void
    1605      568673 : ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
    1606             :                         ip4_local_last_check_t *last_check, u8 *error,
    1607             :                         int is_receive_dpo)
    1608             : {
    1609             :   const dpo_id_t *dpo[2];
    1610             :   load_balance_t *lb[2];
    1611             :   u32 not_last_hit;
    1612             :   u32 lbi[2];
    1613             : 
    1614      568673 :   not_last_hit = last_check->first;
    1615      568673 :   not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
    1616      568673 :   not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
    1617             : 
    1618      568673 :   vnet_buffer (b[0])->ip.fib_index =
    1619      568673 :     vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
    1620      568673 :     vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
    1621       74647 :     vnet_buffer (b[0])->ip.fib_index;
    1622             : 
    1623      568673 :   vnet_buffer (b[1])->ip.fib_index =
    1624      568673 :     vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
    1625      568673 :     vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
    1626       74647 :     vnet_buffer (b[1])->ip.fib_index;
    1627             : 
    1628      568673 :   not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
    1629      568673 :   not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
    1630             : 
    1631      568673 :   vnet_buffer (b[0])->ip.rx_sw_if_index =
    1632      568673 :     vnet_buffer (b[0])->sw_if_index[VLIB_RX];
    1633      568673 :   vnet_buffer (b[1])->ip.rx_sw_if_index =
    1634      568673 :     vnet_buffer (b[1])->sw_if_index[VLIB_RX];
    1635      568673 :   if (is_receive_dpo)
    1636             :     {
    1637             :       const receive_dpo_t *rd0, *rd1;
    1638      568673 :       rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
    1639      568673 :       rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
    1640      568673 :       if (rd0->rd_sw_if_index != ~0)
    1641      568641 :         vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
    1642      568673 :       if (rd1->rd_sw_if_index != ~0)
    1643      568641 :         vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
    1644             :     }
    1645             : 
    1646             :   /*
    1647             :    * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
    1648             :    *  adjacency for the destination address (the local interface address).
    1649             :    * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
    1650             :    *  adjacency for the source address (the remote sender's address)
    1651             :    */
    1652      568673 :   if (PREDICT_TRUE (not_last_hit))
    1653             :     {
    1654       29671 :       ip4_fib_forwarding_lookup_x2 (
    1655       29671 :         vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
    1656       29671 :         &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
    1657             : 
    1658       29671 :       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
    1659       29671 :         vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
    1660       29671 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
    1661             : 
    1662       29671 :       vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
    1663       29671 :         vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
    1664       29671 :       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
    1665             : 
    1666       29671 :       lb[0] = load_balance_get (lbi[0]);
    1667       29671 :       lb[1] = load_balance_get (lbi[1]);
    1668             : 
    1669       29671 :       dpo[0] = load_balance_get_bucket_i (lb[0], 0);
    1670       29671 :       dpo[1] = load_balance_get_bucket_i (lb[1], 0);
    1671             : 
    1672       59342 :       error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
    1673       29671 :                    dpo[0]->dpoi_type == DPO_RECEIVE) ?
    1674             :                   IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
    1675       59355 :       error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
    1676       29670 :                    !fib_urpf_check_size (lb[0]->lb_urpf) &&
    1677          14 :                    ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
    1678             :                   ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
    1679             : 
    1680       59342 :       error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
    1681       29671 :                    dpo[1]->dpoi_type == DPO_RECEIVE) ?
    1682             :                   IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
    1683       59355 :       error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
    1684       29670 :                    !fib_urpf_check_size (lb[1]->lb_urpf) &&
    1685          14 :                    ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
    1686             :                   ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
    1687             : 
    1688       29671 :       last_check->src.as_u32 = ip[1]->src_address.as_u32;
    1689       29671 :       last_check->lbi = lbi[1];
    1690       29671 :       last_check->error = error[1];
    1691       29671 :       last_check->first = 0;
    1692       29671 :       last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
    1693             :     }
    1694             :   else
    1695             :     {
    1696      539002 :       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
    1697      539002 :         vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
    1698      539002 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
    1699             : 
    1700      539002 :       vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
    1701      539002 :         vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
    1702      539002 :       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
    1703             : 
    1704      539002 :       error[0] = last_check->error;
    1705      539002 :       error[1] = last_check->error;
    1706             :     }
    1707      568673 : }
    1708             : 
    1709             : enum ip_local_packet_type_e
    1710             : {
    1711             :   IP_LOCAL_PACKET_TYPE_L4,
    1712             :   IP_LOCAL_PACKET_TYPE_NAT,
    1713             :   IP_LOCAL_PACKET_TYPE_FRAG,
    1714             : };
    1715             : 
    1716             : /**
    1717             :  * Determine packet type and next node.
    1718             :  *
    1719             :  * The expectation is that all packets that are not L4 will skip
    1720             :  * checksums and source checks.
    1721             :  */
    1722             : always_inline u8
    1723     1286780 : ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
    1724             : {
    1725     1286780 :   ip_lookup_main_t *lm = &ip4_main.lookup_main;
    1726             : 
    1727     1286780 :   if (PREDICT_FALSE (ip4_is_fragment (ip)))
    1728             :     {
    1729         432 :       *next = IP_LOCAL_NEXT_REASSEMBLY;
    1730         432 :       return IP_LOCAL_PACKET_TYPE_FRAG;
    1731             :     }
    1732     1286340 :   if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
    1733             :     {
    1734          25 :       *next = lm->local_next_by_ip_protocol[ip->protocol];
    1735          25 :       return IP_LOCAL_PACKET_TYPE_NAT;
    1736             :     }
    1737             : 
    1738     1286320 :   *next = lm->local_next_by_ip_protocol[ip->protocol];
    1739     1286320 :   return IP_LOCAL_PACKET_TYPE_L4;
    1740             : }
    1741             : 
    1742             : static inline uword
    1743       54121 : ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
    1744             :                   vlib_frame_t *frame, int head_of_feature_arc,
    1745             :                   int is_receive_dpo)
    1746             : {
    1747             :   u32 *from, n_left_from;
    1748             :   vlib_node_runtime_t *error_node =
    1749       54121 :     vlib_node_get_runtime (vm, ip4_local_node.index);
    1750             :   u16 nexts[VLIB_FRAME_SIZE], *next;
    1751             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
    1752             :   ip4_header_t *ip[2];
    1753             :   u8 error[2], pt[2];
    1754             : 
    1755       54121 :   ip4_local_last_check_t last_check = {
    1756             :     /*
    1757             :      * 0.0.0.0 can appear as the source address of an IP packet,
    1758             :      * as can any other address, hence the need to use the 'first'
    1759             :      * member to make sure the .lbi is initialised for the first
    1760             :      * packet.
    1761             :      */
    1762             :     .src = { .as_u32 = 0 },
    1763             :     .lbi = ~0,
    1764             :     .error = IP4_ERROR_UNKNOWN_PROTOCOL,
    1765             :     .first = 1,
    1766             :     .fib_index = 0,
    1767             :   };
    1768             : 
    1769       54121 :   from = vlib_frame_vector_args (frame);
    1770       54121 :   n_left_from = frame->n_vectors;
    1771             : 
    1772       54121 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
    1773        4435 :     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
    1774             : 
    1775       54121 :   vlib_get_buffers (vm, from, bufs, n_left_from);
    1776       54121 :   b = bufs;
    1777       54121 :   next = nexts;
    1778             : 
    1779      623000 :   while (n_left_from >= 6)
    1780             :     {
    1781      568879 :       u8 not_batch = 0;
    1782             : 
    1783             :       /* Prefetch next iteration. */
    1784             :       {
    1785      568879 :         vlib_prefetch_buffer_header (b[4], LOAD);
    1786      568879 :         vlib_prefetch_buffer_header (b[5], LOAD);
    1787             : 
    1788      568879 :         clib_prefetch_load (b[4]->data);
    1789      568879 :         clib_prefetch_load (b[5]->data);
    1790             :       }
    1791             : 
    1792      568879 :       error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
    1793             : 
    1794      568879 :       ip[0] = vlib_buffer_get_current (b[0]);
    1795      568879 :       ip[1] = vlib_buffer_get_current (b[1]);
    1796             : 
    1797      568879 :       vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
    1798      568879 :       vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
    1799             : 
    1800      568879 :       pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
    1801      568879 :       pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
    1802             : 
    1803      568879 :       not_batch = pt[0] ^ pt[1];
    1804             : 
    1805      568879 :       if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
    1806         206 :         goto skip_checks;
    1807             : 
    1808      568673 :       if (PREDICT_TRUE (not_batch == 0))
    1809             :         {
    1810      568673 :           ip4_local_check_l4_csum_x2 (vm, b, ip, error);
    1811      568673 :           ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
    1812             :         }
    1813             :       else
    1814             :         {
    1815           0 :           if (!pt[0])
    1816             :             {
    1817           0 :               ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
    1818           0 :               ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
    1819             :                                    is_receive_dpo);
    1820             :             }
    1821           0 :           if (!pt[1])
    1822             :             {
    1823           0 :               ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
    1824           0 :               ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
    1825             :                                    is_receive_dpo);
    1826             :             }
    1827             :         }
    1828             : 
    1829           0 :     skip_checks:
    1830             : 
    1831      568879 :       ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
    1832             :                                     head_of_feature_arc);
    1833      568879 :       ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
    1834             :                                     head_of_feature_arc);
    1835             : 
    1836      568879 :       b += 2;
    1837      568879 :       next += 2;
    1838      568879 :       n_left_from -= 2;
    1839             :     }
    1840             : 
    1841      203140 :   while (n_left_from > 0)
    1842             :     {
    1843      149019 :       error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
    1844             : 
    1845      149019 :       ip[0] = vlib_buffer_get_current (b[0]);
    1846      149019 :       vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
    1847      149019 :       pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
    1848             : 
    1849      149019 :       if (head_of_feature_arc == 0 || pt[0])
    1850          45 :         goto skip_check;
    1851             : 
    1852      148974 :       ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
    1853      148974 :       ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
    1854             :                            is_receive_dpo);
    1855             : 
    1856      149019 :     skip_check:
    1857             : 
    1858      149019 :       ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
    1859             :                                     head_of_feature_arc);
    1860             : 
    1861      149019 :       b += 1;
    1862      149019 :       next += 1;
    1863      149019 :       n_left_from -= 1;
    1864             :     }
    1865             : 
    1866       54121 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
    1867       54121 :   return frame->n_vectors;
    1868             : }
    1869             : 
    1870        2322 : VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
    1871             :                                vlib_frame_t * frame)
    1872             : {
    1873          22 :   return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
    1874             :                            0 /* is_receive_dpo */);
    1875             : }
    1876             : 
    1877      183788 : VLIB_REGISTER_NODE (ip4_local_node) =
    1878             : {
    1879             :   .name = "ip4-local",
    1880             :   .vector_size = sizeof (u32),
    1881             :   .format_trace = format_ip4_forward_next_trace,
    1882             :   .n_errors = IP4_N_ERROR,
    1883             :   .error_counters = ip4_error_counters,
    1884             :   .n_next_nodes = IP_LOCAL_N_NEXT,
    1885             :   .next_nodes =
    1886             :   {
    1887             :     [IP_LOCAL_NEXT_DROP] = "ip4-drop",
    1888             :     [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
    1889             :     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
    1890             :     [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
    1891             :     [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
    1892             :   },
    1893             : };
    1894             : 
    1895       56398 : VLIB_NODE_FN (ip4_receive_local_node)
    1896             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
    1897             : {
    1898       54098 :   return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
    1899             :                            1 /* is_receive_dpo */);
    1900             : }
    1901             : 
    1902      183788 : VLIB_REGISTER_NODE (ip4_receive_local_node) = {
    1903             :   .name = "ip4-receive",
    1904             :   .vector_size = sizeof (u32),
    1905             :   .format_trace = format_ip4_forward_next_trace,
    1906             :   .sibling_of = "ip4-local"
    1907             : };
    1908             : 
    1909        2301 : VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
    1910             :                                           vlib_node_runtime_t * node,
    1911             :                                           vlib_frame_t * frame)
    1912             : {
    1913           1 :   return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
    1914             :                            0 /* is_receive_dpo */);
    1915             : }
    1916             : 
    1917      183788 : VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
    1918             :   .name = "ip4-local-end-of-arc",
    1919             :   .vector_size = sizeof (u32),
    1920             : 
    1921             :   .format_trace = format_ip4_forward_next_trace,
    1922             :   .sibling_of = "ip4-local",
    1923             : };
    1924             : 
    1925       76635 : VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
    1926             :   .arc_name = "ip4-local",
    1927             :   .node_name = "ip4-local-end-of-arc",
    1928             :   .runs_before = 0, /* not before any other features */
    1929             : };
    1930             : 
    1931             : #ifndef CLIB_MARCH_VARIANT
    1932             : void
    1933        2050 : ip4_register_protocol (u32 protocol, u32 node_index)
    1934             : {
    1935        2050 :   vlib_main_t *vm = vlib_get_main ();
    1936        2050 :   ip4_main_t *im = &ip4_main;
    1937        2050 :   ip_lookup_main_t *lm = &im->lookup_main;
    1938             : 
    1939        2050 :   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
    1940        2050 :   lm->local_next_by_ip_protocol[protocol] =
    1941        2050 :     vlib_node_add_next (vm, ip4_local_node.index, node_index);
    1942        2050 : }
    1943             : 
    1944             : void
    1945         101 : ip4_unregister_protocol (u32 protocol)
    1946             : {
    1947         101 :   ip4_main_t *im = &ip4_main;
    1948         101 :   ip_lookup_main_t *lm = &im->lookup_main;
    1949             : 
    1950         101 :   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
    1951         101 :   lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
    1952         101 : }
    1953             : #endif
    1954             : 
    1955             : static clib_error_t *
    1956           0 : show_ip_local_command_fn (vlib_main_t * vm,
    1957             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
    1958             : {
    1959           0 :   ip4_main_t *im = &ip4_main;
    1960           0 :   ip_lookup_main_t *lm = &im->lookup_main;
    1961             :   int i;
    1962             : 
    1963           0 :   vlib_cli_output (vm, "Protocols handled by ip4_local");
    1964           0 :   for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
    1965             :     {
    1966           0 :       if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
    1967             :         {
    1968           0 :           u32 node_index = vlib_get_node (vm,
    1969           0 :                                           ip4_local_node.index)->
    1970           0 :             next_nodes[lm->local_next_by_ip_protocol[i]];
    1971           0 :           vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
    1972             :                            format_vlib_node_name, vm, node_index);
    1973             :         }
    1974             :     }
    1975           0 :   return 0;
    1976             : }
    1977             : 
    1978             : 
    1979             : 
    1980             : /*?
    1981             :  * Display the set of protocols handled by the local IPv4 stack.
    1982             :  *
    1983             :  * @cliexpar
    1984             :  * Example of how to display local protocol table:
    1985             :  * @cliexstart{show ip local}
    1986             :  * Protocols handled by ip4_local
    1987             :  * 1
    1988             :  * 17
    1989             :  * 47
    1990             :  * @cliexend
    1991             : ?*/
    1992             : /* *INDENT-OFF* */
    1993      285289 : VLIB_CLI_COMMAND (show_ip_local, static) =
    1994             : {
    1995             :   .path = "show ip local",
    1996             :   .function = show_ip_local_command_fn,
    1997             :   .short_help = "show ip local",
    1998             : };
    1999             : /* *INDENT-ON* */
    2000             : 
    2001             : typedef enum
    2002             : {
    2003             :   IP4_REWRITE_NEXT_DROP,
    2004             :   IP4_REWRITE_NEXT_ICMP_ERROR,
    2005             :   IP4_REWRITE_NEXT_FRAGMENT,
    2006             :   IP4_REWRITE_N_NEXT            /* Last */
    2007             : } ip4_rewrite_next_t;
    2008             : 
    2009             : /**
    2010             :  * This bits of an IPv4 address to mask to construct a multicast
    2011             :  * MAC address
    2012             :  */
    2013             : #if CLIB_ARCH_IS_BIG_ENDIAN
    2014             : #define IP4_MCAST_ADDR_MASK 0x007fffff
    2015             : #else
    2016             : #define IP4_MCAST_ADDR_MASK 0xffff7f00
    2017             : #endif
    2018             : 
    2019             : always_inline void
    2020    13393700 : ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
    2021             :                u16 adj_packet_bytes, bool df, u16 * next,
    2022             :                u8 is_midchain, u32 * error)
    2023             : {
    2024    13393700 :   if (packet_len > adj_packet_bytes)
    2025             :     {
    2026         409 :       *error = IP4_ERROR_MTU_EXCEEDED;
    2027         409 :       if (df)
    2028             :         {
    2029          79 :           icmp4_error_set_vnet_buffer
    2030             :             (b, ICMP4_destination_unreachable,
    2031             :              ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
    2032             :              adj_packet_bytes);
    2033          79 :           *next = IP4_REWRITE_NEXT_ICMP_ERROR;
    2034             :         }
    2035             :       else
    2036             :         {
    2037             :           /* IP fragmentation */
    2038         330 :           ip_frag_set_vnet_buffer (b, adj_packet_bytes,
    2039             :                                    (is_midchain ?
    2040             :                                     IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
    2041             :                                     IP_FRAG_NEXT_IP_REWRITE), 0);
    2042         330 :           *next = IP4_REWRITE_NEXT_FRAGMENT;
    2043             :         }
    2044             :     }
    2045    13393700 : }
    2046             : 
    2047             : /* increment TTL & update checksum.
    2048             :    Works either endian, so no need for byte swap. */
    2049             : static_always_inline void
    2050         409 : ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
    2051             : {
    2052             :   i32 ttl;
    2053             :   u32 checksum;
    2054         409 :   if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
    2055           0 :     return;
    2056             : 
    2057         409 :   ttl = ip->ttl;
    2058             : 
    2059         409 :   checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
    2060         409 :   checksum += checksum >= 0xffff;
    2061             : 
    2062         409 :   ip->checksum = checksum;
    2063         409 :   ttl += 1;
    2064         409 :   ip->ttl = ttl;
    2065             : 
    2066         409 :   ASSERT (ip4_header_checksum_is_valid (ip) ||
    2067             :           (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
    2068             :           (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
    2069             : }
    2070             : 
    2071             : /* Decrement TTL & update checksum.
    2072             :    Works either endian, so no need for byte swap. */
    2073             : static_always_inline void
    2074    13393700 : ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
    2075             :                             u32 * error)
    2076             : {
    2077             :   i32 ttl;
    2078             :   u32 checksum;
    2079    13393700 :   if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
    2080      173531 :     return;
    2081             : 
    2082    13220200 :   ttl = ip->ttl;
    2083             : 
    2084             :   /* Input node should have reject packets with ttl 0. */
    2085    13220200 :   ASSERT (ip->ttl > 0);
    2086             : 
    2087    13220200 :   checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
    2088    13220200 :   checksum += checksum >= 0xffff;
    2089             : 
    2090    13220200 :   ip->checksum = checksum;
    2091    13220200 :   ttl -= 1;
    2092    13220200 :   ip->ttl = ttl;
    2093             : 
    2094             :   /*
    2095             :    * If the ttl drops below 1 when forwarding, generate
    2096             :    * an ICMP response.
    2097             :    */
    2098    13220200 :   if (PREDICT_FALSE (ttl <= 0))
    2099             :     {
    2100         197 :       *error = IP4_ERROR_TIME_EXPIRED;
    2101         197 :       vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    2102         197 :       icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
    2103             :                                    ICMP4_time_exceeded_ttl_exceeded_in_transit,
    2104             :                                    0);
    2105         197 :       *next = IP4_REWRITE_NEXT_ICMP_ERROR;
    2106             :     }
    2107             : 
    2108             :   /* Verify checksum. */
    2109    13220200 :   ASSERT (ip4_header_checksum_is_valid (ip) ||
    2110             :           (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
    2111             :           (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
    2112             : }
    2113             : 
    2114             : always_inline uword
    2115      292175 : ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
    2116             :                     vlib_frame_t *frame, int do_counters, int is_midchain,
    2117             :                     int is_mcast)
    2118             : {
    2119      292175 :   ip_lookup_main_t *lm = &ip4_main.lookup_main;
    2120      292175 :   u32 *from = vlib_frame_vector_args (frame);
    2121             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
    2122             :   u16 nexts[VLIB_FRAME_SIZE], *next;
    2123             :   u32 n_left_from;
    2124             :   vlib_node_runtime_t *error_node =
    2125      292175 :     vlib_node_get_runtime (vm, ip4_input_node.index);
    2126             : 
    2127      292175 :   n_left_from = frame->n_vectors;
    2128      292175 :   u32 thread_index = vm->thread_index;
    2129             : 
    2130      292175 :   vlib_get_buffers (vm, from, bufs, n_left_from);
    2131      292175 :   clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
    2132             : 
    2133             : #if (CLIB_N_PREFETCHES >= 8)
    2134      292175 :   if (n_left_from >= 6)
    2135             :     {
    2136             :       int i;
    2137      993435 :       for (i = 2; i < 6; i++)
    2138      794748 :         vlib_prefetch_buffer_header (bufs[i], LOAD);
    2139             :     }
    2140             : 
    2141      292175 :   next = nexts;
    2142      292175 :   b = bufs;
    2143     6265320 :   while (n_left_from >= 8)
    2144             :     {
    2145             :       const ip_adjacency_t *adj0, *adj1;
    2146             :       ip4_header_t *ip0, *ip1;
    2147             :       u32 rw_len0, error0, adj_index0;
    2148             :       u32 rw_len1, error1, adj_index1;
    2149             :       u32 tx_sw_if_index0, tx_sw_if_index1;
    2150             :       u8 *p;
    2151             : 
    2152     5973140 :       if (is_midchain)
    2153             :         {
    2154       14939 :           vlib_prefetch_buffer_header (b[6], LOAD);
    2155       14939 :           vlib_prefetch_buffer_header (b[7], LOAD);
    2156             :         }
    2157             : 
    2158     5973140 :       adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
    2159     5973140 :       adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
    2160             : 
    2161             :       /*
    2162             :        * pre-fetch the per-adjacency counters
    2163             :        */
    2164     5973140 :       if (do_counters)
    2165             :         {
    2166          90 :           vlib_prefetch_combined_counter (&adjacency_counters,
    2167             :                                           thread_index, adj_index0);
    2168          90 :           vlib_prefetch_combined_counter (&adjacency_counters,
    2169             :                                           thread_index, adj_index1);
    2170             :         }
    2171             : 
    2172     5973140 :       ip0 = vlib_buffer_get_current (b[0]);
    2173     5973140 :       ip1 = vlib_buffer_get_current (b[1]);
    2174             : 
    2175     5973140 :       error0 = error1 = IP4_ERROR_NONE;
    2176             : 
    2177     5973140 :       ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
    2178     5973140 :       ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
    2179             : 
    2180             :       /* Rewrite packet header and updates lengths. */
    2181     5973140 :       adj0 = adj_get (adj_index0);
    2182     5973140 :       adj1 = adj_get (adj_index1);
    2183             : 
    2184             :       /* Worth pipelining. No guarantee that adj0,1 are hot... */
    2185     5973140 :       rw_len0 = adj0[0].rewrite_header.data_bytes;
    2186     5973140 :       rw_len1 = adj1[0].rewrite_header.data_bytes;
    2187     5973140 :       vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
    2188     5973140 :       vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
    2189             : 
    2190     5973140 :       p = vlib_buffer_get_current (b[2]);
    2191     5973140 :       clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
    2192     5973140 :       clib_prefetch_load (p);
    2193             : 
    2194     5973140 :       p = vlib_buffer_get_current (b[3]);
    2195     5973140 :       clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
    2196     5973140 :       clib_prefetch_load (p);
    2197             : 
    2198             :       /* Check MTU of outgoing interface. */
    2199     5973140 :       u16 ip0_len = clib_net_to_host_u16 (ip0->length);
    2200     5973140 :       u16 ip1_len = clib_net_to_host_u16 (ip1->length);
    2201             : 
    2202     5973140 :       if (b[0]->flags & VNET_BUFFER_F_GSO)
    2203       25428 :         ip0_len = gso_mtu_sz (b[0]);
    2204     5973140 :       if (b[1]->flags & VNET_BUFFER_F_GSO)
    2205       32402 :         ip1_len = gso_mtu_sz (b[1]);
    2206             : 
    2207    11946300 :       ip4_mtu_check (b[0], ip0_len,
    2208     5973140 :                      adj0[0].rewrite_header.max_l3_packet_bytes,
    2209     5973140 :                      ip0->flags_and_fragment_offset &
    2210     5973140 :                      clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
    2211             :                      next + 0, is_midchain, &error0);
    2212    11946300 :       ip4_mtu_check (b[1], ip1_len,
    2213     5973140 :                      adj1[0].rewrite_header.max_l3_packet_bytes,
    2214     5973140 :                      ip1->flags_and_fragment_offset &
    2215     5973140 :                      clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
    2216             :                      next + 1, is_midchain, &error1);
    2217             : 
    2218     5973140 :       if (is_mcast)
    2219             :         {
    2220        2716 :           error0 = ((adj0[0].rewrite_header.sw_if_index ==
    2221        1358 :                      vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
    2222        1358 :                     IP4_ERROR_SAME_INTERFACE : error0);
    2223        1358 :           error1 = ((adj1[0].rewrite_header.sw_if_index ==
    2224        1358 :                      vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
    2225        1358 :                     IP4_ERROR_SAME_INTERFACE : error1);
    2226             :         }
    2227             : 
    2228             :       /* Don't adjust the buffer for ttl issue; icmp-error node wants
    2229             :        * to see the IP header */
    2230     5973140 :       if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
    2231             :         {
    2232     5972810 :           u32 next_index = adj0[0].rewrite_header.next_index;
    2233     5972810 :           vlib_buffer_advance (b[0], -(word) rw_len0);
    2234             : 
    2235     5972810 :           tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
    2236     5972810 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
    2237             : 
    2238     5972810 :           if (PREDICT_FALSE
    2239             :               (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    2240     2964140 :             vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
    2241             :                                                 tx_sw_if_index0,
    2242             :                                                 &next_index, b[0],
    2243             :                                                 adj0->ia_cfg_index);
    2244             : 
    2245     5972810 :           next[0] = next_index;
    2246     5972810 :           if (is_midchain)
    2247       14810 :             vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
    2248             :                                         0 /* is_ip6 */ );
    2249             :         }
    2250             :       else
    2251             :         {
    2252         333 :           b[0]->error = error_node->errors[error0];
    2253         333 :           if (error0 == IP4_ERROR_MTU_EXCEEDED)
    2254         161 :             ip4_ttl_inc (b[0], ip0);
    2255             :         }
    2256     5973140 :       if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
    2257             :         {
    2258     5972900 :           u32 next_index = adj1[0].rewrite_header.next_index;
    2259     5972900 :           vlib_buffer_advance (b[1], -(word) rw_len1);
    2260             : 
    2261     5972900 :           tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
    2262     5972900 :           vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
    2263             : 
    2264     5972900 :           if (PREDICT_FALSE
    2265             :               (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    2266     2953030 :             vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
    2267             :                                                 tx_sw_if_index1,
    2268     2953030 :                                                 &next_index, b[1],
    2269             :                                                 adj1->ia_cfg_index);
    2270     5972900 :           next[1] = next_index;
    2271     5972900 :           if (is_midchain)
    2272       14810 :             vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
    2273             :                                         0 /* is_ip6 */ );
    2274             :         }
    2275             :       else
    2276             :         {
    2277         244 :           b[1]->error = error_node->errors[error1];
    2278         244 :           if (error1 == IP4_ERROR_MTU_EXCEEDED)
    2279         161 :             ip4_ttl_inc (b[1], ip1);
    2280             :         }
    2281             : 
    2282     5973140 :       if (is_midchain)
    2283             :         /* Guess we are only writing on ipv4 header. */
    2284       14939 :         vnet_rewrite_two_headers (adj0[0], adj1[0],
    2285             :                                   ip0, ip1, sizeof (ip4_header_t));
    2286             :       else
    2287             :         /* Guess we are only writing on simple Ethernet header. */
    2288     5958200 :         vnet_rewrite_two_headers (adj0[0], adj1[0],
    2289             :                                   ip0, ip1, sizeof (ethernet_header_t));
    2290             : 
    2291     5973140 :       if (do_counters)
    2292             :         {
    2293          90 :           if (error0 == IP4_ERROR_NONE)
    2294          90 :             vlib_increment_combined_counter
    2295             :               (&adjacency_counters,
    2296             :                thread_index,
    2297             :                adj_index0, 1,
    2298          90 :                vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
    2299             : 
    2300          90 :           if (error1 == IP4_ERROR_NONE)
    2301          90 :             vlib_increment_combined_counter
    2302             :               (&adjacency_counters,
    2303             :                thread_index,
    2304             :                adj_index1, 1,
    2305          90 :                vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
    2306             :         }
    2307             : 
    2308     5973140 :       if (is_midchain)
    2309             :         {
    2310       14939 :           if (error0 == IP4_ERROR_NONE)
    2311       14810 :             adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
    2312       14939 :           if (error1 == IP4_ERROR_NONE)
    2313       14810 :             adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
    2314             :         }
    2315             : 
    2316     5973140 :       if (is_mcast)
    2317             :         {
    2318             :           /* copy bytes from the IP address into the MAC rewrite */
    2319        1358 :           if (error0 == IP4_ERROR_NONE)
    2320        1269 :             vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
    2321        1269 :                                         adj0->rewrite_header.dst_mcast_offset,
    2322             :                                         &ip0->dst_address.as_u32, (u8 *) ip0);
    2323        1358 :           if (error1 == IP4_ERROR_NONE)
    2324        1358 :             vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
    2325        1358 :                                         adj1->rewrite_header.dst_mcast_offset,
    2326             :                                         &ip1->dst_address.as_u32, (u8 *) ip1);
    2327             :         }
    2328             : 
    2329     5973140 :       next += 2;
    2330     5973140 :       b += 2;
    2331     5973140 :       n_left_from -= 2;
    2332             :     }
    2333             : #elif (CLIB_N_PREFETCHES >= 4)
    2334             :   next = nexts;
    2335             :   b = bufs;
    2336             :   while (n_left_from >= 1)
    2337             :     {
    2338             :       ip_adjacency_t *adj0;
    2339             :       ip4_header_t *ip0;
    2340             :       u32 rw_len0, error0, adj_index0;
    2341             :       u32 tx_sw_if_index0;
    2342             :       u8 *p;
    2343             : 
    2344             :       /* Prefetch next iteration */
    2345             :       if (PREDICT_TRUE (n_left_from >= 4))
    2346             :         {
    2347             :           ip_adjacency_t *adj2;
    2348             :           u32 adj_index2;
    2349             : 
    2350             :           vlib_prefetch_buffer_header (b[3], LOAD);
    2351             :           vlib_prefetch_buffer_data (b[2], LOAD);
    2352             : 
    2353             :           /* Prefetch adj->rewrite_header */
    2354             :           adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
    2355             :           adj2 = adj_get (adj_index2);
    2356             :           p = (u8 *) adj2;
    2357             :           CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
    2358             :                          LOAD);
    2359             :         }
    2360             : 
    2361             :       adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
    2362             : 
    2363             :       /*
    2364             :        * Prefetch the per-adjacency counters
    2365             :        */
    2366             :       if (do_counters)
    2367             :         {
    2368             :           vlib_prefetch_combined_counter (&adjacency_counters,
    2369             :                                           thread_index, adj_index0);
    2370             :         }
    2371             : 
    2372             :       ip0 = vlib_buffer_get_current (b[0]);
    2373             : 
    2374             :       error0 = IP4_ERROR_NONE;
    2375             : 
    2376             :       ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
    2377             : 
    2378             :       /* Rewrite packet header and updates lengths. */
    2379             :       adj0 = adj_get (adj_index0);
    2380             : 
    2381             :       /* Rewrite header was prefetched. */
    2382             :       rw_len0 = adj0[0].rewrite_header.data_bytes;
    2383             :       vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
    2384             : 
    2385             :       /* Check MTU of outgoing interface. */
    2386             :       u16 ip0_len = clib_net_to_host_u16 (ip0->length);
    2387             : 
    2388             :       if (b[0]->flags & VNET_BUFFER_F_GSO)
    2389             :         ip0_len = gso_mtu_sz (b[0]);
    2390             : 
    2391             :       ip4_mtu_check (b[0], ip0_len,
    2392             :                      adj0[0].rewrite_header.max_l3_packet_bytes,
    2393             :                      ip0->flags_and_fragment_offset &
    2394             :                      clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
    2395             :                      next + 0, is_midchain, &error0);
    2396             : 
    2397             :       if (is_mcast)
    2398             :         {
    2399             :           error0 = ((adj0[0].rewrite_header.sw_if_index ==
    2400             :                      vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
    2401             :                     IP4_ERROR_SAME_INTERFACE : error0);
    2402             :         }
    2403             : 
    2404             :       /* Don't adjust the buffer for ttl issue; icmp-error node wants
    2405             :        * to see the IP header */
    2406             :       if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
    2407             :         {
    2408             :           u32 next_index = adj0[0].rewrite_header.next_index;
    2409             :           vlib_buffer_advance (b[0], -(word) rw_len0);
    2410             :           tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
    2411             :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
    2412             : 
    2413             :           if (PREDICT_FALSE
    2414             :               (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    2415             :             vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
    2416             :                                                 tx_sw_if_index0,
    2417             :                                                 &next_index, b[0],
    2418             :                                                 adj0->ia_cfg_index);
    2419             :           next[0] = next_index;
    2420             : 
    2421             :           if (is_midchain)
    2422             :             {
    2423             :               vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
    2424             :                                           0 /* is_ip6 */ );
    2425             : 
    2426             :               /* Guess we are only writing on ipv4 header. */
    2427             :               vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
    2428             :             }
    2429             :           else
    2430             :             /* Guess we are only writing on simple Ethernet header. */
    2431             :             vnet_rewrite_one_header (adj0[0], ip0,
    2432             :                                      sizeof (ethernet_header_t));
    2433             : 
    2434             :           /*
    2435             :            * Bump the per-adjacency counters
    2436             :            */
    2437             :           if (do_counters)
    2438             :             vlib_increment_combined_counter
    2439             :               (&adjacency_counters,
    2440             :                thread_index,
    2441             :                adj_index0, 1, vlib_buffer_length_in_chain (vm,
    2442             :                                                            b[0]) + rw_len0);
    2443             : 
    2444             :           if (is_midchain)
    2445             :             adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
    2446             : 
    2447             :           if (is_mcast)
    2448             :             /* copy bytes from the IP address into the MAC rewrite */
    2449             :             vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
    2450             :                                         adj0->rewrite_header.dst_mcast_offset,
    2451             :                                         &ip0->dst_address.as_u32, (u8 *) ip0);
    2452             :         }
    2453             :       else
    2454             :         {
    2455             :           b[0]->error = error_node->errors[error0];
    2456             :           if (error0 == IP4_ERROR_MTU_EXCEEDED)
    2457             :             ip4_ttl_inc (b[0], ip0);
    2458             :         }
    2459             : 
    2460             :       next += 1;
    2461             :       b += 1;
    2462             :       n_left_from -= 1;
    2463             :     }
    2464             : #endif
    2465             : 
    2466     1739620 :   while (n_left_from > 0)
    2467             :     {
    2468             :       ip_adjacency_t *adj0;
    2469             :       ip4_header_t *ip0;
    2470             :       u32 rw_len0, adj_index0, error0;
    2471             :       u32 tx_sw_if_index0;
    2472             : 
    2473     1447440 :       adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
    2474             : 
    2475     1447440 :       adj0 = adj_get (adj_index0);
    2476             : 
    2477     1447440 :       if (do_counters)
    2478         191 :         vlib_prefetch_combined_counter (&adjacency_counters,
    2479             :                                         thread_index, adj_index0);
    2480             : 
    2481     1447440 :       ip0 = vlib_buffer_get_current (b[0]);
    2482             : 
    2483     1447440 :       error0 = IP4_ERROR_NONE;
    2484             : 
    2485     1447440 :       ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
    2486             : 
    2487             : 
    2488             :       /* Update packet buffer attributes/set output interface. */
    2489     1447440 :       rw_len0 = adj0[0].rewrite_header.data_bytes;
    2490     1447440 :       vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
    2491             : 
    2492             :       /* Check MTU of outgoing interface. */
    2493     1447440 :       u16 ip0_len = clib_net_to_host_u16 (ip0->length);
    2494     1447440 :       if (b[0]->flags & VNET_BUFFER_F_GSO)
    2495      159029 :         ip0_len = gso_mtu_sz (b[0]);
    2496             : 
    2497     2894890 :       ip4_mtu_check (b[0], ip0_len,
    2498     1447440 :                      adj0[0].rewrite_header.max_l3_packet_bytes,
    2499     1447440 :                      ip0->flags_and_fragment_offset &
    2500     1447440 :                      clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
    2501             :                      next + 0, is_midchain, &error0);
    2502             : 
    2503     1447440 :       if (is_mcast)
    2504             :         {
    2505         230 :           error0 = ((adj0[0].rewrite_header.sw_if_index ==
    2506         230 :                      vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
    2507         230 :                     IP4_ERROR_SAME_INTERFACE : error0);
    2508             :         }
    2509             : 
    2510             :       /* Don't adjust the buffer for ttl issue; icmp-error node wants
    2511             :        * to see the IP header */
    2512     1447440 :       if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
    2513             :         {
    2514     1447320 :           u32 next_index = adj0[0].rewrite_header.next_index;
    2515     1447320 :           vlib_buffer_advance (b[0], -(word) rw_len0);
    2516     1447320 :           tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
    2517     1447320 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
    2518             : 
    2519     1447320 :           if (PREDICT_FALSE
    2520             :               (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
    2521      841121 :             vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
    2522             :                                                 tx_sw_if_index0,
    2523             :                                                 &next_index, b[0],
    2524             :                                                 adj0->ia_cfg_index);
    2525     1447320 :           next[0] = next_index;
    2526             : 
    2527     1447320 :           if (is_midchain)
    2528             :             {
    2529             :               /* this acts on the packet that is about to be encapped */
    2530        2027 :               vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
    2531             :                                           0 /* is_ip6 */ );
    2532             : 
    2533             :               /* Guess we are only writing on ipv4 header. */
    2534        2027 :               vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
    2535             :             }
    2536             :           else
    2537             :             /* Guess we are only writing on simple Ethernet header. */
    2538     1445300 :             vnet_rewrite_one_header (adj0[0], ip0,
    2539             :                                      sizeof (ethernet_header_t));
    2540             : 
    2541     1447320 :           if (do_counters)
    2542         143 :             vlib_increment_combined_counter
    2543             :               (&adjacency_counters,
    2544             :                thread_index, adj_index0, 1,
    2545         143 :                vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
    2546             : 
    2547     1447320 :           if (is_midchain)
    2548        2027 :             adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
    2549             : 
    2550     1447320 :           if (is_mcast)
    2551             :             /* copy bytes from the IP address into the MAC rewrite */
    2552         228 :             vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
    2553         228 :                                         adj0->rewrite_header.dst_mcast_offset,
    2554             :                                         &ip0->dst_address.as_u32, (u8 *) ip0);
    2555             :         }
    2556             :       else
    2557             :         {
    2558         120 :           b[0]->error = error_node->errors[error0];
    2559             :           /* undo the TTL decrement - we'll be back to do it again */
    2560         120 :           if (error0 == IP4_ERROR_MTU_EXCEEDED)
    2561          87 :             ip4_ttl_inc (b[0], ip0);
    2562             :         }
    2563             : 
    2564     1447440 :       next += 1;
    2565     1447440 :       b += 1;
    2566     1447440 :       n_left_from -= 1;
    2567             :     }
    2568             : 
    2569             : 
    2570             :   /* Need to do trace after rewrites to pick up new packet data. */
    2571      292175 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
    2572        7388 :     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
    2573             : 
    2574      292175 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
    2575      292175 :   return frame->n_vectors;
    2576             : }
    2577             : 
    2578             : /** @brief IPv4 rewrite node.
    2579             :     @node ip4-rewrite
    2580             : 
    2581             :     This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
    2582             :     header checksum, fetch the ip adjacency, check the outbound mtu,
    2583             :     apply the adjacency rewrite, and send pkts to the adjacency
    2584             :     rewrite header's rewrite_next_index.
    2585             : 
    2586             :     @param vm vlib_main_t corresponding to the current thread
    2587             :     @param node vlib_node_runtime_t
    2588             :     @param frame vlib_frame_t whose contents should be dispatched
    2589             : 
    2590             :     @par Graph mechanics: buffer metadata, next index usage
    2591             : 
    2592             :     @em Uses:
    2593             :     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
    2594             :         - the rewrite adjacency index
    2595             :     - <code>adj->lookup_next_index</code>
    2596             :         - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
    2597             :           the packet will be dropped.
    2598             :     - <code>adj->rewrite_header</code>
    2599             :         - Rewrite string length, rewrite string, next_index
    2600             : 
    2601             :     @em Sets:
    2602             :     - <code>b->current_data, b->current_length</code>
    2603             :         - Updated net of applying the rewrite string
    2604             : 
    2605             :     <em>Next Indices:</em>
    2606             :     - <code> adj->rewrite_header.next_index </code>
    2607             :       or @c ip4-drop
    2608             : */
    2609             : 
    2610      293987 : VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
    2611             :                                  vlib_frame_t * frame)
    2612             : {
    2613      291687 :   if (adj_are_counters_enabled ())
    2614         102 :     return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
    2615             :   else
    2616      291585 :     return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
    2617             : }
    2618             : 
    2619        2300 : VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
    2620             :                                        vlib_node_runtime_t * node,
    2621             :                                        vlib_frame_t * frame)
    2622             : {
    2623           0 :   if (adj_are_counters_enabled ())
    2624           0 :     return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
    2625             :   else
    2626           0 :     return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
    2627             : }
    2628             : 
    2629        2691 : VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
    2630             :                                   vlib_node_runtime_t * node,
    2631             :                                   vlib_frame_t * frame)
    2632             : {
    2633         391 :   if (adj_are_counters_enabled ())
    2634           0 :     return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
    2635             :   else
    2636         391 :     return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
    2637             : }
    2638             : 
    2639        2397 : VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
    2640             :                                        vlib_node_runtime_t * node,
    2641             :                                        vlib_frame_t * frame)
    2642             : {
    2643          97 :   if (adj_are_counters_enabled ())
    2644           0 :     return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
    2645             :   else
    2646          97 :     return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
    2647             : }
    2648             : 
    2649        2300 : VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
    2650             :                                         vlib_node_runtime_t * node,
    2651             :                                         vlib_frame_t * frame)
    2652             : {
    2653           0 :   if (adj_are_counters_enabled ())
    2654           0 :     return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
    2655             :   else
    2656           0 :     return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
    2657             : }
    2658             : 
    2659             : /* *INDENT-OFF* */
    2660      183788 : VLIB_REGISTER_NODE (ip4_rewrite_node) = {
    2661             :   .name = "ip4-rewrite",
    2662             :   .vector_size = sizeof (u32),
    2663             : 
    2664             :   .format_trace = format_ip4_rewrite_trace,
    2665             : 
    2666             :   .n_next_nodes = IP4_REWRITE_N_NEXT,
    2667             :   .next_nodes = {
    2668             :     [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
    2669             :     [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
    2670             :     [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
    2671             :   },
    2672             : };
    2673             : 
    2674      183788 : VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
    2675             :   .name = "ip4-rewrite-bcast",
    2676             :   .vector_size = sizeof (u32),
    2677             : 
    2678             :   .format_trace = format_ip4_rewrite_trace,
    2679             :   .sibling_of = "ip4-rewrite",
    2680             : };
    2681             : 
    2682      183788 : VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
    2683             :   .name = "ip4-rewrite-mcast",
    2684             :   .vector_size = sizeof (u32),
    2685             : 
    2686             :   .format_trace = format_ip4_rewrite_trace,
    2687             :   .sibling_of = "ip4-rewrite",
    2688             : };
    2689             : 
    2690      183788 : VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
    2691             :   .name = "ip4-mcast-midchain",
    2692             :   .vector_size = sizeof (u32),
    2693             : 
    2694             :   .format_trace = format_ip4_rewrite_trace,
    2695             :   .sibling_of = "ip4-rewrite",
    2696             : };
    2697             : 
    2698      183788 : VLIB_REGISTER_NODE (ip4_midchain_node) = {
    2699             :   .name = "ip4-midchain",
    2700             :   .vector_size = sizeof (u32),
    2701             :   .format_trace = format_ip4_rewrite_trace,
    2702             :   .sibling_of = "ip4-rewrite",
    2703             : };
    2704             : /* *INDENT-ON */
    2705             : 
    2706             : static clib_error_t *
    2707           0 : set_ip_flow_hash_command_fn (vlib_main_t * vm,
    2708             :                              unformat_input_t * input,
    2709             :                              vlib_cli_command_t * cmd)
    2710             : {
    2711           0 :   int matched = 0;
    2712           0 :   u32 table_id = 0;
    2713           0 :   u32 flow_hash_config = 0;
    2714             :   int rv;
    2715             : 
    2716           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2717             :     {
    2718           0 :       if (unformat (input, "table %d", &table_id))
    2719           0 :         matched = 1;
    2720             : #define _(a, b, v)                                                            \
    2721             :   else if (unformat (input, #a))                                              \
    2722             :   {                                                                           \
    2723             :     flow_hash_config |= v;                                                    \
    2724             :     matched = 1;                                                              \
    2725             :   }
    2726           0 :       foreach_flow_hash_bit
    2727             : #undef _
    2728             :         else
    2729           0 :         break;
    2730             :     }
    2731             : 
    2732           0 :   if (matched == 0)
    2733           0 :     return clib_error_return (0, "unknown input `%U'",
    2734             :                               format_unformat_error, input);
    2735             : 
    2736           0 :   rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
    2737           0 :   switch (rv)
    2738             :     {
    2739           0 :     case 0:
    2740           0 :       break;
    2741             : 
    2742           0 :     case VNET_API_ERROR_NO_SUCH_FIB:
    2743           0 :       return clib_error_return (0, "no such FIB table %d", table_id);
    2744             : 
    2745           0 :     default:
    2746           0 :       clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
    2747           0 :       break;
    2748             :     }
    2749             : 
    2750           0 :   return 0;
    2751             : }
    2752             : 
    2753             : /*?
    2754             :  * Configure the set of IPv4 fields used by the flow hash.
    2755             :  *
    2756             :  * @cliexpar
    2757             :  * Example of how to set the flow hash on a given table:
    2758             :  * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
    2759             :  * Example of display the configured flow hash:
    2760             :  * @cliexstart{show ip fib}
    2761             :  * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
    2762             :  * 0.0.0.0/0
    2763             :  *   unicast-ip4-chain
    2764             :  *   [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
    2765             :  *     [0] [@0]: dpo-drop ip6
    2766             :  * 0.0.0.0/32
    2767             :  *   unicast-ip4-chain
    2768             :  *   [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
    2769             :  *     [0] [@0]: dpo-drop ip6
    2770             :  * 224.0.0.0/8
    2771             :  *   unicast-ip4-chain
    2772             :  *   [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
    2773             :  *     [0] [@0]: dpo-drop ip6
    2774             :  * 6.0.1.2/32
    2775             :  *   unicast-ip4-chain
    2776             :  *   [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
    2777             :  *     [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
    2778             :  * 7.0.0.1/32
    2779             :  *   unicast-ip4-chain
    2780             :  *   [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
    2781             :  *     [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
    2782             :  *     [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
    2783             :  *     [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
    2784             :  *     [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
    2785             :  * 240.0.0.0/8
    2786             :  *   unicast-ip4-chain
    2787             :  *   [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
    2788             :  *     [0] [@0]: dpo-drop ip6
    2789             :  * 255.255.255.255/32
    2790             :  *   unicast-ip4-chain
    2791             :  *   [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
    2792             :  *     [0] [@0]: dpo-drop ip6
    2793             :  * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
    2794             :  * 0.0.0.0/0
    2795             :  *   unicast-ip4-chain
    2796             :  *   [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
    2797             :  *     [0] [@0]: dpo-drop ip6
    2798             :  * 0.0.0.0/32
    2799             :  *   unicast-ip4-chain
    2800             :  *   [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
    2801             :  *     [0] [@0]: dpo-drop ip6
    2802             :  * 172.16.1.0/24
    2803             :  *   unicast-ip4-chain
    2804             :  *   [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
    2805             :  *     [0] [@4]: ipv4-glean: af_packet0
    2806             :  * 172.16.1.1/32
    2807             :  *   unicast-ip4-chain
    2808             :  *   [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
    2809             :  *     [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
    2810             :  * 172.16.1.2/32
    2811             :  *   unicast-ip4-chain
    2812             :  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
    2813             :  *     [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
    2814             :  * 172.16.2.0/24
    2815             :  *   unicast-ip4-chain
    2816             :  *   [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
    2817             :  *     [0] [@4]: ipv4-glean: af_packet1
    2818             :  * 172.16.2.1/32
    2819             :  *   unicast-ip4-chain
    2820             :  *   [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
    2821             :  *     [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
    2822             :  * 224.0.0.0/8
    2823             :  *   unicast-ip4-chain
    2824             :  *   [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
    2825             :  *     [0] [@0]: dpo-drop ip6
    2826             :  * 240.0.0.0/8
    2827             :  *   unicast-ip4-chain
    2828             :  *   [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
    2829             :  *     [0] [@0]: dpo-drop ip6
    2830             :  * 255.255.255.255/32
    2831             :  *   unicast-ip4-chain
    2832             :  *   [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
    2833             :  *     [0] [@0]: dpo-drop ip6
    2834             :  * @cliexend
    2835             : ?*/
    2836             : /* *INDENT-OFF* */
    2837      285289 : VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
    2838             :   .path = "set ip flow-hash",
    2839             :   .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
    2840             :                 "[dport] [proto] [reverse] [gtpv1teid]",
    2841             :   .function = set_ip_flow_hash_command_fn,
    2842             : };
    2843             : /* *INDENT-ON* */
    2844             : 
    2845             : #ifndef CLIB_MARCH_VARIANT
    2846             : int
    2847           0 : vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
    2848             :                              u32 table_index)
    2849             : {
    2850           0 :   vnet_main_t *vnm = vnet_get_main ();
    2851           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    2852           0 :   ip4_main_t *ipm = &ip4_main;
    2853           0 :   ip_lookup_main_t *lm = &ipm->lookup_main;
    2854           0 :   vnet_classify_main_t *cm = &vnet_classify_main;
    2855             :   ip4_address_t *if_addr;
    2856             : 
    2857           0 :   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
    2858           0 :     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
    2859             : 
    2860           0 :   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
    2861           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
    2862             : 
    2863           0 :   vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
    2864           0 :   lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
    2865             : 
    2866           0 :   if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
    2867             : 
    2868           0 :   if (NULL != if_addr)
    2869             :     {
    2870           0 :       fib_prefix_t pfx = {
    2871             :         .fp_len = 32,
    2872             :         .fp_proto = FIB_PROTOCOL_IP4,
    2873             :         .fp_addr.ip4 = *if_addr,
    2874             :       };
    2875             :       u32 fib_index;
    2876             : 
    2877           0 :       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
    2878             :                                                        sw_if_index);
    2879             : 
    2880             : 
    2881           0 :       if (table_index != (u32) ~ 0)
    2882             :         {
    2883           0 :           dpo_id_t dpo = DPO_INVALID;
    2884             : 
    2885           0 :           dpo_set (&dpo,
    2886             :                    DPO_CLASSIFY,
    2887             :                    DPO_PROTO_IP4,
    2888             :                    classify_dpo_create (DPO_PROTO_IP4, table_index));
    2889             : 
    2890           0 :           fib_table_entry_special_dpo_add (fib_index,
    2891             :                                            &pfx,
    2892             :                                            FIB_SOURCE_CLASSIFY,
    2893             :                                            FIB_ENTRY_FLAG_NONE, &dpo);
    2894           0 :           dpo_reset (&dpo);
    2895             :         }
    2896             :       else
    2897             :         {
    2898           0 :           fib_table_entry_special_remove (fib_index,
    2899             :                                           &pfx, FIB_SOURCE_CLASSIFY);
    2900             :         }
    2901             :     }
    2902             : 
    2903           0 :   return 0;
    2904             : }
    2905             : #endif
    2906             : 
    2907             : static clib_error_t *
    2908           0 : set_ip_classify_command_fn (vlib_main_t * vm,
    2909             :                             unformat_input_t * input,
    2910             :                             vlib_cli_command_t * cmd)
    2911             : {
    2912           0 :   u32 table_index = ~0;
    2913           0 :   int table_index_set = 0;
    2914           0 :   u32 sw_if_index = ~0;
    2915             :   int rv;
    2916             : 
    2917           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2918             :     {
    2919           0 :       if (unformat (input, "table-index %d", &table_index))
    2920           0 :         table_index_set = 1;
    2921           0 :       else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
    2922             :                          vnet_get_main (), &sw_if_index))
    2923             :         ;
    2924             :       else
    2925           0 :         break;
    2926             :     }
    2927             : 
    2928           0 :   if (table_index_set == 0)
    2929           0 :     return clib_error_return (0, "classify table-index must be specified");
    2930             : 
    2931           0 :   if (sw_if_index == ~0)
    2932           0 :     return clib_error_return (0, "interface / subif must be specified");
    2933             : 
    2934           0 :   rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
    2935             : 
    2936           0 :   switch (rv)
    2937             :     {
    2938           0 :     case 0:
    2939           0 :       break;
    2940             : 
    2941           0 :     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
    2942           0 :       return clib_error_return (0, "No such interface");
    2943             : 
    2944           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
    2945           0 :       return clib_error_return (0, "No such classifier table");
    2946             :     }
    2947           0 :   return 0;
    2948             : }
    2949             : 
    2950             : /*?
    2951             :  * Assign a classification table to an interface. The classification
    2952             :  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
    2953             :  * commands. Once the table is create, use this command to filter packets
    2954             :  * on an interface.
    2955             :  *
    2956             :  * @cliexpar
    2957             :  * Example of how to assign a classification table to an interface:
    2958             :  * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
    2959             : ?*/
    2960             : /* *INDENT-OFF* */
    2961      285289 : VLIB_CLI_COMMAND (set_ip_classify_command, static) =
    2962             : {
    2963             :     .path = "set ip classify",
    2964             :     .short_help =
    2965             :     "set ip classify intfc <interface> table-index <classify-idx>",
    2966             :     .function = set_ip_classify_command_fn,
    2967             : };
    2968             : /* *INDENT-ON* */
    2969             : 
    2970             : /*
    2971             :  * fd.io coding-style-patch-verification: ON
    2972             :  *
    2973             :  * Local Variables:
    2974             :  * eval: (c-set-style "gnu")
    2975             :  * End:
    2976             :  */

Generated by: LCOV version 1.14