FD.io VPP  v16.06
Vector Packet Processing
pcap.c
Go to the documentation of this file.
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 <vnet/unix/pcap.h>
41 #include <sys/fcntl.h>
42 
43 /* Usage
44 
45 #include <vnet/unix/pcap.h>
46 
47 static pcap_main_t pcap = {
48  .file_name = "/tmp/ip4",
49  .n_packets_to_capture = 2,
50  .packet_type = PCAP_PACKET_TYPE_ip,
51 };
52 
53 To add a buffer:
54 
55  pcap_add_buffer (&pcap, vm, pi0, 128);
56 
57 file will be written after n_packets_to_capture or call to pcap_write (&pcap).
58 
59 */
60 
63 {
64  clib_error_t * error = 0;
65 
66  if (! (pm->flags & PCAP_MAIN_INIT_DONE))
67  {
69  int n;
70 
71  if (! pm->file_name)
72  pm->file_name = "/tmp/vnet.pcap";
73 
74  pm->file_descriptor = open (pm->file_name, O_CREAT | O_TRUNC | O_WRONLY, 0664);
75  if (pm->file_descriptor < 0)
76  {
77  error = clib_error_return_unix (0, "failed to open `%s'", pm->file_name);
78  goto done;
79  }
80 
82  pm->n_packets_captured = 0;
83  pm->n_pcap_data_written = 0;
84 
85  /* Write file header. */
86  memset (&fh, 0, sizeof (fh));
87  fh.magic = 0xa1b2c3d4;
88  fh.major_version = 2;
89  fh.minor_version = 4;
90  fh.time_zone = 0;
91  fh.max_packet_size_in_bytes = 1 << 16;
92  fh.packet_type = pm->packet_type;
93  n = write (pm->file_descriptor, &fh, sizeof (fh));
94  if (n != sizeof (fh))
95  {
96  if (n < 0)
97  error = clib_error_return_unix (0, "write file header `%s'", pm->file_name);
98  else
99  error = clib_error_return (0, "short write of file header `%s'", pm->file_name);
100  goto done;
101  }
102  }
103 
104  do {
105  int n = vec_len (pm->pcap_data) - pm->n_pcap_data_written;
106 
107  if (n > 0)
108  {
109  n = write (pm->file_descriptor,
111  n);
112  if (n < 0 && unix_error_is_fatal (errno))
113  {
114  error = clib_error_return_unix (0, "write `%s'", pm->file_name);
115  goto done;
116  }
117  }
118  pm->n_pcap_data_written += n;
119  if (pm->n_pcap_data_written >= vec_len (pm->pcap_data))
120  {
122  break;
123  }
124  } while (pm->n_packets_captured >= pm->n_packets_to_capture);
125 
127  {
128  close (pm->file_descriptor);
129  pm->flags &= ~PCAP_MAIN_INIT_DONE;
130  pm->file_descriptor = -1;
131  }
132 
133  done:
134  if (error)
135  {
136  if (pm->file_descriptor >= 0)
137  close (pm->file_descriptor);
138  }
139  return error;
140 }
141 
143 {
144  clib_error_t * error = 0;
145  int fd, need_swap, n;
148 
149  fd = open (pm->file_name, O_RDONLY);
150  if (fd < 0)
151  {
152  error = clib_error_return_unix (0, "open `%s'", pm->file_name);
153  goto done;
154  }
155 
156  if (read (fd, &fh, sizeof (fh)) != sizeof (fh))
157  {
158  error = clib_error_return_unix (0, "read file header `%s'", pm->file_name);
159  goto done;
160  }
161 
162  need_swap = 0;
163  if (fh.magic == 0xd4c3b2a1)
164  {
165  need_swap = 1;
166 #define _(t,f) fh.f = clib_byte_swap_##t (fh.f);
168 #undef _
169  }
170 
171  if (fh.magic != 0xa1b2c3d4)
172  {
173  error = clib_error_return (0, "bad magic `%s'", pm->file_name);
174  goto done;
175  }
176 
177  pm->min_packet_bytes = 0;
178  pm->max_packet_bytes = 0;
179  while ((n = read (fd, &ph, sizeof (ph))) != 0)
180  {
181  u8 * data;
182 
183  if (need_swap)
184  {
185 #define _(t,f) ph.f = clib_byte_swap_##t (ph.f);
187 #undef _
188  }
189 
190  data = vec_new (u8, ph.n_bytes_in_packet);
191  if (read (fd, data, ph.n_packet_bytes_stored_in_file) != ph.n_packet_bytes_stored_in_file)
192  {
193  error = clib_error_return (0, "short read `%s'", pm->file_name);
194  goto done;
195  }
196 
197  if (vec_len (pm->packets_read) == 0)
198  pm->min_packet_bytes = pm->max_packet_bytes = ph.n_bytes_in_packet;
199  else
200  {
201  pm->min_packet_bytes = clib_min (pm->min_packet_bytes, ph.n_bytes_in_packet);
202  pm->max_packet_bytes = clib_max (pm->max_packet_bytes, ph.n_bytes_in_packet);
203  }
204 
205  vec_add1 (pm->packets_read, data);
206  }
207 
208  done:
209  if (fd >= 0)
210  close (fd);
211  return error;
212 
213 }
char * file_name
Definition: pcap.h:107
#define clib_min(x, y)
Definition: clib.h:295
u32 flags
Definition: pcap.h:117
int file_descriptor
Definition: pcap.h:121
u32 n_packets_to_capture
Definition: pcap.h:110
u32 max_packet_bytes
Definition: pcap.h:131
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
Definition: vec.h:268
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define foreach_pcap_packet_header
Definition: pcap.h:86
u32 n_pcap_data_written
Definition: pcap.h:123
u8 * pcap_data
Definition: pcap.h:126
#define clib_error_return_unix(e, args...)
Definition: error.h:115
always_inline word unix_error_is_fatal(word error)
Definition: error.h:130
clib_error_t * pcap_read(pcap_main_t *pm)
Definition: pcap.c:142
clib_error_t * pcap_write(pcap_main_t *pm)
Definition: pcap.c:62
#define PCAP_MAIN_INIT_DONE
Definition: pcap.h:118
#define clib_max(x, y)
Definition: clib.h:288
u32 min_packet_bytes
Definition: pcap.h:131
pcap_packet_type_t packet_type
Definition: pcap.h:112
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u8 ** packets_read
Definition: pcap.h:129
#define clib_error_return(e, args...)
Definition: error.h:112
u32 n_packets_captured
Definition: pcap.h:115
#define foreach_pcap_file_header
Definition: pcap.h:58