Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "base/os.h"
7 : #include <sys/types.h>
8 : #include <arpa/inet.h>
9 : #include <netinet/in.h>
10 : #include <netinet/ip6.h>
11 : #include <netinet/icmp6.h>
12 :
13 : #include "init/agent_param.h"
14 : #include "cmn/agent_cmn.h"
15 : #include "diag/diag.h"
16 : #include "base/address_util.h"
17 : #include "oper/ecmp_load_balance.h"
18 : #include "oper/interface_common.h"
19 : #include "oper/nexthop.h"
20 : #include "oper/route_common.h"
21 : #include "oper/vrf.h"
22 : #include "oper/tunnel_nh.h"
23 : #include "pkt/control_interface.h"
24 : #include "pkt/pkt_handler.h"
25 : #include "pkt/proto.h"
26 : #include "pkt/flow_table.h"
27 : #include "pkt/flow_proto.h"
28 : #include "pkt/pkt_types.h"
29 : #include "pkt/pkt_init.h"
30 : #include "cmn/agent_stats.h"
31 : #include "pkt/packet_buffer.h"
32 : #include "vr_types.h"
33 : #include "vr_defs.h"
34 : #include "vr_mpls.h"
35 :
36 : #define PKT_TRACE(obj, arg) \
37 : do { \
38 : std::ostringstream _str; \
39 : _str << arg; \
40 : Pkt##obj::TraceMsg(PacketTraceBuf, __FILE__, __LINE__, _str.str()); \
41 : } while (false) \
42 :
43 : const std::size_t PktTrace::kPktMaxTraceSize;
44 :
45 : ////////////////////////////////////////////////////////////////////////////////
46 : namespace {
47 75 : inline bool IsBfdkeepalivePkt(const AgentHdr &hdr)
48 : {
49 : // For the BFD traped packets, BFD state info is available in 'cmd_param'
50 75 : if ((hdr.cmd == AGENT_TRAP_BFD) && (hdr.cmd_param == 0xc0)) {
51 0 : return true;
52 : }
53 75 : return false;
54 : }
55 :
56 : } // namespace
57 :
58 2 : PktHandler::PktHandler(Agent *agent, PktModule *pkt_module) :
59 4 : stats_(), agent_(agent), pkt_module_(pkt_module),
60 2 : work_queue_(TaskScheduler::GetInstance()->GetTaskId("Agent::PktHandler"), 0,
61 : boost::bind(&PktHandler::ProcessPacket, this, _1)),
62 2 : work_queue_bfd_ka_(TaskScheduler::GetInstance()->GetTaskId("Agent::BFD_KA"), 0,
63 2 : boost::bind(&PktHandler::ProcessBfdDataPacket, this, _1))
64 : {
65 2 : work_queue_.set_name("Packet Handler Queue");
66 2 : work_queue_.set_measure_busy_time(agent_->MeasureQueueDelay());
67 : // BFD keep alive packet processing
68 2 : work_queue_bfd_ka_.set_name("Packet BFD Data Queue");
69 2 : work_queue_bfd_ka_.set_measure_busy_time(agent_->MeasureQueueDelay());
70 34 : for (int i = 0; i < MAX_MODULES; ++i) {
71 32 : if (i == PktHandler::DHCP || i == PktHandler::DHCPV6 ||
72 : i == PktHandler::DNS)
73 6 : pkt_trace_.at(i).set_pkt_trace_size(512);
74 : else
75 26 : pkt_trace_.at(i).set_pkt_trace_size(128);
76 : }
77 2 : }
78 :
79 4 : PktHandler::~PktHandler() {
80 2 : work_queue_.Shutdown();
81 4 : }
82 :
83 26 : void PktHandler::Register(PktModuleName type, Proto *proto) {
84 26 : proto_list_.at(type) = proto;
85 26 : if (type == BFD) {
86 2 : bfd_keepalive_proto_ = proto;
87 : }
88 26 : }
89 :
90 0 : uint32_t PktHandler::EncapHeaderLen() const {
91 0 : return agent_->pkt()->control_interface()->EncapsulationLength();
92 : }
93 :
94 : // Send packet to tap interface
95 2204 : void PktHandler::Send(const AgentHdr &hdr, const PacketBufferPtr &buff) {
96 2204 : stats_.PktSent(PktHandler::PktModuleName(buff->module()));
97 2204 : pkt_trace_.at(buff->module()).AddPktTrace(PktTrace::Out, buff->data_len(),
98 : buff->data(), &hdr);
99 2204 : if (agent_->pkt()->control_interface()->Send(hdr, buff) <= 0) {
100 0 : PKT_TRACE(Err, "Error sending packet");
101 : }
102 2204 : return;
103 : }
104 :
105 78 : void PktHandler::CalculatePortIP(PktInfo *pkt) {
106 78 : const Interface *in = NULL;
107 78 : const VmInterface *intf = NULL;
108 78 : const Interface *pkt_in_intf = NULL;
109 78 : bool ingress= false;
110 : VmInterface::FatFlowIgnoreAddressType ignore_addr;
111 : uint8_t protocol;
112 :
113 : const NextHop *nh =
114 78 : agent()->nexthop_table()->FindNextHop(pkt->agent_hdr.nh);
115 78 : if (!nh) {
116 78 : return;
117 : }
118 :
119 78 : if (nh->GetType() == NextHop::INTERFACE) {
120 36 : const InterfaceNH *intf_nh = static_cast<const InterfaceNH *>(nh);
121 36 : in = intf_nh->GetInterface();
122 42 : } else if (nh->GetType() == NextHop::VLAN) {
123 0 : const VlanNH *vlan_nh = static_cast<const VlanNH *>(nh);
124 0 : in = vlan_nh->GetInterface();
125 42 : } else if (nh->GetType() == NextHop::COMPOSITE) {
126 37 : const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
127 :
128 37 : if (comp_nh->composite_nh_type() == Composite::LOCAL_ECMP) {
129 37 : in = comp_nh->GetFirstLocalEcmpMemberInterface();
130 : }
131 : }
132 :
133 78 : if (in) {
134 73 : intf = dynamic_cast<const VmInterface *>(in);
135 : }
136 :
137 78 : if (!intf) {
138 6 : return;
139 : }
140 :
141 72 : if (intf->fat_flow_list().list_.size() == 0) {
142 69 : return;
143 : }
144 :
145 3 : if (intf->ExcludeFromFatFlow(pkt->family, pkt->ip_saddr, pkt->ip_daddr)) {
146 0 : return;
147 : }
148 3 : uint16_t sport = pkt->sport;
149 3 : if (pkt->ip_proto == IPPROTO_ICMP || pkt->ip_proto == IPPROTO_IGMP) {
150 0 : sport = 0;
151 : }
152 :
153 3 : protocol = pkt->ip_proto;
154 : /*
155 : * For ICMPv6 change the protocol to ICMP as the same value is used when it is
156 : * stored in the fat flow rule
157 : */
158 3 : if (pkt->ip_proto == IPPROTO_ICMPV6) {
159 0 : protocol = IPPROTO_ICMP;
160 : }
161 :
162 3 : pkt->is_fat_flow_src_prefix = false;
163 3 : pkt->is_fat_flow_dst_prefix = false;
164 :
165 3 : if (pkt->sport < pkt->dport) {
166 2 : if (intf->IsFatFlowPortBased(protocol, sport, &ignore_addr)) {
167 2 : pkt->dport = 0;
168 2 : pkt->ignore_address = ignore_addr;
169 2 : return;
170 : }
171 :
172 0 : if (intf->IsFatFlowPortBased(protocol, pkt->dport, &ignore_addr)) {
173 0 : pkt->sport = 0;
174 0 : pkt->ignore_address = ignore_addr;
175 0 : return;
176 : }
177 : } else {
178 1 : if (intf->IsFatFlowPortBased(protocol, pkt->dport, &ignore_addr)) {
179 1 : if (pkt->dport == pkt->sport) {
180 0 : pkt->same_port_number = true;
181 : }
182 1 : pkt->sport = 0;
183 1 : pkt->ignore_address = ignore_addr;
184 1 : return;
185 : }
186 :
187 0 : if (intf->IsFatFlowPortBased(protocol, sport, &ignore_addr)) {
188 0 : pkt->dport = 0;
189 0 : pkt->ignore_address = ignore_addr;
190 0 : return;
191 : }
192 : }
193 : /* If Fat-flow port is 0, then both source and destination ports have to
194 : * be ignored */
195 0 : if (intf->IsFatFlowPortBased(protocol, 0, &ignore_addr)) {
196 0 : pkt->sport = 0;
197 0 : pkt->dport = 0;
198 0 : pkt->ignore_address = ignore_addr;
199 0 : return;
200 : }
201 :
202 : // Check for fat flow based on prefix aggregation
203 0 : pkt_in_intf = Agent::GetInstance()->interface_table()->FindInterface(
204 0 : pkt->agent_hdr.ifindex);
205 0 : ingress = PktFlowInfo::ComputeDirection(pkt_in_intf);
206 : // set the src and dst prefix to src & dst ip to begin with
207 0 : pkt->ip_ff_src_prefix = pkt->ip_saddr;
208 0 : pkt->ip_ff_dst_prefix = pkt->ip_daddr;
209 0 : intf->IsFatFlowPrefixAggregation(ingress, protocol,
210 0 : (uint16_t *)&pkt->sport,
211 0 : (uint16_t *) &pkt->dport,
212 : &pkt->same_port_number,
213 : &pkt->ip_ff_src_prefix,
214 : &pkt->ip_ff_dst_prefix,
215 : &pkt->is_fat_flow_src_prefix,
216 : &pkt->is_fat_flow_dst_prefix,
217 : &pkt->ignore_address);
218 : }
219 :
220 111 : bool PktHandler::IsBFDHealthCheckPacket(const PktInfo *pkt_info,
221 : const Interface *intrface) {
222 111 : if (intrface->type() == Interface::VM_INTERFACE &&
223 138 : pkt_info->ip_proto == IPPROTO_UDP &&
224 27 : (pkt_info->dport == BFD_SINGLEHOP_CONTROL_PORT ||
225 27 : pkt_info->dport == BFD_MULTIHOP_CONTROL_PORT ||
226 27 : pkt_info->dport == BFD_ECHO_PORT)) {
227 0 : return true;
228 : }
229 :
230 111 : return false;
231 : }
232 :
233 111 : bool PktHandler::IsSegmentHealthCheckPacket(const PktInfo *pkt_info,
234 : const Interface *intrface) {
235 155 : if (intrface->type() == Interface::VM_INTERFACE &&
236 44 : pkt_info->ip_proto == IPPROTO_ICMP) {
237 17 : if (pkt_info->icmp_chksum == 0xffff) {
238 0 : return true;
239 : }
240 17 : return pkt_info->is_segment_hc_pkt;
241 : }
242 94 : return false;
243 : }
244 :
245 : // Validate the BFD Keepalive packet received
246 0 : PktHandler::PktModuleName PktHandler::ParseBfdDataPacket(const AgentHdr &hdr,
247 : PktInfo *pkt_info,
248 : uint8_t *pkt) {
249 :
250 0 : PktType::Type pkt_type = PktType::INVALID;
251 0 : pkt_info->agent_hdr = hdr;
252 :
253 0 : int len = 0, ret = 0;
254 :
255 : // Parse packet before computing forwarding mode. Packet is parsed
256 : // independent of packet forwarding mode
257 0 : len += ParseEthernetHeader(pkt_info, (pkt + len));
258 0 : if (pkt_info->ether_type != ETHERTYPE_IP) {
259 0 : agent_->stats()->incr_pkt_drop_due_to_invalid_ethertype();
260 0 : return INVALID;
261 : }
262 :
263 : // IP Packets
264 0 : ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
265 0 : if(ret == -1) {
266 0 : return INVALID;
267 : }
268 0 : len += ret;
269 :
270 : // Check if the BFD KA packet
271 0 : if (pkt_info->ip_proto == IPPROTO_UDP &&
272 0 : pkt_info->dport == BFD_SINGLEHOP_CONTROL_PORT &&
273 0 : (pkt_info->data[0] & 0x20)) {
274 0 : return BFD;
275 : }
276 :
277 0 : return INVALID;
278 : }
279 :
280 : // Process the packet received from tap interface
281 78 : PktHandler::PktModuleName PktHandler::ParsePacket(const AgentHdr &hdr,
282 : PktInfo *pkt_info,
283 : uint8_t *pkt) {
284 78 : PktType::Type pkt_type = PktType::INVALID;
285 78 : Interface *intf = NULL;
286 :
287 78 : pkt_info->agent_hdr = hdr;
288 78 : if (!IsValidInterface(hdr.ifindex, &intf)) {
289 0 : return INVALID;
290 : }
291 :
292 : // Parse packet before computing forwarding mode. Packet is parsed
293 : // indepndent of packet forwarding mode
294 78 : if (ParseUserPkt(pkt_info, intf, pkt_type, pkt) < 0) {
295 0 : return INVALID;
296 : }
297 :
298 78 : if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) {
299 : // In case of a control packet from a TOR served by us, the ifindex
300 : // is modified to index of the VM interface; validate this interface.
301 0 : if (!IsValidInterface(pkt_info->agent_hdr.ifindex, &intf)) {
302 0 : return INVALID;
303 : }
304 : }
305 :
306 78 : pkt_info->vrf = pkt_info->agent_hdr.vrf;
307 :
308 :
309 78 : if (hdr.cmd == AgentHdr::TRAP_MAC_MOVE ||
310 78 : hdr.cmd == AgentHdr::TRAP_MAC_LEARN ||
311 78 : hdr.cmd == AgentHdr::TRAP_MAC_IP_LEARNING) {
312 0 : return MAC_LEARNING;
313 : }
314 :
315 78 : bool is_flow_packet = IsFlowPacket(pkt_info);
316 : // Look for DHCP packets if corresponding service is enabled
317 : // Service processing over-rides ACL/Flow and forwarding configuration
318 78 : if (!is_flow_packet && intf->dhcp_enabled() && (pkt_type == PktType::UDP)) {
319 0 : if (pkt_info->ip && (pkt_info->dport == DHCP_SERVER_PORT ||
320 0 : pkt_info->sport == DHCP_CLIENT_PORT)) {
321 0 : return DHCP;
322 : }
323 : }
324 78 : if (!is_flow_packet && intf->dhcp_enabled_v6() && (pkt_type == PktType::UDP)) {
325 0 : if (pkt_info->ip6 && (pkt_info->dport == DHCPV6_SERVER_PORT ||
326 0 : pkt_info->sport == DHCPV6_CLIENT_PORT)) {
327 0 : return DHCPV6;
328 : }
329 : }
330 :
331 : // Handle ARP packet
332 78 : if (pkt_type == PktType::ARP) {
333 0 : return ARP;
334 : }
335 :
336 : // Packets needing flow
337 78 : if (is_flow_packet) {
338 78 : CalculatePortIP(pkt_info);
339 78 : if ((pkt_info->ip && pkt_info->family == Address::INET) ||
340 0 : (pkt_info->ip6 && pkt_info->family == Address::INET6)) {
341 78 : return FLOW;
342 : } else {
343 0 : PKT_TRACE(Err, "Flow trap for non-IP packet for interface "
344 : "index <" << hdr.ifindex << ">");
345 0 : agent_->stats()->pkt_drop_due_to_flow_trap();
346 0 : return INVALID;
347 : }
348 : }
349 :
350 : // Look for DNS packets if corresponding service is enabled
351 : // Service processing over-rides ACL/Flow
352 0 : if (intf->dns_enabled() && (pkt_type == PktType::UDP)) {
353 0 : if (pkt_info->dport == DNS_SERVER_PORT) {
354 0 : return DNS;
355 : }
356 : }
357 :
358 : // Look for IP packets that need ARP resolution
359 0 : if (pkt_info->ip && hdr.cmd == AgentHdr::TRAP_RESOLVE) {
360 0 : return ARP;
361 : }
362 :
363 : // send time exceeded ICMP messages to diag module
364 0 : if (IsDiagPacket(pkt_info)) {
365 0 : return DIAG;
366 : }
367 :
368 0 : if (IsBFDHealthCheckPacket(pkt_info, intf)) {
369 0 : return BFD;
370 : }
371 :
372 0 : if (pkt_type == PktType::ICMP && IsSegmentHealthCheckPacket(pkt_info,
373 : intf)) {
374 0 : return DIAG;
375 : }
376 :
377 0 : if (pkt_type == PktType::ICMP && IsGwPacket(intf, pkt_info->ip_daddr)) {
378 0 : return ICMP;
379 : }
380 :
381 : // Look for IP6 packets that need NDP resolution
382 0 : if (pkt_info->ip6 && hdr.cmd == AgentHdr::TRAP_RESOLVE) {
383 0 : return ICMPV6;
384 : }
385 :
386 0 : if (pkt_type == PktType::ICMPV6) {
387 0 : if (hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
388 0 : return ICMPV6_ERROR;
389 : }
390 0 : return ICMPV6;
391 : }
392 :
393 0 : if (pkt_type == PktType::IGMP) {
394 0 : return IGMP;
395 : }
396 :
397 0 : if(pkt_info->ip6 && hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
398 0 : return ICMPV6_ERROR;
399 : }
400 :
401 0 : if (pkt_info->ip && hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
402 0 : return ICMP_ERROR;
403 : }
404 :
405 0 : if (hdr.cmd == AgentHdr::TRAP_DIAG && (pkt_info->ip || pkt_info->ip6)) {
406 0 : return DIAG;
407 : }
408 :
409 0 : return INVALID;
410 : }
411 :
412 75 : void PktHandler::HandleRcvPkt(const AgentHdr &hdr, const PacketBufferPtr &buff){
413 : // Enqueue packets to a workqueue to decouple from ASIO and run in
414 : // exclusion with DB
415 : boost::shared_ptr<PacketBufferEnqueueItem>
416 75 : info(new PacketBufferEnqueueItem(hdr, buff));
417 :
418 : // BFD Keepalive packets are enqueued to a seperate work queue
419 : // so that its job run without dependence on dB tasks
420 75 : if (IsBfdkeepalivePkt(hdr)) {
421 0 : work_queue_bfd_ka_.Enqueue(info);
422 : } else {
423 75 : work_queue_.Enqueue(info);
424 : }
425 75 : }
426 :
427 75 : bool PktHandler::ProcessPacket(boost::shared_ptr<PacketBufferEnqueueItem> item) {
428 75 : agent_->stats()->incr_pkt_exceptions();
429 75 : const AgentHdr &hdr = item->hdr;
430 75 : const PacketBufferPtr &buff = item->buff;
431 75 : boost::shared_ptr<PktInfo> pkt_info (new PktInfo(buff));
432 75 : uint8_t *pkt = buff->data();
433 75 : PktModuleName mod = ParsePacket(hdr, pkt_info.get(), pkt);
434 75 : PktModuleEnqueue(mod, hdr, pkt_info, pkt);
435 75 : if (mod == INVALID) {
436 0 : pkt_info.reset();
437 : }
438 :
439 75 : return true;
440 75 : }
441 : // Process BFD keepalives (BFD packets with state 'UP') in a seperate task
442 : // that is independent of Db Task
443 0 : bool PktHandler::ProcessBfdDataPacket(boost::shared_ptr<PacketBufferEnqueueItem> item) {
444 0 : const AgentHdr &hdr = item->hdr;
445 0 : const PacketBufferPtr &buff = item->buff;
446 0 : uint8_t *pkt = buff->data();
447 : PktModuleName mod;
448 :
449 : // In certain Agent restart race condition, Agent would restart but
450 : // vrouter is not in sync yet with agent restart. In this condition
451 : // there could be BFD packets from the prior session could be trapped
452 : // in vrouter and injected to the Agent's PKT0 i/f So, don't process
453 : // BFD packets received, prior to agent init done.
454 0 : if (!bfd_keepalive_proto_ || (agent_->init_done() == false)) {
455 0 : PKT_TRACE(Err, "BFD proto_list is not Initialized. Ignoring");
456 0 : return true;
457 : }
458 :
459 0 : boost::shared_ptr<PktInfo> pkt_info (new PktInfo(buff));
460 0 : mod = ParseBfdDataPacket(hdr, pkt_info.get(), pkt);
461 0 : if (mod == BFD) {
462 0 : pkt_info->is_bfd_keepalive = true;
463 0 : pkt_info->packet_buffer()->set_module(mod);
464 0 : bfd_keepalive_proto_->Enqueue(pkt_info);
465 0 : proto_list_.at(BFD)->ProcessStats(PktStatsType::PKT_RX_ENQUEUE);
466 : } else {
467 0 : proto_list_.at(BFD)->ProcessStats(PktStatsType::PKT_RX_DROP_STATS);
468 0 : pkt_info.reset();
469 : }
470 0 : return true;
471 0 : }
472 :
473 75 : void PktHandler::PktModuleEnqueue(PktModuleName mod, const AgentHdr &hdr,
474 : boost::shared_ptr<PktInfo> pkt_info,
475 : uint8_t * pkt) {
476 75 : pkt_info->packet_buffer()->set_module(mod);
477 75 : stats_.PktRcvd(mod);
478 75 : if (mod == INVALID) {
479 0 : agent_->stats()->incr_pkt_dropped();
480 0 : pkt_trace_.at(mod).AddPktTrace(PktTrace::In, pkt_info->len, pkt, &hdr);
481 0 : return;
482 : }
483 75 : Enqueue(mod, pkt_info);
484 : }
485 :
486 : // Compute L2/L3 forwarding mode for pacekt.
487 : // Forwarding mode is L3 if,
488 : // - Packet uses L3 label
489 : // - DMAC in packet is VRRP Mac or VHOST MAC or receiving physical interface MAC
490 : // Else forwarding mode is L2
491 0 : bool PktHandler::ComputeForwardingMode(PktInfo *pkt_info,
492 : const Interface *intf) const {
493 0 : if (pkt_info->tunnel.type.GetType() == TunnelType::MPLS_GRE ||
494 0 : pkt_info->tunnel.type.GetType() == TunnelType::MPLS_UDP) {
495 0 : return pkt_info->l3_label;
496 : }
497 :
498 0 : if (pkt_info->dmac == agent_->vrrp_mac()) {
499 0 : return true;
500 : }
501 :
502 0 : if (pkt_info->dmac == agent_->vhost_interface()->mac()) {
503 0 : return true;
504 : }
505 :
506 0 : if (intf && intf->type() == Interface::PHYSICAL &&
507 0 : pkt_info->dmac == intf->mac()) {
508 0 : return true;
509 : }
510 :
511 0 : return false;
512 : }
513 :
514 78 : void PktHandler::SetOuterIp(PktInfo *pkt_info, uint8_t *pkt) {
515 78 : if (pkt_info->ether_type != ETHERTYPE_IP) {
516 0 : return;
517 : }
518 78 : struct ip *ip_hdr = (struct ip *)pkt;
519 78 : pkt_info->tunnel.ip = ip_hdr;
520 78 : pkt_info->tunnel.ip_saddr = ntohl(ip_hdr->ip_src.s_addr);
521 78 : pkt_info->tunnel.ip_daddr = ntohl(ip_hdr->ip_dst.s_addr);
522 : }
523 :
524 78 : void PktHandler::SetOuterMac(PktInfo *pkt_info) {
525 78 : pkt_info->tunnel.eth = pkt_info->eth;
526 78 : }
527 :
528 :
529 93 : int PktHandler::ParseEthernetHeader(PktInfo *pkt_info, uint8_t *pkt) {
530 93 : int len = 0;
531 93 : pkt_info->eth = (struct ether_header *) (pkt + len);
532 93 : pkt_info->smac = MacAddress(pkt_info->eth->ether_shost);
533 93 : pkt_info->dmac = MacAddress(pkt_info->eth->ether_dhost);
534 93 : pkt_info->ether_type = ntohs(pkt_info->eth->ether_type);
535 93 : len += sizeof(struct ether_header);
536 :
537 : //strip service vlan and customer vlan in packet
538 93 : while (pkt_info->ether_type == ETHERTYPE_VLAN ||
539 93 : pkt_info->ether_type == ETHERTYPE_QINQ) {
540 0 : pkt_info->ether_type = ntohs(*((uint16_t *)(pkt + len + 2)));
541 0 : len += VLAN_HDR_LEN;
542 : }
543 :
544 93 : if (pkt_info->ether_type == ETHERTYPE_PBB) {
545 : //Parse inner payload
546 0 : pkt_info->pbb_header = (uint32_t *)(pkt + len);
547 0 : pkt_info->b_smac = pkt_info->smac;
548 0 : pkt_info->b_dmac = pkt_info->dmac;
549 0 : pkt_info->i_sid = ntohl(*(pkt_info->pbb_header)) & 0x00FFFFFF;
550 0 : len += ParseEthernetHeader(pkt_info, pkt + len + PBB_HEADER_LEN);
551 : }
552 :
553 93 : return len;
554 : }
555 :
556 131 : int PktHandler::ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type,
557 : uint8_t *pkt) {
558 131 : int len = 0;
559 131 : uint16_t ip_payload_len = 0;
560 131 : if (pkt_info->ether_type == ETHERTYPE_IP) {
561 131 : struct ip *ip = (struct ip *)(pkt + len);
562 131 : pkt_info->ip = ip;
563 131 : pkt_info->family = Address::INET;
564 131 : pkt_info->ip_saddr = IpAddress(Ip4Address(ntohl(ip->ip_src.s_addr)));
565 131 : pkt_info->ip_daddr = IpAddress(Ip4Address(ntohl(ip->ip_dst.s_addr)));
566 131 : pkt_info->ip_proto = ip->ip_p;
567 131 : pkt_info->ttl = ip->ip_ttl;
568 131 : uint8_t ip_header_len = (ip->ip_hl << 2);
569 131 : ip_payload_len = ip->ip_len - ip_header_len;
570 131 : len += ip_header_len;
571 0 : } else if (pkt_info->ether_type == ETHERTYPE_IPV6) {
572 0 : pkt_info->family = Address::INET6;
573 0 : ip6_hdr *ip = (ip6_hdr *)(pkt + len);
574 0 : pkt_info->ip6 = ip;
575 0 : pkt_info->ip = NULL;
576 : Ip6Address::bytes_type addr;
577 :
578 0 : for (int i = 0; i < 16; i++) {
579 0 : addr[i] = ip->ip6_src.s6_addr[i];
580 : }
581 0 : pkt_info->ip_saddr = IpAddress(Ip6Address(addr));
582 :
583 0 : for (int i = 0; i < 16; i++) {
584 0 : addr[i] = ip->ip6_dst.s6_addr[i];
585 : }
586 0 : pkt_info->ip_daddr = IpAddress(Ip6Address(addr));
587 0 : pkt_info->ttl = ip->ip6_hlim;
588 :
589 0 : uint8_t proto = ip->ip6_ctlun.ip6_un1.ip6_un1_nxt;
590 0 : len += sizeof(ip6_hdr);
591 0 : if (proto == IPPROTO_FRAGMENT) {
592 0 : ip6_frag *nxt = (ip6_frag *)(pkt + len);
593 0 : proto = nxt->ip6f_nxt;
594 0 : len += sizeof(ip6_frag);
595 : }
596 :
597 0 : pkt_info->ip_proto = proto;
598 : } else {
599 0 : LOG(ERROR,
600 : "Error EthType = Non IP/IPv6. BackTrace: " << AgentBackTrace(1));
601 0 : agent_->stats()->incr_pkt_drop_due_to_invalid_ethertype();
602 0 : return -1;
603 : }
604 :
605 131 : switch (pkt_info->ip_proto) {
606 61 : case IPPROTO_UDP : {
607 61 : pkt_info->transp.udp = (udphdr *) (pkt + len);
608 61 : len += sizeof(udphdr);
609 61 : pkt_info->data = (pkt + len);
610 :
611 61 : pkt_info->dport = ntohs(pkt_info->transp.udp->uh_dport);
612 61 : pkt_info->sport = ntohs(pkt_info->transp.udp->uh_sport);
613 61 : pkt_type = PktType::UDP;
614 61 : break;
615 : }
616 :
617 2 : case IPPROTO_TCP : {
618 2 : pkt_info->transp.tcp = (tcphdr *) (pkt + len);
619 2 : len += sizeof(tcphdr);
620 2 : pkt_info->data = (pkt + len);
621 :
622 2 : pkt_info->dport = ntohs(pkt_info->transp.tcp->th_dport);
623 2 : pkt_info->sport = ntohs(pkt_info->transp.tcp->th_sport);
624 2 : pkt_info->tcp_ack = pkt_info->transp.tcp->th_flags & TH_ACK;
625 2 : pkt_type = PktType::TCP;
626 2 : break;
627 : }
628 :
629 0 : case IPPROTO_SCTP : {
630 0 : pkt_info->transp.sctp = (sctphdr *) (pkt + len);
631 0 : len += sizeof(sctphdr);
632 0 : pkt_info->data = (pkt + len);
633 0 : pkt_info->dport = ntohs(pkt_info->transp.sctp->th_dport);
634 0 : pkt_info->sport = ntohs(pkt_info->transp.sctp->th_sport);
635 0 : pkt_type = PktType::SCTP;
636 0 : break;
637 : }
638 :
639 19 : case IPPROTO_ICMP: {
640 19 : pkt_info->transp.icmp = (struct icmp *) (pkt + len);
641 19 : pkt_type = PktType::ICMP;
642 :
643 19 : struct icmp *icmp = (struct icmp *)(pkt + len);
644 19 : pkt_info->icmp_chksum = icmp->icmp_cksum;
645 19 : pkt_info->dport = htons(icmp->icmp_type);
646 19 : if (icmp->icmp_type == ICMP_ECHO || icmp->icmp_type == ICMP_ECHOREPLY) {
647 19 : pkt_info->dport = ICMP_ECHOREPLY;
648 19 : pkt_info->sport = htons(icmp->icmp_id);
649 19 : pkt_info->data = (pkt + len + ICMP_MINLEN);
650 19 : uint16_t icmp_payload_len = ip_payload_len - ICMP_MINLEN;
651 19 : if (icmp_payload_len >= sizeof(AgentDiagPktData)) {
652 19 : AgentDiagPktData *ad = (AgentDiagPktData *)pkt_info->data;
653 19 : string value(ad->data_, (sizeof(ad->data_) - 1));
654 19 : if (value.compare(0, (sizeof(ad->data_) - 1),
655 19 : DiagTable::kDiagData) == 0) {
656 0 : pkt_info->is_segment_hc_pkt = true;
657 : }
658 19 : }
659 19 : } else if (IsFlowPacket(pkt_info) &&
660 0 : ((icmp->icmp_type == ICMP_DEST_UNREACH) ||
661 0 : (icmp->icmp_type == ICMP_TIME_EXCEEDED))) {
662 : //Agent has to look at inner payload
663 : //and recalculate the parameter
664 : //Handle this only for packets requiring flow miss
665 0 : if(ParseIpPacket(pkt_info, pkt_type, pkt + len + sizeof(icmp)) == -1) {
666 0 : return -1;
667 : }
668 : //Swap the key parameter, which would be used as key
669 0 : IpAddress src_ip = pkt_info->ip_saddr;
670 0 : pkt_info->ip_saddr = pkt_info->ip_daddr;
671 0 : pkt_info->ip_daddr = src_ip;
672 0 : if (pkt_info->ip_proto != IPPROTO_ICMP) {
673 0 : uint16_t port = pkt_info->sport;
674 0 : pkt_info->sport = pkt_info->dport;
675 0 : pkt_info->dport = port;
676 : }
677 : } else {
678 0 : pkt_info->sport = 0;
679 : }
680 19 : break;
681 : }
682 :
683 0 : case IPPROTO_ICMPV6: {
684 0 : pkt_type = PktType::ICMPV6;
685 0 : icmp6_hdr *icmp = (icmp6_hdr *)(pkt + len);
686 0 : pkt_info->transp.icmp6 = icmp;
687 :
688 0 : pkt_info->dport = htons(icmp->icmp6_type);
689 0 : if (icmp->icmp6_type == ICMP6_ECHO_REQUEST ||
690 0 : icmp->icmp6_type == ICMP6_ECHO_REPLY) {
691 0 : pkt_info->dport = ICMP6_ECHO_REPLY;
692 0 : pkt_info->sport = htons(icmp->icmp6_id);
693 0 : } else if (IsFlowPacket(pkt_info) &&
694 0 : icmp->icmp6_type < ICMP6_ECHO_REQUEST) {
695 : //Agent has to look at inner payload
696 : //and recalculate the parameter
697 : //Handle this only for packets requiring flow miss
698 0 : if(ParseIpPacket(pkt_info, pkt_type, pkt + len + sizeof(icmp)) == -1) {
699 0 : return -1;
700 : }
701 : //Swap the key parameter, which would be used as key
702 0 : IpAddress src_ip = pkt_info->ip_saddr;
703 0 : pkt_info->ip_saddr = pkt_info->ip_daddr;
704 0 : pkt_info->ip_daddr = src_ip;
705 0 : if (pkt_info->ip_proto != IPPROTO_ICMPV6) {
706 0 : uint16_t port = pkt_info->sport;
707 0 : pkt_info->sport = pkt_info->dport;
708 0 : pkt_info->dport = port;
709 : }
710 : } else {
711 0 : pkt_info->sport = 0;
712 : }
713 0 : break;
714 : }
715 :
716 0 : case IPPROTO_IGMP: {
717 0 : pkt_info->transp.igmp = (struct igmp *) (pkt + len);
718 0 : pkt_type = PktType::IGMP;
719 :
720 0 : pkt_info->dport = 0;
721 0 : pkt_info->sport = 0;
722 0 : pkt_info->data = (pkt + len);
723 0 : break;
724 : }
725 :
726 49 : default: {
727 49 : pkt_type = PktType::IP;
728 49 : pkt_info->dport = 0;
729 49 : pkt_info->sport = 0;
730 49 : break;
731 : }
732 : }
733 :
734 131 : return len;
735 : }
736 :
737 49 : int PktHandler::ParseControlWord(PktInfo *pkt_info, uint8_t *pkt,
738 : const MplsLabel *mpls) {
739 49 : uint32_t ret = 0;
740 49 : if (mpls->IsFabricMulticastReservedLabel() == true) {
741 : //Check if there is a control word
742 0 : uint32_t *control_word = (uint32_t *)(pkt);
743 0 : if (*control_word == kMulticastControlWord) {
744 0 : pkt_info->l3_label = false;
745 0 : ret += kMulticastControlWordSize + sizeof(VxlanHdr) +
746 : sizeof(udphdr) + sizeof(ip);
747 : }
748 49 : } else if (pkt_info->l3_label == false) {
749 7 : bool layer2_control_word = false;
750 : const InterfaceNH *intf_nh =
751 7 : dynamic_cast<const InterfaceNH *>(mpls->nexthop());
752 7 : if (intf_nh && intf_nh->layer2_control_word()) {
753 0 : layer2_control_word = true;
754 : }
755 :
756 : const CompositeNH *comp_nh =
757 7 : dynamic_cast<const CompositeNH *>(mpls->nexthop());
758 7 : if (comp_nh && comp_nh->layer2_control_word()) {
759 0 : layer2_control_word = true;
760 : }
761 :
762 : const VrfNH *vrf_nh =
763 7 : dynamic_cast<const VrfNH *>(mpls->nexthop());
764 7 : if (vrf_nh && vrf_nh->layer2_control_word()) {
765 0 : layer2_control_word = true;
766 : }
767 :
768 : //Check if there is a control word
769 7 : uint32_t *control_word = (uint32_t *)(pkt);
770 7 : if (layer2_control_word && *control_word == kMulticastControlWord) {
771 0 : ret += kMulticastControlWordSize;
772 : }
773 : }
774 :
775 49 : return ret;
776 : }
777 :
778 49 : int PktHandler::ParseMplsHdr(PktInfo *pkt_info, uint8_t *pkt) {
779 49 : MplsHdr *hdr = (MplsHdr *)(pkt);
780 :
781 : // MPLS Header validation. Check for,
782 : // - There is single label
783 49 : uint32_t mpls_host = ntohl(hdr->hdr);
784 49 : pkt_info->tunnel.label = (mpls_host & 0xFFFFF000) >> 12;
785 49 : uint32_t ret = sizeof(MplsHdr);
786 :
787 49 : if ((mpls_host & 0x100) == 0) {
788 : // interpret outer label 0xffffff as no label
789 0 : if (((mpls_host & 0xFFFFF000) >> 12) !=
790 : MplsTable::kInvalidLabel) {
791 0 : pkt_info->tunnel.label = MplsTable::kInvalidLabel;
792 0 : PKT_TRACE(Err, "Unexpected MPLS Label Stack. Ignoring");
793 0 : return -1;
794 : }
795 0 : hdr = (MplsHdr *) (pkt + 4);
796 0 : mpls_host = ntohl(hdr->hdr);
797 0 : pkt_info->tunnel.label = (mpls_host & 0xFFFFF000) >> 12;
798 0 : if ((mpls_host & 0x100) == 0) {
799 0 : pkt_info->tunnel.label = MplsTable::kInvalidLabel;
800 0 : PKT_TRACE(Err, "Unexpected MPLS Label Stack. Ignoring");
801 0 : return -1;
802 : }
803 0 : ret += sizeof(MplsHdr);
804 :
805 : }
806 :
807 49 : uint32_t label = pkt_info->tunnel.label;
808 49 : MplsLabelKey mpls_key(label);
809 :
810 49 : const MplsLabel *mpls = static_cast<const MplsLabel *>(
811 49 : agent_->mpls_table()->FindActiveEntry(&mpls_key));
812 49 : if (mpls == NULL) {
813 0 : PKT_TRACE(Err, "Invalid MPLS Label <" << label << ">. Ignoring");
814 0 : pkt_info->tunnel.label = MplsTable::kInvalidLabel;
815 0 : return -1;
816 : }
817 :
818 49 : pkt_info->l3_label = true;
819 49 : const InterfaceNH *nh = dynamic_cast<const InterfaceNH *>(mpls->nexthop());
820 49 : if (nh && nh->IsBridge()) {
821 7 : pkt_info->l3_label = false;
822 : }
823 :
824 49 : const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(mpls->nexthop());
825 49 : if (cnh && cnh->composite_nh_type() != Composite::LOCAL_ECMP) {
826 0 : pkt_info->l3_label = false;
827 : }
828 :
829 49 : const VrfNH *vrf_nh = dynamic_cast<const VrfNH *>(mpls->nexthop());
830 49 : if (vrf_nh && vrf_nh->bridge_nh() == true) {
831 0 : pkt_info->l3_label = false;
832 : }
833 :
834 49 : ret += ParseControlWord(pkt_info, pkt + ret, mpls);
835 49 : return ret;
836 49 : }
837 :
838 : // Parse MPLSoGRE header
839 49 : int PktHandler::ParseMPLSoGRE(PktInfo *pkt_info, uint8_t *pkt) {
840 49 : GreHdr *gre = (GreHdr *)(pkt);
841 49 : if (gre->protocol != ntohs(VR_GRE_PROTO_MPLS)) {
842 0 : PKT_TRACE(Err, "Non-MPLS protocol <" << ntohs(gre->protocol) <<
843 : "> in GRE header");
844 0 : return -1;
845 : }
846 :
847 49 : int len = sizeof(GreHdr);
848 :
849 : int tmp;
850 49 : tmp = ParseMplsHdr(pkt_info, (pkt + len));
851 49 : if (tmp < 0) {
852 0 : return tmp;
853 : }
854 49 : len += tmp;
855 :
856 49 : if (pkt_info->l3_label == false) {
857 7 : tmp = ParseEthernetHeader(pkt_info, (pkt + len));
858 7 : if (tmp < 0)
859 0 : return tmp;
860 7 : len += tmp;
861 : }
862 :
863 49 : pkt_info->tunnel.type.SetType(TunnelType::MPLS_GRE);
864 49 : return (len);
865 : }
866 :
867 0 : int PktHandler::ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt) {
868 0 : int len = ParseMplsHdr(pkt_info, pkt);
869 0 : if (len < 0) {
870 0 : return len;
871 : }
872 :
873 0 : if (pkt_info->l3_label == false) {
874 0 : len += ParseEthernetHeader(pkt_info, (pkt + len));
875 : }
876 :
877 0 : pkt_info->tunnel.type.SetType(TunnelType::MPLS_UDP);
878 0 : return len;
879 : }
880 :
881 4 : int PktHandler::ParseVxlan(PktInfo *pkt_info, uint8_t *pkt) {
882 4 : VxlanHdr *vxlan = (VxlanHdr *)(pkt);
883 4 : pkt_info->tunnel.vxlan_id = htonl(vxlan->vxlan_id) >> 8;
884 :
885 4 : int len = sizeof(vxlan);
886 4 : len += ParseEthernetHeader(pkt_info, (pkt + len));
887 :
888 4 : pkt_info->tunnel.type.SetType(TunnelType::VXLAN);
889 4 : pkt_info->l3_label = false;
890 4 : return len;
891 : }
892 :
893 4 : int PktHandler::ParseUDPTunnels(PktInfo *pkt_info, uint8_t *pkt) {
894 4 : int len = 0;
895 4 : if (pkt_info->dport == VXLAN_UDP_DEST_PORT)
896 4 : len = ParseVxlan(pkt_info, (pkt + len));
897 0 : else if (pkt_info->dport == MPLS_OVER_UDP_DEST_PORT ||
898 0 : pkt_info->dport == IANA_MPLS_OVER_UDP_DEST_PORT)
899 0 : len = ParseMPLSoUDP(pkt_info, (pkt + len));
900 :
901 4 : return len;
902 : }
903 :
904 131 : bool PktHandler::ValidateIpPacket(PktInfo *pkt_info) {
905 : // For ICMP, IGMP, make sure IP is IPv4, else fail the parsing
906 : // so that we don't go ahead and access the ip header later
907 131 : if (((pkt_info->ip_proto == IPPROTO_ICMP) ||
908 131 : (pkt_info->ip_proto == IPPROTO_IGMP)) && (!pkt_info->ip)) {
909 0 : return false;
910 : }
911 : // If ip proto is ICMPv6, then make sure IP is IPv6, else fail
912 : // the parsing so that we don't go ahead and access the ip6 header
913 : // later
914 131 : if ((pkt_info->ip_proto == IPPROTO_ICMPV6) && (!pkt_info->ip6)) {
915 0 : return false;
916 : }
917 131 : return true;
918 : }
919 :
920 78 : int PktHandler::ParseUserPkt(PktInfo *pkt_info, Interface *intf,
921 : PktType::Type &pkt_type, uint8_t *pkt) {
922 78 : int len = 0, ret = 0;
923 : bool pkt_ok;
924 :
925 : // get to the actual packet header
926 78 : len += ParseEthernetHeader(pkt_info, (pkt + len));
927 :
928 : // Parse payload
929 78 : if (pkt_info->ether_type == ETHERTYPE_ARP) {
930 0 : pkt_info->arp = (ether_arp *) (pkt + len);
931 0 : pkt_type = PktType::ARP;
932 : union {
933 : uint8_t data[sizeof(in_addr_t)];
934 : in_addr_t addr;
935 : } bytes;
936 0 : memcpy(bytes.data, pkt_info->arp->arp_spa, sizeof(in_addr_t));
937 0 : in_addr_t spa = ntohl(bytes.addr);
938 0 : pkt_info->ip_saddr = IpAddress(Ip4Address(spa));
939 0 : return len;
940 : }
941 :
942 : // Identify NON-IP Packets
943 78 : if (pkt_info->ether_type != ETHERTYPE_IP &&
944 0 : pkt_info->ether_type != ETHERTYPE_IPV6) {
945 0 : pkt_info->data = (pkt + len);
946 0 : pkt_type = PktType::NON_IP;
947 0 : return len;
948 : }
949 : // Copy IP fields from outer header assuming tunnel is present. If tunnel
950 : // is not present, the values here will be ignored
951 78 : SetOuterMac(pkt_info);
952 78 : SetOuterIp(pkt_info, (pkt + len));
953 :
954 : // IP Packets
955 78 : ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
956 78 : if(ret == -1) {
957 0 : return -1;
958 : }
959 78 : len += ret;
960 :
961 78 : if (!ValidateIpPacket(pkt_info)) {
962 0 : agent_->stats()->incr_pkt_invalid_ip_pkt();
963 0 : return -1;
964 : }
965 :
966 : // If packet is an IP fragment and not flow trap, ignore it
967 78 : if (IgnoreFragmentedPacket(pkt_info)) {
968 0 : agent_->stats()->incr_pkt_fragments_dropped();
969 0 : return -1;
970 : }
971 :
972 : // If it is a packet from TOR that we serve, dont parse any further
973 78 : if (IsManagedTORPacket(intf, pkt_info, pkt_type, (pkt + len), &pkt_ok)) {
974 0 : return len;
975 78 : } else if (!pkt_ok) {
976 : // invalid pkt received from tor
977 0 : agent_->stats()->incr_pkt_invalid_frm_tor();
978 0 : return -1;
979 : }
980 :
981 78 : if (IsDiagPacket(pkt_info) &&
982 0 : (pkt_info->agent_hdr.cmd != AgentHdr::TRAP_ROUTER_ALERT)) {
983 0 : return len;
984 : }
985 :
986 : // If tunneling is not enabled on interface or if it is a DHCP packet,
987 : // dont parse any further
988 : // if (intf->IsTunnelEnabled() == false || IsDHCPPacket(pkt_info)) {
989 78 : if (intf->IsTunnelEnabled() == false) {
990 25 : agent_->stats()->incr_pkt_drop_due_to_disable_tnl();
991 25 : return len;
992 : }
993 53 : else if (IsDHCPPacket(pkt_info)) {
994 0 : return len;
995 : }
996 :
997 53 : int tunnel_len = 0;
998 : // Do tunnel processing only if IP-DA is ours
999 106 : if (pkt_info->family == Address::INET &&
1000 106 : pkt_info->ip_daddr.to_v4() == agent_->router_id()) {
1001 : // Look for supported headers
1002 53 : switch (pkt_info->ip_proto) {
1003 49 : case IPPROTO_GRE :
1004 : // Parse MPLSoGRE tunnel
1005 49 : tunnel_len = ParseMPLSoGRE(pkt_info, (pkt + len));
1006 49 : break;
1007 :
1008 4 : case IPPROTO_UDP:
1009 : // Parse MPLSoUDP tunnel
1010 4 : tunnel_len = ParseUDPTunnels(pkt_info, (pkt + len));
1011 4 : break;
1012 :
1013 0 : default:
1014 0 : break;
1015 : }
1016 : }
1017 :
1018 53 : if (tunnel_len < 0) {
1019 : // Found tunnel packet, but error in decoding
1020 0 : pkt_type = PktType::INVALID;
1021 0 : agent_->stats()->incr_pkt_drop_due_to_decode_error();
1022 0 : return tunnel_len;
1023 : }
1024 :
1025 53 : if (tunnel_len == 0) {
1026 0 : return len;
1027 : }
1028 :
1029 53 : len += tunnel_len;
1030 :
1031 : // Find IPv4/IPv6 Packet based on first nibble in payload
1032 53 : if (((pkt + len)[0] & 0x60) == 0x60) {
1033 0 : pkt_info->ether_type = ETHERTYPE_IPV6;
1034 : } else {
1035 53 : pkt_info->ether_type = ETHERTYPE_IP;
1036 : }
1037 :
1038 :
1039 53 : ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
1040 53 : if(ret == -1) {
1041 0 : return -1;
1042 : }
1043 53 : len += ret;
1044 :
1045 : // validate inner iphdr
1046 53 : if (!ValidateIpPacket(pkt_info)) {
1047 0 : agent_->stats()->incr_pkt_invalid_ip_pkt();
1048 0 : return -1;
1049 : }
1050 :
1051 53 : return len;
1052 : }
1053 :
1054 : // Enqueue an inter-task message to the specified module
1055 1074 : void PktHandler::SendMessage(PktModuleName mod, InterTaskMsg *msg) {
1056 1074 : if (mod < MAX_MODULES) {
1057 1074 : boost::shared_ptr<PktInfo> pkt_info(new PktInfo(mod, msg));
1058 1074 : if (!(proto_list_.at(mod)->Enqueue(pkt_info))) {
1059 0 : PKT_TRACE(Err, "Threshold exceeded while enqueuing IPC Message <" <<
1060 : mod << ">");
1061 : }
1062 1074 : }
1063 1074 : }
1064 :
1065 78 : bool PktHandler::IgnoreFragmentedPacket(PktInfo *pkt_info) {
1066 78 : if (pkt_info->ip) {
1067 78 : uint16_t offset = htons(pkt_info->ip->ip_off);
1068 78 : if (((offset & IP_MF) || (offset & IP_OFFMASK)) &&
1069 0 : !IsFlowPacket(pkt_info))
1070 0 : return true;
1071 0 : } else if (pkt_info->ip6) {
1072 0 : uint8_t proto = pkt_info->ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
1073 0 : if (proto == IPPROTO_FRAGMENT) {
1074 0 : if (IsFlowPacket(pkt_info) ||
1075 0 : pkt_info->agent_hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
1076 0 : return false;
1077 : } else {
1078 0 : return true;
1079 : }
1080 : }
1081 : }
1082 :
1083 78 : return false;
1084 : }
1085 :
1086 53 : bool PktHandler::IsDHCPPacket(PktInfo *pkt_info) {
1087 : // Do not consider source port in case we are looking at UDP tunnel header
1088 53 : if (pkt_info->dport == VXLAN_UDP_DEST_PORT ||
1089 49 : pkt_info->dport == MPLS_OVER_UDP_DEST_PORT ||
1090 49 : pkt_info->dport == IANA_MPLS_OVER_UDP_DEST_PORT) {
1091 4 : return false;
1092 : }
1093 :
1094 49 : if (pkt_info->dport == DHCP_SERVER_PORT ||
1095 49 : pkt_info->sport == DHCP_CLIENT_PORT) {
1096 : // we dont handle DHCPv6 coming from fabric
1097 0 : return true;
1098 : }
1099 49 : return false;
1100 : }
1101 :
1102 1 : bool PktHandler::IsToRDevice(uint32_t vrf_id, const IpAddress &ip) {
1103 1 : if (agent()->tsn_enabled() == false)
1104 1 : return false;
1105 :
1106 0 : if (ip.is_v4() == false)
1107 0 : return false;
1108 0 : Ip4Address ip4 = ip.to_v4();
1109 :
1110 0 : VrfEntry *vrf = agent()->vrf_table()->FindVrfFromId(vrf_id);
1111 0 : if (vrf == NULL)
1112 0 : return false;
1113 :
1114 : BridgeAgentRouteTable *table = static_cast<BridgeAgentRouteTable *>
1115 0 : (vrf->GetBridgeRouteTable());
1116 0 : if (table == NULL)
1117 0 : return false;
1118 :
1119 0 : BridgeRouteEntry *rt = table->FindRoute(MacAddress::BroadcastMac());
1120 0 : if (rt == NULL)
1121 0 : return false;
1122 :
1123 0 : const CompositeNH *nh = dynamic_cast<const CompositeNH *>
1124 0 : (rt->GetActiveNextHop());
1125 0 : if (nh == NULL)
1126 0 : return false;
1127 :
1128 0 : ComponentNHList::const_iterator it = nh->begin();
1129 0 : while (it != nh->end()) {
1130 0 : const CompositeNH *tor_nh = dynamic_cast<const CompositeNH *>
1131 0 : ((*it)->nh());
1132 0 : if (tor_nh == NULL) {
1133 0 : it++;
1134 0 : continue;
1135 : }
1136 :
1137 0 : if (tor_nh->composite_nh_type() != Composite::TOR &&
1138 0 : tor_nh->composite_nh_type() != Composite::EVPN) {
1139 0 : it++;
1140 0 : continue;
1141 : }
1142 :
1143 0 : ComponentNHList::const_iterator tor_it = tor_nh->begin();
1144 0 : while (tor_it != tor_nh->end()) {
1145 0 : const TunnelNH *tun_nh = dynamic_cast<const TunnelNH *>
1146 0 : ((*tor_it)->nh());
1147 0 : if (tun_nh == NULL) {
1148 0 : tor_it++;
1149 0 : continue;
1150 : }
1151 0 : if (*tun_nh->GetDip() == ip4) {
1152 0 : return true;
1153 : }
1154 0 : tor_it++;
1155 : }
1156 :
1157 0 : it++;
1158 : }
1159 :
1160 0 : return false;
1161 : }
1162 :
1163 : // We can receive DHCP / DNS packets on physical port from TOR ports managed
1164 : // by a TOR services node. Check if the source mac is the mac address of a
1165 : // VM interface available in the node.
1166 78 : bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info,
1167 : PktType::Type &pkt_type, uint8_t *pkt, bool *pkt_ok) {
1168 78 : *pkt_ok = true;
1169 78 : if (intf->type() != Interface::PHYSICAL) {
1170 25 : return false;
1171 : }
1172 :
1173 53 : if (pkt_type != PktType::UDP || pkt_info->dport != VXLAN_UDP_DEST_PORT)
1174 49 : return false;
1175 :
1176 : // Get VXLAN id and point to original L2 frame after the VXLAN header
1177 4 : pkt += 8;
1178 :
1179 : // get to the actual packet header
1180 4 : pkt += ParseEthernetHeader(pkt_info, pkt);
1181 :
1182 : ether_addr addr;
1183 4 : memcpy(addr.ether_addr_octet, pkt_info->eth->ether_shost, ETH_ALEN);
1184 4 : MacAddress address(addr);
1185 4 : const VrfEntry *vrf = agent_->vrf_table()->
1186 4 : FindVrfFromId(pkt_info->agent_hdr.vrf);
1187 4 : if (vrf == NULL)
1188 0 : return false;
1189 : BridgeAgentRouteTable *bridge_table =
1190 4 : dynamic_cast<BridgeAgentRouteTable *>(vrf->GetBridgeRouteTable());
1191 4 : if(bridge_table == NULL) {
1192 0 : LOG(ERROR,
1193 : "Error bridge_table == NULL. BackTrace: " << AgentBackTrace(1));
1194 0 : _Exit(0);
1195 : }
1196 4 : const VmInterface *vm_intf = bridge_table->FindVmFromDhcpBinding(address);
1197 4 : if (vm_intf == NULL) {
1198 3 : return false;
1199 : }
1200 :
1201 1 : if (IsToRDevice(vm_intf->vrf_id(), pkt_info->ip_saddr) == false) {
1202 1 : return false;
1203 : }
1204 :
1205 : // update agent_hdr to reflect the VM interface data
1206 : // cmd_param is set to physical interface id
1207 0 : pkt_info->agent_hdr.cmd = AgentHdr::TRAP_TOR_CONTROL_PKT;
1208 0 : pkt_info->agent_hdr.cmd_param = pkt_info->agent_hdr.ifindex;
1209 0 : pkt_info->agent_hdr.ifindex = vm_intf->id();
1210 :
1211 : // Parse payload
1212 0 : if (pkt_info->ether_type == ETHERTYPE_ARP) {
1213 0 : pkt_info->arp = (ether_arp *) pkt;
1214 0 : pkt_type = PktType::ARP;
1215 0 : return true;
1216 : }
1217 :
1218 : // Identify NON-IP Packets
1219 0 : if (pkt_info->ether_type != ETHERTYPE_IP &&
1220 0 : pkt_info->ether_type != ETHERTYPE_IPV6) {
1221 0 : pkt_info->data = pkt;
1222 0 : pkt_type = PktType::NON_IP;
1223 0 : return true;
1224 : }
1225 :
1226 : // IP Packets
1227 0 : if(ParseIpPacket(pkt_info, pkt_type, pkt) == -1) {
1228 0 : *pkt_ok = false; //Don't process any further
1229 0 : return false;
1230 : }
1231 0 : if (!ValidateIpPacket(pkt_info)) {
1232 0 : *pkt_ok = false;
1233 0 : return false;
1234 : }
1235 0 : return true;
1236 : }
1237 :
1238 78 : bool PktHandler::IsFlowPacket(PktInfo *pkt_info) {
1239 78 : if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS ||
1240 0 : pkt_info->agent_hdr.cmd == AgentHdr::TRAP_FLOW_ACTION_HOLD) {
1241 78 : return true;
1242 : }
1243 0 : return false;
1244 : }
1245 :
1246 0 : bool PktHandler::IsFlowPacket(const AgentHdr &agent_hdr) {
1247 0 : if (agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS ||
1248 0 : agent_hdr.cmd == AgentHdr::TRAP_FLOW_ACTION_HOLD) {
1249 0 : return true;
1250 : }
1251 0 : return false;
1252 : }
1253 :
1254 78 : bool PktHandler::IsDiagPacket(PktInfo *pkt_info) {
1255 78 : if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ZERO_TTL ||
1256 78 : pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ICMP_ERROR
1257 78 : || pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ROUTER_ALERT)
1258 0 : return true;
1259 78 : return false;
1260 : }
1261 :
1262 : // Check if the packet is destined to the VM's default GW
1263 6 : bool PktHandler::IsGwPacket(const Interface *intf, const IpAddress &dst_ip) {
1264 6 : if (!intf || intf->type() != Interface::VM_INTERFACE)
1265 0 : return false;
1266 :
1267 6 : const VmInterface *vm_intf = static_cast<const VmInterface *>(intf);
1268 6 : if (vm_intf->vmi_type() != VmInterface::GATEWAY) {
1269 : //Gateway interface doesnt have IP address
1270 6 : if (dst_ip.is_v6() && vm_intf->primary_ip6_addr().is_unspecified())
1271 0 : return false;
1272 6 : else if (dst_ip.is_v4() && vm_intf->primary_ip_addr().is_unspecified())
1273 0 : return false;
1274 : }
1275 6 : const VnEntry *vn = vm_intf->vn();
1276 6 : if (vn) {
1277 6 : const std::vector<VnIpam> &ipam = vn->GetVnIpam();
1278 18 : for (unsigned int i = 0; i < ipam.size(); ++i) {
1279 12 : if (dst_ip.is_v4()) {
1280 12 : if (!ipam[i].IsV4()) {
1281 0 : continue;
1282 : }
1283 24 : if (ipam[i].default_gw == dst_ip ||
1284 12 : ipam[i].dns_server == dst_ip) {
1285 0 : return true;
1286 : }
1287 : } else {
1288 0 : if (!ipam[i].IsV6()) {
1289 0 : continue;
1290 : }
1291 0 : if (ipam[i].default_gw == dst_ip ||
1292 0 : ipam[i].dns_server == dst_ip) {
1293 0 : return true;
1294 : }
1295 : }
1296 :
1297 : }
1298 : }
1299 :
1300 6 : return false;
1301 : }
1302 :
1303 78 : bool PktHandler::IsValidInterface(uint32_t ifindex, Interface **intrface) {
1304 78 : Interface *intf = agent_->interface_table()->FindInterface(ifindex);
1305 78 : if (intf == NULL) {
1306 0 : PKT_TRACE(Err, "Invalid interface index <" << ifindex << ">");
1307 0 : agent_->stats()->incr_pkt_invalid_interface();
1308 0 : return false;
1309 : }
1310 :
1311 78 : *intrface = intf;
1312 78 : return true;
1313 : }
1314 :
1315 0 : void PktHandler::PktTraceIterate(PktModuleName mod, PktTraceCallback cb) {
1316 0 : if (!cb.empty()) {
1317 0 : PktTrace &pkt(pkt_trace_.at(mod));
1318 0 : pkt.Iterate(cb);
1319 : }
1320 0 : }
1321 :
1322 75 : void PktHandler::PktStats::PktRcvd(PktModuleName mod) {
1323 75 : if (mod < MAX_MODULES)
1324 75 : received[mod]++;
1325 75 : }
1326 :
1327 2204 : void PktHandler::PktStats::PktSent(PktModuleName mod) {
1328 2204 : if (mod < MAX_MODULES)
1329 2204 : sent[mod]++;
1330 2204 : }
1331 :
1332 0 : void PktHandler::PktStats::PktQThresholdExceeded(PktModuleName mod) {
1333 0 : if (mod < MAX_MODULES)
1334 0 : q_threshold_exceeded[mod]++;
1335 0 : }
1336 :
1337 : ///////////////////////////////////////////////////////////////////////////////
1338 :
1339 78 : PktInfo::PktInfo(const PacketBufferPtr &buff) :
1340 78 : module(PktHandler::INVALID),
1341 78 : pkt(buff->data()), len(buff->data_len()), max_pkt_len(buff->buffer_len()),
1342 78 : data(), ipc(), family(Address::UNSPEC), type(PktType::INVALID), agent_hdr(),
1343 78 : ether_type(-1), ip_saddr(), ip_daddr(), ip_proto(), sport(), dport(),
1344 78 : ttl(0), icmp_chksum(0), tcp_ack(false), tunnel(),
1345 78 : l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
1346 78 : ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
1347 78 : is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
1348 78 : is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
1349 312 : eth(), arp(), ip(), ip6(), packet_buffer_(buff) {
1350 78 : transp.tcp = 0;
1351 78 : }
1352 :
1353 0 : PktInfo::PktInfo(const PacketBufferPtr &buff, const AgentHdr &hdr) :
1354 0 : pkt(buff->data()), len(buff->data_len()), max_pkt_len(buff->buffer_len()),
1355 0 : data(), ipc(), family(Address::UNSPEC), type(PktType::INVALID),
1356 0 : agent_hdr(hdr), ether_type(-1), ip_saddr(), ip_daddr(), ip_proto(), sport(),
1357 0 : dport(), ttl(0), icmp_chksum(0), tcp_ack(false), tunnel(),
1358 0 : l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
1359 0 : ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
1360 0 : is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
1361 0 : is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
1362 0 : eth(), arp(), ip(), ip6(), packet_buffer_(buff) {
1363 0 : transp.tcp = 0;
1364 0 : }
1365 :
1366 2432 : PktInfo::PktInfo(Agent *agent, uint32_t buff_len, PktHandler::PktModuleName mod,
1367 2432 : uint32_t mdata) :
1368 2432 : module(mod),
1369 2432 : len(), max_pkt_len(), data(), ipc(), family(Address::UNSPEC),
1370 2432 : type(PktType::INVALID), agent_hdr(), ether_type(-1), ip_saddr(), ip_daddr(),
1371 4864 : ip_proto(), sport(), dport(), ttl(0), icmp_chksum(0), tcp_ack(false),
1372 2432 : tunnel(), l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
1373 2432 : ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
1374 2432 : is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
1375 2432 : is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
1376 7296 : eth(),arp(), ip(), ip6() {
1377 :
1378 : packet_buffer_ = agent->pkt()->packet_buffer_manager()->Allocate
1379 2432 : (module, buff_len, mdata);
1380 2432 : pkt = packet_buffer_->data();
1381 2432 : len = packet_buffer_->data_len();
1382 2432 : max_pkt_len = packet_buffer_->buffer_len();
1383 :
1384 2432 : transp.tcp = 0;
1385 2432 : }
1386 :
1387 1113 : PktInfo::PktInfo(PktHandler::PktModuleName mod, InterTaskMsg *msg) :
1388 1113 : module(mod),
1389 1113 : pkt(), len(), max_pkt_len(0), data(), ipc(msg), family(Address::UNSPEC),
1390 1113 : type(PktType::MESSAGE), agent_hdr(), ether_type(-1), ip_saddr(), ip_daddr(),
1391 2226 : ip_proto(), sport(), dport(), ttl(0), icmp_chksum(0), tcp_ack(false),
1392 1113 : tunnel(), l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
1393 1113 : ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
1394 1113 : is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
1395 1113 : is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
1396 3339 : eth(), arp(), ip(), ip6(), packet_buffer_() {
1397 1113 : transp.tcp = 0;
1398 1113 : }
1399 :
1400 7243 : PktInfo::~PktInfo() {
1401 7243 : }
1402 :
1403 336 : const AgentHdr &PktInfo::GetAgentHdr() const {
1404 336 : return agent_hdr;
1405 : }
1406 :
1407 75 : void PktInfo::reset_packet_buffer() {
1408 75 : packet_buffer_.reset();
1409 75 : }
1410 :
1411 113 : void PktInfo::AllocPacketBuffer(Agent *agent, uint32_t module, uint16_t len,
1412 : uint32_t mdata) {
1413 : packet_buffer_ = agent->pkt()->packet_buffer_manager()->Allocate
1414 113 : (module, len, mdata);
1415 113 : pkt = packet_buffer_->data();
1416 113 : len = packet_buffer_->data_len();
1417 113 : max_pkt_len = packet_buffer_->buffer_len();
1418 113 : }
1419 :
1420 2204 : void PktInfo::set_len(uint32_t x) {
1421 2204 : packet_buffer_->set_len(x);
1422 2204 : len = x;
1423 2204 : }
1424 :
1425 0 : void PktInfo::UpdateHeaderPtr() {
1426 0 : eth = (struct ether_header *)(pkt);
1427 0 : ip = (struct ip *)(eth + 1);
1428 0 : transp.tcp = (struct tcphdr *)(ip + 1);
1429 0 : }
1430 :
1431 62 : std::size_t PktInfo::hash(const Agent *agent,
1432 : const EcmpLoadBalance &ecmp_load_balance) const {
1433 62 : std::size_t seed = 0;
1434 : // Bug: 1687879
1435 : // Consider that source compute has 2 member ECMP - compute-1 and compute-2
1436 : // Compute-1 is chosed in hash is even and Compute-2 is chosen if hash
1437 : // is add.
1438 : //
1439 : // On Compute-1, the hash computation uses same 5-tuple and will always
1440 : // result in even number. As a result, flows from Compute-1 will go to
1441 : // even-numbered ECMP members and never odd-numbered members.
1442 : // If Compute-2 happens to have only 2 members, all flows go to ecmp-index
1443 : // 0 and never to 1
1444 : //
1445 : // Solution:
1446 : // We need to ensure that hash computed in Compute-1 and Compute-2 are
1447 : // different. We also want to have same hash on agent restarts. So, include
1448 : // vhost-ip also to compute hash
1449 62 : if (agent->params()->flow_use_rid_in_hash()) {
1450 62 : boost::hash_combine(seed, agent->router_id().to_ulong());
1451 : }
1452 :
1453 62 : if (family == Address::INET) {
1454 62 : if (ecmp_load_balance.is_source_ip_set()) {
1455 62 : boost::hash_combine(seed, ip_saddr.to_v4().to_ulong());
1456 : }
1457 62 : if (ecmp_load_balance.is_destination_ip_set()) {
1458 62 : boost::hash_combine(seed, ip_daddr.to_v4().to_ulong());
1459 : }
1460 0 : } else if (family == Address::INET6) {
1461 0 : if (ecmp_load_balance.is_source_ip_set()) {
1462 : uint32_t words[4];
1463 0 : memcpy(words, ip_saddr.to_v6().to_bytes().data(), sizeof(words));
1464 0 : boost::hash_combine(seed, words[0]);
1465 0 : boost::hash_combine(seed, words[1]);
1466 0 : boost::hash_combine(seed, words[2]);
1467 0 : boost::hash_combine(seed, words[3]);
1468 : }
1469 :
1470 0 : if (ecmp_load_balance.is_destination_ip_set()) {
1471 : uint32_t words[4];
1472 0 : memcpy(words, ip_daddr.to_v6().to_bytes().data(), sizeof(words));
1473 0 : boost::hash_combine(seed, words[0]);
1474 0 : boost::hash_combine(seed, words[1]);
1475 0 : boost::hash_combine(seed, words[2]);
1476 0 : boost::hash_combine(seed, words[3]);
1477 : }
1478 : } else {
1479 0 : assert(0);
1480 : }
1481 62 : if (ecmp_load_balance.is_ip_protocol_set()) {
1482 62 : boost::hash_combine(seed, ip_proto);
1483 : }
1484 62 : if (ecmp_load_balance.is_source_port_set()) {
1485 62 : boost::hash_combine(seed, sport);
1486 : }
1487 62 : if (ecmp_load_balance.is_destination_port_set()) {
1488 62 : boost::hash_combine(seed, dport);
1489 : }
1490 :
1491 : // When only the sport changes by 2, its observed that only the lower 32
1492 : // bits of hash changes. Just hash combine upper and lower 32 bit numbers
1493 : // to randomize in case of incremental sport numbers
1494 62 : std::size_t hash = 0;
1495 62 : boost::hash_combine(hash, (seed & 0xFFFFFFFF));
1496 62 : boost::hash_combine(hash, (seed >> 16));
1497 62 : return hash;
1498 : }
1499 :
1500 0 : uint32_t PktInfo::GetUdpPayloadLength() const {
1501 0 : if (ip_proto == IPPROTO_UDP) {
1502 0 : return ntohs(transp.udp->uh_ulen) - sizeof(udphdr);
1503 : }
1504 0 : return 0;
1505 : }
1506 :
1507 1074 : void PktHandler::AddPktTrace(PktModuleName module, PktTrace::Direction dir,
1508 : const PktInfo *pkt) {
1509 1074 : pkt_trace_.at(module).AddPktTrace(PktTrace::In, pkt->len, pkt->pkt,
1510 : &pkt->agent_hdr);
1511 1074 : }
1512 :
1513 75 : void PktHandler::Enqueue(PktModuleName module,
1514 : boost::shared_ptr<PktInfo> pkt_info) {
1515 75 : if (!(proto_list_.at(module)->Enqueue(pkt_info))) {
1516 0 : stats_.PktQThresholdExceeded(module);
1517 : }
1518 75 : return;
1519 : }
1520 :
1521 : ///////////////////////////////////////////////////////////////////////////////
1522 3278 : void PktTrace::Pkt::Copy(Direction d, std::size_t l, uint8_t *msg,
1523 : std::size_t pkt_trace_size, const AgentHdr *hdr) {
1524 3278 : uint16_t hdr_len = sizeof(AgentHdr);
1525 3278 : dir = d;
1526 3278 : len = l + hdr_len;
1527 3278 : memcpy(pkt, hdr, hdr_len);
1528 3278 : memcpy(pkt + hdr_len, msg, std::min(l, (pkt_trace_size - hdr_len)));
1529 3278 : }
1530 :
1531 3278 : void PktTrace::AddPktTrace(Direction dir, std::size_t len, uint8_t *msg,
1532 : const AgentHdr *hdr) {
1533 3278 : if (num_buffers_) {
1534 3278 : end_ = (end_ + 1) % num_buffers_;
1535 3278 : pkt_buffer_[end_].Copy(dir, len, msg, pkt_trace_size_, hdr);
1536 3278 : count_ = std::min((count_ + 1), (uint32_t) num_buffers_);
1537 : }
1538 3278 : }
|