bmv2
Designing your own switch target with bmv2
pcap_file.h
1 /* Copyright 2013-present Barefoot Networks, Inc.
2  *
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 #ifndef BM_BM_SIM_PCAP_FILE_H_
17 #define BM_BM_SIM_PCAP_FILE_H_
18 
19 #include <pcap.h>
20 
21 #include <stdexcept>
22 #include <mutex>
23 #include <cassert>
24 #include <vector>
25 #include <string>
26 #include <memory>
27 #include <unordered_map>
28 
29 #include "packet_handler.h"
30 
31 namespace bm {
32 
33 // A PcapPacket is a packet that has been read from a Pcap file.
34 // These packets can only be created by the PcapFileIn class.
35 class PcapPacket {
36  private:
37  unsigned port; // port index where packet originated
38  const u_char *data; // type defined in pcap.h
39  // The packet is only valid as long as the cursor
40  // in the PcapFileIn is not changed, since the pcap_header*
41  // points to a buffer returned by the pcap library.
42  const pcap_pkthdr *pcap_header;
43 
44  PcapPacket(unsigned port, const u_char *data, const pcap_pkthdr *pcap_header)
45  : port(port),
46  data(data),
47  pcap_header(pcap_header) { }
48 
49  // Only class that can call constructor
50  friend class PcapFileIn;
51 
52  public:
53  static std::string timevalToString(const struct timeval *tv);
54 
55  const char *getData() const { return reinterpret_cast<const char *>(data); }
56  unsigned getLength() const { return static_cast<unsigned>(pcap_header->len); }
57  const struct timeval *getTime() const { return &pcap_header->ts; }
58  unsigned getPort() const { return port; }
59 };
60 
61 class PcapFileBase {
62  protected:
63  unsigned port; // port number represented by this file
64  std::string filename;
65 
66  PcapFileBase(unsigned port, std::string filename);
67 };
68 
69 // C++ wrapper around a pcap file that is used for reading:
70 // A stream-like abstraction of a PCAP (Packet capture) file.
71 // Assumes that all packets in a file are sorted on time.
72 class PcapFileIn : public PcapFileBase {
73  public:
74  PcapFileIn(unsigned port, std::string filename);
75  virtual ~PcapFileIn();
76 
77  // Returns pointer to current packet
78  std::unique_ptr<PcapPacket> current() const;
79  // Advances to next packet. Should be called before current().
80  // Returns 'false' on end of file.
81  bool moveNext();
82  // restart from the beginning
83  void reset();
84  // True if we have reached end of file.
85  bool atEOF() const;
86 
87  private:
88  pcap_t *pcap;
89  pcap_pkthdr *current_header;
90  const u_char *current_data;
91 
92  enum class State {
93  Uninitialized,
94  Opened,
95  Reading,
96  AtEnd
97  };
98 
99  State state;
100 
101  private:
102  void open();
103  bool advance();
104  void deallocate();
105 
106  PcapFileIn(PcapFileIn const& ) = delete;
107  PcapFileIn& operator=(PcapFileIn const&) = delete;
108 };
109 
110 
111 class PcapFileOut :
112  public PcapFileBase {
113  public:
114  // port is not really used
115  PcapFileOut(unsigned port, std::string filename);
116  virtual ~PcapFileOut();
117  void writePacket(const char *data, unsigned length);
118 
119  private:
120  pcap_t *pcap;
121  pcap_dumper_t *dumper;
122 
123  PcapFileOut(PcapFileOut const& ) = delete;
124  PcapFileOut& operator=(PcapFileOut const&) = delete;
125 };
126 
127 
128 // Reads data from a set of Pcap files; returns packets in order
129 // of their timestamps.
130 class PcapFilesReader :
131  public PacketDispatcherIface {
132  public:
133  // Read packets from a set of files in timestamp order. Each file is
134  // associated to a port number corresponding to its index in the files vector.
135  // If 'respectTiming' is true, the PcapFilesReader only emits packets at the
136  // proper times, adjusted relative to the time of the 'start' call. In this
137  // case the 'start' method should probably be invoked by the caller on a
138  // separate thread. 'wait_time_in_seconds' is the time that the reader should
139  // wait before starting to process packets.
140  PcapFilesReader(bool respectTiming, unsigned wait_time_in_seconds);
141  // Add a file corresponding to the specified port.
142  void addFile(unsigned port, std::string file);
143  void start(); // start processing the pcap files
144 
145  // Invoked every time a packet is read
146  PacketDispatcherIface::ReturnCode set_packet_handler(
147  const PacketHandler &handler, void *cookie);
148 
149  private:
150  std::vector<std::unique_ptr<PcapFileIn>> files;
151  unsigned nonEmptyFiles;
152  unsigned wait_time_in_seconds;
153  bool respectTiming;
154  // Time when observable starts to read packets
155  struct timeval startTime;
156  // Time of first packet across all files
157  struct timeval firstPacketTime;
158  // constant zero (could be static, but it's easier to initialize it this way)
159  struct timeval zero;
160 
161  // index of next file to read packet from
162  unsigned scheduledIndex;
163  bool started;
164 
165  void scan();
166  void schedulePacket(unsigned index, const struct timeval *delay);
167  void timerFired(); // send a scheduled packet
168 
169  PcapFilesReader(PcapFilesReader const& ) = delete;
170  PcapFilesReader& operator=(PcapFilesReader const&) = delete;
171 
172  // Function to call when a packet is read
173  PacketHandler handler;
174  void *cookie;
175 };
176 
177 
178 // Writes data to a set of Pcap files.
179 class PcapFilesWriter : public PacketReceiverIface {
180  public:
181  PcapFilesWriter();
182  // Add a file corresponding to the specified port.
183  void addFile(unsigned port, std::string file);
184  void send_packet(int port_num, const char *buffer, int len);
185 
186  private:
187  std::unordered_map<unsigned, std::unique_ptr<PcapFileOut>> files;
188 
189  PcapFilesWriter(PcapFilesWriter const& ) = delete;
190  PcapFilesWriter& operator=(PcapFilesWriter const&) = delete;
191 };
192 
193 } // namespace bm
194 
195 #endif // BM_BM_SIM_PCAP_FILE_H_