Line data Source code
1 : /*
2 : * * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : * * Copyright Contributors to the OpenSDN project
4 : * */
5 :
6 : #include <stdint.h>
7 : #include "base/os.h"
8 : #include <map>
9 : #include "vr_defs.h"
10 : #include "base/timer.h"
11 : #include "cmn/agent_cmn.h"
12 : #include "pkt/proto.h"
13 : #include "pkt/proto_handler.h"
14 : #include "diag/diag_pkt_handler.h"
15 : #include "diag/diag.h"
16 : #include "diag/diag_proto.h"
17 : #include "diag/ping.h"
18 : #include "diag/overlay_ping.h"
19 : #include "diag/segment_health_check.h"
20 : #include "oper/mirror_table.h"
21 : #include <oper/bridge_route.h>
22 : #include <oper/vxlan.h>
23 : #include <netinet/icmp6.h>
24 : #include "services/icmpv6_handler.h"
25 :
26 : using namespace boost::posix_time;
27 0 : void DiagPktHandler::SetReply() {
28 0 : AgentDiagPktData *ad = (AgentDiagPktData *)pkt_info_->data;
29 0 : ad->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
30 0 : }
31 :
32 0 : void DiagPktHandler::SetDiagChkSum() {
33 : uint8_t proto;
34 0 : if (pkt_info_->ip) {
35 0 : proto = pkt_info_->ip->ip_p;
36 : } else {
37 0 : proto = pkt_info_->ip6->ip6_nxt;
38 : }
39 0 : switch(proto) {
40 0 : case IPPROTO_TCP:
41 0 : pkt_info_->transp.tcp->th_sum = 0xffff;
42 0 : break;
43 :
44 0 : case IPPROTO_UDP:
45 0 : pkt_info_->transp.udp->uh_sum = 0xffff;
46 0 : break;
47 :
48 0 : case IPPROTO_ICMP:
49 0 : pkt_info_->transp.icmp->icmp_cksum = 0xffff;
50 0 : break;
51 0 : case IPPROTO_ICMPV6:
52 0 : pkt_info_->transp.icmp6->icmp6_cksum = 0xffff;
53 0 : break;
54 :
55 0 : default:
56 0 : break;
57 : }
58 0 : }
59 :
60 0 : void DiagPktHandler::BuildReply() {
61 0 : SetReply();
62 0 : Swap();
63 0 : SetDiagChkSum();
64 0 : }
65 :
66 0 : void DiagPktHandler::Reply() {
67 0 : BuildReply();
68 0 : Send(GetInterfaceIndex(), GetVrfIndex(), AgentHdr::TX_ROUTE,
69 : CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
70 0 : }
71 :
72 0 : void DiagPktHandler::SegmentHealthCheckReply() {
73 0 : diag_table_->diag_proto()->IncrementDiagStats(GetInterfaceIndex(),
74 : DiagProto::REQUESTS_RECEIVED);
75 0 : BuildReply();
76 0 : Send(GetInterfaceIndex(), GetVrfIndex(), AgentHdr::TX_SWITCH,
77 : CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
78 0 : diag_table_->diag_proto()->IncrementDiagStats(GetInterfaceIndex(),
79 : DiagProto::REPLIES_SENT);
80 0 : }
81 :
82 0 : bool DiagPktHandler::IsTraceRoutePacket() {
83 0 : if (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ZERO_TTL ||
84 0 : pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ICMP_ERROR)
85 0 : return true;
86 :
87 0 : return false;
88 : }
89 :
90 0 : bool DiagPktHandler::IsOverlayPingPacket() {
91 0 : if (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ROUTER_ALERT)
92 0 : return true;
93 0 : return false;
94 : }
95 :
96 0 : bool DiagPktHandler::HandleTraceRoutePacket() {
97 :
98 0 : uint32_t rabit = 0;
99 : uint8_t ttl;
100 0 : if (pkt_info_->ether_type == ETHERTYPE_IP) {
101 0 : ttl = pkt_info_->ip->ip_ttl;
102 0 : } else if (pkt_info_->ether_type == ETHERTYPE_IPV6) {
103 0 : ttl = pkt_info_->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
104 : } else {
105 0 : return true;
106 : }
107 :
108 0 : if (ttl == 0 ) {
109 0 : if (pkt_info_->dport == VXLAN_UDP_DEST_PORT) {
110 0 : VxlanHdr *vxlan = (VxlanHdr *)(pkt_info_->transp.udp + 1);
111 0 : rabit = ntohl(vxlan->reserved) & OverlayPing::kVxlanRABit;
112 : }
113 :
114 0 : if (rabit) {
115 0 : SendOverlayResponse();
116 : } else {
117 0 : if (pkt_info_->ether_type == ETHERTYPE_IP) {
118 0 : SendTimeExceededPacket();
119 : } else {
120 0 : SendTimeExceededV6Packet();
121 : }
122 : }
123 0 : return true;
124 : }
125 0 : return HandleTraceRouteResponse();
126 : }
127 :
128 : // Send time exceeded ICMP packet
129 0 : void DiagPktHandler::SendTimeExceededPacket() {
130 : // send IP header + 128 bytes from incoming pkt in the icmp response
131 0 : uint16_t icmp_len = pkt_info_->ip->ip_hl * 4 + 128;
132 0 : if (ntohs(pkt_info_->ip->ip_len) < icmp_len)
133 0 : icmp_len = ntohs(pkt_info_->ip->ip_len);
134 0 : boost::scoped_array<uint8_t> icmp_payload(new uint8_t[icmp_len]);
135 0 : memcpy(icmp_payload.get(), pkt_info_->ip, icmp_len);
136 0 : DiagEntry::DiagKey key = -1;
137 0 : if (!ParseIcmpData(icmp_payload.get(), icmp_len, (uint16_t *)&key, true))
138 0 : return;
139 :
140 0 : char *ptr = (char *)pkt_info_->pkt;
141 0 : uint16_t buf_len = pkt_info_->max_pkt_len;
142 :
143 : // Retain the agent-header before ethernet header
144 0 : uint16_t len = (char *)pkt_info_->eth - (char *)pkt_info_->pkt;
145 :
146 0 : Ip4Address src_ip(0);
147 0 : VmInterface *vm_itf = dynamic_cast<VmInterface *>
148 0 : (agent()->interface_table()->FindInterface(GetInterfaceIndex()));
149 0 : if (vm_itf == NULL) {
150 0 : src_ip = agent()->router_id();
151 : } else {
152 0 : if (vm_itf->vn() == NULL) {
153 0 : return;
154 : }
155 0 : const VnIpam *ipam = vm_itf->vn()->GetIpam(pkt_info_->ip_saddr.to_v4());
156 0 : if (ipam == NULL) {
157 0 : return;
158 : }
159 0 : src_ip = ipam->default_gw.to_v4();
160 : }
161 :
162 : // Form ICMP Packet with EthHdr - IP Header - ICMP Header
163 0 : len += EthHdr(ptr + len, buf_len - len, agent()->vhost_interface()->mac(),
164 0 : MacAddress(pkt_info_->eth->ether_shost), ETHERTYPE_IP,
165 : VmInterface::kInvalidVlanId);
166 :
167 0 : uint16_t ip_len = sizeof(iphdr) + 8 + icmp_len;
168 0 : len += IpHdr(ptr + len, buf_len - len, ip_len,
169 0 : htonl(src_ip.to_ulong()),
170 0 : htonl(pkt_info_->ip_saddr.to_v4().to_ulong()),
171 : IPPROTO_ICMP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
172 :
173 0 : struct icmp *hdr = (struct icmp *) (ptr + len);
174 0 : memset((uint8_t *)hdr, 0, 8);
175 0 : hdr->icmp_type = ICMP_TIME_EXCEEDED;
176 0 : hdr->icmp_code = ICMP_EXC_TTL;
177 0 : memcpy(ptr + len + 8, icmp_payload.get(), icmp_len);
178 0 : IcmpChecksum((char *)hdr, 8 + icmp_len);
179 0 : len += 8 + icmp_len;
180 :
181 0 : pkt_info_->set_len(len);
182 :
183 0 : Send(GetInterfaceIndex(), pkt_info_->vrf, AgentHdr::TX_SWITCH,
184 : PktHandler::ICMP);
185 0 : }
186 :
187 :
188 0 : void DiagPktHandler::SendTimeExceededV6Packet() {
189 : uint8_t icmp_payload[icmp_payload_len];
190 0 : uint16_t icmp_len = ntohs(pkt_info_->ip6->ip6_plen);
191 :
192 0 : if (icmp_len > icmp_payload_len)
193 0 : icmp_len = icmp_payload_len;
194 0 : memcpy(icmp_payload, pkt_info_->ip6, icmp_len);
195 :
196 0 : DiagEntry::DiagKey key = -1;
197 0 : if (!ParseIcmpData(icmp_payload, icmp_len, (uint16_t *)&key, false))
198 0 : return;
199 :
200 0 : char *buff = (char *)pkt_info_->pkt;
201 0 : uint16_t buff_len = pkt_info_->max_pkt_len;
202 : // Retain the agent-header before ethernet header
203 :
204 0 : uint16_t eth_len = EthHdr(buff, buff_len, GetInterfaceIndex(),
205 : agent()->vhost_interface()->mac(),
206 0 : MacAddress(pkt_info_->eth->ether_shost),
207 0 : ETHERTYPE_IPV6);
208 :
209 0 : VmInterface *vm_itf = dynamic_cast<VmInterface *>
210 0 : (agent()->interface_table()->FindInterface(GetInterfaceIndex()));
211 0 : if (vm_itf == NULL || vm_itf->layer3_forwarding() == false ||
212 0 : vm_itf->vn() == NULL) {
213 0 : return;
214 : }
215 :
216 0 : const VnIpam *ipam = vm_itf->vn()->GetIpam(pkt_info_->ip_saddr.to_v6());
217 0 : if (ipam == NULL)
218 0 : return ;
219 :
220 0 : pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len);
221 0 : Ip6Hdr(pkt_info_->ip6, icmp_len+ICMP_UNREACH_HDR_LEN, IPV6_ICMP_NEXT_HEADER,
222 0 : DEFAULT_IP_TTL, ipam->default_gw.to_v6().to_bytes().data(),
223 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data());
224 :
225 0 : icmp6_hdr *icmp = pkt_info_->transp.icmp6 =
226 0 : (icmp6_hdr *)(pkt_info_->pkt + eth_len
227 0 : + sizeof(ip6_hdr));
228 0 : icmp->icmp6_type = ICMP_TIME_EXCEEDED;
229 0 : icmp->icmp6_code = ICMP_EXC_TTL;
230 0 : icmp->icmp6_mtu = 0;
231 0 : icmp->icmp6_cksum = 0;
232 0 : icmp->icmp6_cksum =
233 0 : Icmpv6Csum(ipam->default_gw.to_v6().to_bytes().data(),
234 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data(),
235 : icmp, icmp_len);
236 0 : memcpy(buff + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN,
237 : icmp_payload, icmp_len);
238 0 : pkt_info_->set_len(icmp_len + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN);
239 :
240 : uint16_t command =
241 0 : (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
242 0 : (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH;
243 :
244 0 : Send(GetInterfaceIndex(), pkt_info_->vrf, command,
245 : PktHandler::ICMPV6);
246 :
247 : }
248 :
249 0 : bool DiagPktHandler::HandleTraceRouteResponse() {
250 0 : uint8_t *data = (uint8_t *)(pkt_info_->transp.icmp) + 8;
251 0 : uint16_t len = pkt_info_->len - (data - pkt_info_->pkt);
252 0 : bool is_v4 = pkt_info_->ether_type == ETHERTYPE_IP;
253 0 : DiagEntry::DiagKey key = -1;
254 : // if it is Overlay packet get the key from Oam data
255 0 : if (IsOverlayPingPacket()) {
256 0 : OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
257 0 : key = ntohs(oamdata->org_handle_);
258 : } else {
259 0 : if (!ParseIcmpData(data, len, (uint16_t *)&key, is_v4))
260 0 : return true;
261 : }
262 :
263 0 : DiagEntry *entry = diag_table_->Find(key);
264 0 : if (!entry) return true;
265 :
266 0 : if (is_v4)
267 0 : address_ = pkt_info_->ip_saddr.to_v4().to_string();
268 : else {
269 0 : address_ = pkt_info_->ip_saddr.to_v6().to_string();
270 : }
271 0 : entry->HandleReply(this);
272 :
273 : DiagEntryOp *op;
274 0 : if (IsDone()) {
275 0 : op = new DiagEntryOp(DiagEntryOp::DEL, entry);
276 : } else {
277 0 : op = new DiagEntryOp(DiagEntryOp::RETRY, entry);
278 : }
279 0 : entry->diag_table()->Enqueue(op);
280 :
281 0 : return true;
282 : }
283 :
284 0 : bool DiagPktHandler::ParseIcmpData(const uint8_t *data, uint16_t data_len,
285 : uint16_t *key, bool is_v4) {
286 0 : if (data_len < sizeof(struct ip))
287 0 : return false;
288 0 : struct ip *ip_hdr = (struct ip *)(data);
289 0 : *key = ntohs(ip_hdr->ip_id);
290 0 : uint16_t len = sizeof(struct ip);
291 : uint8_t protocol;
292 :
293 0 : if (ip_hdr->ip_src.s_addr == htonl(agent()->router_id().to_ulong()) ||
294 0 : ip_hdr->ip_dst.s_addr == htonl(agent()->router_id().to_ulong())) {
295 : // Check inner header
296 0 : switch (ip_hdr->ip_p) {
297 0 : case IPPROTO_GRE : {
298 0 : if (data_len < len + sizeof(GreHdr))
299 0 : return true;
300 0 : len += sizeof(GreHdr);
301 0 : break;
302 : }
303 :
304 0 : case IPPROTO_UDP : {
305 0 : if (data_len < len + sizeof(udphdr))
306 0 : return true;
307 0 : len += sizeof(udphdr);
308 0 : break;
309 : }
310 :
311 0 : default: {
312 0 : return true;
313 : }
314 : }
315 0 : len += sizeof(MplsHdr);
316 0 : if (is_v4) {
317 0 : if (data_len < len + sizeof(struct ip))
318 0 : return true;
319 0 : ip_hdr = (struct ip *)(data + len);
320 0 : len += sizeof(struct ip);
321 0 : protocol = ip_hdr->ip_p;
322 : } else {
323 0 : if (data_len < len + sizeof(struct ip6_hdr))
324 0 : return true;
325 0 : struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(data + len);
326 0 : len += sizeof(struct ip6_hdr);
327 0 : protocol = ip6_hdr->ip6_nxt;
328 : }
329 0 : switch (protocol) {
330 0 : case IPPROTO_TCP:
331 0 : len += sizeof(tcphdr);
332 0 : break;
333 :
334 0 : case IPPROTO_UDP:
335 0 : len += sizeof(udphdr);
336 0 : break;
337 :
338 0 : case IPPROTO_ICMP:
339 0 : len += 8;
340 0 : break;
341 0 : case IPPROTO_ICMPV6:
342 0 : len += 8;
343 0 : break;
344 0 : default:
345 0 : return true;
346 : }
347 0 : if (data_len < len + sizeof(AgentDiagPktData))
348 0 : return true;
349 :
350 0 : AgentDiagPktData *agent_data = (AgentDiagPktData *)(data + len);
351 0 : if (ntohl(agent_data->op_) == AgentDiagPktData::DIAG_REQUEST) {
352 0 : agent_data->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
353 0 : } else if (ntohl(agent_data->op_) == AgentDiagPktData::DIAG_REPLY) {
354 0 : *key = ntohs(agent_data->key_);
355 0 : done_ = true;
356 : }
357 : }
358 :
359 0 : return true;
360 : }
361 :
362 0 : bool DiagPktHandler::Run() {
363 0 : bool isoverlay_packet = IsOverlayPingPacket();
364 0 : AgentDiagPktData *ad = NULL;
365 0 : AgentDiagPktData tempdata;
366 :
367 0 : if (IsTraceRoutePacket()) {
368 0 : return HandleTraceRoutePacket();
369 : }
370 :
371 0 : if (isoverlay_packet) {
372 : // Process Overlay packet
373 : // papulate diag data AgentDiagPktData here
374 0 : memset((void*)&tempdata, 0, sizeof(AgentDiagPktData));
375 0 : ad = &tempdata;
376 0 : OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
377 0 : if (oamdata->msg_type_ == OverlayOamPktData::OVERLAY_ECHO_REQUEST) {
378 0 : ad->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
379 0 : } else if (oamdata->msg_type_ == OverlayOamPktData::OVERLAY_ECHO_REPLY) {
380 0 : ad->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
381 : }
382 :
383 0 : ad->key_ = oamdata->org_handle_;
384 : } else {
385 0 : ad = (AgentDiagPktData *)pkt_info_->data;
386 : }
387 :
388 0 : if (!ad) {
389 : //Ignore if packet doesnt have proper L4 header
390 0 : return true;
391 : }
392 :
393 0 : SegmentHealthCheckPkt *segment_hc_pkt = NULL;
394 0 : DiagEntry::DiagKey key = ntohs(ad->key_);
395 0 : DiagEntry *entry = diag_table_->Find(key);
396 0 : if (entry) {
397 0 : segment_hc_pkt = dynamic_cast< SegmentHealthCheckPkt * >(entry);
398 : }
399 0 : if (ntohl(ad->op_) == AgentDiagPktData::DIAG_REQUEST) {
400 : //Request received swap the packet
401 : //and dump the packet back
402 0 : if (isoverlay_packet) {
403 : // Reply packet with after setting the TLV content.
404 0 : SendOverlayResponse();
405 0 : return true;
406 : }
407 0 : if (segment_hc_pkt) {
408 0 : SegmentHealthCheckReply();
409 : } else {
410 0 : Reply();
411 : }
412 0 : return true;
413 : }
414 :
415 0 : if (ntohl(ad->op_) != AgentDiagPktData::DIAG_REPLY) {
416 0 : return true;
417 : }
418 : //Reply for a query we sent
419 0 : if (!entry) {
420 0 : return true;
421 : }
422 0 : entry->HandleReply(this);
423 :
424 0 : if (segment_hc_pkt) {
425 : /* No further processing required for Segment Health check packet */
426 0 : return true;
427 : }
428 :
429 0 : if (entry->GetSeqNo() == entry->GetMaxAttempts()) {
430 : DiagEntryOp *op;
431 0 : op = new DiagEntryOp(DiagEntryOp::DEL, entry);
432 0 : entry->diag_table()->Enqueue(op);
433 : } else {
434 0 : entry->Retry();
435 : }
436 :
437 0 : return true;
438 : }
439 :
440 0 : void DiagPktHandler::TcpHdr(in_addr_t src, uint16_t sport, in_addr_t dst,
441 : uint16_t dport, bool is_syn, uint32_t seq_no,
442 : uint16_t len) {
443 0 : struct tcphdr *tcp = pkt_info_->transp.tcp;
444 0 : tcp->th_sport = htons(sport);
445 0 : tcp->th_dport = htons(dport);
446 :
447 0 : if (is_syn) {
448 0 : tcp->th_flags &= ~TH_ACK;
449 : } else {
450 : //If not sync, by default we are sending an ack
451 0 : tcp->th_flags &= ~TH_SYN;
452 : }
453 :
454 0 : tcp->th_seq = htons(seq_no);
455 0 : tcp->th_ack = htons(seq_no + 1);
456 : //Just a random number;
457 0 : tcp->th_win = htons(1000);
458 0 : tcp->th_off = 5;
459 0 : tcp->th_sum = 0;
460 0 : tcp->th_sum = TcpCsum(src, dst, len, tcp);
461 0 : }
462 :
463 0 : void DiagPktHandler::TcpHdr(uint16_t len, const uint8_t *src, uint16_t sport,
464 : const uint8_t *dest, uint16_t dport, bool is_syn,
465 : uint32_t seq_no, uint8_t next_hdr){
466 0 : struct tcphdr *tcp = pkt_info_->transp.tcp;
467 0 : tcp->th_sport = htons(sport);
468 0 : tcp->th_dport = htons(dport);
469 :
470 0 : if (is_syn) {
471 0 : tcp->th_flags &= ~TH_ACK;
472 : } else {
473 : //If not sync, by default we are sending an ack
474 0 : tcp->th_flags &= ~TH_SYN;
475 : }
476 :
477 0 : tcp->th_seq = htons(seq_no);
478 0 : tcp->th_ack = htons(seq_no + 1);
479 : //Just a random number;
480 0 : tcp->th_win = htons(1000);
481 0 : tcp->th_off = 5;
482 0 : tcp->th_sum = 0;
483 0 : tcp->th_sum = Ipv6Csum(src, dest, len, next_hdr, (uint16_t *)tcp);
484 0 : }
485 :
486 0 : uint16_t DiagPktHandler::TcpCsum(in_addr_t src, in_addr_t dest, uint16_t len,
487 : tcphdr *tcp) {
488 0 : uint32_t sum = 0;
489 0 : PseudoTcpHdr phdr(src, dest, htons(len));
490 0 : sum = Sum((uint16_t *)&phdr, sizeof(PseudoTcpHdr), sum);
491 0 : return Csum((uint16_t *)tcp, len, sum);
492 : }
493 :
494 0 : void DiagPktHandler::SwapL4() {
495 0 : if (pkt_info_->ip_proto == IPPROTO_TCP) {
496 0 : tcphdr *tcp = pkt_info_->transp.tcp;
497 0 : TcpHdr(htonl(pkt_info_->ip_daddr.to_v4().to_ulong()),
498 0 : ntohs(tcp->th_dport),
499 0 : htonl(pkt_info_->ip_saddr.to_v4().to_ulong()),
500 0 : ntohs(tcp->th_sport), false, ntohs(tcp->th_ack),
501 0 : ntohs(pkt_info_->ip->ip_len) - sizeof(struct ip));
502 0 : } else if (pkt_info_->ip_proto == IPPROTO_UDP) {
503 0 : udphdr *udp = pkt_info_->transp.udp;
504 0 : UdpHdr(ntohs(udp->uh_ulen), pkt_info_->ip_daddr.to_v4().to_ulong(),
505 0 : ntohs(udp->uh_dport), pkt_info_->ip_saddr.to_v4().to_ulong(),
506 0 : ntohs(udp->uh_sport));
507 0 : } else if (pkt_info_->ip_proto == IPPROTO_ICMP) {
508 0 : struct icmp *hdr = (struct icmp *) (pkt_info_->transp.icmp);
509 0 : if (hdr->icmp_type == ICMP_ECHO) {
510 0 : hdr->icmp_type = ICMP_ECHOREPLY;
511 0 : hdr->icmp_code = 0;
512 : }
513 : /* We do not change sequence and identifier fields of ICMP header */
514 : }
515 0 : }
516 :
517 0 : void DiagPktHandler::Swapv6L4() {
518 0 : if (pkt_info_->ip_proto == IPPROTO_TCP) {
519 0 : tcphdr *tcp = pkt_info_->transp.tcp;
520 0 : TcpHdr(ntohs(pkt_info_->ip6->ip6_ctlun.ip6_un1.ip6_un1_plen) - sizeof(struct ip6_hdr),
521 0 : pkt_info_->ip_daddr.to_v6().to_bytes().data(), ntohs(tcp->th_dport),
522 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data(), ntohs(tcp->th_sport),
523 0 : false, ntohs(tcp->th_ack), IPPROTO_TCP);
524 0 : } else if (pkt_info_->ip_proto == IPPROTO_UDP) {
525 0 : udphdr *udp = pkt_info_->transp.udp;
526 0 : UdpHdr(ntohs(udp->uh_ulen), pkt_info_->ip_daddr.to_v6().to_bytes().data(),
527 0 : ntohs(udp->uh_dport), pkt_info_->ip_saddr.to_v6().to_bytes().data(),
528 0 : ntohs(udp->uh_sport), IPPROTO_UDP);
529 : }
530 0 : }
531 :
532 0 : void DiagPktHandler::SwapIpHdr() {
533 : //IpHdr expects IP address to be in network format
534 0 : struct ip *ip = pkt_info_->ip;
535 0 : IpHdr(ntohs(ip->ip_len), ip->ip_dst.s_addr,
536 0 : ip->ip_src.s_addr, ip->ip_p, DEFAULT_IP_ID, DEFAULT_IP_TTL);
537 0 : }
538 :
539 0 : void DiagPktHandler::SwapIp6Hdr() {
540 : //Ip6Hdr expects IPv6 address to be in network format
541 0 : struct ip6_hdr *ip6 = pkt_info_->ip6;
542 0 : Ip6Hdr(ip6, ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen),
543 0 : ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt, DEFAULT_IP_TTL,
544 0 : pkt_info_->ip_daddr.to_v6().to_bytes().data(),
545 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data());
546 0 : }
547 :
548 0 : void DiagPktHandler::SwapEthHdr() {
549 0 : struct ether_header *eth = pkt_info_->eth;
550 0 : EthHdr(MacAddress(eth->ether_dhost), MacAddress(eth->ether_shost), ntohs(eth->ether_type));
551 0 : }
552 :
553 0 : void DiagPktHandler::Swap() {
554 0 : if (pkt_info_->ether_type == ETHERTYPE_IPV6) {
555 0 : Swapv6L4();
556 0 : SwapIp6Hdr();
557 : } else {
558 0 : SwapL4();
559 0 : SwapIpHdr();
560 : }
561 0 : SwapEthHdr();
562 0 : }
563 :
564 0 : void DiagPktHandler::SetReturnCode(OverlayOamPktData *oamdata) {
565 0 : oamdata->return_code_ = OverlayOamPktData::OVERLAY_SEGMENT_NOT_PRESENT;
566 :
567 0 : uint16_t type = ntohs(oamdata->oamtlv_.type_);
568 0 : if (type != OamTlv::VXLAN_PING_IPv4 && type != OamTlv::VXLAN_PING_IPv6) {
569 0 : return;
570 : }
571 :
572 0 : const int tlv_length = ntohs(oamdata->oamtlv_.length_);
573 : // VXLAN VNI and IPv4 / IPv6 sender address
574 0 : int parsed_tlv = (type == OamTlv::VXLAN_PING_IPv4) ? 8 : 20;
575 :
576 : VxLanId *vxlan =
577 0 : Agent::GetInstance()->vxlan_table()->Find(pkt_info_->tunnel.vxlan_id);
578 0 : if (!vxlan) {
579 0 : return;
580 : }
581 :
582 0 : const VrfNH *vrf_nh = dynamic_cast<const VrfNH *> (vxlan->nexthop());
583 0 : if (!vrf_nh) {
584 0 : return;
585 : }
586 :
587 0 : const VrfEntry *vrf = vrf_nh->GetVrf();
588 0 : if (!vrf || vrf->IsDeleted()) {
589 0 : return;
590 : }
591 :
592 0 : oamdata->return_code_ = OverlayOamPktData::RETURN_CODE_OK;
593 0 : while (tlv_length - parsed_tlv >= (int) sizeof(SubTlv)) {
594 0 : SubTlv *subtlv = (SubTlv *) (oamdata->oamtlv_.data_ + parsed_tlv);
595 0 : parsed_tlv += sizeof(SubTlv);
596 :
597 0 : const int subtlv_length = ntohs(subtlv->length_);
598 0 : if (ntohs(subtlv->type_) != SubTlv::END_SYSTEM_MAC) {
599 0 : parsed_tlv += subtlv_length;
600 0 : continue;
601 : }
602 :
603 0 : int parsed_subtlv = 0;
604 : // check that we have bytes for MAC (6) and return code (2)
605 0 : while (subtlv_length - parsed_subtlv >=
606 : (int) sizeof(SubTlv::EndSystemMac)) {
607 0 : SubTlv::EndSystemMac *end_system_mac =
608 : (SubTlv::EndSystemMac *)
609 0 : (oamdata->oamtlv_.data_ + parsed_tlv + parsed_subtlv);
610 0 : MacAddress mac(end_system_mac->mac);
611 : BridgeAgentRouteTable *table =
612 0 : static_cast<BridgeAgentRouteTable *> (vrf->GetBridgeRouteTable());
613 0 : if (table->FindRoute(mac, Peer::EVPN_PEER) != NULL ||
614 0 : table->FindRoute(mac, Peer::LOCAL_VM_PORT_PEER) != NULL ||
615 0 : table->FindRoute(mac, Peer::LOCAL_VM_PEER) != NULL) {
616 0 : end_system_mac->return_code = htons(SubTlv::END_SYSTEM_PRESENT);
617 : } else {
618 0 : end_system_mac->return_code =
619 0 : htons(SubTlv::END_SYSTEM_NOT_PRESENT);
620 : }
621 0 : parsed_subtlv += sizeof(SubTlv::EndSystemMac);
622 : }
623 0 : parsed_tlv += subtlv_length;
624 : }
625 : }
626 :
627 0 : void DiagPktHandler::TunnelHdrSwap() {
628 0 : struct ether_header *eth = pkt_info_->tunnel.eth;
629 0 : EthHdr((char *)eth, sizeof(struct ether_header), MacAddress(eth->ether_dhost),
630 0 : MacAddress(eth->ether_shost), ntohs(eth->ether_type),
631 : VmInterface::kInvalidVlanId);
632 0 : struct ip *ip = pkt_info_->tunnel.ip;
633 0 : IpHdr((char *)ip, sizeof(struct ip), ntohs(ip->ip_len),ip->ip_dst.s_addr,
634 0 : ip->ip_src.s_addr, ip->ip_p, DEFAULT_IP_ID, DEFAULT_IP_TTL);
635 0 : }
636 :
637 0 : void DiagPktHandler::SendOverlayResponse() {
638 0 : Agent *agent = Agent::GetInstance();
639 0 : TunnelHdrSwap();
640 :
641 0 : OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
642 0 : if (oamdata->reply_mode_ == OverlayOamPktData::DONT_REPLY) {
643 0 : return ;
644 : }
645 :
646 0 : SetReturnCode(oamdata);
647 :
648 0 : oamdata->msg_type_ = OverlayOamPktData::OVERLAY_ECHO_REPLY;
649 : boost::posix_time::ptime
650 0 : epoch(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
651 0 : boost::posix_time::ptime time = microsec_clock::universal_time();
652 0 : boost::posix_time::time_duration td = time - epoch;
653 0 : oamdata->timerecv_sec_ = htonl(td.total_seconds());
654 0 : oamdata->timerecv_misec_ = htonl(td.total_microseconds() -
655 0 : (td.total_seconds()*1000000));
656 :
657 0 : PhysicalInterfaceKey key1(agent->fabric_interface_name());
658 0 : Interface *intf = static_cast<Interface *>
659 0 : (agent->interface_table()->Find(&key1, true));
660 0 : Send(intf->id(), agent->fabric_vrf()->vrf_id(),
661 : AgentHdr::TX_SWITCH, CMD_PARAM_PACKET_CTRL,
662 : CMD_PARAM_1_DIAG, PktHandler::DIAG);
663 0 : }
|