-
Notifications
You must be signed in to change notification settings - Fork 390
/
pkt_handler.h
342 lines (288 loc) · 10.2 KB
/
pkt_handler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/
#ifndef vnsw_agent_pkt_handler_hpp
#define vnsw_agent_pkt_handler_hpp
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <tbb/atomic.h>
#include <boost/array.hpp>
#include <net/address.h>
#include <net/mac_address.h>
#include <oper/mirror_table.h>
#include <oper/nexthop.h>
#include <pkt/pkt_trace.h>
#include <pkt/packet_buffer.h>
#include "vr_defs.h"
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCPV6_SERVER_PORT 547
#define DHCPV6_CLIENT_PORT 546
#define DNS_SERVER_PORT 53
#define VXLAN_UDP_DEST_PORT 4789
#define MPLS_OVER_UDP_DEST_PORT 51234
#define IPv4_ALEN 4
#define ARP_TX_BUFF_LEN 128
#define IPC_HDR_LEN (sizeof(struct ether_header) + sizeof(struct agent_hdr))
#define IP_PROTOCOL ETHERTYPE_IP
#define VLAN_PROTOCOL 0x8100
#define DEFAULT_IP_TTL 64
#define DEFAULT_IP_ID 0
#define VLAN_HDR_LEN 4
#define ICMP_UNREACH_HDR_LEN 8
struct PktInfo;
struct agent_hdr;
class PacketBuffer;
class Proto;
struct InterTaskMsg {
InterTaskMsg(uint16_t command): cmd(command) {}
virtual ~InterTaskMsg() {}
uint16_t cmd;
};
struct GreHdr {
GreHdr() : flags(), protocol() {}
~GreHdr() {}
uint16_t flags;
uint16_t protocol;
};
struct MplsHdr {
MplsHdr() : hdr() {}
~MplsHdr() {}
uint32_t hdr;
};
struct VxlanHdr {
VxlanHdr() : reserved(0), vxlan_id(0) { }
VxlanHdr(uint32_t id) : reserved(0), vxlan_id((id) << 8) { }
~VxlanHdr() { }
uint32_t reserved;
uint32_t vxlan_id;
};
struct PktType {
enum Type {
INVALID,
ARP,
IP,
UDP,
TCP,
ICMP,
ICMPV6,
NON_IP,
MESSAGE
};
};
struct AgentHdr {
// Packet commands between agent and vrouter. The values must be in-sync
// with vrouter/include/vr_defs.h
enum PktCommand {
TX_SWITCH = AGENT_CMD_SWITCH,
TX_ROUTE = AGENT_CMD_ROUTE,
TRAP_ARP = AGENT_TRAP_ARP,
TRAP_L2_PROTOCOL = AGENT_TRAP_L2_PROTOCOLS,
TRAP_NEXTHOP = AGENT_TRAP_NEXTHOP,
TRAP_RESOLVE = AGENT_TRAP_RESOLVE,
TRAP_FLOW_MISS = AGENT_TRAP_FLOW_MISS,
TRAP_L3_PROTOCOLS = AGENT_TRAP_L3_PROTOCOLS,
TRAP_DIAG = AGENT_TRAP_DIAG,
TRAP_ECMP_RESOLVE = AGENT_TRAP_ECMP_RESOLVE,
TRAP_SOURCE_MISMATCH = AGENT_TRAP_SOURCE_MISMATCH,
TRAP_HANDLE_DF = AGENT_TRAP_HANDLE_DF,
TRAP_TOR_CONTROL_PKT = AGENT_TRAP_TOR_CONTROL_PKT,
TRAP_ZERO_TTL = AGENT_TRAP_ZERO_TTL,
TRAP_ICMP_ERROR = AGENT_TRAP_ICMP_ERROR,
INVALID = MAX_AGENT_HDR_COMMANDS
};
enum PktCommandParams {
PACKET_CMD_PARAM_CTRL = CMD_PARAM_PACKET_CTRL,
PACKET_CMD_PARAM_DIAG = CMD_PARAM_1_DIAG,
MAX_PACKET_CMD_PARAM = MAX_CMD_PARAMS,
};
AgentHdr() :
ifindex(-1), vrf(-1), cmd(-1), cmd_param(-1), cmd_param_1(-1),
nh(-1), flow_index(-1), mtu(0) {}
AgentHdr(uint32_t ifindex_p, uint32_t vrf_p, uint16_t cmd_p) :
ifindex(ifindex_p), vrf(vrf_p), cmd(cmd_p), cmd_param(-1),
cmd_param_1(-1), nh(-1), flow_index(-1), mtu(0) {}
AgentHdr(uint32_t ifindex_p, uint32_t vrf_p, uint16_t cmd_p,
uint32_t param1, uint32_t param2) :
ifindex(ifindex_p), vrf(vrf_p), cmd(cmd_p), cmd_param(param1),
cmd_param_1(param2), nh(-1), flow_index(-1), mtu(0) {}
~AgentHdr() {}
// Fields from agent_hdr
uint32_t ifindex;
uint32_t vrf;
uint16_t cmd;
uint32_t cmd_param;
uint32_t cmd_param_1;
uint32_t nh;
uint32_t flow_index;
uint16_t mtu;
};
// Tunnel header decoded from the MPLSoGRE/MPLSoUDP encapsulated packet on
// fabric. Supports only IPv4 addresses since only IPv4 is supported on fabric
struct TunnelInfo {
TunnelInfo() :
type(TunnelType::INVALID), label(-1), vxlan_id(-1), src_port(0),
ip_saddr(), ip_daddr() {}
~TunnelInfo() {}
TunnelType type;
uint32_t label; // Valid only for MPLSoGRE and MPLSoUDP
uint32_t vxlan_id; // Valid only for VXLAN
uint16_t src_port; // Valid only for VXLAN and MPLSoUDP
uint32_t ip_saddr;
uint32_t ip_daddr;
};
// Receive packets from the pkt0 (tap) interface, parse and send the packet to
// appropriate protocol task. Also, protocol tasks can send packets to pkt0
// or to other tasks.
class PktHandler {
public:
typedef boost::function<bool(boost::shared_ptr<PktInfo>)> RcvQueueFunc;
typedef boost::function<void(PktTrace::Pkt &)> PktTraceCallback;
enum PktModuleName {
INVALID,
FLOW,
ARP,
DHCP,
DHCPV6,
DNS,
ICMP,
ICMPV6,
DIAG,
ICMP_ERROR,
RX_PACKET,
MAX_MODULES
};
struct PktStats {
uint32_t sent[MAX_MODULES];
uint32_t received[MAX_MODULES];
uint32_t q_threshold_exceeded[MAX_MODULES];
uint32_t dropped;
void Reset() {
for (int i = 0; i < MAX_MODULES; ++i) {
sent[i] = received[i] = q_threshold_exceeded[i] = 0;
}
dropped = 0;
}
PktStats() { Reset(); }
void PktRcvd(PktModuleName mod);
void PktSent(PktModuleName mod);
void PktQThresholdExceeded(PktModuleName mod);
};
PktHandler(Agent *, PktModule *pkt_module);
virtual ~PktHandler();
void Register(PktModuleName type, RcvQueueFunc cb);
void Register(PktModuleName type, Proto *proto);
void Send(const AgentHdr &hdr, const PacketBufferPtr &buff);
PktModuleName ParsePacket(const AgentHdr &hdr, PktInfo *pkt_info,
uint8_t *pkt);
int ParseUserPkt(PktInfo *pkt_info, Interface *intf,
PktType::Type &pkt_type, uint8_t *pkt);
// identify pkt type and send to the registered handler
void HandleRcvPkt(const AgentHdr &hdr, const PacketBufferPtr &buff);
void SendMessage(PktModuleName mod, InterTaskMsg *msg);
bool IsGwPacket(const Interface *intf, const IpAddress &dst_ip);
const PktStats &GetStats() const { return stats_; }
void ClearStats() { stats_.Reset(); }
void PktTraceIterate(PktModuleName mod, PktTraceCallback cb);
void PktTraceClear(PktModuleName mod) { pkt_trace_.at(mod).Clear(); }
void PktTraceBuffers(PktModuleName mod, uint32_t buffers) {
pkt_trace_.at(mod).set_num_buffers(buffers);
}
uint32_t PktTraceBuffers(PktModuleName mod) const {
return pkt_trace_.at(mod).num_buffers();
}
uint32_t PktTraceSize(PktModuleName mod) const {
return pkt_trace_.at(mod).pkt_trace_size();
}
void AddPktTrace(PktModuleName module, PktTrace::Direction dir,
const PktInfo *pkt);
uint32_t EncapHeaderLen() const;
Agent *agent() const { return agent_; }
PktModule *pkt_module() const { return pkt_module_; }
void Enqueue(PktModuleName module, boost::shared_ptr<PktInfo> pkt_info);
private:
int ParseEthernetHeader(PktInfo *pkt_info, uint8_t *pkt);
int ParseMplsHdr(PktInfo *pkt_info, uint8_t *pkt);
int ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type,
uint8_t *ptr);
int ParseMPLSoGRE(PktInfo *pkt_info, uint8_t *pkt);
int ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt);
int ParseUDPTunnels(PktInfo *pkt_info, uint8_t *pkt);
int ParseVxlan(PktInfo *pkt_info, uint8_t *pkt);
int ParseUdp(PktInfo *pkt_info, uint8_t *pkt);
void ComputeForwardingMode(PktInfo *pkt_info) const;
void SetOuterIp(PktInfo *pkt_info, uint8_t *pkt);
bool IgnoreFragmentedPacket(PktInfo *pkt_info);
bool IsDHCPPacket(PktInfo *pkt_info);
bool IsValidInterface(uint32_t ifindex, Interface **interface);
bool IsToRDevice(uint32_t vrf_id, const IpAddress &ip);
bool IsManagedTORPacket(Interface *intf, PktInfo *pkt_info,
PktType::Type &pkt_type, uint8_t *pkt);
bool IsDiagPacket(PktInfo *pkt_info);
boost::array<Proto *, MAX_MODULES> proto_list_;
PktStats stats_;
boost::array<PktTrace, MAX_MODULES> pkt_trace_;
DBTableBase::ListenerId iid_;
Agent *agent_;
PktModule *pkt_module_;
DISALLOW_COPY_AND_ASSIGN(PktHandler);
};
// Info from the parsed packet
struct PktInfo {
PktHandler::PktModuleName module;
uint8_t *pkt;
uint16_t len;
uint16_t max_pkt_len;
uint8_t *data;
InterTaskMsg *ipc;
Address::Family family;
PktType::Type type;
AgentHdr agent_hdr;
uint16_t ether_type;
// Fields extracted for processing in agent
uint32_t vrf;
MacAddress smac;
MacAddress dmac;
IpAddress ip_saddr;
IpAddress ip_daddr;
uint8_t ip_proto;
uint32_t sport;
uint32_t dport;
bool tcp_ack;
TunnelInfo tunnel;
// Forwarding mode for packet - l3/l2
mutable bool l3_forwarding;
bool l3_label;
// Pointer to different headers in user packet
struct ether_header *eth;
struct ether_arp *arp;
struct ip *ip;
struct ip6_hdr *ip6;
union {
struct tcphdr *tcp;
struct udphdr *udp;
struct icmp *icmp;
struct icmp6_hdr *icmp6;
} transp;
PktInfo(Agent *agent, uint32_t buff_len, PktHandler::PktModuleName module,
uint32_t mdata);
PktInfo(const PacketBufferPtr &buff);
PktInfo(PktHandler::PktModuleName module, InterTaskMsg *msg);
virtual ~PktInfo();
const AgentHdr &GetAgentHdr() const;
void UpdateHeaderPtr();
std::size_t hash() const;
PacketBuffer *packet_buffer() const { return packet_buffer_.get(); }
PacketBufferPtr packet_buffer_ptr() const { return packet_buffer_; }
void AllocPacketBuffer(Agent *agent, uint32_t module, uint16_t len,
uint32_t mdata);
void set_len(uint32_t len);
void reset_packet_buffer();
private:
PacketBufferPtr packet_buffer_;
};
#endif