Removing the --socket-mem eal parameter
[samplevnf.git] / VNFs / DPPD-PROX / tools / flow_extract / pcappkt.cpp
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <pcap.h>
18 #include <inttypes.h>
19 #include <cstring>
20 #include <arpa/inet.h>
21 #include <iostream>
22 #include <fstream>
23 #include <cstdlib>
24 #include "allocator.hpp"
25 #include "pcappkt.hpp"
26
27 Allocator *PcapPkt::allocator = NULL;
28
29 void* PcapPkt::operator new(size_t size)
30 {
31         if (allocator)
32                 return allocator->alloc(size);
33         else
34                 return ::operator new(size);
35 }
36
37 void PcapPkt::operator delete(void *pointer)
38 {
39         if (!allocator)
40                 :: operator delete(pointer);
41 }
42
43 PcapPkt::PcapPkt(uint8_t *mem)
44 {
45         header = *(struct pcap_pkthdr *)mem;
46         mem += sizeof(header);
47         buf = new uint8_t[header.len];
48         memcpy(buf, mem, header.len);
49 }
50
51 PcapPkt::PcapPkt()
52 {
53         buf = new uint8_t[1514];
54         memset(&header, 0, sizeof(header));
55 }
56
57 PcapPkt::PcapPkt(const PcapPkt& other)
58 {
59         if (!allocator) {
60                 buf = new uint8_t[other.len()];
61         }
62         else {
63                 buf = (uint8_t *)allocator->alloc(other.len());
64         }
65
66         memcpy(buf, other.buf, other.len());
67         header = other.header;
68 }
69
70 PcapPkt::~PcapPkt()
71 {
72         if (!allocator)
73                 delete[] buf;
74 }
75
76 #define ETYPE_IPv4      0x0008  /* IPv4 in little endian */
77 #define ETYPE_IPv6      0xDD86  /* IPv6 in little endian */
78 #define ETYPE_ARP       0x0608  /* ARP in little endian */
79 #define ETYPE_VLAN      0x0081  /* 802-1aq - VLAN */
80 #define ETYPE_MPLSU     0x4788  /* MPLS unicast */
81 #define ETYPE_MPLSM     0x4888  /* MPLS multicast */
82 #define ETYPE_8021ad    0xA888  /* Q-in-Q */
83 #define ETYPE_LLDP      0xCC88  /* Link Layer Discovery Protocol (LLDP) */
84 #define ETYPE_EoGRE     0x5865  /* EoGRE in little endian */
85
86 struct ipv4_hdr {
87         uint8_t  version_ihl;           /**< version and header length */
88         uint8_t  type_of_service;       /**< type of service */
89         uint16_t total_length;          /**< length of packet */
90         uint16_t packet_id;             /**< packet ID */
91         uint16_t fragment_offset;       /**< fragmentation offset */
92         uint8_t  time_to_live;          /**< time to live */
93         uint8_t  next_proto_id;         /**< protocol ID */
94         uint16_t hdr_checksum;          /**< header checksum */
95         uint32_t src_addr;              /**< source address */
96         uint32_t dst_addr;              /**< destination address */
97 } __attribute__((__packed__));
98
99 struct ether_addr {
100         uint8_t addr_bytes[6]; /**< Address bytes in transmission order */
101 } __attribute__((__packed__));
102
103 struct ether_hdr {
104         struct ether_addr d_addr; /**< Destination address. */
105         struct ether_addr s_addr; /**< Source address. */
106         uint16_t ether_type;      /**< Frame type. */
107 } __attribute__((__packed__));
108
109 struct vlan_hdr {
110         uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
111         uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
112 } __attribute__((__packed__));
113
114 struct udp_hdr {
115         uint16_t src_port;    /**< UDP source port. */
116         uint16_t dst_port;    /**< UDP destination port. */
117         uint16_t dgram_len;   /**< UDP datagram length */
118         uint16_t dgram_cksum; /**< UDP datagram checksum */
119 } __attribute__((__packed__));
120
121 struct pkt_tuple PcapPkt::parsePkt(const uint8_t **l4_hdr, uint16_t *hdr_len, const uint8_t **l5, uint32_t *l5_len) const
122 {
123         struct pkt_tuple pt = {0};
124
125         const struct ether_hdr *peth = (struct ether_hdr *)buf;
126         int l2_types_count = 0;
127         const struct ipv4_hdr* pip = 0;
128
129         switch (peth->ether_type) {
130         case ETYPE_IPv4:
131                         pip = (const struct ipv4_hdr *)(peth + 1);
132                 break;
133         case ETYPE_VLAN: {
134                 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
135                 if (vlan->eth_proto == ETYPE_IPv4) {
136                         pip = (const struct ipv4_hdr *)(peth + 1);
137                 }
138                 else if (vlan->eth_proto == ETYPE_VLAN) {
139                         const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
140                         if (vlan->eth_proto == ETYPE_IPv4) {
141                                 pip = (const struct ipv4_hdr *)(peth + 1);
142                         }
143                         else if (vlan->eth_proto == ETYPE_IPv6) {
144                                 throw 0;
145                         }
146                         else {
147                                 /* TODO: handle BAD PACKET */
148                                 throw 0;
149                         }
150                 }
151         }
152                 break;
153         case ETYPE_8021ad: {
154                 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
155                 if (vlan->eth_proto == ETYPE_VLAN) {
156                         const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
157                         if (vlan->eth_proto == ETYPE_IPv4) {
158                                 pip = (const struct ipv4_hdr *)(peth + 1);
159                         }
160                         else {
161                                 throw 0;
162                         }
163                 }
164                 else {
165                         throw 0;
166                 }
167         }
168                 break;
169         case ETYPE_MPLSU:
170                 break;
171         default:
172                 break;
173         }
174
175         /* L3 */
176         if ((pip->version_ihl >> 4) == 4) {
177
178                 if ((pip->version_ihl & 0x0f) != 0x05) {
179                         /* TODO: optional fields */
180                         throw 0;
181                 }
182
183                 pt.proto_id = pip->next_proto_id;
184                 pt.src_addr = pip->src_addr;
185                 pt.dst_addr = pip->dst_addr;
186         }
187         else {
188                 /* TODO: IPv6 and bad packets */
189                 throw 0;
190         }
191
192         /* L4 parser */
193         if (pt.proto_id == IPPROTO_UDP) {
194                 const struct udp_hdr *udp = (const struct udp_hdr*)(pip + 1);
195                 if (l4_hdr)
196                         *l4_hdr = (const uint8_t*)udp;
197                 if (hdr_len)
198                         *hdr_len = (const uint8_t*)udp - buf;
199                 pt.src_port = udp->src_port;
200                 pt.dst_port = udp->dst_port;
201                 if (l5)
202                         *l5 = ((const uint8_t*)udp) + sizeof(struct udp_hdr);
203                 if (l5_len)
204                         *l5_len = ntohs(udp->dgram_len) - sizeof(struct udp_hdr);
205         }
206         else if (pt.proto_id == IPPROTO_TCP) {
207                 const struct tcp_hdr *tcp = (const struct tcp_hdr *)(pip + 1);
208                 if (l4_hdr)
209                         *l4_hdr = (const uint8_t*)tcp;
210                 if (hdr_len)
211                         *hdr_len = (const uint8_t*)tcp - buf;
212                 pt.src_port = tcp->src_port;
213                 pt.dst_port = tcp->dst_port;
214
215                 if (l5)
216                         *l5 = ((const uint8_t*)tcp) + ((tcp->data_off >> 4)*4);
217                 if (l5_len)
218                         *l5_len = ntohs(pip->total_length) - sizeof(struct ipv4_hdr) - ((tcp->data_off >> 4)*4);
219         }
220         else {
221                 fprintf(stderr, "unsupported protocol %d\n", pt.proto_id);
222                 throw 0;
223         }
224
225         return pt;
226 }
227
228 void PcapPkt::toMem(uint8_t *mem) const
229 {
230         memcpy(mem, &header, sizeof(header));
231         mem += sizeof(header);
232         memcpy(mem, buf, header.len);
233 }
234
235 void PcapPkt::fromMem(uint8_t *mem)
236 {
237         memcpy(&header, mem, sizeof(header));
238         mem += sizeof(header);
239         memcpy(buf, mem, header.len);
240 }
241
242 void PcapPkt::toFile(ofstream *file) const
243 {
244         file->write(reinterpret_cast<const char *>(&header), sizeof(header));
245         file->write(reinterpret_cast<const char *>(buf), header.len);
246 }
247 size_t PcapPkt::memSize() const
248 {
249         return sizeof(header) + header.len;
250 }
251
252 PcapPkt::L4Proto PcapPkt::getProto() const
253 {
254         struct pkt_tuple pt = parsePkt();
255         return pt.proto_id == IPPROTO_TCP? PROTO_TCP : PROTO_UDP;
256 }
257
258 ostream& operator<<(ostream& stream, const pkt_tuple &other)
259 {
260         stream << other.src_addr << ","
261                << other.dst_addr << ","
262                << (int)other.proto_id << ","
263                << other.src_port << ","
264                << other.dst_port;
265         return stream;
266 }