LCOV - code coverage report
Current view: top level - vnet/ip - ip4_input.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 110 130 84.6 %
Date: 2023-10-26 01:39:38 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 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             : #ifndef included_ip_input_h
      41             : #define included_ip_input_h
      42             : 
      43             : #include <vnet/ip/ip.h>
      44             : #include <vnet/ethernet/ethernet.h>
      45             : #include <vppinfra/vector/ip_csum.h>
      46             : 
      47             : typedef enum
      48             : {
      49             :   IP4_INPUT_NEXT_DROP,
      50             :   IP4_INPUT_NEXT_PUNT,
      51             :   IP4_INPUT_NEXT_OPTIONS,
      52             :   IP4_INPUT_NEXT_LOOKUP,
      53             :   IP4_INPUT_NEXT_LOOKUP_MULTICAST,
      54             :   IP4_INPUT_NEXT_ICMP_ERROR,
      55             :   IP4_INPUT_N_NEXT,
      56             : } ip4_input_next_t;
      57             : 
      58             : static_always_inline void
      59    13551747 : check_ver_opt_csum (ip4_header_t * ip, u8 * error, int verify_checksum)
      60             : {
      61    13551747 :   if (PREDICT_FALSE (ip->ip_version_and_header_length != 0x45))
      62             :     {
      63          91 :       if ((ip->ip_version_and_header_length & 0xf0) != 0x40)
      64          67 :         *error = IP4_ERROR_VERSION;
      65          24 :       else if ((ip->ip_version_and_header_length & 0x0f) < 5)
      66           0 :         *error = IP4_ERROR_HDR_TOO_SHORT;
      67             :       else
      68             :         {
      69          24 :           *error = IP4_ERROR_OPTIONS;
      70          48 :           if (verify_checksum &&
      71          24 :               clib_ip_csum ((u8 *) ip, ip4_header_bytes (ip)) != 0)
      72           0 :             *error = IP4_ERROR_BAD_CHECKSUM;
      73             :         }
      74             :     }
      75    13551647 :   else if (PREDICT_FALSE (verify_checksum &&
      76             :                           clib_ip_csum ((u8 *) ip, sizeof (ip4_header_t)) !=
      77             :                             0))
      78         197 :     *error = IP4_ERROR_BAD_CHECKSUM;
      79    13551747 : }
      80             : 
      81             : always_inline void
      82     3284680 : ip4_input_check_x4 (vlib_main_t * vm,
      83             :                     vlib_node_runtime_t * error_node,
      84             :                     vlib_buffer_t ** p, ip4_header_t ** ip,
      85             :                     u16 * next, int verify_checksum)
      86             : {
      87             :   u8 error0, error1, error2, error3;
      88             :   u32 ip_len0, cur_len0;
      89             :   u32 ip_len1, cur_len1;
      90             :   u32 ip_len2, cur_len2;
      91             :   u32 ip_len3, cur_len3;
      92             :   i32 len_diff0, len_diff1, len_diff2, len_diff3;
      93             : 
      94     3284680 :   error0 = error1 = error2 = error3 = IP4_ERROR_NONE;
      95             : 
      96     3284680 :   check_ver_opt_csum (ip[0], &error0, verify_checksum);
      97     3284680 :   check_ver_opt_csum (ip[1], &error1, verify_checksum);
      98     3284680 :   check_ver_opt_csum (ip[2], &error2, verify_checksum);
      99     3284690 :   check_ver_opt_csum (ip[3], &error3, verify_checksum);
     100             : 
     101     3284690 :   if (PREDICT_FALSE (ip[0]->ttl < 1))
     102           0 :     error0 = IP4_ERROR_TIME_EXPIRED;
     103     3284690 :   if (PREDICT_FALSE (ip[1]->ttl < 1))
     104           0 :     error1 = IP4_ERROR_TIME_EXPIRED;
     105     3284690 :   if (PREDICT_FALSE (ip[2]->ttl < 1))
     106           0 :     error2 = IP4_ERROR_TIME_EXPIRED;
     107     3284690 :   if (PREDICT_FALSE (ip[3]->ttl < 1))
     108           0 :     error3 = IP4_ERROR_TIME_EXPIRED;
     109             : 
     110             :   /* Drop fragmentation offset 1 packets. */
     111     3284690 :   error0 = ip4_get_fragment_offset (ip[0]) == 1 ?
     112             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
     113     3284690 :   error1 = ip4_get_fragment_offset (ip[1]) == 1 ?
     114             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
     115     3284690 :   error2 = ip4_get_fragment_offset (ip[2]) == 1 ?
     116             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error2;
     117     3284690 :   error3 = ip4_get_fragment_offset (ip[3]) == 1 ?
     118             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error3;
     119             : 
     120             :   /* Verify lengths. */
     121     3284680 :   ip_len0 = clib_net_to_host_u16 (ip[0]->length);
     122     3284680 :   ip_len1 = clib_net_to_host_u16 (ip[1]->length);
     123     3284670 :   ip_len2 = clib_net_to_host_u16 (ip[2]->length);
     124     3284680 :   ip_len3 = clib_net_to_host_u16 (ip[3]->length);
     125             : 
     126             :   /* IP length must be at least minimal IP header. */
     127     3284670 :   error0 = ip_len0 < sizeof (ip[0][0]) ? IP4_ERROR_TOO_SHORT : error0;
     128     3284670 :   error1 = ip_len1 < sizeof (ip[1][0]) ? IP4_ERROR_TOO_SHORT : error1;
     129     3284670 :   error2 = ip_len2 < sizeof (ip[2][0]) ? IP4_ERROR_TOO_SHORT : error2;
     130     3284670 :   error3 = ip_len3 < sizeof (ip[3][0]) ? IP4_ERROR_TOO_SHORT : error3;
     131             : 
     132     3284670 :   cur_len0 = vlib_buffer_length_in_chain (vm, p[0]);
     133     3284680 :   cur_len1 = vlib_buffer_length_in_chain (vm, p[1]);
     134     3284670 :   cur_len2 = vlib_buffer_length_in_chain (vm, p[2]);
     135     3284670 :   cur_len3 = vlib_buffer_length_in_chain (vm, p[3]);
     136             : 
     137     3284660 :   len_diff0 = cur_len0 - ip_len0;
     138     3284660 :   len_diff1 = cur_len1 - ip_len1;
     139     3284660 :   len_diff2 = cur_len2 - ip_len2;
     140     3284660 :   len_diff3 = cur_len3 - ip_len3;
     141             : 
     142     3284660 :   error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
     143     3284660 :   error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
     144     3284660 :   error2 = len_diff2 < 0 ? IP4_ERROR_BAD_LENGTH : error2;
     145     3284660 :   error3 = len_diff3 < 0 ? IP4_ERROR_BAD_LENGTH : error3;
     146             : 
     147     3284660 :   if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
     148             :     {
     149          64 :       if (error0 == IP4_ERROR_TIME_EXPIRED)
     150             :         {
     151           0 :           icmp4_error_set_vnet_buffer (p[0], ICMP4_time_exceeded,
     152             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     153             :                                        0);
     154           0 :           next[0] = IP4_INPUT_NEXT_ICMP_ERROR;
     155             :         }
     156             :       else
     157          64 :         next[0] = error0 != IP4_ERROR_OPTIONS ?
     158             :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     159          64 :       p[0]->error = error_node->errors[error0];
     160             :     }
     161     3284660 :   if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
     162             :     {
     163          65 :       if (error1 == IP4_ERROR_TIME_EXPIRED)
     164             :         {
     165           0 :           icmp4_error_set_vnet_buffer (p[1], ICMP4_time_exceeded,
     166             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     167             :                                        0);
     168           0 :           next[1] = IP4_INPUT_NEXT_ICMP_ERROR;
     169             :         }
     170             :       else
     171          65 :         next[1] = error1 != IP4_ERROR_OPTIONS ?
     172             :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     173          65 :       p[1]->error = error_node->errors[error1];
     174             :     }
     175     3284660 :   if (PREDICT_FALSE (error2 != IP4_ERROR_NONE))
     176             :     {
     177          64 :       if (error2 == IP4_ERROR_TIME_EXPIRED)
     178             :         {
     179           0 :           icmp4_error_set_vnet_buffer (p[2], ICMP4_time_exceeded,
     180             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     181             :                                        0);
     182           0 :           next[2] = IP4_INPUT_NEXT_ICMP_ERROR;
     183             :         }
     184             :       else
     185          64 :         next[2] = error2 != IP4_ERROR_OPTIONS ?
     186             :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     187          64 :       p[2]->error = error_node->errors[error2];
     188             :     }
     189     3284660 :   if (PREDICT_FALSE (error3 != IP4_ERROR_NONE))
     190             :     {
     191          64 :       if (error3 == IP4_ERROR_TIME_EXPIRED)
     192             :         {
     193           0 :           icmp4_error_set_vnet_buffer (p[3], ICMP4_time_exceeded,
     194             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     195             :                                        0);
     196           0 :           next[3] = IP4_INPUT_NEXT_ICMP_ERROR;
     197             :         }
     198             :       else
     199          64 :         next[3] = error3 != IP4_ERROR_OPTIONS ?
     200             :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     201          64 :       p[3]->error = error_node->errors[error3];
     202             :     }
     203     3284660 : }
     204             : 
     205             : always_inline void
     206        1490 : ip4_input_check_x2 (vlib_main_t * vm,
     207             :                     vlib_node_runtime_t * error_node,
     208             :                     vlib_buffer_t * p0, vlib_buffer_t * p1,
     209             :                     ip4_header_t * ip0, ip4_header_t * ip1,
     210             :                     u32 * next0, u32 * next1, int verify_checksum)
     211             : {
     212             :   u8 error0, error1;
     213             :   u32 ip_len0, cur_len0;
     214             :   u32 ip_len1, cur_len1;
     215             :   i32 len_diff0, len_diff1;
     216             : 
     217        1490 :   error0 = error1 = IP4_ERROR_NONE;
     218             : 
     219        1490 :   check_ver_opt_csum (ip0, &error0, verify_checksum);
     220        1490 :   check_ver_opt_csum (ip1, &error1, verify_checksum);
     221             : 
     222        1490 :   if (PREDICT_FALSE (ip0->ttl < 1))
     223           0 :     error0 = IP4_ERROR_TIME_EXPIRED;
     224        1490 :   if (PREDICT_FALSE (ip1->ttl < 1))
     225           0 :     error1 = IP4_ERROR_TIME_EXPIRED;
     226             : 
     227             :   /* Drop fragmentation offset 1 packets. */
     228        1490 :   error0 = ip4_get_fragment_offset (ip0) == 1 ?
     229             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
     230        1490 :   error1 = ip4_get_fragment_offset (ip1) == 1 ?
     231             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
     232             : 
     233             :   /* Verify lengths. */
     234        1490 :   ip_len0 = clib_net_to_host_u16 (ip0->length);
     235        1490 :   ip_len1 = clib_net_to_host_u16 (ip1->length);
     236             : 
     237             :   /* IP length must be at least minimal IP header. */
     238        1490 :   error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
     239        1490 :   error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
     240             : 
     241        1490 :   cur_len0 = vlib_buffer_length_in_chain (vm, p0);
     242        1490 :   cur_len1 = vlib_buffer_length_in_chain (vm, p1);
     243             : 
     244        1490 :   len_diff0 = cur_len0 - ip_len0;
     245        1490 :   len_diff1 = cur_len1 - ip_len1;
     246             : 
     247        1490 :   error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
     248        1490 :   error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
     249             : 
     250        1490 :   if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
     251             :     {
     252          62 :       if (error0 == IP4_ERROR_TIME_EXPIRED)
     253             :         {
     254           0 :           icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
     255             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     256             :                                        0);
     257           0 :           *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
     258             :         }
     259             :       else
     260          62 :         *next0 = error0 != IP4_ERROR_OPTIONS ?
     261          62 :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     262          62 :       p0->error = error_node->errors[error0];
     263             :     }
     264        1490 :   if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
     265             :     {
     266          62 :       if (error1 == IP4_ERROR_TIME_EXPIRED)
     267             :         {
     268           0 :           icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
     269             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     270             :                                        0);
     271           0 :           *next1 = IP4_INPUT_NEXT_ICMP_ERROR;
     272             :         }
     273             :       else
     274          62 :         *next1 = error1 != IP4_ERROR_OPTIONS ?
     275          62 :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     276          62 :       p1->error = error_node->errors[error1];
     277             :     }
     278        1490 : }
     279             : 
     280             : always_inline void
     281      410128 : ip4_input_check_x1 (vlib_main_t * vm,
     282             :                     vlib_node_runtime_t * error_node,
     283             :                     vlib_buffer_t * p0,
     284             :                     ip4_header_t * ip0, u32 * next0, int verify_checksum)
     285             : {
     286             :   u32 ip_len0, cur_len0;
     287             :   i32 len_diff0;
     288             :   u8 error0;
     289             : 
     290      410128 :   error0 = IP4_ERROR_NONE;
     291             : 
     292      410128 :   check_ver_opt_csum (ip0, &error0, verify_checksum);
     293             : 
     294      410128 :   if (PREDICT_FALSE (ip0->ttl < 1))
     295           1 :     error0 = IP4_ERROR_TIME_EXPIRED;
     296             : 
     297             :   /* Drop fragmentation offset 1 packets. */
     298      410128 :   error0 = ip4_get_fragment_offset (ip0) == 1 ?
     299             :     IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
     300             : 
     301             :   /* Verify lengths. */
     302      410128 :   ip_len0 = clib_net_to_host_u16 (ip0->length);
     303             : 
     304             :   /* IP length must be at least minimal IP header. */
     305      410128 :   error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
     306             : 
     307      410128 :   cur_len0 = vlib_buffer_length_in_chain (vm, p0);
     308             : 
     309      410128 :   len_diff0 = cur_len0 - ip_len0;
     310             : 
     311      410128 :   error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
     312             : 
     313      410128 :   if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
     314             :     {
     315          43 :       if (error0 == IP4_ERROR_TIME_EXPIRED)
     316             :         {
     317           1 :           icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
     318             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     319             :                                        0);
     320           1 :           *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
     321             :         }
     322             :       else
     323          42 :         *next0 = error0 != IP4_ERROR_OPTIONS ?
     324          42 :           IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
     325          43 :       p0->error = error_node->errors[error0];
     326             :     }
     327      410128 : }
     328             : 
     329             : /*
     330             :  * fd.io coding-style-patch-verification: ON
     331             :  *
     332             :  * Local Variables:
     333             :  * eval: (c-set-style "gnu")
     334             :  * End:
     335             :  */
     336             : 
     337             : #endif

Generated by: LCOV version 1.14