LCOV - code coverage report
Current view: top level - vnet/ip - ip4_input.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 133 135 98.5 %
Date: 2023-10-26 01:39:38 Functions: 21 27 77.8 %

          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_input.c: IP v4 input node
      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/ip/ip4_input.h>
      41             : #include <vnet/ethernet/ethernet.h>
      42             : #include <vnet/pg/pg.h>
      43             : #include <vnet/ppp/ppp.h>
      44             : #include <vnet/hdlc/hdlc.h>
      45             : #include <vnet/util/throttle.h>
      46             : 
      47             : typedef struct
      48             : {
      49             :   u8 packet_data[64];
      50             : } ip4_input_trace_t;
      51             : 
      52             : static u8 *
      53      348992 : format_ip4_input_trace (u8 * s, va_list * va)
      54             : {
      55      348992 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      56      348992 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      57      348992 :   ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
      58             : 
      59      348992 :   s = format (s, "%U",
      60      348992 :               format_ip4_header, t->packet_data, sizeof (t->packet_data));
      61             : 
      62      348992 :   return s;
      63             : }
      64             : 
      65             : static_always_inline u32
      66    13548700 : ip4_input_set_next (u32 sw_if_index, vlib_buffer_t * b, int arc_enabled)
      67             : {
      68    13548700 :   ip4_main_t *im = &ip4_main;
      69    13548700 :   ip_lookup_main_t *lm = &im->lookup_main;
      70             :   u32 next;
      71             :   u8 arc;
      72             : 
      73    13548700 :   ip4_header_t *ip = vlib_buffer_get_current (b);
      74             : 
      75    13548700 :   if (PREDICT_FALSE (ip4_address_is_multicast (&ip->dst_address)))
      76             :     {
      77        2116 :       next = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
      78        2116 :       arc = lm->mcast_feature_arc_index;
      79             :     }
      80             :   else
      81             :     {
      82    13546600 :       next = IP4_INPUT_NEXT_LOOKUP;
      83    13546600 :       arc = lm->ucast_feature_arc_index;
      84             :     }
      85             : 
      86    13548700 :   if (arc_enabled)
      87     1475900 :     vnet_feature_arc_start (arc, sw_if_index, &next, b);
      88             : 
      89    13548700 :   return next;
      90             : }
      91             : 
      92             : static_always_inline void
      93     1519010 : ip4_input_check_sw_if_index (vlib_main_t * vm,
      94             :                              vlib_simple_counter_main_t * cm, u32 sw_if_index,
      95             :                              u32 * last_sw_if_index, u32 * cnt,
      96             :                              int *arc_enabled)
      97             : {
      98     1519010 :   ip4_main_t *im = &ip4_main;
      99     1519010 :   ip_lookup_main_t *lm = &im->lookup_main;
     100             :   u32 thread_index;
     101     1519010 :   if (*last_sw_if_index == sw_if_index)
     102             :     {
     103     1153710 :       (*cnt)++;
     104     1153710 :       return;
     105             :     }
     106             : 
     107      365296 :   thread_index = vm->thread_index;
     108      365296 :   if (*cnt)
     109       68772 :     vlib_increment_simple_counter (cm, thread_index, *last_sw_if_index, *cnt);
     110      365296 :   *cnt = 1;
     111      365296 :   *last_sw_if_index = sw_if_index;
     112             : 
     113      719611 :   if (vnet_have_features (lm->ucast_feature_arc_index, sw_if_index) ||
     114      354315 :       vnet_have_features (lm->mcast_feature_arc_index, sw_if_index))
     115       10981 :     *arc_enabled = 1;
     116             :   else
     117      354315 :     *arc_enabled = 0;
     118             : }
     119             : 
     120             : /* Validate IP v4 packets and pass them either to forwarding code
     121             :    or drop/punt exception packets. */
     122             : always_inline uword
     123      296524 : ip4_input_inline (vlib_main_t * vm,
     124             :                   vlib_node_runtime_t * node,
     125             :                   vlib_frame_t * frame, int verify_checksum)
     126             : {
     127      296524 :   vnet_main_t *vnm = vnet_get_main ();
     128             :   u32 n_left_from, *from;
     129      296524 :   u32 thread_index = vm->thread_index;
     130             :   vlib_node_runtime_t *error_node =
     131      296524 :     vlib_node_get_runtime (vm, ip4_input_node.index);
     132             :   vlib_simple_counter_main_t *cm;
     133             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     134             :   ip4_header_t *ip[4];
     135             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     136             :   u32 sw_if_index[4];
     137      296524 :   u32 last_sw_if_index = ~0;
     138      296524 :   u32 cnt = 0;
     139      296524 :   int arc_enabled = 0;
     140             : 
     141      296524 :   from = vlib_frame_vector_args (frame);
     142      296524 :   n_left_from = frame->n_vectors;
     143             : 
     144      296524 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     145       12731 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     146             :                                    /* stride */ 1,
     147             :                                    sizeof (ip4_input_trace_t));
     148             : 
     149      296524 :   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
     150             :                          VNET_INTERFACE_COUNTER_IP4);
     151             : 
     152      296524 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     153      296524 :   b = bufs;
     154      296524 :   next = nexts;
     155             : #if (CLIB_N_PREFETCHES >= 8)
     156     3581190 :   while (n_left_from >= 4)
     157             :     {
     158     3284670 :       u32 x = 0;
     159             : 
     160             :       /* Prefetch next iteration. */
     161     3284670 :       if (n_left_from >= 12)
     162             :         {
     163     2890850 :           vlib_prefetch_buffer_header (b[8], LOAD);
     164     2890850 :           vlib_prefetch_buffer_header (b[9], LOAD);
     165     2890850 :           vlib_prefetch_buffer_header (b[10], LOAD);
     166     2890850 :           vlib_prefetch_buffer_header (b[11], LOAD);
     167             : 
     168     2890850 :           vlib_prefetch_buffer_data (b[4], LOAD);
     169     2890850 :           vlib_prefetch_buffer_data (b[5], LOAD);
     170     2890840 :           vlib_prefetch_buffer_data (b[6], LOAD);
     171     2890840 :           vlib_prefetch_buffer_data (b[7], LOAD);
     172             :         }
     173             : 
     174     3284660 :       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
     175     3284660 :       vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
     176     3284660 :       vnet_buffer (b[2])->ip.adj_index[VLIB_RX] = ~0;
     177     3284660 :       vnet_buffer (b[3])->ip.adj_index[VLIB_RX] = ~0;
     178             : 
     179     3284660 :       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     180     3284660 :       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     181     3284660 :       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
     182     3284660 :       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
     183             : 
     184     3284660 :       x |= sw_if_index[0] ^ last_sw_if_index;
     185     3284660 :       x |= sw_if_index[1] ^ last_sw_if_index;
     186     3284660 :       x |= sw_if_index[2] ^ last_sw_if_index;
     187     3284660 :       x |= sw_if_index[3] ^ last_sw_if_index;
     188             : 
     189     3284660 :       if (PREDICT_TRUE (x == 0))
     190             :         {
     191             :           /* we deal with 4 more packets sharing the same sw_if_index
     192             :              with the previous one, so we can optimize */
     193     3007420 :           cnt += 4;
     194     3007420 :           if (arc_enabled)
     195             :             {
     196       87434 :               next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
     197       87442 :               next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
     198       87449 :               next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
     199       87461 :               next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
     200             :             }
     201             :           else
     202             :             {
     203     2919990 :               next[0] = ip4_input_set_next (sw_if_index[0], b[0], 0);
     204     2919990 :               next[1] = ip4_input_set_next (sw_if_index[1], b[1], 0);
     205     2919990 :               next[2] = ip4_input_set_next (sw_if_index[2], b[2], 0);
     206     2919990 :               next[3] = ip4_input_set_next (sw_if_index[3], b[3], 0);
     207             :             }
     208             :         }
     209             :       else
     210             :         {
     211      277237 :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
     212             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     213      277237 :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
     214             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     215      277237 :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[2],
     216             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     217      277237 :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[3],
     218             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     219             : 
     220      277237 :           next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
     221      277237 :           next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
     222      277237 :           next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
     223      277237 :           next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
     224             :         }
     225             : 
     226     3284690 :       ip[0] = vlib_buffer_get_current (b[0]);
     227     3284690 :       ip[1] = vlib_buffer_get_current (b[1]);
     228     3284680 :       ip[2] = vlib_buffer_get_current (b[2]);
     229     3284680 :       ip[3] = vlib_buffer_get_current (b[3]);
     230             : 
     231     3284680 :       ip4_input_check_x4 (vm, error_node, b, ip, next, verify_checksum);
     232             : 
     233             :       /* next */
     234     3284660 :       b += 4;
     235     3284660 :       next += 4;
     236     3284660 :       n_left_from -= 4;
     237             :     }
     238             : #elif (CLIB_N_PREFETCHES >= 4)
     239             :   while (n_left_from >= 2)
     240             :     {
     241             :       u32 x = 0;
     242             :       u32 next0, next1;
     243             : 
     244             :       /* Prefetch next iteration. */
     245             :       if (n_left_from >= 6)
     246             :         {
     247             :           vlib_prefetch_buffer_header (b[4], LOAD);
     248             :           vlib_prefetch_buffer_header (b[5], LOAD);
     249             : 
     250             :           vlib_prefetch_buffer_data (b[2], LOAD);
     251             :           vlib_prefetch_buffer_data (b[3], LOAD);
     252             :         }
     253             : 
     254             :       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
     255             :       vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
     256             : 
     257             :       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     258             :       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     259             : 
     260             :       x |= sw_if_index[0] ^ last_sw_if_index;
     261             :       x |= sw_if_index[1] ^ last_sw_if_index;
     262             : 
     263             :       if (PREDICT_TRUE (x == 0))
     264             :         {
     265             :           /* we deal with 2 more packets sharing the same sw_if_index
     266             :              with the previous one, so we can optimize */
     267             :           cnt += 2;
     268             :           if (arc_enabled)
     269             :             {
     270             :               next0 = ip4_input_set_next (sw_if_index[0], b[0], 1);
     271             :               next1 = ip4_input_set_next (sw_if_index[1], b[1], 1);
     272             :             }
     273             :           else
     274             :             {
     275             :               next0 = ip4_input_set_next (sw_if_index[0], b[0], 0);
     276             :               next1 = ip4_input_set_next (sw_if_index[1], b[1], 0);
     277             :             }
     278             :         }
     279             :       else
     280             :         {
     281             :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
     282             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     283             :           ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
     284             :                                        &last_sw_if_index, &cnt, &arc_enabled);
     285             : 
     286             :           next0 = ip4_input_set_next (sw_if_index[0], b[0], 1);
     287             :           next1 = ip4_input_set_next (sw_if_index[1], b[1], 1);
     288             :         }
     289             : 
     290             :       ip[0] = vlib_buffer_get_current (b[0]);
     291             :       ip[1] = vlib_buffer_get_current (b[1]);
     292             : 
     293             :       ip4_input_check_x2 (vm, error_node, b[0], b[1], ip[0], ip[1],
     294             :                           &next0, &next1, verify_checksum);
     295             :       next[0] = (u16) next0;
     296             :       next[1] = (u16) next1;
     297             : 
     298             :       /* next */
     299             :       b += 2;
     300             :       next += 2;
     301             :       n_left_from -= 2;
     302             :     }
     303             : #endif
     304             : 
     305      706585 :   while (n_left_from)
     306             :     {
     307             :       u32 next0;
     308      410061 :       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
     309      410061 :       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     310      410061 :       ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
     311             :                                    &cnt, &arc_enabled);
     312      410061 :       next0 = ip4_input_set_next (sw_if_index[0], b[0], arc_enabled);
     313      410061 :       ip[0] = vlib_buffer_get_current (b[0]);
     314      410061 :       ip4_input_check_x1 (vm, error_node, b[0], ip[0], &next0,
     315             :                           verify_checksum);
     316      410062 :       next[0] = next0;
     317             : 
     318             :       /* next */
     319      410062 :       b += 1;
     320      410062 :       next += 1;
     321      410062 :       n_left_from -= 1;
     322             :     }
     323             : 
     324      296524 :   vlib_increment_simple_counter (cm, thread_index, last_sw_if_index, cnt);
     325      296524 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     326      296524 :   return frame->n_vectors;
     327             : }
     328             : 
     329             : /** \brief IPv4 input node.
     330             :     @node ip4-input
     331             : 
     332             :     This is the IPv4 input node: validates ip4 header checksums,
     333             :     verifies ip header lengths, discards pkts with expired TTLs,
     334             :     and sends pkts to the set of ip feature nodes configured on
     335             :     the rx interface.
     336             : 
     337             :     @param vm vlib_main_t corresponding to the current thread
     338             :     @param node vlib_node_runtime_t
     339             :     @param frame vlib_frame_t whose contents should be dispatched
     340             : 
     341             :     @par Graph mechanics: buffer metadata, next index usage
     342             : 
     343             :     @em Uses:
     344             :     - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
     345             :       multicast status.
     346             :     - <code>b->current_config_index</code> corresponding to each pkt's
     347             :       rx sw_if_index.
     348             :          - This sets the per-packet graph trajectory, ensuring that
     349             :            each packet visits the per-interface features in order.
     350             : 
     351             :     - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
     352             :         - Indicates the @c sw_if_index value of the interface that the
     353             :           packet was received on.
     354             : 
     355             :     @em Sets:
     356             :     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
     357             :         - The lookup result adjacency index.
     358             : 
     359             :     <em>Next Indices:</em>
     360             :     - Dispatches pkts to the (first) feature node:
     361             :       <code> vnet_get_config_data (... &next0 ...); </code>
     362             :       or @c error-drop
     363             : */
     364      293883 : VLIB_NODE_FN (ip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     365             :                                vlib_frame_t * frame)
     366             : {
     367      291583 :   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
     368             : }
     369             : 
     370        7241 : VLIB_NODE_FN (ip4_input_no_checksum_node) (vlib_main_t * vm,
     371             :                                            vlib_node_runtime_t * node,
     372             :                                            vlib_frame_t * frame)
     373             : {
     374        4941 :   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
     375             : }
     376             : 
     377             : /* *INDENT-OFF* */
     378      183788 : VLIB_REGISTER_NODE (ip4_input_node) = {
     379             :   .name = "ip4-input",
     380             :   .vector_size = sizeof (u32),
     381             :   .protocol_hint = VLIB_NODE_PROTO_HINT_IP4,
     382             : 
     383             :   .n_errors = IP4_N_ERROR,
     384             :   .error_counters = ip4_error_counters,
     385             : 
     386             :   .n_next_nodes = IP4_INPUT_N_NEXT,
     387             :   .next_nodes = {
     388             :     [IP4_INPUT_NEXT_DROP] = "error-drop",
     389             :     [IP4_INPUT_NEXT_PUNT] = "error-punt",
     390             :     [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
     391             :     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
     392             :     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
     393             :     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     394             :   },
     395             : 
     396             :   .format_buffer = format_ip4_header,
     397             :   .format_trace = format_ip4_input_trace,
     398             : };
     399             : 
     400      183788 : VLIB_REGISTER_NODE (ip4_input_no_checksum_node) = {
     401             :   .name = "ip4-input-no-checksum",
     402             :   .vector_size = sizeof (u32),
     403             : 
     404             :   .sibling_of = "ip4-input",
     405             :   .format_buffer = format_ip4_header,
     406             :   .format_trace = format_ip4_input_trace,
     407             : };
     408             : /* *INDENT-ON* */
     409             : 
     410             : static clib_error_t *
     411         575 : ip4_init (vlib_main_t * vm)
     412             : {
     413             :   clib_error_t *error;
     414             : 
     415         575 :   ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
     416         575 :   ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
     417         575 :   hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
     418             : 
     419             :   {
     420             :     extern vlib_node_registration_t ip4_input_no_checksum_node;
     421             :     pg_node_t *pn;
     422         575 :     pn = pg_get_node (ip4_input_node.index);
     423         575 :     pn->unformat_edit = unformat_pg_ip4_header;
     424         575 :     pn = pg_get_node (ip4_input_no_checksum_node.index);
     425         575 :     pn->unformat_edit = unformat_pg_ip4_header;
     426             :   }
     427             : 
     428         575 :   if ((error = vlib_call_init_function (vm, ip4_cli_init)))
     429           0 :     return error;
     430             : 
     431         575 :   if ((error = vlib_call_init_function
     432             :        (vm, ip4_source_and_port_range_check_init)))
     433           0 :     return error;
     434             : 
     435             :   /* Set flow hash to something non-zero. */
     436         575 :   ip4_main.flow_hash_seed = 0xdeadbeef;
     437             : 
     438             :   /* Default TTL for packets we generate. */
     439         575 :   ip4_main.host_config.ttl = 64;
     440             : 
     441         575 :   return error;
     442             : }
     443             : 
     444       13823 : VLIB_INIT_FUNCTION (ip4_init);
     445             : 
     446             : /*
     447             :  * fd.io coding-style-patch-verification: ON
     448             :  *
     449             :  * Local Variables:
     450             :  * eval: (c-set-style "gnu")
     451             :  * End:
     452             :  */

Generated by: LCOV version 1.14