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