LCOV - code coverage report
Current view: top level - vnet/udp - udp_pg.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 71 85 83.5 %
Date: 2023-07-05 22:20:52 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015-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/udp_pg: UDP 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/pg/pg.h>
      41             : #include <vnet/ip/ip.h>           /* for unformat_udp_udp_port */
      42             : #include <vnet/udp/udp.h>
      43             : 
      44             : #define UDP_PG_EDIT_LENGTH (1 << 0)
      45             : #define UDP_PG_EDIT_CHECKSUM (1 << 1)
      46             : 
      47             : always_inline void
      48           7 : udp_pg_edit_function_inline (pg_main_t * pg,
      49             :                              pg_stream_t * s,
      50             :                              pg_edit_group_t * g,
      51             :                              u32 * packets, u32 n_packets, u32 flags)
      52             : {
      53           7 :   vlib_main_t *vm = vlib_get_main ();
      54             :   u32 ip_offset, udp_offset;
      55             : 
      56           7 :   udp_offset = g->start_byte_offset;
      57           7 :   ip_offset = (g - 1)->start_byte_offset;
      58             : 
      59         337 :   while (n_packets >= 1)
      60             :     {
      61             :       vlib_buffer_t *p0;
      62             :       ip4_header_t *ip0;
      63             :       udp_header_t *udp0;
      64             :       u32 udp_len0;
      65             : 
      66         330 :       p0 = vlib_get_buffer (vm, packets[0]);
      67         330 :       n_packets -= 1;
      68         330 :       packets += 1;
      69             : 
      70         330 :       ip0 = (void *) (p0->data + ip_offset);
      71         330 :       udp0 = (void *) (p0->data + udp_offset);
      72         330 :       udp_len0 = vlib_buffer_length_in_chain (vm, p0) - udp_offset;
      73             : 
      74         330 :       if (flags & UDP_PG_EDIT_LENGTH)
      75         330 :         udp0->length = clib_host_to_net_u16 (udp_len0);
      76             :       else
      77           0 :         udp_len0 = clib_host_to_net_u16 (udp0->length);
      78             : 
      79             :       /* Initialize checksum with header. */
      80         330 :       if (flags & UDP_PG_EDIT_CHECKSUM)
      81             :         {
      82             :           ip_csum_t sum0;
      83             : 
      84         200 :           sum0 = clib_mem_unaligned (&ip0->src_address, u64);
      85             : 
      86         200 :           sum0 = ip_csum_with_carry
      87         200 :             (sum0, clib_host_to_net_u32 (udp_len0 + (ip0->protocol << 16)));
      88             : 
      89             :           /* Invalidate possibly old checksum. */
      90         200 :           udp0->checksum = 0;
      91             : 
      92             :           sum0 =
      93         200 :             ip_incremental_checksum_buffer (vm, p0, udp_offset, udp_len0,
      94             :                                             sum0);
      95             : 
      96         200 :           sum0 = ~ip_csum_fold (sum0);
      97             : 
      98             :           /* Zero checksum means checksumming disabled. */
      99         200 :           sum0 = sum0 != 0 ? sum0 : 0xffff;
     100             : 
     101         200 :           udp0->checksum = sum0;
     102             :         }
     103             :     }
     104           7 : }
     105             : 
     106             : static void
     107           7 : udp_pg_edit_function (pg_main_t * pg,
     108             :                       pg_stream_t * s,
     109             :                       pg_edit_group_t * g, u32 * packets, u32 n_packets)
     110             : {
     111           7 :   switch (g->edit_function_opaque)
     112             :     {
     113           4 :     case UDP_PG_EDIT_LENGTH:
     114           4 :       udp_pg_edit_function_inline (pg, s, g, packets, n_packets,
     115             :                                    UDP_PG_EDIT_LENGTH);
     116           4 :       break;
     117             : 
     118           0 :     case UDP_PG_EDIT_CHECKSUM:
     119           0 :       udp_pg_edit_function_inline (pg, s, g, packets, n_packets,
     120             :                                    UDP_PG_EDIT_CHECKSUM);
     121           0 :       break;
     122             : 
     123           3 :     case UDP_PG_EDIT_CHECKSUM | UDP_PG_EDIT_LENGTH:
     124           3 :       udp_pg_edit_function_inline (pg, s, g, packets, n_packets,
     125             :                                    UDP_PG_EDIT_CHECKSUM | UDP_PG_EDIT_LENGTH);
     126           3 :       break;
     127             : 
     128           0 :     default:
     129           0 :       ASSERT (0);
     130           0 :       break;
     131             :     }
     132           7 : }
     133             : 
     134             : typedef struct
     135             : {
     136             :   pg_edit_t src_port, dst_port;
     137             :   pg_edit_t length;
     138             :   pg_edit_t checksum;
     139             : } pg_udp_header_t;
     140             : 
     141             : static inline void
     142           5 : pg_udp_header_init (pg_udp_header_t * p)
     143             : {
     144             :   /* Initialize fields that are not bit fields in the IP header. */
     145             : #define _(f) pg_edit_init (&p->f, udp_header_t, f);
     146           5 :   _(src_port);
     147           5 :   _(dst_port);
     148           5 :   _(length);
     149           5 :   _(checksum);
     150             : #undef _
     151           5 : }
     152             : 
     153             : uword
     154           5 : unformat_pg_udp_header (unformat_input_t * input, va_list * args)
     155             : {
     156           5 :   pg_stream_t *s = va_arg (*args, pg_stream_t *);
     157             :   pg_udp_header_t *p;
     158             :   u32 group_index;
     159             : 
     160           5 :   p = pg_create_edit_group (s, sizeof (p[0]), sizeof (udp_header_t),
     161             :                             &group_index);
     162           5 :   pg_udp_header_init (p);
     163             : 
     164             :   /* Defaults. */
     165           5 :   p->checksum.type = PG_EDIT_UNSPECIFIED;
     166           5 :   p->length.type = PG_EDIT_UNSPECIFIED;
     167             : 
     168           5 :   if (!unformat (input, "UDP: %U -> %U",
     169             :                  unformat_pg_edit,
     170             :                  unformat_tcp_udp_port, &p->src_port,
     171             :                  unformat_pg_edit, unformat_tcp_udp_port, &p->dst_port))
     172           0 :     goto error;
     173             : 
     174             :   /* Parse options. */
     175             :   while (1)
     176             :     {
     177           7 :       if (unformat (input, "length %U",
     178             :                     unformat_pg_edit, unformat_pg_number, &p->length))
     179             :         ;
     180             : 
     181           7 :       else if (unformat (input, "checksum %U",
     182             :                          unformat_pg_edit, unformat_pg_number, &p->checksum))
     183             :         ;
     184             : 
     185             :       /* Can't parse input: try next protocol level. */
     186             :       else
     187           5 :         break;
     188             :     }
     189             : 
     190             :   {
     191           5 :     ip_main_t *im = &ip_main;
     192             :     u16 dst_port;
     193             :     tcp_udp_port_info_t *pi;
     194             : 
     195             :     /* For the pg format of applications over UDP local */
     196           5 :     udp_dst_port_info_t *pi2 = NULL;
     197             : 
     198           5 :     pi = 0;
     199           5 :     if (p->dst_port.type == PG_EDIT_FIXED)
     200             :       {
     201           5 :         dst_port = pg_edit_get_value (&p->dst_port, PG_EDIT_LO);
     202           5 :         pi = ip_get_tcp_udp_port_info (im, dst_port);
     203           5 :         pi2 = udp_get_dst_port_info (&udp_main, dst_port, UDP_IP4);
     204           5 :         if (!pi2)
     205           5 :           pi2 = udp_get_dst_port_info (&udp_main, dst_port, UDP_IP6);
     206             :       }
     207             : 
     208           5 :     if (pi && pi->unformat_pg_edit
     209           0 :         && unformat_user (input, pi->unformat_pg_edit, s))
     210             :       ;
     211           5 :     else if (pi2 && pi2->unformat_pg_edit
     212           0 :              && unformat_user (input, pi2->unformat_pg_edit, s))
     213             :       ;
     214           5 :     else if (!unformat_user (input, unformat_pg_payload, s))
     215           0 :       goto error;
     216             : 
     217           5 :     p = pg_get_edit_group (s, group_index);
     218           5 :     if (p->checksum.type == PG_EDIT_UNSPECIFIED
     219           2 :         || p->length.type == PG_EDIT_UNSPECIFIED)
     220             :       {
     221           5 :         pg_edit_group_t *g = pg_stream_get_group (s, group_index);
     222           5 :         g->edit_function = udp_pg_edit_function;
     223           5 :         g->edit_function_opaque = 0;
     224           5 :         if (p->checksum.type == PG_EDIT_UNSPECIFIED)
     225           3 :           g->edit_function_opaque |= UDP_PG_EDIT_CHECKSUM;
     226           5 :         if (p->length.type == PG_EDIT_UNSPECIFIED)
     227           5 :           g->edit_function_opaque |= UDP_PG_EDIT_LENGTH;
     228             :       }
     229             : 
     230           5 :     return 1;
     231             :   }
     232             : 
     233           0 : error:
     234             :   /* Free up any edits we may have added. */
     235           0 :   pg_free_edit_group (s);
     236           0 :   return 0;
     237             : }
     238             : 
     239             : 
     240             : /*
     241             :  * fd.io coding-style-patch-verification: ON
     242             :  *
     243             :  * Local Variables:
     244             :  * eval: (c-set-style "gnu")
     245             :  * End:
     246             :  */

Generated by: LCOV version 1.14