LCOV - code coverage report
Current view: top level - vnet/ip - ip_checksum.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 25 34 73.5 %
Date: 2023-10-26 01:39:38 Functions: 6 7 85.7 %

          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             :  * ip4/ip_checksum.c: ip/tcp/udp checksums
      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/ip.h>
      41             : 
      42             : static ip_csum_t
      43    49594200 : _ip_incremental_checksum (ip_csum_t sum, void *_data, uword n_bytes)
      44             : {
      45    49594200 :   uword data = pointer_to_uword (_data);
      46             :   ip_csum_t sum0, sum1;
      47             : 
      48    49594200 :   sum0 = 0;
      49    49594200 :   sum1 = sum;
      50             : 
      51             :   /*
      52             :    * Align pointer to 64 bits. The ip checksum is a 16-bit
      53             :    * one's complememt sum. It's impractical to optimize
      54             :    * the calculation if the incoming address is odd.
      55             :    */
      56             : #define _(t)                                    \
      57             : do {                                            \
      58             :   if (n_bytes >= sizeof (t)                  \
      59             :       && sizeof (t) < sizeof (ip_csum_t)     \
      60             :       && (data % (2 * sizeof (t))) != 0)        \
      61             :     {                                           \
      62             :       sum0 += * uword_to_pointer (data, t *);   \
      63             :       data += sizeof (t);                       \
      64             :       n_bytes -= sizeof (t);                    \
      65             :     }                                           \
      66             : } while (0)
      67             : 
      68    49594200 :   if (PREDICT_TRUE ((data & 1) == 0))
      69             :     {
      70    49594200 :       _(u16);
      71             :       if (BITS (ip_csum_t) > 32)
      72    49594200 :         _(u32);
      73             :     }
      74             : #undef _
      75             : 
      76             :   {
      77    49594200 :     ip_csum_t *d = uword_to_pointer (data, ip_csum_t *);
      78             : 
      79  4198290000 :     while (n_bytes >= 2 * sizeof (d[0]))
      80             :       {
      81  4148690000 :         sum0 = ip_csum_with_carry (sum0, d[0]);
      82  4148690000 :         sum1 = ip_csum_with_carry (sum1, d[1]);
      83  4148690000 :         d += 2;
      84  4148690000 :         n_bytes -= 2 * sizeof (d[0]);
      85             :       }
      86             : 
      87    49594200 :     data = pointer_to_uword (d);
      88             :   }
      89             : 
      90             : #define _(t)                                                            \
      91             : do {                                                                    \
      92             :   if (n_bytes >= sizeof (t) && sizeof (t) <= sizeof (ip_csum_t))  \
      93             :     {                                                                   \
      94             :       sum0 = ip_csum_with_carry (sum0, * uword_to_pointer (data, t *)); \
      95             :       data += sizeof (t);                                               \
      96             :       n_bytes -= sizeof (t);                                            \
      97             :     }                                                                   \
      98             : } while (0)
      99             : 
     100             :   if (BITS (ip_csum_t) > 32)
     101    49594200 :     _(u64);
     102    49594200 :   _(u32);
     103    49594200 :   _(u16);
     104    49594200 :   _(u8);
     105             : 
     106             : #undef _
     107             : 
     108             :   /* Combine even and odd sums. */
     109    49594200 :   sum0 = ip_csum_with_carry (sum0, sum1);
     110             : 
     111    49594200 :   return sum0;
     112             : }
     113             : 
     114             : /*
     115             :  * Note: the tcp / udp checksum calculation is performance critical
     116             :  * [e.g. when NIC h/w offload is not available],
     117             :  * so it's worth producing architecture-dependent code.
     118             :  *
     119             :  * ip_incremental_checksum() is an always-inlined static
     120             :  * function which uses the function pointer we set up in
     121             :  * ip_checksum_init().
     122             :  */
     123             : 
     124             : ip_csum_t (*vnet_incremental_checksum_fp) (ip_csum_t, void *, uword);
     125             : 
     126             : clib_error_t *
     127         575 : ip_checksum_init (vlib_main_t *vm)
     128             : {
     129         575 :   vnet_incremental_checksum_fp = _ip_incremental_checksum;
     130         575 :   return 0;
     131             : }
     132             : 
     133       44351 : VLIB_INIT_FUNCTION (ip_checksum_init);
     134             : 
     135             : #if CLIB_DEBUG > 0
     136             : 
     137             : static const char test_pkt[] = {
     138             :   0x45, 0x00, 0x00, 0x3c, 0x5d, 0x6f, 0x40, 0x00,
     139             :   0x40, 0x06, 0x3f, 0x6b, 0x0a, 0x76, 0x72, 0x44,
     140             :   0x0a, 0x56, 0x16, 0xd2,
     141             : };
     142             : 
     143             : static clib_error_t *
     144           0 : test_ip_checksum_fn (vlib_main_t * vm,
     145             :                      unformat_input_t * input, vlib_cli_command_t * cmd)
     146             : {
     147             :   u16 csum;
     148             :   ip4_header_t *hp;
     149           0 :   u8 *align_test = 0;
     150             :   int offset;
     151             : 
     152           0 :   vec_validate (align_test, ARRAY_LEN (test_pkt) + 7);
     153             : 
     154           0 :   for (offset = 0; offset < 8; offset++)
     155             :     {
     156           0 :       memcpy (align_test + offset, test_pkt, ARRAY_LEN (test_pkt));
     157             : 
     158           0 :       hp = (ip4_header_t *) (align_test + offset);
     159           0 :       csum = ip4_header_checksum (hp);
     160             : 
     161           0 :       vlib_cli_output (vm, "offset %d checksum %u expected result 27455",
     162             :                        offset, (u32) csum);
     163             :     }
     164             : 
     165           0 :   return 0;
     166             : }
     167             : 
     168             : /* *INDENT-OFF* */
     169      285289 : VLIB_CLI_COMMAND (test_checksum, static) =
     170             : {
     171             :   .path = "test ip checksum",
     172             :   .short_help = "test ip checksum",
     173             :   .function = test_ip_checksum_fn,
     174             : };
     175             : /* *INDENT-ON* */
     176             : 
     177             : #endif /* CLIB_DEBUG */
     178             : 
     179             : /*
     180             :  * fd.io coding-style-patch-verification: ON
     181             :  *
     182             :  * Local Variables:
     183             :  * eval: (c-set-style "gnu")
     184             :  * End:
     185             :  */

Generated by: LCOV version 1.14