LCOV - code coverage report
Current view: top level - vppinfra - pcap.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 66 89 74.2 %
Date: 2023-10-26 01:39:38 Functions: 3 3 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             :  * pcap.c: libpcap packet capture format
      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 <fcntl.h>
      41             : #include <vppinfra/pcap.h>
      42             : 
      43             : /**
      44             :  * @file
      45             :  * @brief PCAP function.
      46             :  *
      47             :  * Usage:
      48             :  *
      49             :  * <code><pre>
      50             :  * \#include <vppinfra/pcap.h>
      51             :  *
      52             :  * static pcap_main_t pcap = {
      53             :  *  .file_name = "/tmp/ip4",
      54             :  *  .n_packets_to_capture = 2,
      55             :  *  .packet_type = PCAP_PACKET_TYPE_ip,
      56             :  * };
      57             :  * </pre></code>
      58             :  *
      59             :  * To add a buffer:
      60             :  *
      61             :  *  <code><pre>pcap_add_buffer (&pcap, vm, pi0, 128);</pre></code>
      62             :  *
      63             :  * File will be written after @c n_packets_to_capture or call to pcap_write (&amp;pcap).
      64             :  *
      65             : */
      66             : 
      67             : /**
      68             :  * @brief Close PCAP file
      69             :  *
      70             :  * @return rc - clib_error_t
      71             :  *
      72             :  */
      73             : __clib_export clib_error_t *
      74       13993 : pcap_close (pcap_main_t * pm)
      75             : {
      76       13993 :   close (pm->file_descriptor);
      77       13993 :   pm->flags &= ~PCAP_MAIN_INIT_DONE;
      78       13993 :   pm->file_descriptor = -1;
      79       13993 :   return 0;
      80             : }
      81             : 
      82             : /**
      83             :  * @brief Write PCAP file
      84             :  *
      85             :  * @return rc - clib_error_t
      86             :  *
      87             :  */
      88             : __clib_export clib_error_t *
      89       17388 : pcap_write (pcap_main_t * pm)
      90             : {
      91       17388 :   clib_error_t *error = 0;
      92             : 
      93       17388 :   if (!(pm->flags & PCAP_MAIN_INIT_DONE))
      94             :     {
      95             :       pcap_file_header_t fh;
      96             :       int n;
      97             : 
      98       14648 :       if (!pm->file_name)
      99           0 :         pm->file_name = "/tmp/vnet.pcap";
     100             : 
     101       14648 :       pm->file_descriptor =
     102       14648 :         open (pm->file_name, O_CREAT | O_TRUNC | O_WRONLY, 0664);
     103       14648 :       if (pm->file_descriptor < 0)
     104             :         {
     105             :           error =
     106           0 :             clib_error_return_unix (0, "failed to open `%s'", pm->file_name);
     107           0 :           goto done;
     108             :         }
     109             : 
     110       14648 :       pm->flags |= PCAP_MAIN_INIT_DONE;
     111       14648 :       pm->n_packets_captured = 0;
     112       14648 :       pm->n_pcap_data_written = 0;
     113       14648 :       clib_spinlock_init (&pm->lock);
     114             : 
     115             :       /* Write file header. */
     116       14648 :       clib_memset (&fh, 0, sizeof (fh));
     117       14648 :       fh.magic = 0xa1b2c3d4;
     118       14648 :       fh.major_version = 2;
     119       14648 :       fh.minor_version = 4;
     120       14648 :       fh.time_zone = 0;
     121       14648 :       fh.max_packet_size_in_bytes = 1 << 16;
     122       14648 :       fh.packet_type = pm->packet_type;
     123       14648 :       n = write (pm->file_descriptor, &fh, sizeof (fh));
     124       14648 :       if (n != sizeof (fh))
     125             :         {
     126           0 :           if (n < 0)
     127             :             error =
     128           0 :               clib_error_return_unix (0, "write file header `%s'",
     129             :                                       pm->file_name);
     130             :           else
     131             :             error =
     132           0 :               clib_error_return (0, "short write of file header `%s'",
     133             :                                  pm->file_name);
     134           0 :           goto done;
     135             :         }
     136             :     }
     137             : 
     138       34776 :   while (vec_len (pm->pcap_data) > pm->n_pcap_data_written)
     139             :     {
     140       17388 :       i64 n = vec_len (pm->pcap_data) - pm->n_pcap_data_written;
     141             : 
     142       34776 :       n = write (pm->file_descriptor,
     143       17388 :                  vec_elt_at_index (pm->pcap_data, pm->n_pcap_data_written),
     144             :                  n);
     145             : 
     146       17388 :       if (n < 0 && unix_error_is_fatal (errno))
     147             :         {
     148           0 :           error = clib_error_return_unix (0, "write `%s'", pm->file_name);
     149           0 :           goto done;
     150             :         }
     151       17388 :       pm->n_pcap_data_written += n;
     152             :     }
     153             : 
     154       17388 :   if (pm->n_pcap_data_written >= vec_len (pm->pcap_data))
     155             :     {
     156       17388 :       vec_reset_length (pm->pcap_data);
     157       17388 :       pm->n_pcap_data_written = 0;
     158             :     }
     159             : 
     160           0 : done:
     161       17388 :   if (error)
     162             :     {
     163           0 :       if (pm->file_descriptor >= 0)
     164           0 :         close (pm->file_descriptor);
     165             :     }
     166       17388 :   return error;
     167             : }
     168             : 
     169             : /**
     170             :  * @brief Read PCAP file
     171             :  *
     172             :  * @return rc - clib_error_t
     173             :  *
     174             :  */
     175             : __clib_export clib_error_t *
     176       15657 : pcap_read (pcap_main_t * pm)
     177             : {
     178       15657 :   clib_error_t *error = 0;
     179             :   int fd, need_swap, n;
     180             :   pcap_file_header_t fh;
     181             :   pcap_packet_header_t ph;
     182             : 
     183       15657 :   fd = open (pm->file_name, O_RDONLY);
     184       15657 :   if (fd < 0)
     185             :     {
     186           0 :       error = clib_error_return_unix (0, "open `%s'", pm->file_name);
     187           0 :       goto done;
     188             :     }
     189             : 
     190       15657 :   if (read (fd, &fh, sizeof (fh)) != sizeof (fh))
     191             :     {
     192             :       error =
     193           0 :         clib_error_return_unix (0, "read file header `%s'", pm->file_name);
     194           0 :       goto done;
     195             :     }
     196             : 
     197       15657 :   need_swap = 0;
     198       15657 :   if (fh.magic == 0xd4c3b2a1)
     199             :     {
     200           0 :       need_swap = 1;
     201             : #define _(t,f) fh.f = clib_byte_swap_##t (fh.f);
     202           0 :       foreach_pcap_file_header;
     203             : #undef _
     204             :     }
     205             : 
     206       15657 :   if (fh.magic != 0xa1b2c3d4)
     207             :     {
     208           0 :       error = clib_error_return (0, "bad magic `%s'", pm->file_name);
     209           0 :       goto done;
     210             :     }
     211             : 
     212       15657 :   pm->min_packet_bytes = 0;
     213       15657 :   pm->max_packet_bytes = 0;
     214      576006 :   while ((n = read (fd, &ph, sizeof (ph))) != 0)
     215             :     {
     216             :       u8 *data;
     217             :       u64 timestamp;
     218             :       u32 timestamp_sec;
     219             :       u32 timestamp_usec;
     220             : 
     221      560349 :       if (need_swap)
     222             :         {
     223             : #define _(t,f) ph.f = clib_byte_swap_##t (ph.f);
     224           0 :           foreach_pcap_packet_header;
     225             : #undef _
     226             :         }
     227             : 
     228      560349 :       data = vec_new (u8, ph.n_bytes_in_packet);
     229      560349 :       if (read (fd, data, ph.n_packet_bytes_stored_in_file) !=
     230      560349 :           ph.n_packet_bytes_stored_in_file)
     231             :         {
     232           0 :           error = clib_error_return (0, "short read `%s'", pm->file_name);
     233           0 :           goto done;
     234             :         }
     235             : 
     236      560349 :       if (vec_len (pm->packets_read) == 0)
     237       15657 :         pm->min_packet_bytes = pm->max_packet_bytes = ph.n_bytes_in_packet;
     238             :       else
     239             :         {
     240      544692 :           pm->min_packet_bytes =
     241      544692 :             clib_min (pm->min_packet_bytes, ph.n_bytes_in_packet);
     242      544692 :           pm->max_packet_bytes =
     243      544692 :             clib_max (pm->max_packet_bytes, ph.n_bytes_in_packet);
     244             :         }
     245             : 
     246      560349 :       timestamp_sec = ph.time_in_sec;
     247      560349 :       timestamp_usec = ph.time_in_usec;
     248      560349 :       timestamp = ((u64) timestamp_sec) * 1000000 + (u64) timestamp_usec;
     249      560349 :       vec_add1 (pm->packets_read, data);
     250      560349 :       vec_add1 (pm->timestamps, timestamp);
     251             :     }
     252             : 
     253       15657 : done:
     254       15657 :   if (fd >= 0)
     255       15657 :     close (fd);
     256       15657 :   return error;
     257             : 
     258             : }
     259             : 
     260             : /*
     261             :  * fd.io coding-style-patch-verification: ON
     262             :  *
     263             :  * Local Variables:
     264             :  * eval: (c-set-style "gnu")
     265             :  * End:
     266             :  */

Generated by: LCOV version 1.14