LCOV - code coverage report
Current view: top level - vnet/ip - ip4_pg.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 102 145 70.3 %
Date: 2023-07-05 22:20:52 Functions: 4 4 100.0 %

          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_pg: IP v4 packet-generator interface
      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             : #include <vnet/pg/pg.h>
      42             : 
      43             : #define IP4_PG_EDIT_CHECKSUM (1 << 0)
      44             : #define IP4_PG_EDIT_LENGTH (1 << 1)
      45             : 
      46             : static_always_inline void
      47           1 : compute_length_and_or_checksum (vlib_main_t * vm,
      48             :                                 u32 * packets,
      49             :                                 u32 n_packets,
      50             :                                 u32 ip_header_offset, u32 flags)
      51             : {
      52           1 :   ASSERT (flags != 0);
      53             : 
      54          51 :   while (n_packets >= 2)
      55             :     {
      56             :       u32 pi0, pi1;
      57             :       vlib_buffer_t *p0, *p1;
      58             :       ip4_header_t *ip0, *ip1;
      59             :       ip_csum_t sum0, sum1;
      60             : 
      61          50 :       pi0 = packets[0];
      62          50 :       pi1 = packets[1];
      63          50 :       p0 = vlib_get_buffer (vm, pi0);
      64          50 :       p1 = vlib_get_buffer (vm, pi1);
      65          50 :       n_packets -= 2;
      66          50 :       packets += 2;
      67             : 
      68          50 :       ip0 = (void *) (p0->data + ip_header_offset);
      69          50 :       ip1 = (void *) (p1->data + ip_header_offset);
      70             : 
      71          50 :       if (flags & IP4_PG_EDIT_LENGTH)
      72             :         {
      73           0 :           ip0->length =
      74           0 :             clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) -
      75             :                                   ip_header_offset);
      76           0 :           ip1->length =
      77           0 :             clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p1) -
      78             :                                   ip_header_offset);
      79             :         }
      80             : 
      81          50 :       if (flags & IP4_PG_EDIT_CHECKSUM)
      82             :         {
      83          50 :           ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
      84          50 :           ASSERT (ip4_header_bytes (ip1) == sizeof (ip1[0]));
      85             : 
      86          50 :           ip0->checksum = 0;
      87          50 :           ip1->checksum = 0;
      88             : 
      89          50 :           ip4_partial_header_checksum_x2 (ip0, ip1, sum0, sum1);
      90          50 :           ip0->checksum = ~ip_csum_fold (sum0);
      91          50 :           ip1->checksum = ~ip_csum_fold (sum1);
      92             : 
      93          50 :           ASSERT (ip4_header_checksum_is_valid (ip0));
      94          50 :           ASSERT (ip4_header_checksum_is_valid (ip1));
      95             :         }
      96             :     }
      97             : 
      98           1 :   while (n_packets >= 1)
      99             :     {
     100             :       u32 pi0;
     101             :       vlib_buffer_t *p0;
     102             :       ip4_header_t *ip0;
     103             :       ip_csum_t sum0;
     104             : 
     105           0 :       pi0 = packets[0];
     106           0 :       p0 = vlib_get_buffer (vm, pi0);
     107           0 :       n_packets -= 1;
     108           0 :       packets += 1;
     109             : 
     110           0 :       ip0 = (void *) (p0->data + ip_header_offset);
     111             : 
     112           0 :       if (flags & IP4_PG_EDIT_LENGTH)
     113           0 :         ip0->length =
     114           0 :           clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) -
     115             :                                 ip_header_offset);
     116             : 
     117           0 :       if (flags & IP4_PG_EDIT_CHECKSUM)
     118             :         {
     119           0 :           ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
     120             : 
     121           0 :           ip0->checksum = 0;
     122             : 
     123           0 :           ip4_partial_header_checksum_x1 (ip0, sum0);
     124           0 :           ip0->checksum = ~ip_csum_fold (sum0);
     125             : 
     126           0 :           ASSERT (ip4_header_checksum_is_valid (ip0));
     127             :         }
     128             :     }
     129           1 : }
     130             : 
     131             : static void
     132           1 : ip4_pg_edit_function (pg_main_t * pg,
     133             :                       pg_stream_t * s,
     134             :                       pg_edit_group_t * g, u32 * packets, u32 n_packets)
     135             : {
     136           1 :   vlib_main_t *vm = vlib_get_main ();
     137             :   u32 ip_offset;
     138             : 
     139           1 :   ip_offset = g->start_byte_offset;
     140             : 
     141           1 :   switch (g->edit_function_opaque)
     142             :     {
     143           0 :     case IP4_PG_EDIT_LENGTH:
     144           0 :       compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
     145             :                                       IP4_PG_EDIT_LENGTH);
     146           0 :       break;
     147             : 
     148           1 :     case IP4_PG_EDIT_CHECKSUM:
     149           1 :       compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
     150             :                                       IP4_PG_EDIT_CHECKSUM);
     151           1 :       break;
     152             : 
     153           0 :     case IP4_PG_EDIT_LENGTH | IP4_PG_EDIT_CHECKSUM:
     154           0 :       compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
     155             :                                       IP4_PG_EDIT_LENGTH
     156             :                                       | IP4_PG_EDIT_CHECKSUM);
     157           0 :       break;
     158             : 
     159           0 :     default:
     160           0 :       ASSERT (0);
     161           0 :       break;
     162             :     }
     163           1 : }
     164             : 
     165             : typedef struct
     166             : {
     167             :   pg_edit_t ip_version, header_length;
     168             :   pg_edit_t tos;
     169             :   pg_edit_t length;
     170             : 
     171             :   pg_edit_t fragment_id, fragment_offset;
     172             : 
     173             :   /* Flags together with fragment offset. */
     174             :   pg_edit_t mf_flag, df_flag, ce_flag;
     175             : 
     176             :   pg_edit_t ttl;
     177             : 
     178             :   pg_edit_t protocol;
     179             : 
     180             :   pg_edit_t checksum;
     181             : 
     182             :   pg_edit_t src_address, dst_address;
     183             : } pg_ip4_header_t;
     184             : 
     185             : static inline void
     186           3 : pg_ip4_header_init (pg_ip4_header_t * p)
     187             : {
     188             :   /* Initialize fields that are not bit fields in the IP header. */
     189             : #define _(f) pg_edit_init (&p->f, ip4_header_t, f);
     190           3 :   _(tos);
     191           3 :   _(length);
     192           3 :   _(fragment_id);
     193           3 :   _(ttl);
     194           3 :   _(protocol);
     195           3 :   _(checksum);
     196           3 :   _(src_address);
     197           3 :   _(dst_address);
     198             : #undef _
     199             : 
     200             :   /* Initialize bit fields. */
     201           3 :   pg_edit_init_bitfield (&p->header_length, ip4_header_t,
     202             :                          ip_version_and_header_length, 0, 4);
     203           3 :   pg_edit_init_bitfield (&p->ip_version, ip4_header_t,
     204             :                          ip_version_and_header_length, 4, 4);
     205             : 
     206           3 :   pg_edit_init_bitfield (&p->fragment_offset, ip4_header_t,
     207             :                          flags_and_fragment_offset, 0, 13);
     208           3 :   pg_edit_init_bitfield (&p->mf_flag, ip4_header_t,
     209             :                          flags_and_fragment_offset, 13, 1);
     210           3 :   pg_edit_init_bitfield (&p->df_flag, ip4_header_t,
     211             :                          flags_and_fragment_offset, 14, 1);
     212           3 :   pg_edit_init_bitfield (&p->ce_flag, ip4_header_t,
     213             :                          flags_and_fragment_offset, 15, 1);
     214           3 : }
     215             : 
     216             : uword
     217           3 : unformat_pg_ip4_header (unformat_input_t * input, va_list * args)
     218             : {
     219           3 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     220             :   pg_ip4_header_t *p;
     221             :   u32 group_index;
     222             : 
     223           3 :   p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ip4_header_t),
     224             :                             &group_index);
     225           3 :   pg_ip4_header_init (p);
     226             : 
     227             :   /* Defaults. */
     228           3 :   pg_edit_set_fixed (&p->ip_version, 4);
     229           3 :   pg_edit_set_fixed (&p->header_length, sizeof (ip4_header_t) / sizeof (u32));
     230             : 
     231           3 :   pg_edit_set_fixed (&p->tos, 0);
     232           3 :   pg_edit_set_fixed (&p->ttl, 64);
     233             : 
     234           3 :   pg_edit_set_fixed (&p->fragment_id, 0);
     235           3 :   pg_edit_set_fixed (&p->fragment_offset, 0);
     236           3 :   pg_edit_set_fixed (&p->mf_flag, 0);
     237           3 :   pg_edit_set_fixed (&p->df_flag, 0);
     238           3 :   pg_edit_set_fixed (&p->ce_flag, 0);
     239             : 
     240           3 :   p->length.type = PG_EDIT_UNSPECIFIED;
     241           3 :   p->checksum.type = PG_EDIT_UNSPECIFIED;
     242             : 
     243           3 :   if (unformat (input, "%U: %U -> %U",
     244             :                 unformat_pg_edit,
     245             :                 unformat_ip_protocol, &p->protocol,
     246             :                 unformat_pg_edit,
     247             :                 unformat_ip4_address, &p->src_address,
     248             :                 unformat_pg_edit, unformat_ip4_address, &p->dst_address))
     249           3 :     goto found;
     250             : 
     251           0 :   if (!unformat (input, "%U:",
     252             :                  unformat_pg_edit, unformat_ip_protocol, &p->protocol))
     253           0 :     goto error;
     254             : 
     255           3 : found:
     256             :   /* Parse options. */
     257             :   while (1)
     258             :     {
     259           7 :       if (unformat (input, "version %U",
     260             :                     unformat_pg_edit, unformat_pg_number, &p->ip_version))
     261             :         ;
     262             : 
     263           7 :       else if (unformat (input, "header-length %U",
     264             :                          unformat_pg_edit,
     265             :                          unformat_pg_number, &p->header_length))
     266             :         ;
     267             : 
     268           7 :       else if (unformat (input, "tos %U",
     269             :                          unformat_pg_edit, unformat_pg_number, &p->tos))
     270             :         ;
     271             : 
     272           7 :       else if (unformat (input, "length %U",
     273             :                          unformat_pg_edit, unformat_pg_number, &p->length))
     274             :         ;
     275             : 
     276           7 :       else if (unformat (input, "checksum %U",
     277             :                          unformat_pg_edit, unformat_pg_number, &p->checksum))
     278             :         ;
     279             : 
     280           5 :       else if (unformat (input, "ttl %U",
     281             :                          unformat_pg_edit, unformat_pg_number, &p->ttl))
     282             :         ;
     283             : 
     284           3 :       else if (unformat (input, "fragment id %U offset %U",
     285             :                          unformat_pg_edit,
     286             :                          unformat_pg_number, &p->fragment_id,
     287             :                          unformat_pg_edit,
     288             :                          unformat_pg_number, &p->fragment_offset))
     289             :         {
     290             :           int i;
     291           0 :           for (i = 0; i < ARRAY_LEN (p->fragment_offset.values); i++)
     292           0 :             pg_edit_set_value (&p->fragment_offset, i,
     293           0 :                                pg_edit_get_value (&p->fragment_offset,
     294             :                                                   i) / 8);
     295             : 
     296             :         }
     297             : 
     298             :       /* Flags. */
     299           3 :       else if (unformat (input, "mf") || unformat (input, "MF"))
     300           0 :         pg_edit_set_fixed (&p->mf_flag, 1);
     301             : 
     302           3 :       else if (unformat (input, "df") || unformat (input, "DF"))
     303           0 :         pg_edit_set_fixed (&p->df_flag, 1);
     304             : 
     305           3 :       else if (unformat (input, "ce") || unformat (input, "CE"))
     306           0 :         pg_edit_set_fixed (&p->ce_flag, 1);
     307             : 
     308             :       /* Can't parse input: try next protocol level. */
     309             :       else
     310             :         break;
     311             :     }
     312             : 
     313             :   {
     314           3 :     ip_main_t *im = &ip_main;
     315             :     ip_protocol_t protocol;
     316             :     ip_protocol_info_t *pi;
     317             : 
     318           3 :     pi = 0;
     319           3 :     if (p->protocol.type == PG_EDIT_FIXED)
     320             :       {
     321           3 :         protocol = pg_edit_get_value (&p->protocol, PG_EDIT_LO);
     322           3 :         pi = ip_get_protocol_info (im, protocol);
     323             :       }
     324             : 
     325           3 :     if (pi && pi->unformat_pg_edit
     326           3 :         && unformat_user (input, pi->unformat_pg_edit, s))
     327             :       ;
     328             : 
     329           0 :     else if (!unformat_user (input, unformat_pg_payload, s))
     330           0 :       goto error;
     331             : 
     332           3 :     if (p->length.type == PG_EDIT_UNSPECIFIED
     333           3 :         && s->min_packet_bytes == s->max_packet_bytes
     334           3 :         && group_index + 1 < vec_len (s->edit_groups))
     335             :       {
     336           3 :         pg_edit_set_fixed (&p->length,
     337             :                            pg_edit_group_n_bytes (s, group_index));
     338             :       }
     339             : 
     340             :     /* Compute IP header checksum if all edits are fixed. */
     341           3 :     if (p->checksum.type == PG_EDIT_UNSPECIFIED)
     342             :       {
     343             :         ip4_header_t fixed_header, fixed_mask, cmp_mask;
     344             : 
     345             :         /* See if header is all fixed and specified except for
     346             :            checksum field. */
     347           1 :         clib_memset (&cmp_mask, ~0, sizeof (cmp_mask));
     348           1 :         cmp_mask.checksum = 0;
     349             : 
     350           1 :         pg_edit_group_get_fixed_packet_data (s, group_index,
     351             :                                              &fixed_header, &fixed_mask);
     352           1 :         if (!memcmp (&fixed_mask, &cmp_mask, sizeof (cmp_mask)))
     353           0 :           pg_edit_set_fixed (&p->checksum,
     354           0 :                              clib_net_to_host_u16 (ip4_header_checksum
     355             :                                                    (&fixed_header)));
     356             :       }
     357             : 
     358           3 :     p = pg_get_edit_group (s, group_index);
     359           3 :     if (p->length.type == PG_EDIT_UNSPECIFIED
     360           3 :         || p->checksum.type == PG_EDIT_UNSPECIFIED)
     361             :       {
     362           1 :         pg_edit_group_t *g = pg_stream_get_group (s, group_index);
     363           1 :         g->edit_function = ip4_pg_edit_function;
     364           1 :         g->edit_function_opaque = 0;
     365           1 :         if (p->length.type == PG_EDIT_UNSPECIFIED)
     366           0 :           g->edit_function_opaque |= IP4_PG_EDIT_LENGTH;
     367           1 :         if (p->checksum.type == PG_EDIT_UNSPECIFIED)
     368           1 :           g->edit_function_opaque |= IP4_PG_EDIT_CHECKSUM;
     369             :       }
     370             : 
     371           3 :     return 1;
     372             :   }
     373             : 
     374           0 : error:
     375             :   /* Free up any edits we may have added. */
     376           0 :   pg_free_edit_group (s);
     377           0 :   return 0;
     378             : }
     379             : 
     380             : 
     381             : /*
     382             :  * fd.io coding-style-patch-verification: ON
     383             :  *
     384             :  * Local Variables:
     385             :  * eval: (c-set-style "gnu")
     386             :  * End:
     387             :  */

Generated by: LCOV version 1.14