LCOV - code coverage report
Current view: top level - vnet/tcp - tcp_pg.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 117 0.0 %
Date: 2023-07-05 22:20:52 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016-2019 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/tcp_pg: TCP 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             : /* TCP flags bit 0 first. */
      44             : #define foreach_tcp_flag                        \
      45             :   _ (FIN)                                       \
      46             :   _ (SYN)                                       \
      47             :   _ (RST)                                       \
      48             :   _ (PSH)                                       \
      49             :   _ (ACK)                                       \
      50             :   _ (URG)                                       \
      51             :   _ (ECE)                                       \
      52             :   _ (CWR)
      53             : 
      54             : #define foreach_tcp_options                                                   \
      55             :   _ (mss, TCP_OPTION_MSS, TCP_OPTION_LEN_MSS, 1)                              \
      56             :   _ (timestamp, TCP_OPTION_TIMESTAMP, TCP_OPTION_LEN_TIMESTAMP, 2)            \
      57             :   _ (winscale, TCP_OPTION_WINDOW_SCALE, TCP_OPTION_LEN_WINDOW_SCALE, 1)       \
      58             :   _ (sackperm, TCP_OPTION_SACK_PERMITTED, TCP_OPTION_LEN_SACK_PERMITTED, 0)   \
      59             :   _ (sack, TCP_OPTION_SACK_BLOCK, TCP_OPTION_LEN_SACK_BLOCK, 0)
      60             : 
      61             : static void
      62           0 : tcp_pg_edit_function (pg_main_t * pg,
      63             :                       pg_stream_t * s,
      64             :                       pg_edit_group_t * g, u32 * packets, u32 n_packets)
      65             : {
      66           0 :   vlib_main_t *vm = vlib_get_main ();
      67             :   u32 ip_offset, tcp_offset;
      68             : 
      69           0 :   tcp_offset = g->start_byte_offset;
      70           0 :   ip_offset = (g - 1)->start_byte_offset;
      71             : 
      72           0 :   while (n_packets >= 1)
      73             :     {
      74             :       vlib_buffer_t *p0;
      75             :       ip4_header_t *ip0;
      76             :       tcp_header_t *tcp0;
      77             :       ip_csum_t sum0;
      78             :       u32 tcp_len0;
      79             : 
      80           0 :       p0 = vlib_get_buffer (vm, packets[0]);
      81           0 :       n_packets -= 1;
      82           0 :       packets += 1;
      83             : 
      84           0 :       ASSERT (p0->current_data == 0);
      85           0 :       ip0 = (void *) (p0->data + ip_offset);
      86           0 :       tcp0 = (void *) (p0->data + tcp_offset);
      87             :       /* if IP length has been specified, then calculate the length based on buffer */
      88           0 :       if (ip0->length == 0)
      89           0 :         tcp_len0 = vlib_buffer_length_in_chain (vm, p0) - tcp_offset;
      90             :       else
      91           0 :         tcp_len0 = clib_net_to_host_u16 (ip0->length) - tcp_offset;
      92             : 
      93             :       /* Initialize checksum with header. */
      94             :       if (BITS (sum0) == 32)
      95             :         {
      96             :           sum0 = clib_mem_unaligned (&ip0->src_address, u32);
      97             :           sum0 =
      98             :             ip_csum_with_carry (sum0,
      99             :                                 clib_mem_unaligned (&ip0->dst_address, u32));
     100             :         }
     101             :       else
     102           0 :         sum0 = clib_mem_unaligned (&ip0->src_address, u64);
     103             : 
     104           0 :       sum0 = ip_csum_with_carry
     105           0 :         (sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
     106             : 
     107             :       /* Invalidate possibly old checksum. */
     108           0 :       tcp0->checksum = 0;
     109             : 
     110             :       sum0 =
     111           0 :         ip_incremental_checksum_buffer (vm, p0, tcp_offset, tcp_len0, sum0);
     112             : 
     113           0 :       tcp0->checksum = ~ip_csum_fold (sum0);
     114             :     }
     115           0 : }
     116             : 
     117             : typedef struct
     118             : {
     119             :   pg_edit_t src, dst;
     120             :   pg_edit_t seq_number, ack_number;
     121             :   pg_edit_t data_offset_and_reserved;
     122             : #define _(f) pg_edit_t f##_flag;
     123             :     foreach_tcp_flag
     124             : #undef _
     125             :     pg_edit_t window;
     126             :   pg_edit_t checksum;
     127             :   pg_edit_t urgent_pointer;
     128             : } pg_tcp_header_t;
     129             : 
     130             : static inline void
     131           0 : pg_tcp_header_init (pg_tcp_header_t * p)
     132             : {
     133             :   /* Initialize fields that are not bit fields in the IP header. */
     134             : #define _(f) pg_edit_init (&p->f, tcp_header_t, f);
     135           0 :   _(src);
     136           0 :   _(dst);
     137           0 :   _(seq_number);
     138           0 :   _(ack_number);
     139           0 :   _(window);
     140           0 :   _(checksum);
     141           0 :   _(urgent_pointer);
     142             : #undef _
     143             : 
     144             :   /* Initialize bit fields. */
     145             : #define _(f)                                            \
     146             :   pg_edit_init_bitfield (&p->f##_flag, tcp_header_t,     \
     147             :                          flags,                         \
     148             :                          TCP_FLAG_BIT_##f, 1);
     149             : 
     150           0 :   foreach_tcp_flag
     151             : #undef _
     152           0 :     pg_edit_init_bitfield (&p->data_offset_and_reserved, tcp_header_t,
     153             :                            data_offset_and_reserved, 4, 4);
     154           0 : }
     155             : 
     156             : uword
     157           0 : unformat_pg_tcp_header (unformat_input_t * input, va_list * args)
     158             : {
     159           0 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     160             :   pg_tcp_header_t *pth;
     161           0 :   u32 header_group_index, opt_group_index = ~0, noop_len, opts_len = 0;
     162             : 
     163           0 :   pth = pg_create_edit_group (s, sizeof (pth[0]), sizeof (tcp_header_t),
     164             :                               &header_group_index);
     165           0 :   pg_tcp_header_init (pth);
     166             : 
     167             :   /* Defaults. */
     168           0 :   pg_edit_set_fixed (&pth->seq_number, 0);
     169           0 :   pg_edit_set_fixed (&pth->ack_number, 0);
     170             : 
     171           0 :   pg_edit_set_fixed (&pth->window, 4096);
     172           0 :   pg_edit_set_fixed (&pth->urgent_pointer, 0);
     173             : 
     174             : #define _(f) pg_edit_set_fixed (&pth->f##_flag, 0);
     175           0 :   foreach_tcp_flag
     176             : #undef _
     177           0 :     pth->checksum.type = PG_EDIT_UNSPECIFIED;
     178             : 
     179           0 :   if (!unformat (input, "TCP: %U -> %U", unformat_pg_edit,
     180             :                  unformat_tcp_udp_port, &pth->src, unformat_pg_edit,
     181             :                  unformat_tcp_udp_port, &pth->dst))
     182           0 :     goto error;
     183             : 
     184             :   /* Parse options. */
     185             :   while (1)
     186             :     {
     187           0 :       if (unformat (input, "window %U", unformat_pg_edit, unformat_pg_number,
     188             :                     &pth->window))
     189             :         ;
     190             : 
     191           0 :       else if (unformat (input, "checksum %U", unformat_pg_edit,
     192             :                          unformat_pg_number, &pth->checksum))
     193             :         ;
     194             : 
     195           0 :       else if (unformat (input, "seqnum %U", unformat_pg_edit,
     196             :                          unformat_pg_number, &pth->seq_number))
     197             :         ;
     198           0 :       else if (unformat (input, "acknum %U", unformat_pg_edit,
     199             :                          unformat_pg_number, &pth->ack_number))
     200             :         ;
     201             :       /* Flags. */
     202             : #define _(f)                                                                  \
     203             :   else if (unformat (input, #f)) pg_edit_set_fixed (&pth->f##_flag, 1);
     204           0 :       foreach_tcp_flag
     205             : #undef _
     206             :         /* Can't parse input: try TCP options and next protocol level. */
     207           0 :         else break;
     208             :     }
     209             : 
     210           0 :   while (unformat (input, "opt"))
     211             :     {
     212             :       int i;
     213             :       pg_edit_t *opt_header, *opt_values;
     214             :       u8 type, opt_len, n_values;
     215             : 
     216             :       /* first allocate a new edit group for options */
     217           0 :       if (opt_group_index == ~0)
     218           0 :         (void) pg_create_edit_group (s, 0, 0, &opt_group_index);
     219             : 
     220             :       if (false)
     221             :         {
     222             :         }
     223             : #define _(n, t, l, k)                                                         \
     224             :   else if (unformat (input, #n))                                              \
     225             :   {                                                                           \
     226             :     type = (t);                                                               \
     227             :     opt_len = (l);                                                            \
     228             :     n_values = (k);                                                           \
     229             :   }
     230           0 :       foreach_tcp_options
     231             : #undef _
     232             :         else
     233             :       {
     234             :         /* unknown TCP option */
     235           0 :         break;
     236             :       }
     237             : 
     238             : #define pg_tcp_option_init(e, o, b)                                           \
     239             :   do                                                                          \
     240             :     {                                                                         \
     241             :       *(o) += (b);                                                            \
     242             :       (e)->lsb_bit_offset = *(o) > 0 ? (*(o) -1) * BITS (u8) : 0;             \
     243             :       (e)->n_bits = (b) *BITS (u8);                                           \
     244             :     }                                                                         \
     245             :   while (0);
     246             : 
     247             :       /* if we don't know how many values to read, just ask */
     248           0 :       if (n_values == 0 &&
     249           0 :           unformat (input, "nvalues %D", sizeof (n_values), &n_values))
     250             :         {
     251           0 :           switch (type)
     252             :             {
     253           0 :             case TCP_OPTION_SACK_BLOCK:
     254             :               /* each sack block is composed of 2 32-bits values */
     255           0 :               n_values *= 2;
     256             :               /*
     257             :                 opt_len contains the length of a single sack block,
     258             :                 it needs to be updated to contains the final number of bytes
     259             :                 for the sack options
     260             :               */
     261           0 :               opt_len = 2 + 2 * opt_len;
     262           0 :               break;
     263           0 :             default:
     264             :               /* unknown variable options */
     265           0 :               continue;
     266             :             }
     267           0 :         }
     268             : 
     269           0 :       opt_header = pg_add_edits (s, sizeof (pg_edit_t) * (2 + n_values),
     270             :                                  opt_len, opt_group_index);
     271           0 :       pg_tcp_option_init (opt_header, &opts_len, 1);
     272           0 :       pg_tcp_option_init (opt_header + 1, &opts_len, 1);
     273           0 :       pg_edit_set_fixed (opt_header, type);
     274           0 :       pg_edit_set_fixed (opt_header + 1, opt_len);
     275           0 :       opt_values = opt_header + 2;
     276             : 
     277           0 :       switch (type)
     278             :         {
     279           0 :         case TCP_OPTION_MSS:
     280           0 :           pg_tcp_option_init (opt_values, &opts_len, 2);
     281           0 :           break;
     282           0 :         case TCP_OPTION_WINDOW_SCALE:
     283           0 :           pg_tcp_option_init (opt_values, &opts_len, 1);
     284           0 :           break;
     285           0 :         case TCP_OPTION_TIMESTAMP:
     286             :         case TCP_OPTION_SACK_BLOCK:
     287           0 :           for (i = 0; i < n_values; ++i)
     288           0 :             pg_tcp_option_init (opt_values + i, &opts_len, 4);
     289           0 :           break;
     290           0 :         default:
     291           0 :           break;
     292             :         }
     293             : 
     294           0 :       for (i = 0; i < n_values; ++i)
     295             :         {
     296           0 :           if (!unformat (input, "%U", unformat_pg_edit, unformat_pg_number,
     297           0 :                          opt_values + i))
     298           0 :             goto error;
     299             :         }
     300             :     }
     301             : 
     302             :   /* add TCP NO-OP options to fill options up to a 4-bytes boundary */
     303           0 :   noop_len = (TCP_OPTS_ALIGN - opts_len % TCP_OPTS_ALIGN) % TCP_OPTS_ALIGN;
     304           0 :   if (noop_len > 0)
     305             :     {
     306             :       pg_edit_t *noop_edit;
     307           0 :       u8 *noops = 0;
     308             : 
     309           0 :       vec_validate (noops, noop_len - 1);
     310           0 :       clib_memset (noops, 1, noop_len);
     311             : 
     312             :       noop_edit =
     313           0 :         pg_add_edits (s, sizeof (noop_edit[0]), noop_len, opt_group_index);
     314           0 :       pg_tcp_option_init (noop_edit, &opts_len, noop_len);
     315           0 :       noop_edit->type = PG_EDIT_FIXED;
     316           0 :       noop_edit->values[PG_EDIT_LO] = noops;
     317             :     }
     318             : #undef pg_tcp_option_init
     319             : 
     320             :   /* set the data offset according to options */
     321           0 :   pg_edit_set_fixed (&pth->data_offset_and_reserved,
     322           0 :                      (sizeof (tcp_header_t) + opts_len) / sizeof (u32));
     323             : 
     324             :   {
     325           0 :     ip_main_t *im = &ip_main;
     326             :     u16 dst_port;
     327             :     tcp_udp_port_info_t *pi;
     328             : 
     329           0 :     pi = 0;
     330           0 :     if (pth->dst.type == PG_EDIT_FIXED)
     331             :       {
     332           0 :         dst_port = pg_edit_get_value (&pth->dst, PG_EDIT_LO);
     333           0 :         pi = ip_get_tcp_udp_port_info (im, dst_port);
     334             :       }
     335             : 
     336           0 :     if (pi && pi->unformat_pg_edit &&
     337           0 :         unformat_user (input, pi->unformat_pg_edit, s))
     338             :       ;
     339             : 
     340           0 :     else if (!unformat_user (input, unformat_pg_payload, s))
     341           0 :       goto error;
     342             : 
     343           0 :     if (pth->checksum.type == PG_EDIT_UNSPECIFIED)
     344             :       {
     345           0 :         pg_edit_group_t *g = pg_stream_get_group (s, header_group_index);
     346           0 :         g->edit_function = tcp_pg_edit_function;
     347           0 :         g->edit_function_opaque = 0;
     348             :       }
     349             : 
     350           0 :     return 1;
     351             :   }
     352             : 
     353           0 : error:
     354             :   /* Free up any edits we may have added. */
     355           0 :   pg_free_edit_group (s);
     356           0 :   return 0;
     357             : }
     358             : 
     359             : /*
     360             :  * fd.io coding-style-patch-verification: ON
     361             :  *
     362             :  * Local Variables:
     363             :  * eval: (c-set-style "gnu")
     364             :  * End:
     365             :  */

Generated by: LCOV version 1.14